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

68527: Merged V4.2-BUG-FIX (4.2.3) to HEAD-BUG-FIX (4.3/Cloud)
      68302: Merged V4.1-BUG-FIX (4.1.9) to V4.2-BUG-FIX (4.2.3)
         68117: MNT-11315: Merged V4.1.6 (4.1.6.17) to V4.1-BUG-FIX (4.1.9)
            64849: Merged DEV to PATCHES/V4.1.6 (4.1.6.11)
               63976 : MNT-10797 : Support HTTP Basic auth for /alfresco/cmisatom CMIS binding when using kerberos
                  - Added fallback authentication mechanism for webdav authentication filter for kerberos. So it should be possible to login via BASIC authentication when kerbeross SSO enabled.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@70409 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Alan Davis
2014-05-16 16:29:37 +00:00
parent 7fb813b6ac
commit 49c93a5978
3 changed files with 261 additions and 0 deletions

View File

@@ -274,6 +274,10 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
restartLoginChallenge(context, req, resp);
return false;
}
else if (isFallbackEnabled())
{
return performFallbackAuthentication(context, req, resp);
}
}
// Check if the user is already authenticated
@@ -631,6 +635,12 @@ public abstract class BaseKerberosAuthenticationFilter extends BaseSSOAuthentica
getLogger().debug("Issuing login challenge to browser.");
// Force the logon to start again
resp.setHeader("WWW-Authenticate", "Negotiate");
if (isFallbackEnabled())
{
includeFallbackAuth(context, req, resp);
}
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
writeLoginPageLink(context, req, resp);

View File

@@ -73,6 +73,8 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
private boolean m_isActive = true;
private AuthenticationDriver fallbackDelegate;
protected static final String MIME_HTML_TEXT = "text/html";
/**
@@ -104,6 +106,24 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
return m_isActive;
}
/**
* Activates or deactivates the fallback authentication support for this filter
*
* @param delegate
*/
public final void setFallback(AuthenticationDriver delegate)
{
this.fallbackDelegate = delegate;
}
/**
* @return <code>true</code> if fallback authentication enabled
*/
public final boolean isFallbackEnabled()
{
return fallbackDelegate != null;
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
@@ -551,6 +571,53 @@ public abstract class BaseSSOAuthenticationFilter extends BaseAuthenticationFilt
}
}
/**
* Include into response authentication method that is supported by fallback mechanism
*
* @param context ServletContext
* @param req HttpServletRequest
* @param resp HttpServletResponse
* @throws IOException
*/
protected void includeFallbackAuth(ServletContext context, HttpServletRequest req, HttpServletResponse resp) throws IOException
{
fallbackDelegate.restartLoginChallenge(context, req, resp);
}
/**
* Delegate authentication to the fallback mechanism
*
* @param context ServletContext
* @param req HttpServletRequest
* @param resp HttpServletResponse
* @return
* @throws IOException
* @throws ServletException
*/
protected boolean performFallbackAuthentication(ServletContext context, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
{
if (getLogger().isDebugEnabled())
{
getLogger().debug("Performing fallback authentication...");
}
boolean fallbackSuccess = fallbackDelegate.authenticateRequest(context, req, resp);
if (!fallbackSuccess)
{
restartLoginChallenge(context, req, resp);
if (getLogger().isDebugEnabled())
{
getLogger().debug("Fallback authentication failed. Restarting login...");
}
}
if (fallbackSuccess && getLogger().isDebugEnabled())
{
getLogger().debug("Fallback authentication succeeded.");
}
return fallbackSuccess;
}
}

View File

@@ -0,0 +1,184 @@
/*
* Copyright (C) 2005-2014 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.repo.webdav.auth;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.SessionUser;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* <p>
* Basic HTTP web authentication implementation. Main purpose to use as fallback authentication with SSO filters.
* </p>
*
* @author pavel.yurkevich
*/
public class SSOFallbackBasicAuthenticationDriver implements AuthenticationDriver
{
public static final String AUTHENTICATION_USER = "_alfAuthTicket";
private Log logger = LogFactory.getLog(SSOFallbackBasicAuthenticationDriver.class);
private AuthenticationService authenticationService;
private PersonService personService;
private NodeService nodeService;
private TransactionService transactionService;
private String userAttributeName = AUTHENTICATION_USER;
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setUserAttributeName(String userAttributeName)
{
this.userAttributeName = userAttributeName;
}
@Override
public boolean authenticateRequest(ServletContext context, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
String authHdr = request.getHeader("Authorization");
HttpSession session = request.getSession(false);
SessionUser user = session == null ? null : (SessionUser) session.getAttribute(userAttributeName);
if (user == null)
{
if (authHdr != null && authHdr.length() > 5 && authHdr.substring(0, 5).equalsIgnoreCase("Basic"))
{
String basicAuth = new String(Base64.decodeBase64(authHdr.substring(5).getBytes()));
String username = null;
String password = null;
int pos = basicAuth.indexOf(":");
if (pos != -1)
{
username = basicAuth.substring(0, pos);
password = basicAuth.substring(pos + 1);
}
else
{
username = basicAuth;
password = "";
}
try
{
if (logger.isDebugEnabled())
logger.debug("Authenticating user '" + username + "'");
authenticationService.authenticate(username, password.toCharArray());
final RetryingTransactionCallback<SessionUser> callback = new RetryingTransactionCallback<SessionUser>()
{
@Override
public SessionUser execute() throws Throwable
{
NodeRef personNodeRef = personService.getPerson(authenticationService.getCurrentUserName());
String username = (String) nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME);
NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER);
return new WebDAVUser(username, authenticationService.getCurrentTicket(), homeSpaceRef);
}
};
user = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<SessionUser>()
{
public SessionUser doWork() throws Exception
{
return transactionService.getRetryingTransactionHelper().doInTransaction(callback, true);
}
}, AuthenticationUtil.SYSTEM_USER_NAME);
if (logger.isDebugEnabled())
logger.debug("Authenticated user '" + username + "'");
request.getSession().setAttribute(userAttributeName, user);
return true;
}
catch (AuthenticationException ex)
{
// Do nothing, user object will be null
}
}
}
else
{
try
{
authenticationService.validate(user.getTicket());
return true;
}
catch (AuthenticationException ex)
{
session.invalidate();
}
}
return false;
}
@Override
public void restartLoginChallenge(ServletContext context, HttpServletRequest request, HttpServletResponse response)
throws IOException
{
if (logger.isDebugEnabled())
{
logger.debug("Including Basic HTTP authentication into response headers...");
}
response.addHeader("WWW-Authenticate", "Basic realm=\"Alfresco Server\"");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}