saml: Implement logic to check response against X509 keys Signed-off-by: Rohit Yadav <rohit.ya...@shapeblue.com>
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/7687b731 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/7687b731 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/7687b731 Branch: refs/heads/master Commit: 7687b7311a9813a2c422e592e8ad1d50a4f8284e Parents: 47ccce8 Author: Rohit Yadav <rohit.ya...@shapeblue.com> Authored: Sun Aug 24 20:48:25 2014 +0200 Committer: Rohit Yadav <rohit.ya...@shapeblue.com> Committed: Thu Aug 28 19:45:24 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/7687b731/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<PluggableAPIAuthenticator> authenticators) { + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7687b731/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/7687b731/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; + } }