From 67b210fe869910a530e01a35cc1a18b141107416 Mon Sep 17 00:00:00 2001 From: inosh-perera Date: Thu, 12 May 2016 10:37:58 +0530 Subject: [PATCH] adding mutual ssl support in clustered setup --- .../mgt/core/impl/CertificateGenerator.java | 13 ++++ .../service/CertificateManagementService.java | 2 + .../CertificateManagementServiceImpl.java | 4 ++ .../CertificateAuthenticator.java | 65 +++++++++++-------- 4 files changed, 58 insertions(+), 26 deletions(-) diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/impl/CertificateGenerator.java b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/impl/CertificateGenerator.java index d1882b3096..f6c051ebc2 100755 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/impl/CertificateGenerator.java +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/impl/CertificateGenerator.java @@ -288,6 +288,19 @@ public class CertificateGenerator { return lookUpCertificate; } + public CertificateResponse verifyCertificateDN(String distinguishedName) throws KeystoreException { + CertificateResponse lookUpCertificate = null; + KeyStoreReader keyStoreReader = new KeyStoreReader(); + if (distinguishedName != null && !distinguishedName.isEmpty()) { + String[] dnSplits = distinguishedName.split("/CN="); + if (dnSplits != null) { + String commonNameExtracted = dnSplits[dnSplits.length-1]; + lookUpCertificate = keyStoreReader.getCertificateBySerial(commonNameExtracted); + } + } + return lookUpCertificate; + } + public static String getCommonName(X509Certificate requestCertificate) { String distinguishedName = requestCertificate.getSubjectDN().getName(); if(distinguishedName != null && !distinguishedName.isEmpty()) { diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/service/CertificateManagementService.java b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/service/CertificateManagementService.java index c91f0f34d6..d294dbc224 100644 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/service/CertificateManagementService.java +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/service/CertificateManagementService.java @@ -56,6 +56,8 @@ public interface CertificateManagementService { public CertificateResponse verifyPEMSignature(X509Certificate requestCertificate) throws KeystoreException; + public CertificateResponse verifySubjectDN(String requestDN) throws KeystoreException; + public X509Certificate extractCertificateFromSignature(String headerSignature) throws KeystoreException; String extractChallengeToken(X509Certificate certificate); diff --git a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/service/CertificateManagementServiceImpl.java b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/service/CertificateManagementServiceImpl.java index 7157d08e6b..89fd9b4827 100644 --- a/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/service/CertificateManagementServiceImpl.java +++ b/components/certificate-mgt/org.wso2.carbon.certificate.mgt.core/src/main/java/org/wso2/carbon/certificate/mgt/core/service/CertificateManagementServiceImpl.java @@ -108,6 +108,10 @@ public class CertificateManagementServiceImpl implements CertificateManagementSe return certificateGenerator.verifyPEMSignature(requestCertificate); } + @Override public CertificateResponse verifySubjectDN(String requestDN) throws KeystoreException { + return certificateGenerator.verifyCertificateDN(requestDN); + } + public X509Certificate extractCertificateFromSignature(String headerSignature) throws KeystoreException { return certificateGenerator.extractCertificateFromSignature(headerSignature); } diff --git a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/CertificateAuthenticator.java b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/CertificateAuthenticator.java index 6b40e2022b..0f9026a3a4 100644 --- a/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/CertificateAuthenticator.java +++ b/components/webapp-authenticator-framework/org.wso2.carbon.webapp.authenticator.framework/src/main/java/org/wso2/carbon/webapp/authenticator/framework/authenticator/CertificateAuthenticator.java @@ -28,6 +28,7 @@ public class CertificateAuthenticator implements WebappAuthenticator { private static final Log log = LogFactory.getLog(CertificateAuthenticator.class); private static final String CERTIFICATE_AUTHENTICATOR = "CertificateAuth"; private static final String MUTUAL_AUTH_HEADER = "mutual-auth-header"; + private static final String PROXY_MUTUAL_AUTH_HEADER = "proxy-mutual-auth-header"; private static final String CERTIFICATE_VERIFICATION_HEADER = "certificate-verification-header"; private static final String CLIENT_CERTIFICATE_ATTRIBUTE = "javax.servlet.request.X509Certificate"; @@ -38,8 +39,8 @@ public class CertificateAuthenticator implements WebappAuthenticator { @Override public boolean canHandle(Request request) { - if (request.getHeader(CERTIFICATE_VERIFICATION_HEADER) != null || request.getHeader(MUTUAL_AUTH_HEADER) != - null) { + if (request.getHeader(CERTIFICATE_VERIFICATION_HEADER) != null || request.getHeader(MUTUAL_AUTH_HEADER) != null + || request.getHeader(PROXY_MUTUAL_AUTH_HEADER) != null) { return true; } return false; @@ -56,35 +57,20 @@ public class CertificateAuthenticator implements WebappAuthenticator { String certVerificationHeader = request.getContext().findParameter(CERTIFICATE_VERIFICATION_HEADER); try { - - if (request.getHeader(MUTUAL_AUTH_HEADER) != null) { + // When there is a load balancer terminating mutual SSL, it should pass this header along and + // as the value of this header, the client certificate subject dn should be passed. + if (request.getHeader(PROXY_MUTUAL_AUTH_HEADER) != null) { + CertificateResponse certificateResponse = AuthenticatorFrameworkDataHolder.getInstance(). + getCertificateManagementService().verifySubjectDN(request.getHeader(PROXY_MUTUAL_AUTH_HEADER)); + authenticationInfo = checkCertificateResponse(certificateResponse); + } + else if (request.getHeader(MUTUAL_AUTH_HEADER) != null) { X509Certificate[] clientCertificate = (X509Certificate[]) request. getAttribute(CLIENT_CERTIFICATE_ATTRIBUTE); if (clientCertificate != null && clientCertificate[0] != null) { CertificateResponse certificateResponse = AuthenticatorFrameworkDataHolder.getInstance(). getCertificateManagementService().verifyPEMSignature(clientCertificate[0]); - if (certificateResponse == null) { - authenticationInfo.setStatus(Status.FAILURE); - authenticationInfo.setMessage("Certificate sent doesn't match any certificate in the store." + - " Unauthorized access attempt."); - } else if (certificateResponse.getCommonName() != null && !certificateResponse.getCommonName(). - isEmpty()) { - authenticationInfo.setTenantId(certificateResponse.getTenantId()); - authenticationInfo.setStatus(Status.CONTINUE); - authenticationInfo.setUsername(certificateResponse.getCommonName()); - try { - authenticationInfo.setTenantDomain(Utils. - getTenantDomain( - certificateResponse.getTenantId())); - } catch (AuthenticationException e) { - authenticationInfo.setStatus(Status.FAILURE); - authenticationInfo.setMessage("Could not identify tenant domain."); - } - } else { - authenticationInfo.setStatus(Status.FAILURE); - authenticationInfo.setMessage("A matching certificate is found, " + - "but the serial number is missing in the database."); - } + authenticationInfo = checkCertificateResponse(certificateResponse); } else { authenticationInfo.setStatus(Status.FAILURE); @@ -133,6 +119,33 @@ public class CertificateAuthenticator implements WebappAuthenticator { return authenticationInfo; } + private AuthenticationInfo checkCertificateResponse(CertificateResponse certificateResponse) { + AuthenticationInfo authenticationInfo = new AuthenticationInfo(); + if (certificateResponse == null) { + authenticationInfo.setStatus(Status.FAILURE); + authenticationInfo.setMessage("Certificate sent doesn't match any certificate in the store." + + " Unauthorized access attempt."); + } else if (certificateResponse.getCommonName() != null && !certificateResponse.getCommonName(). + isEmpty()) { + authenticationInfo.setTenantId(certificateResponse.getTenantId()); + authenticationInfo.setStatus(Status.CONTINUE); + authenticationInfo.setUsername(certificateResponse.getCommonName()); + try { + authenticationInfo.setTenantDomain(Utils. + getTenantDomain( + certificateResponse.getTenantId())); + } catch (AuthenticationException e) { + authenticationInfo.setStatus(Status.FAILURE); + authenticationInfo.setMessage("Could not identify tenant domain."); + } + } else { + authenticationInfo.setStatus(Status.FAILURE); + authenticationInfo.setMessage("A matching certificate is found, " + + "but the serial number is missing in the database."); + } + return authenticationInfo; + } + @Override public String getName() { return CERTIFICATE_AUTHENTICATOR;