Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)

90921: MNT-12765 - No endpoints can be configured in Share that use external-auth and a different URL - as they will be redirected down the URL for 'alfresco' endpoint.
   Merged PROPERTY_GROUP_PROTOTYPING (5.0/Cloud) to HEAD-BUG-FIX (5.0/Cloud)
      90742: Refactoring of SSO paths
       - Added Session User authentication support to RemoteUserAuthenticatorFactory - so can use cookie based auth for example with Public API route.
       - Tidy up of common duplicated code constants e.g. _alfAuthTicket
       - Added Global Authentication Filter around the /api/* endpoint to allow SSO active over Public API


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@94744 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2015-01-31 11:07:31 +00:00
parent e9a5d1c670
commit df3a2630ab
5 changed files with 180 additions and 141 deletions

View File

@@ -18,11 +18,17 @@
*/ */
package org.alfresco.repo.web.scripts.servlet; package org.alfresco.repo.web.scripts.servlet;
import javax.servlet.http.HttpSession;
import org.alfresco.repo.SessionUser;
import org.alfresco.repo.management.subsystems.ActivateableBean; import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.external.RemoteUserMapper; import org.alfresco.repo.security.authentication.external.RemoteUserMapper;
import org.alfresco.repo.web.auth.AuthenticationListener; import org.alfresco.repo.web.auth.AuthenticationListener;
import org.alfresco.repo.web.auth.TicketCredentials; import org.alfresco.repo.web.auth.TicketCredentials;
import org.alfresco.repo.web.auth.WebCredentials;
import org.alfresco.repo.webdav.auth.AuthenticationDriver;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Authenticator; import org.springframework.extensions.webscripts.Authenticator;
@@ -80,18 +86,54 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
@Override @Override
public boolean authenticate(RequiredAuthentication required, boolean isGuest) public boolean authenticate(RequiredAuthentication required, boolean isGuest)
{ {
boolean authenticated = false;
// retrieve the remote user if configured and available - authenticate that user directly // retrieve the remote user if configured and available - authenticate that user directly
final String userId = getRemoteUser(); final String userId = getRemoteUser();
if (userId != null) if (userId != null)
{ {
authenticationComponent.setCurrentUser(userId); authenticationComponent.setCurrentUser(userId);
listener.userAuthenticated(new TicketCredentials(authenticationService.getCurrentTicket())); listener.userAuthenticated(new TicketCredentials(authenticationService.getCurrentTicket()));
return true; authenticated = true;
} }
else else
{ {
return super.authenticate(required, isGuest); // is there a Session which might contain a valid user ticket?
HttpSession session = servletReq.getHttpServletRequest().getSession(false);
if (session != null)
{
try
{
SessionUser user = (SessionUser)session.getAttribute(AuthenticationDriver.AUTHENTICATION_USER);
if (user != null)
{
// Validate the ticket for the current SessionUser
authenticationService.validate(user.getTicket());
if (logger.isDebugEnabled())
logger.debug("Ticket is valid; retaining cached user in session.");
listener.userAuthenticated(new TicketCredentials(user.getTicket()));
authenticated = true;
}
else
{
authenticated = super.authenticate(required, isGuest);
}
}
catch (AuthenticationException authErr)
{
if (logger.isDebugEnabled())
logger.debug("An Authentication error occur, removing User session: ", authErr);
session.removeAttribute(AuthenticationDriver.AUTHENTICATION_USER);
session.invalidate();
listener.authenticationFailed(new WebCredentials() {});
}
}
else
{
authenticated = super.authenticate(required, isGuest);
}
} }
return authenticated;
} }
/** /**

View File

@@ -33,6 +33,8 @@ import javax.servlet.http.HttpServletResponse;
*/ */
public interface AuthenticationDriver public interface AuthenticationDriver
{ {
public static final String AUTHENTICATION_USER = "_alfAuthTicket";
/** /**
* Authenticate user based on information in http request such as Authorization header or cached session * Authenticate user based on information in http request such as Authorization header or cached session
* information. * information.

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2005-2013 Alfresco Software Limited. * Copyright (C) 2005-2014 Alfresco Software Limited.
* *
* This file is part of Alfresco * This file is part of Alfresco
* *
@@ -85,7 +85,6 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
this.serverConfiguration = serverConfiguration; this.serverConfiguration = serverConfiguration;
} }
/** /**
* Activates or deactivates the bean * Activates or deactivates the bean
* *
@@ -166,8 +165,6 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
{ {
} }
/** /**
* Callback executed on successful ticket validation during Type3 Message processing. * Callback executed on successful ticket validation during Type3 Message processing.
* *
@@ -211,7 +208,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
protected boolean onLoginComplete(ServletContext sc, HttpServletRequest req, HttpServletResponse res, boolean userInit) protected boolean onLoginComplete(ServletContext sc, HttpServletRequest req, HttpServletResponse res, boolean userInit)
throws IOException throws IOException
{ {
return true; return true;
} }
/** /**
@@ -223,7 +220,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
protected final String mapClientAddressToDomain(String clientIP) protected final String mapClientAddressToDomain(String clientIP)
{ {
// Check if there are any domain mappings // Check if there are any domain mappings
SecurityConfigSection securityConfigSection = getSecurityConfigSection(); SecurityConfigSection securityConfigSection = getSecurityConfigSection();
if (securityConfigSection != null && securityConfigSection.hasDomainMappings() == false) if (securityConfigSection != null && securityConfigSection.hasDomainMappings() == false)
{ {
return null; return null;
@@ -267,75 +264,75 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
*/ */
protected boolean checkForTicketParameter(ServletContext servletContext, HttpServletRequest req, HttpServletResponse resp) protected boolean checkForTicketParameter(ServletContext servletContext, HttpServletRequest req, HttpServletResponse resp)
{ {
// Check if the request includes an authentication ticket // Check if the request includes an authentication ticket
boolean ticketValid = false; boolean ticketValid = false;
String ticket = req.getParameter(ARG_TICKET); String ticket = req.getParameter(ARG_TICKET);
if (ticket != null && ticket.length() != 0) if (ticket != null && ticket.length() != 0)
{ {
if (getLogger().isDebugEnabled()) if (getLogger().isDebugEnabled())
getLogger().debug( getLogger().debug(
"Logon via ticket from " + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":" "Logon via ticket from " + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":"
+ req.getRemotePort() + ")" + " ticket=" + ticket); + req.getRemotePort() + ")" + " ticket=" + ticket);
UserTransaction tx = null; UserTransaction tx = null;
try try
{
// Get a cached user with a valid ticket
SessionUser user = getSessionUser(servletContext, req, resp, true);
// If this isn't the same ticket, invalidate the session
if (user != null && !ticket.equals(user.getTicket()))
{ {
if (getLogger().isDebugEnabled()) // Get a cached user with a valid ticket
getLogger().debug("The ticket doesn't match, invalidate the session."); SessionUser user = getSessionUser(servletContext, req, resp, true);
invalidateSession(req);
user = null;
}
// If we don't yet have a valid cached user, validate the ticket and create one // If this isn't the same ticket, invalidate the session
if (user == null) if (user != null && !ticket.equals(user.getTicket()))
{
if (getLogger().isDebugEnabled())
getLogger().debug("The ticket doesn't match, invalidate the session.");
invalidateSession(req);
user = null;
}
// If we don't yet have a valid cached user, validate the ticket and create one
if (user == null)
{
if (getLogger().isDebugEnabled())
getLogger().debug("There is no valid cached user, validate the ticket and create one.");
authenticationService.validate(ticket);
user = createUserEnvironment(req.getSession(), authenticationService.getCurrentUserName(),
authenticationService.getCurrentTicket(), true);
}
// Indicate the ticket parameter was specified, and valid
ticketValid = true;
}
catch (AuthenticationException authErr)
{ {
if (getLogger().isDebugEnabled()) if (getLogger().isDebugEnabled())
getLogger().debug("There is no valid cached user, validate the ticket and create one."); getLogger().debug("Failed to authenticate user ticket: " + authErr.getMessage(), authErr);
authenticationService.validate(ticket);
user = createUserEnvironment(req.getSession(), authenticationService.getCurrentUserName(),
authenticationService.getCurrentTicket(), true);
} }
catch (Throwable e)
// Indicate the ticket parameter was specified, and valid {
if (getLogger().isDebugEnabled())
ticketValid = true;
}
catch (AuthenticationException authErr)
{
if (getLogger().isDebugEnabled())
getLogger().debug("Failed to authenticate user ticket: " + authErr.getMessage(), authErr);
}
catch (Throwable e)
{
if (getLogger().isDebugEnabled())
getLogger().debug("Error during ticket validation and user creation: " + e.getMessage(), e); getLogger().debug("Error during ticket validation and user creation: " + e.getMessage(), e);
} }
finally finally
{ {
try try
{ {
if (tx != null) if (tx != null)
{ {
tx.rollback(); tx.rollback();
} }
} }
catch (Exception tex) catch (Exception tex)
{ {
} }
} }
} }
// Return the ticket parameter status // Return the ticket parameter status
return ticketValid; return ticketValid;
} }
/** /**
@@ -346,12 +343,12 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
* @exception IOException * @exception IOException
*/ */
protected void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res) protected void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res)
throws IOException throws IOException
{ {
if (getLogger().isDebugEnabled()) if (getLogger().isDebugEnabled())
getLogger().debug("redirectToLoginPage..."); getLogger().debug("redirectToLoginPage...");
if (hasLoginPage()) if (hasLoginPage())
res.sendRedirect(req.getContextPath() + "/faces" + getLoginPage()); res.sendRedirect(req.getContextPath() + "/faces" + getLoginPage());
} }
/** /**
@@ -361,7 +358,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
*/ */
protected final boolean hasLoginPage() protected final boolean hasLoginPage()
{ {
return m_loginPage != null ? true : false; return m_loginPage != null ? true : false;
} }
/** /**
@@ -371,7 +368,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
*/ */
protected final String getLoginPage() protected final String getLoginPage()
{ {
return m_loginPage; return m_loginPage;
} }
/** /**
@@ -381,7 +378,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
*/ */
protected final void setLoginPage( String loginPage) protected final void setLoginPage( String loginPage)
{ {
m_loginPage = loginPage; m_loginPage = loginPage;
} }
/** /**
@@ -391,7 +388,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
*/ */
protected final boolean allowsTicketLogons() protected final boolean allowsTicketLogons()
{ {
return m_ticketLogons; return m_ticketLogons;
} }
/** /**
@@ -401,7 +398,7 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
*/ */
public final void setTicketLogons( boolean ticketsAllowed) public final void setTicketLogons( boolean ticketsAllowed)
{ {
m_ticketLogons = ticketsAllowed; m_ticketLogons = ticketsAllowed;
} }
/** /**
@@ -413,23 +410,23 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
*/ */
protected final boolean isNTLMSSPBlob( byte[] byts, int offset) protected final boolean isNTLMSSPBlob( byte[] byts, int offset)
{ {
// Check if the blob has the NTLMSSP signature // Check if the blob has the NTLMSSP signature
boolean isNTLMSSP = false; boolean isNTLMSSP = false;
if (( byts.length - offset) >= NTLM.Signature.length) { if (( byts.length - offset) >= NTLM.Signature.length) {
// Check for the NTLMSSP signature // Check for the NTLMSSP signature
int idx = 0; int idx = 0;
while ( idx < NTLM.Signature.length && byts[offset + idx] == NTLM.Signature[ idx]) while ( idx < NTLM.Signature.length && byts[offset + idx] == NTLM.Signature[ idx])
idx++; idx++;
if ( idx == NTLM.Signature.length) if ( idx == NTLM.Signature.length)
isNTLMSSP = true; isNTLMSSP = true;
} }
return isNTLMSSP; return isNTLMSSP;
} }
/** /**

View File

@@ -49,8 +49,6 @@ import org.apache.commons.logging.LogFactory;
*/ */
public class SSOFallbackBasicAuthenticationDriver implements AuthenticationDriver public class SSOFallbackBasicAuthenticationDriver implements AuthenticationDriver
{ {
public static final String AUTHENTICATION_USER = "_alfAuthTicket";
private Log logger = LogFactory.getLog(SSOFallbackBasicAuthenticationDriver.class); private Log logger = LogFactory.getLog(SSOFallbackBasicAuthenticationDriver.class);
private AuthenticationService authenticationService; private AuthenticationService authenticationService;
@@ -58,7 +56,7 @@ public class SSOFallbackBasicAuthenticationDriver implements AuthenticationDrive
private NodeService nodeService; private NodeService nodeService;
private TransactionService transactionService; private TransactionService transactionService;
private String userAttributeName = AUTHENTICATION_USER; private String userAttributeName = AuthenticationDriver.AUTHENTICATION_USER;
public void setAuthenticationService(AuthenticationService authenticationService) public void setAuthenticationService(AuthenticationService authenticationService)
{ {