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/142b23ad
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/142b23ad
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/142b23ad

Branch: refs/heads/saml2
Commit: 142b23ad1028c265141db5888f3bd20314092af7
Parents: a758941
Author: Rohit Yadav <rohit.ya...@shapeblue.com>
Authored: Sun Aug 24 20:48:25 2014 +0200
Committer: Rohit Yadav <rohit.ya...@shapeblue.com>
Committed: Sun Aug 24 20:48:25 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/142b23ad/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/142b23ad/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/142b23ad/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;
+    }
 }

Reply via email to