From e895e57280fdd76ded051d10e130286f93aa15df Mon Sep 17 00:00:00 2001 From: Will Abson Date: Wed, 25 Jun 2014 15:31:06 +0000 Subject: [PATCH] Merged HEAD-BUG-FIX (5.0/Cloud) to HEAD (4.3/Cloud) 71601: Merged V4.2-BUG-FIX (4.2.3) to HEAD-BUG-FIX (4.3/Cloud) 70356: MNT-11233: DEV to V4.2-BUG-FIX (4.2.3) 67973: MNT-11233: Alfresco CMIS API /alfresco/api/-default-/cmis/versions/1.1/atom cannot be used with external authentication - Move RemoteUserMapper from Web-Client to Repository project. Use RemoteUserMapper in PublicApiAuthenticator to retrieve remote user from request. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@74695 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../external/external-filter-context.xml | 19 -- .../external/external-filter.properties | 4 - .../web-client-application-context.xml | 15 -- .../web/app/servlet/AuthenticationHelper.java | 2 +- .../app/servlet/DefaultRemoteUserMapper.java | 243 ------------------ .../auth/BasicAuthenticationHandler.java | 2 +- .../servlet/DefaultRemoteUserMapperTest.java | 124 --------- .../servlet/KerberosRemoteUserMapperTest.java | 2 +- 8 files changed, 3 insertions(+), 408 deletions(-) delete mode 100644 config/alfresco/subsystems/Authentication/external/external-filter.properties delete mode 100644 source/java/org/alfresco/web/app/servlet/DefaultRemoteUserMapper.java delete mode 100644 source/test-java/org/alfresco/web/app/servlet/DefaultRemoteUserMapperTest.java diff --git a/config/alfresco/subsystems/Authentication/external/external-filter-context.xml b/config/alfresco/subsystems/Authentication/external/external-filter-context.xml index c367d355fc..45daeeb387 100644 --- a/config/alfresco/subsystems/Authentication/external/external-filter-context.xml +++ b/config/alfresco/subsystems/Authentication/external/external-filter-context.xml @@ -2,25 +2,6 @@ - - - - ${external.authentication.proxyUserName} - - - ${external.authentication.proxyHeader} - - - ${external.authentication.enabled} - - - ${external.authentication.userIdPattern} - - - - - - diff --git a/config/alfresco/subsystems/Authentication/external/external-filter.properties b/config/alfresco/subsystems/Authentication/external/external-filter.properties deleted file mode 100644 index 476a605f81..0000000000 --- a/config/alfresco/subsystems/Authentication/external/external-filter.properties +++ /dev/null @@ -1,4 +0,0 @@ -external.authentication.proxyUserName=alfresco-system -external.authentication.proxyHeader=X-Alfresco-Remote-User -external.authentication.enabled=true -external.authentication.userIdPattern= diff --git a/config/alfresco/web-client-application-context.xml b/config/alfresco/web-client-application-context.xml index 1ed59f7f7d..e1f60687e7 100644 --- a/config/alfresco/web-client-application-context.xml +++ b/config/alfresco/web-client-application-context.xml @@ -138,21 +138,6 @@ - - - - - - - org.alfresco.repo.webdav.auth.RemoteUserMapper - org.alfresco.repo.management.subsystems.ActivateableBean - - - - remoteUserMapper - - - diff --git a/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java b/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java index b1051c4f40..35a285330d 100644 --- a/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java +++ b/source/java/org/alfresco/web/app/servlet/AuthenticationHelper.java @@ -35,9 +35,9 @@ 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.RemoteUserMapper; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.transaction.RetryingTransactionHelper; -import org.alfresco.repo.webdav.auth.RemoteUserMapper; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; diff --git a/source/java/org/alfresco/web/app/servlet/DefaultRemoteUserMapper.java b/source/java/org/alfresco/web/app/servlet/DefaultRemoteUserMapper.java deleted file mode 100644 index c62f5d7c8d..0000000000 --- a/source/java/org/alfresco/web/app/servlet/DefaultRemoteUserMapper.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2005-2010 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 . - */ -package org.alfresco.web.app.servlet; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.servlet.http.HttpServletRequest; - -import org.alfresco.repo.management.subsystems.ActivateableBean; -import org.alfresco.repo.security.authentication.AuthenticationUtil; -import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; -import org.alfresco.service.cmr.security.PersonService; - -import org.alfresco.repo.webdav.auth.RemoteUserMapper; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -/** - * A default {@link RemoteUserMapper} implementation. Extracts a user ID using - * {@link HttpServletRequest#getRemoteUser()} and optionally from a configured request header. If there is no configured - * proxy user name, it returns the request header user name if there is one, or the remote user name otherwise. If there - * is a configured proxy user, then it returns the request header user name if the remote user matches the proxy user, - * or the remote user otherwise. An optional regular expression defining how to convert the header to a user ID can be - * configured using {@link #setUserIdPattern(String)}. This allows for the secure proxying of requests from a Surf - * client such as Alfresco Share using SSL client certificates. - * - * @author dward - */ -public class DefaultRemoteUserMapper implements RemoteUserMapper, ActivateableBean -{ - /** The remote identity used to 'proxy' requests securely in the name of another user. */ - private String proxyUserName = "alfresco-system"; - - /** The header containing the ID of a proxied user. */ - private String proxyHeader = "X-Alfresco-Remote-User"; - - /** Is this mapper enabled? */ - private boolean isEnabled; - - /** Regular expression for extracting a user ID from the header. */ - private Pattern userIdPattern; - - /** The person service. */ - private PersonService personService; - - static Log logger = LogFactory.getLog(DefaultRemoteUserMapper.class); - - /** - * Sets the name of the remote user used to 'proxy' requests securely in the name of another user. Typically this - * remote identity will be protected by an SSL client certificate. - * - * @param proxyUserName - * the proxy user name. If null or empty, then the header will be checked regardless of - * remote user identity. - */ - public void setProxyUserName(String proxyUserName) - { - this.proxyUserName = proxyUserName == null || proxyUserName.length() == 0 ? null : proxyUserName; - } - - /** - * Sets the name of the header containing the ID of a proxied user. - * - * @param proxyHeader - * the proxy header name - */ - public void setProxyHeader(String proxyHeader) - { - this.proxyHeader = proxyHeader == null || proxyHeader.length() == 0 ? null : proxyHeader; - } - - /** - * Controls whether the mapper is enabled. When disabled {@link #getRemoteUser(HttpServletRequest)} will always - * return null - * - * @param isEnabled - * Is this mapper enabled? - */ - public void setActive(boolean isEnabled) - { - this.isEnabled = isEnabled; - } - - /** - * Sets a regular expression for extracting a user ID from the header. If this is not set, then the entire contents - * of the header will be used as the user ID. - * - * @param userIdPattern - * the regular expression - */ - public void setUserIdPattern(String userIdPattern) - { - this.userIdPattern = userIdPattern == null || userIdPattern.length() == 0 ? null : Pattern - .compile(userIdPattern); - } - - /** - * Sets the person service. - * - * @param personService - * the person service - */ - public void setPersonService(PersonService personService) - { - this.personService = personService; - } - - /* - * (non-Javadoc) - * @see org.alfresco.web.app.servlet.RemoteUserMapper#getRemoteUser(javax.servlet.http.HttpServletRequest) - */ - public String getRemoteUser(HttpServletRequest request) - { - if (logger.isDebugEnabled()) - logger.debug("Getting RemoteUser from http request."); - if (!this.isEnabled) - { - if (logger.isDebugEnabled()) - logger.debug("DefaultRemoteUserMapper is disabled, returning null."); - return null; - } - String remoteUserId = request.getRemoteUser(); - String headerUserId = extractUserFromProxyHeader(request); - if (logger.isDebugEnabled()) - { - logger.debug("The remote user id is: " + remoteUserId); - logger.debug("The header user id is: " + headerUserId); - logger.debug("The proxy user name is: " + this.proxyUserName); - } - if (this.proxyUserName == null) - { - // Normalize the user ID taking into account case sensitivity settings - String normalizedUserId = normalizeUserId(headerUserId != null ? headerUserId : remoteUserId); - if (logger.isDebugEnabled()) - logger.debug("Returning " + normalizedUserId); - return normalizedUserId; - } - else if (remoteUserId == null) - { - if (logger.isDebugEnabled()) - logger.debug("Returning null"); - return null; - } - else - { - // Normalize the user ID taking into account case sensitivity settings - String normalizedUserId = normalizeUserId(remoteUserId.equals(this.proxyUserName) ? headerUserId : remoteUserId); - if (logger.isDebugEnabled()) - logger.debug("Returning " + normalizedUserId); - return normalizedUserId; - } - } - - /** - * Normalizes a user id, taking into account existing user accounts and case sensitivity settings. - * - * @param userId - * the user id - * @return the string - */ - private String normalizeUserId(final String userId) - { - if (userId == null) - { - return null; - } - String normalized = AuthenticationUtil.runAs(new RunAsWork() - { - public String doWork() throws Exception - { - return personService.getUserIdentifier(userId); - } - }, AuthenticationUtil.getSystemUserName()); - if (logger.isDebugEnabled()) - logger.debug("The normalized user name is: " + normalized + " for user id " + userId); - return normalized == null ? userId : normalized; - } - - /* - * (non-Javadoc) - * @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive() - */ - public boolean isActive() - { - return this.isEnabled; - } - - /** - * Extracts a user ID from the proxy header. If a user ID pattern has been configured returns the contents of the - * first matching regular expression group or null. Otherwise returns the trimmed header contents or - * null. - * - * @param request - * the request - * @return the user ID - */ - private String extractUserFromProxyHeader(HttpServletRequest request) - { - if (this.proxyHeader == null) - { - return null; - } - String userId = request.getHeader(this.proxyHeader); - if (userId == null) - { - return null; - } - if (this.userIdPattern == null) - { - userId = userId.trim(); - } - else - { - Matcher matcher = this.userIdPattern.matcher(userId); - if (matcher.matches()) - { - userId = matcher.group(1).trim(); - } - else - { - return null; - } - } - return userId.length() == 0 ? null : userId; - } - -} diff --git a/source/java/org/alfresco/web/sharepoint/auth/BasicAuthenticationHandler.java b/source/java/org/alfresco/web/sharepoint/auth/BasicAuthenticationHandler.java index a1408adb7b..4761ffd85d 100644 --- a/source/java/org/alfresco/web/sharepoint/auth/BasicAuthenticationHandler.java +++ b/source/java/org/alfresco/web/sharepoint/auth/BasicAuthenticationHandler.java @@ -30,7 +30,7 @@ import org.alfresco.repo.SessionUser; 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.webdav.auth.RemoteUserMapper; +import org.alfresco.repo.security.authentication.external.RemoteUserMapper; import org.alfresco.repo.web.auth.AuthenticationListener; import org.alfresco.repo.web.auth.TicketCredentials; import org.alfresco.repo.web.auth.BasicAuthCredentials; diff --git a/source/test-java/org/alfresco/web/app/servlet/DefaultRemoteUserMapperTest.java b/source/test-java/org/alfresco/web/app/servlet/DefaultRemoteUserMapperTest.java deleted file mode 100644 index 06c654eb8b..0000000000 --- a/source/test-java/org/alfresco/web/app/servlet/DefaultRemoteUserMapperTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2005-2010 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 . - */ -package org.alfresco.web.app.servlet; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import javax.servlet.http.HttpServletRequest; - -import org.alfresco.repo.management.subsystems.AbstractChainedSubsystemTest; -import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory; -import org.alfresco.repo.management.subsystems.DefaultChildApplicationContextManager; -import org.alfresco.repo.webdav.auth.RemoteUserMapper; -import org.alfresco.util.ApplicationContextHelper; -import org.springframework.context.ApplicationContext; - - -/** - * @author dward - * - */ -public class DefaultRemoteUserMapperTest extends AbstractChainedSubsystemTest -{ - ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - DefaultChildApplicationContextManager childApplicationContextManager; - ChildApplicationContextFactory childApplicationContextFactory; - - /* (non-Javadoc) - * @see junit.framework.TestCase#setUp() - */ - @Override - protected void setUp() throws Exception - { - childApplicationContextManager = (DefaultChildApplicationContextManager) ctx.getBean("Authentication"); - childApplicationContextManager.stop(); - childApplicationContextManager.setProperty("chain", "external1:external"); - childApplicationContextFactory = getChildApplicationContextFactory(childApplicationContextManager, "external1"); - } - - - /* (non-Javadoc) - * @see junit.framework.TestCase#tearDown() - */ - @Override - protected void tearDown() throws Exception - { - childApplicationContextManager.destroy(); - childApplicationContextManager = null; - childApplicationContextFactory = null; - } - - - public void testUnproxiedHeader() throws Exception - { - // Clear the proxy user name - childApplicationContextFactory.stop(); - childApplicationContextFactory.setProperty("external.authentication.proxyUserName", ""); - - // Mock a request with a username in the header - HttpServletRequest mockRequest = mock(HttpServletRequest.class); - when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn("AdMiN"); - assertEquals("admin", ((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean( - "remoteUserMapper")).getRemoteUser(mockRequest)); - - // Mock an unauthenticated request - when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn(null); - assertNull(((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean( - "remoteUserMapper")).getRemoteUser(mockRequest)); - - // Mock a remote user request - when(mockRequest.getRemoteUser()).thenReturn("ADMIN"); - assertEquals("admin", ((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean( - "remoteUserMapper")).getRemoteUser(mockRequest)); - } - - - public void testProxiedHeader() throws Exception - { - // Set the proxy user name - childApplicationContextFactory.stop(); - childApplicationContextFactory.setProperty("external.authentication.proxyUserName", "bob"); - - // Mock a request with both a user and a header - HttpServletRequest mockRequest = mock(HttpServletRequest.class); - when(mockRequest.getRemoteUser()).thenReturn("bob"); - when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn("AdMiN"); - assertEquals("admin", ((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean( - "remoteUserMapper")).getRemoteUser(mockRequest)); - - // Now try header pattern matching - childApplicationContextFactory.stop(); - childApplicationContextFactory.setProperty("external.authentication.userIdPattern", "abc-(.*)-999"); - when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn("abc-AdMiN-999"); - assertEquals("admin", ((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean( - "remoteUserMapper")).getRemoteUser(mockRequest)); - - // Try a request with an invalid match - when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn("abc-AdMiN-998"); - assertNull(((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean( - "remoteUserMapper")).getRemoteUser(mockRequest)); - - // Try a request without the remote user - when(mockRequest.getRemoteUser()).thenReturn(null); - assertNull(((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean( - "remoteUserMapper")).getRemoteUser(mockRequest)); - } - -} diff --git a/source/test-java/org/alfresco/web/app/servlet/KerberosRemoteUserMapperTest.java b/source/test-java/org/alfresco/web/app/servlet/KerberosRemoteUserMapperTest.java index f02dbc3932..712ae10d1d 100644 --- a/source/test-java/org/alfresco/web/app/servlet/KerberosRemoteUserMapperTest.java +++ b/source/test-java/org/alfresco/web/app/servlet/KerberosRemoteUserMapperTest.java @@ -38,6 +38,7 @@ import org.alfresco.repo.admin.SysAdminParams; import org.alfresco.repo.security.authentication.TicketComponent; import org.alfresco.repo.security.authentication.AuthenticationServiceImpl; import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.external.DefaultRemoteUserMapper; import org.alfresco.repo.security.authentication.jaas.JAASAuthenticationComponent; import org.alfresco.repo.web.auth.NoopAuthenticationListener; import org.alfresco.repo.webdav.auth.KerberosAuthenticationFilter; @@ -45,7 +46,6 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; -import org.alfresco.web.app.servlet.DefaultRemoteUserMapper; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass;