mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-08 14:51:49 +00:00
Merged HEAD-BUG-FIX (5.1/Cloud) to HEAD (5.1/Cloud)
104179: Merged 5.0.N (5.0.2) to HEAD-BUG-FIX (5.1/Cloud) 104080: Merged DEV (5.0.2) to 5.0.N (5.0.2) 104074: MNT-13989: securing external authentication with non null external.authentication.proxyUserName fails - Added SSL certificate subject DN validation in case of external.authentication.proxyUserName is set. - Added JUnit test. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@104262 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -19,6 +19,7 @@
|
|||||||
package org.alfresco.repo.security.authentication.external;
|
package org.alfresco.repo.security.authentication.external;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -152,9 +153,40 @@ public class DefaultRemoteUserMapper implements RemoteUserMapper, ActivateableBe
|
|||||||
}
|
}
|
||||||
else if (remoteUserId == null)
|
else if (remoteUserId == null)
|
||||||
{
|
{
|
||||||
|
String normalizedUserId = null;
|
||||||
|
// Try to extract the remote user from SSL certificate
|
||||||
|
// MNT-13989
|
||||||
|
X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
|
||||||
|
if (request.getScheme().toLowerCase().equals("https") && certs != null && certs.length > 0)
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Checking SSL certificate subject DN to match " + this.proxyUserName);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < certs.length; i++)
|
||||||
|
{
|
||||||
|
String subjectDN = certs[i].getSubjectX500Principal().getName();
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("Found subject DN " + subjectDN);
|
||||||
|
}
|
||||||
|
if (subjectDN.equals(this.proxyUserName))
|
||||||
|
{
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug("The subject DN " + subjectDN + " matches " + this.proxyUserName);
|
||||||
|
}
|
||||||
|
// Found the subject distinguished name
|
||||||
|
remoteUserId = subjectDN;
|
||||||
|
// Normalize the user ID taking into account case sensitivity settings
|
||||||
|
normalizedUserId = normalizeUserId(headerUserId != null ? headerUserId : remoteUserId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.debug("Returning null");
|
logger.debug("Returning " + normalizedUserId);
|
||||||
return null;
|
return normalizedUserId;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
* Copyright (C) 2005-2015 Alfresco Software Limited.
|
||||||
*
|
*
|
||||||
* This file is part of Alfresco
|
* This file is part of Alfresco
|
||||||
*
|
*
|
||||||
@@ -21,15 +21,17 @@ package org.alfresco.repo.security.authentication.external;
|
|||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import javax.security.auth.x500.X500Principal;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.alfresco.repo.management.subsystems.AbstractChainedSubsystemTest;
|
import org.alfresco.repo.management.subsystems.AbstractChainedSubsystemTest;
|
||||||
import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
|
import org.alfresco.repo.management.subsystems.ChildApplicationContextFactory;
|
||||||
import org.alfresco.repo.management.subsystems.DefaultChildApplicationContextManager;
|
import org.alfresco.repo.management.subsystems.DefaultChildApplicationContextManager;
|
||||||
import org.alfresco.repo.security.authentication.external.RemoteUserMapper;
|
|
||||||
import org.alfresco.util.ApplicationContextHelper;
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author dward
|
* @author dward
|
||||||
@@ -82,7 +84,7 @@ public class DefaultRemoteUserMapperTest extends AbstractChainedSubsystemTest
|
|||||||
// Mock an unauthenticated request
|
// Mock an unauthenticated request
|
||||||
when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn(null);
|
when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn(null);
|
||||||
assertNull(((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
assertNull(((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
||||||
"remoteUserMapper")).getRemoteUser(mockRequest));
|
"remoteUserMapper")).getRemoteUser(mockRequest));
|
||||||
|
|
||||||
// Mock a remote user request
|
// Mock a remote user request
|
||||||
when(mockRequest.getRemoteUser()).thenReturn("ADMIN");
|
when(mockRequest.getRemoteUser()).thenReturn("ADMIN");
|
||||||
@@ -99,6 +101,7 @@ public class DefaultRemoteUserMapperTest extends AbstractChainedSubsystemTest
|
|||||||
|
|
||||||
// Mock a request with both a user and a header
|
// Mock a request with both a user and a header
|
||||||
HttpServletRequest mockRequest = mock(HttpServletRequest.class);
|
HttpServletRequest mockRequest = mock(HttpServletRequest.class);
|
||||||
|
when(mockRequest.getScheme()).thenReturn("http");
|
||||||
when(mockRequest.getRemoteUser()).thenReturn("bob");
|
when(mockRequest.getRemoteUser()).thenReturn("bob");
|
||||||
when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn("AdMiN");
|
when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn("AdMiN");
|
||||||
assertEquals("admin", ((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
assertEquals("admin", ((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
||||||
@@ -120,6 +123,48 @@ public class DefaultRemoteUserMapperTest extends AbstractChainedSubsystemTest
|
|||||||
when(mockRequest.getRemoteUser()).thenReturn(null);
|
when(mockRequest.getRemoteUser()).thenReturn(null);
|
||||||
assertNull(((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
assertNull(((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
||||||
"remoteUserMapper")).getRemoteUser(mockRequest));
|
"remoteUserMapper")).getRemoteUser(mockRequest));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MNT-13989
|
||||||
|
* Test simulates the extraction of subject distinguished name from a client SSL certificate
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void testRemoteUserFromCert() throws Exception
|
||||||
|
{
|
||||||
|
childApplicationContextFactory.stop();
|
||||||
|
childApplicationContextFactory.setProperty("external.authentication.proxyUserName", "CN=alfresco-system");
|
||||||
|
childApplicationContextFactory.setProperty("external.authentication.proxyHeader", "X-Alfresco-Remote-User");
|
||||||
|
|
||||||
|
X509Certificate cert = mock(X509Certificate.class);
|
||||||
|
X500Principal principal = new X500Principal("CN=alfresco-system");
|
||||||
|
when(cert.getSubjectX500Principal()).thenReturn(principal);
|
||||||
|
X509Certificate[] certs = {cert};
|
||||||
|
HttpServletRequest mockRequest = mock(HttpServletRequest.class);
|
||||||
|
|
||||||
|
// Mock a request with a header and a cert
|
||||||
|
when(mockRequest.getRemoteUser()).thenReturn(null);
|
||||||
|
when(mockRequest.getScheme()).thenReturn("https");
|
||||||
|
when(mockRequest.getAttribute("javax.servlet.request.X509Certificate")).thenReturn(certs);
|
||||||
|
when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn("admin");
|
||||||
|
assertEquals("admin", ((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
||||||
|
"remoteUserMapper")).getRemoteUser(mockRequest));
|
||||||
|
|
||||||
|
// Mock a request with a cert and no header
|
||||||
|
when(mockRequest.getRemoteUser()).thenReturn(null);
|
||||||
|
when(mockRequest.getScheme()).thenReturn("https");
|
||||||
|
when(mockRequest.getAttribute("javax.servlet.request.X509Certificate")).thenReturn(certs);
|
||||||
|
when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn(null);
|
||||||
|
assertEquals("CN=alfresco-system", ((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
||||||
|
"remoteUserMapper")).getRemoteUser(mockRequest));
|
||||||
|
|
||||||
|
// Mock a request with no cert and a header
|
||||||
|
when(mockRequest.getRemoteUser()).thenReturn(null);
|
||||||
|
when(mockRequest.getScheme()).thenReturn("http");
|
||||||
|
when(mockRequest.getAttribute("javax.servlet.request.X509Certificate")).thenReturn(null);
|
||||||
|
when(mockRequest.getHeader("X-Alfresco-Remote-User")).thenReturn("admin");
|
||||||
|
assertNull(((RemoteUserMapper) childApplicationContextFactory.getApplicationContext().getBean(
|
||||||
|
"remoteUserMapper")).getRemoteUser(mockRequest));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user