Return-Path: X-Original-To: apmail-cloudstack-commits-archive@www.apache.org Delivered-To: apmail-cloudstack-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id EC29F110A3 for ; Mon, 25 Aug 2014 15:36:11 +0000 (UTC) Received: (qmail 10147 invoked by uid 500); 25 Aug 2014 15:35:59 -0000 Delivered-To: apmail-cloudstack-commits-archive@cloudstack.apache.org Received: (qmail 10030 invoked by uid 500); 25 Aug 2014 15:35:58 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 9786 invoked by uid 99); 25 Aug 2014 15:35:58 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 25 Aug 2014 15:35:58 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id A9AB39CDB45; Mon, 25 Aug 2014 15:35:58 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: bhaisaab@apache.org To: commits@cloudstack.apache.org Date: Mon, 25 Aug 2014 15:36:33 -0000 Message-Id: <011fe2f52e1d4dcf9182ef7241e3a359@git.apache.org> In-Reply-To: <3bdbbdbdf5cb401da3ba74a23305a32c@git.apache.org> References: <3bdbbdbdf5cb401da3ba74a23305a32c@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [37/52] git commit: updated refs/heads/saml2 to 1d809ff saml: Implement logic to check response against X509 keys Signed-off-by: Rohit Yadav Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/b84b2c14 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/b84b2c14 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/b84b2c14 Branch: refs/heads/saml2 Commit: b84b2c147f3511da7b91aed79daf56afaef6a85b Parents: e709dab Author: Rohit Yadav Authored: Sun Aug 24 20:48:25 2014 +0200 Committer: Rohit Yadav Committed: Mon Aug 25 17:33:28 2014 +0200 ---------------------------------------------------------------------- .../command/SAML2LogoutAPIAuthenticatorCmd.java | 6 ++ .../cloudstack/saml/SAML2AuthManager.java | 15 +++- .../cloudstack/saml/SAML2AuthManagerImpl.java | 85 ++++++++++++++++---- 3 files changed, 87 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b84b2c14/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LogoutAPIAuthenticatorCmd.java ---------------------------------------------------------------------- diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LogoutAPIAuthenticatorCmd.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LogoutAPIAuthenticatorCmd.java index 32e2f99..723209f 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LogoutAPIAuthenticatorCmd.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LogoutAPIAuthenticatorCmd.java @@ -24,11 +24,13 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.auth.APIAuthenticationType; import org.apache.cloudstack.api.auth.APIAuthenticator; +import org.apache.cloudstack.api.auth.PluggableAPIAuthenticator; import org.apache.cloudstack.api.response.LogoutCmdResponse; import org.apache.log4j.Logger; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import java.util.List; import java.util.Map; @APICommand(name = "samlslo", description = "SAML Global Log Out API", responseObject = LogoutCmdResponse.class, entityType = {}) @@ -70,4 +72,8 @@ public class SAML2LogoutAPIAuthenticatorCmd extends BaseCmd implements APIAuthen public APIAuthenticationType getAPIType() { return APIAuthenticationType.LOGOUT_API; } + + @Override + public void setAuthenticators(List authenticators) { + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b84b2c14/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java ---------------------------------------------------------------------- diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java index c01cf21..507fa04 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManager.java @@ -17,11 +17,20 @@ package org.apache.cloudstack.saml; -public interface SAML2AuthManager { +import org.apache.cloudstack.api.auth.PluggableAPIAuthenticator; + +import java.security.cert.X509Certificate; + +public interface SAML2AuthManager extends PluggableAPIAuthenticator { public String getServiceProviderId(); - public String getSpSingleSignOnUrl(); - public String getSpSingleLogOutUrl(); + public String getIdentityProviderId(); + public X509Certificate getIdpSigningKey(); + public X509Certificate getIdpEncryptionKey(); + + public String getSpSingleSignOnUrl(); public String getIdpSingleSignOnUrl(); + + public String getSpSingleLogOutUrl(); public String getIdpSingleLogOutUrl(); } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b84b2c14/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java ---------------------------------------------------------------------- diff --git a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java index 41595b6..7ef126a 100644 --- a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java +++ b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java @@ -23,32 +23,48 @@ import org.apache.cloudstack.api.command.SAML2LoginAPIAuthenticatorCmd; import org.apache.cloudstack.api.command.SAML2LogoutAPIAuthenticatorCmd; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.log4j.Logger; +import org.opensaml.DefaultBootstrap; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.KeyDescriptor; import org.opensaml.saml2.metadata.SingleLogoutService; import org.opensaml.saml2.metadata.SingleSignOnService; import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.xml.ConfigurationException; import org.opensaml.xml.parse.BasicParserPool; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.keyinfo.KeyInfoHelper; import org.springframework.stereotype.Component; import javax.ejb.Local; import javax.inject.Inject; +import javax.xml.stream.FactoryConfigurationError; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; @Component -@Local(value = {PluggableAPIAuthenticator.class, SAML2AuthManager.class}) -public class SAML2AuthManagerImpl extends AdapterBase implements PluggableAPIAuthenticator, SAML2AuthManager { +@Local(value = {SAML2AuthManager.class, PluggableAPIAuthenticator.class}) +public class SAML2AuthManagerImpl extends AdapterBase implements SAML2AuthManager { private static final Logger s_logger = Logger.getLogger(SAML2AuthManagerImpl.class); private String serviceProviderId; - private String spSingleSignOnUrl; - private String spSingleLogOutUrl; + private String identityProviderId; + + private X509Certificate idpSigningKey; + private X509Certificate idpEncryptionKey; + private String spSingleSignOnUrl; private String idpSingleSignOnUrl; + + private String spSingleLogOutUrl; private String idpSingleLogOutUrl; + private HTTPMetadataProvider idpMetaDataProvider; + @Inject ConfigurationDao _configDao; @@ -59,6 +75,8 @@ public class SAML2AuthManagerImpl extends AdapterBase implements PluggableAPIAut @Override public boolean start() { this.serviceProviderId = _configDao.getValue(Config.SAMLServiceProviderID.key()); + this.identityProviderId = _configDao.getValue(Config.SAMLIdentityProviderID.key()); + this.spSingleSignOnUrl = _configDao.getValue(Config.SAMLServiceProviderSingleSignOnURL.key()); this.spSingleLogOutUrl = _configDao.getValue(Config.SAMLServiceProviderSingleLogOutURL.key()); @@ -71,31 +89,54 @@ public class SAML2AuthManagerImpl extends AdapterBase implements PluggableAPIAut } try { - HTTPMetadataProvider idpMetaDataProvider = new HTTPMetadataProvider(idpMetaDataUrl, tolerance); - + DefaultBootstrap.bootstrap(); + idpMetaDataProvider = new HTTPMetadataProvider(idpMetaDataUrl, tolerance); idpMetaDataProvider.setRequireValidMetadata(true); idpMetaDataProvider.setParserPool(new BasicParserPool()); idpMetaDataProvider.initialize(); - EntityDescriptor idpEntityDescriptor = idpMetaDataProvider.getEntityDescriptor("Some entity id"); - for (SingleSignOnService ssos: idpEntityDescriptor.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleSignOnServices()) { - if (ssos.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - this.idpSingleSignOnUrl = ssos.getLocation(); + EntityDescriptor idpEntityDescriptor = idpMetaDataProvider.getEntityDescriptor(this.identityProviderId); + + IDPSSODescriptor idpssoDescriptor = idpEntityDescriptor.getIDPSSODescriptor(SAMLConstants.SAML20P_NS); + if (idpssoDescriptor != null) { + for (SingleSignOnService ssos: idpssoDescriptor.getSingleSignOnServices()) { + if (ssos.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { + this.idpSingleSignOnUrl = ssos.getLocation(); + } } - } - for (SingleLogoutService slos: idpEntityDescriptor.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices()) { - if (slos.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - this.idpSingleLogOutUrl = slos.getLocation(); + + for (SingleLogoutService slos: idpssoDescriptor.getSingleLogoutServices()) { + if (slos.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { + this.idpSingleLogOutUrl = slos.getLocation(); + } } - } + for (KeyDescriptor kd: idpssoDescriptor.getKeyDescriptors()) { + if (kd.getUse() == UsageType.SIGNING) { + try { + this.idpSigningKey = KeyInfoHelper.getCertificates(kd.getKeyInfo()).get(0); + } catch (CertificateException ignored) { + } + } + if (kd.getUse() == UsageType.ENCRYPTION) { + try { + this.idpEncryptionKey = KeyInfoHelper.getCertificates(kd.getKeyInfo()).get(0); + } catch (CertificateException ignored) { + } + } + } + } else { + s_logger.warn("Provided IDP XML Metadata does not contain IDPSSODescriptor, SAML authentication may not work"); + } } catch (MetadataProviderException e) { s_logger.error("Unable to read SAML2 IDP MetaData URL, error:" + e.getMessage()); s_logger.error("SAML2 Authentication may be unavailable"); + } catch (ConfigurationException | FactoryConfigurationError e) { + s_logger.error("OpenSAML bootstrapping failed: error: " + e.getMessage()); } if (this.idpSingleLogOutUrl == null || this.idpSingleSignOnUrl == null) { - s_logger.error("The current IDP does not support HTTP redirected authentication, SAML based authentication cannot work with this IDP"); + s_logger.error("SAML based authentication won't work"); } return true; @@ -128,4 +169,16 @@ public class SAML2AuthManagerImpl extends AdapterBase implements PluggableAPIAut public String getSpSingleLogOutUrl() { return spSingleLogOutUrl; } + + public String getIdentityProviderId() { + return identityProviderId; + } + + public X509Certificate getIdpSigningKey() { + return idpSigningKey; + } + + public X509Certificate getIdpEncryptionKey() { + return idpEncryptionKey; + } }