MNT-23880 Integrate the Alfresco Admin Console with the IDS (#2362)

* MNT-23880 Integrate IDS with the Admin Console

* MNT-23880 Remove diamond expressions

* MNT-23880 Refactor

* MNT-23880 Move requesting authentication

* MNT-23880 Fix comment

* MNT-23880 Check if AdminConsoleAuthenticator is active

* MNT-23880 Fix DefaultAdminConsoleAuthenticator + PMD issues

* MNT-23880 Fix PMD issues

* MNT-23880 Refactor

* MNT-23880 Refactor RemoteUserAuthenticatorFactory
This commit is contained in:
Damian Ujma
2023-12-14 11:30:53 +01:00
committed by GitHub
parent 5580609010
commit 06c35ea379
17 changed files with 1317 additions and 44 deletions

View File

@@ -34,6 +34,7 @@ import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.external.AdminConsoleAuthenticator;
import org.alfresco.repo.security.authentication.external.RemoteUserMapper;
import org.alfresco.repo.web.auth.AuthenticationListener;
import org.alfresco.repo.web.auth.TicketCredentials;
@@ -67,16 +68,18 @@ import java.util.Set;
*/
public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactory
{
private static Log logger = LogFactory.getLog(RemoteUserAuthenticatorFactory.class);
private static final Log LOGGER = LogFactory.getLog(RemoteUserAuthenticatorFactory.class);
public static final long GET_REMOTE_USER_TIMEOUT_MILLISECONDS_DEFAULT = 10000L; // 10 sec
protected RemoteUserMapper remoteUserMapper;
protected AuthenticationComponent authenticationComponent;
protected AdminConsoleAuthenticator adminConsoleAuthenticator;
private boolean alwaysAllowBasicAuthForAdminConsole = true;
List<String> adminConsoleScriptFamilies;
long getRemoteUserTimeoutMilliseconds = GET_REMOTE_USER_TIMEOUT_MILLISECONDS_DEFAULT;
public void setRemoteUserMapper(RemoteUserMapper remoteUserMapper)
{
this.remoteUserMapper = remoteUserMapper;
@@ -117,6 +120,12 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
this.getRemoteUserTimeoutMilliseconds = getRemoteUserTimeoutMilliseconds;
}
public void setAdminConsoleAuthenticator(
AdminConsoleAuthenticator adminConsoleAuthenticator)
{
this.adminConsoleAuthenticator = adminConsoleAuthenticator;
}
@Override
public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res)
{
@@ -140,36 +149,46 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
{
boolean authenticated = false;
if (logger.isTraceEnabled())
if (LOGGER.isTraceEnabled())
{
logger.trace("Authenticate level required: " + required + " is guest: " + isGuest);
LOGGER.trace("Authenticate level required: " + required + " is guest: " + isGuest);
}
String userId = null;
if (isRemoteUserMapperActive())
{
if (isAlwaysAllowBasicAuthForAdminConsole())
{
final boolean useTimeoutForAdminAccessingAdminConsole = shouldUseTimeoutForAdminAccessingAdminConsole(required, isGuest);
if (useTimeoutForAdminAccessingAdminConsole && isBasicAuthHeaderPresentForAdmin())
{
return callBasicAuthForAdminConsoleAccess(required, isGuest);
}
try
{
userId = getRemoteUserWithTimeout(useTimeoutForAdminAccessingAdminConsole);
}
catch (AuthenticationTimeoutException e)
{
//return basic auth challenge
return false;
}
}
else
if (servletReq.getServiceMatch() != null &&
isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript()) && isAdminConsoleAuthenticatorActive())
{
// retrieve the remote user if configured and available - authenticate that user directly
userId = getRemoteUser();
userId = getAdminConsoleUser();
}
if (userId == null)
{
if (isAlwaysAllowBasicAuthForAdminConsole())
{
final boolean useTimeoutForAdminAccessingAdminConsole = shouldUseTimeoutForAdminAccessingAdminConsole(required, isGuest);
if (useTimeoutForAdminAccessingAdminConsole && isBasicAuthHeaderPresentForAdmin())
{
return callBasicAuthForAdminConsoleAccess(required, isGuest);
}
try
{
userId = getRemoteUserWithTimeout(useTimeoutForAdminAccessingAdminConsole);
}
catch (AuthenticationTimeoutException e)
{
//return basic auth challenge
return false;
}
}
else
{
// retrieve the remote user if configured and available - authenticate that user directly
userId = getRemoteUser();
}
}
}
@@ -208,9 +227,9 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
{
// Validate the ticket for the current SessionUser
authenticationService.validate(user.getTicket());
if (logger.isDebugEnabled())
if (LOGGER.isDebugEnabled())
{
logger.debug("Ticket is valid. Retaining cached user in session.");
LOGGER.debug("Ticket is valid. Retaining cached user in session.");
}
listener.userAuthenticated(new TicketCredentials(user.getTicket()));
authenticated = true;
@@ -222,9 +241,9 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
}
catch (AuthenticationException authErr)
{
if (logger.isDebugEnabled())
if (LOGGER.isDebugEnabled())
{
logger.debug("An Authentication error occur. Removing User session.", authErr);
LOGGER.debug("An Authentication error occur. Removing User session.", authErr);
}
session.removeAttribute(AuthenticationDriver.AUTHENTICATION_USER);
session.invalidate();
@@ -236,15 +255,20 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
authenticated = super.authenticate(required, isGuest);
}
}
if(!authenticated && servletReq.getServiceMatch() != null &&
isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript()) && isAdminConsoleAuthenticatorActive())
{
adminConsoleAuthenticator.requestAuthentication(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
}
return authenticated;
}
private boolean callBasicAuthForAdminConsoleAccess(RequiredAuthentication required, boolean isGuest)
{
// return REST call, after a timeout/basic auth challenge
if (logger.isTraceEnabled())
if (LOGGER.isTraceEnabled())
{
logger.trace("An Admin Console request has come in with Basic Auth headers present for an admin user.");
LOGGER.trace("An Admin Console request has come in with Basic Auth headers present for an admin user.");
}
// In order to prompt for another password, in case it was not entered correctly,
// the output of this method should be returned by the calling "authenticate" method;
@@ -258,9 +282,9 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
boolean useTimeoutForAdminAccessingAdminConsole = RequiredAuthentication.admin.equals(required) && !isGuest &&
servletReq.getServiceMatch() != null && isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript());
if (logger.isTraceEnabled())
if (LOGGER.isTraceEnabled())
{
logger.trace("Should ensure that the admins can login with basic auth: " + useTimeoutForAdminAccessingAdminConsole);
LOGGER.trace("Should ensure that the admins can login with basic auth: " + useTimeoutForAdminAccessingAdminConsole);
}
return useTimeoutForAdminAccessingAdminConsole;
}
@@ -270,6 +294,11 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
return remoteUserMapper != null && (!(remoteUserMapper instanceof ActivateableBean) || ((ActivateableBean) remoteUserMapper).isActive());
}
private boolean isAdminConsoleAuthenticatorActive()
{
return adminConsoleAuthenticator != null && (!(adminConsoleAuthenticator instanceof ActivateableBean) || ((ActivateableBean) adminConsoleAuthenticator).isActive());
}
protected boolean isAdminConsoleWebScript(WebScript webScript)
{
if (webScript == null || adminConsoleScriptFamilies == null || webScript.getDescription() == null
@@ -278,9 +307,9 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
return false;
}
if (logger.isTraceEnabled())
if (LOGGER.isTraceEnabled())
{
logger.trace("WebScript: " + webScript + " has these families: " + webScript.getDescription().getFamilys());
LOGGER.trace("WebScript: " + webScript + " has these families: " + webScript.getDescription().getFamilys());
}
// intersect the "family" sets defined
@@ -288,9 +317,9 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
families.retainAll(adminConsoleScriptFamilies);
final boolean isAdminConsole = !families.isEmpty();
if (logger.isTraceEnabled() && isAdminConsole)
if (LOGGER.isTraceEnabled() && isAdminConsole)
{
logger.trace("Detected an Admin Console webscript: " + webScript );
LOGGER.trace("Detected an Admin Console webscript: " + webScript);
}
return isAdminConsole;
@@ -316,7 +345,7 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
}
catch (Exception e)
{
logger.warn("Exception trying to get the remote user: " + e.getMessage(), e);
LOGGER.warn("Exception trying to get the remote user: " + e.getMessage(), e);
}
returnedRemoteUser = getRemoteUserRunnable.getReturnedRemoteUser();
@@ -330,9 +359,9 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
final String message = "Could not get the remote user in a reasonable time: " + getRemoteUserTimeoutMilliseconds + " milliseconds. "
+ "Adjust the timeout property 'authentication.getRemoteUserTimeoutMilliseconds' if required.";
if (logger.isWarnEnabled())
if (LOGGER.isWarnEnabled())
{
logger.warn("Returning basic auth challenge for Admin Console. Cause: " + message);
LOGGER.warn("Returning basic auth challenge for Admin Console. Cause: " + message);
}
HttpServletResponse res = servletRes.getHttpServletResponse();
res.setStatus(401);
@@ -379,15 +408,29 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
private void logRemoteUserID(String userId)
{
if (logger.isDebugEnabled())
if (LOGGER.isDebugEnabled())
{
String message = (userId == null) ?
"No external user ID in request." :
"Extracted external user ID from request: " + AuthenticationUtil.maskUsername(userId);
logger.debug(message);
LOGGER.debug(message);
}
}
protected String getAdminConsoleUser()
{
String userId = null;
if (isRemoteUserMapperActive())
{
userId = adminConsoleAuthenticator.getAdminConsoleUser(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
}
logRemoteUserID(userId);
return userId;
}
class GetRemoteUserRunnable implements Runnable
{
private volatile String returnedRemoteUser;

View File

@@ -213,6 +213,7 @@
<property name="authenticationComponent" ref="authenticationComponent" />
<property name="authenticationListener" ref="webScriptAuthenticationListener"/>
<property name="remoteUserMapper" ref="RemoteUserMapper" />
<property name="adminConsoleAuthenticator" ref="AdminConsoleAuthenticator" />
<property name="alwaysAllowBasicAuthForAdminConsole">
<value>${authentication.alwaysAllowBasicAuthForAdminConsole.enabled}</value>
</property>