saml: Have the plugin use IDP metadata from URL, get values from Config

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

Branch: refs/heads/saml2
Commit: 828f0d5f7f84f91e46245a697317ed19ad83525a
Parents: 5b30649
Author: Rohit Yadav <rohit.ya...@shapeblue.com>
Authored: Sun Aug 24 17:34:20 2014 +0200
Committer: Rohit Yadav <rohit.ya...@shapeblue.com>
Committed: Sun Aug 24 17:37:55 2014 +0200

----------------------------------------------------------------------
 .../cloudstack/saml2/spring-saml2-context.xml   |   2 +-
 .../command/SAML2LoginAPIAuthenticatorCmd.java  |  28 +++-
 .../cloudstack/saml/SAML2AuthManagerImpl.java   | 131 +++++++++++++++++++
 .../cloudstack/saml/SAML2AuthServiceImpl.java   |  51 --------
 4 files changed, 153 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/828f0d5f/plugins/user-authenticators/saml2/resources/META-INF/cloudstack/saml2/spring-saml2-context.xml
----------------------------------------------------------------------
diff --git 
a/plugins/user-authenticators/saml2/resources/META-INF/cloudstack/saml2/spring-saml2-context.xml
 
b/plugins/user-authenticators/saml2/resources/META-INF/cloudstack/saml2/spring-saml2-context.xml
index 15e085d..92f89b8 100644
--- 
a/plugins/user-authenticators/saml2/resources/META-INF/cloudstack/saml2/spring-saml2-context.xml
+++ 
b/plugins/user-authenticators/saml2/resources/META-INF/cloudstack/saml2/spring-saml2-context.xml
@@ -29,7 +29,7 @@
         <property name="name" value="SAML2"/>
     </bean>
 
-    <bean id="SAML2Manager" 
class="org.apache.cloudstack.saml.SAML2AuthServiceImpl">
+    <bean id="SAML2Manager" 
class="org.apache.cloudstack.saml.SAML2AuthManagerImpl">
         <property name="name" value="SAML2Auth"/>
     </bean>
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/828f0d5f/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
----------------------------------------------------------------------
diff --git 
a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
 
b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
index 463df7d..ec3a4d2 100644
--- 
a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
+++ 
b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java
@@ -17,7 +17,6 @@
 
 package org.apache.cloudstack.api.command;
 
-import org.apache.cloudstack.api.ApiServerService;
 import com.cloud.api.response.ApiResponseSerializer;
 import com.cloud.exception.CloudAuthenticationException;
 import com.cloud.user.Account;
@@ -27,6 +26,7 @@ import com.cloud.utils.db.EntityManager;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.ApiServerService;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
@@ -34,6 +34,7 @@ import org.apache.cloudstack.api.auth.APIAuthenticationType;
 import org.apache.cloudstack.api.auth.APIAuthenticator;
 import org.apache.cloudstack.api.response.LoginCmdResponse;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.saml.SAML2AuthManager;
 import org.apache.cloudstack.utils.auth.SAMLUtils;
 import org.apache.log4j.Logger;
 import org.opensaml.DefaultBootstrap;
@@ -79,6 +80,8 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd 
implements APIAuthent
     ApiServerService _apiServer;
     @Inject
     EntityManager _entityMgr;
+    @Inject
+    SAML2AuthManager _samlAuthManager;
 
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
@@ -108,13 +111,20 @@ public class SAML2LoginAPIAuthenticatorCmd extends 
BaseCmd implements APIAuthent
         throw new ServerApiException(ApiErrorCode.METHOD_NOT_ALLOWED, "This is 
an authentication api, cannot be used directly");
     }
 
-    public String buildAuthnRequestUrl(String consumerUrl, String 
identityProviderUrl) {
-        String randomId = new BigInteger(130, new SecureRandom()).toString(32);
-        String spId = "org.apache.cloudstack";
+    public String buildAuthnRequestUrl(String idpUrl) {
+        String randomSecureId = new BigInteger(130, new 
SecureRandom()).toString(32);
+        String spId = _samlAuthManager.getServiceProviderId();
+        String consumerUrl = _samlAuthManager.getSpSingleSignOnUrl();
+        String identityProviderUrl = _samlAuthManager.getIdpSingleSignOnUrl();
+
+        if (idpUrl != null) {
+            identityProviderUrl = idpUrl;
+        }
+
         String redirectUrl = "";
         try {
             DefaultBootstrap.bootstrap();
-            AuthnRequest authnRequest = 
SAMLUtils.buildAuthnRequestObject(randomId, spId, identityProviderUrl, 
consumerUrl);
+            AuthnRequest authnRequest = 
SAMLUtils.buildAuthnRequestObject(randomSecureId, spId, identityProviderUrl, 
consumerUrl);
             redirectUrl = identityProviderUrl + "?SAMLRequest=" + 
SAMLUtils.encodeSAMLRequest(authnRequest);
         } catch (ConfigurationException | FactoryConfigurationError | 
MarshallingException | IOException e) {
             s_logger.error("SAML AuthnRequest message building error: " + 
e.getMessage());
@@ -137,8 +147,12 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd 
implements APIAuthent
     public String authenticate(final String command, final Map<String, 
Object[]> params, final HttpSession session, final String remoteAddress, final 
String responseType, final StringBuilder auditTrailSb, final 
HttpServletResponse resp) throws ServerApiException {
         try {
             if (!params.containsKey("SAMLResponse")) {
-                final String[] idps = (String[])params.get("idpurl");
-                String redirectUrl = 
buildAuthnRequestUrl("http://localhost:8080/client/api?command=samlsso";, 
idps[0]);
+                String idpUrl = null;
+                final String[] idps = 
(String[])params.get(ApiConstants.IDP_URL);
+                if (idps != null && idps.length > 0) {
+                    idpUrl = idps[0];
+                }
+                String redirectUrl = buildAuthnRequestUrl(idpUrl);
                 resp.sendRedirect(redirectUrl);
                 return "";
             } else {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/828f0d5f/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
new file mode 100644
index 0000000..41595b6
--- /dev/null
+++ 
b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java
@@ -0,0 +1,131 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.saml;
+
+import com.cloud.configuration.Config;
+import com.cloud.utils.component.AdapterBase;
+import org.apache.cloudstack.api.auth.PluggableAPIAuthenticator;
+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.common.xml.SAMLConstants;
+import org.opensaml.saml2.metadata.EntityDescriptor;
+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.parse.BasicParserPool;
+import org.springframework.stereotype.Component;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+@Local(value = {PluggableAPIAuthenticator.class, SAML2AuthManager.class})
+public class SAML2AuthManagerImpl extends AdapterBase implements 
PluggableAPIAuthenticator, SAML2AuthManager {
+    private static final Logger s_logger = 
Logger.getLogger(SAML2AuthManagerImpl.class);
+
+    private String serviceProviderId;
+    private String spSingleSignOnUrl;
+    private String spSingleLogOutUrl;
+
+    private String idpSingleSignOnUrl;
+    private String idpSingleLogOutUrl;
+
+    @Inject
+    ConfigurationDao _configDao;
+
+    protected SAML2AuthManagerImpl() {
+        super();
+    }
+
+    @Override
+    public boolean start() {
+        this.serviceProviderId = 
_configDao.getValue(Config.SAMLServiceProviderID.key());
+        this.spSingleSignOnUrl = 
_configDao.getValue(Config.SAMLServiceProviderSingleSignOnURL.key());
+        this.spSingleLogOutUrl = 
_configDao.getValue(Config.SAMLServiceProviderSingleLogOutURL.key());
+
+        String idpMetaDataUrl = 
_configDao.getValue(Config.SAMLIdentityProviderMetadataURL.key());
+
+        int tolerance = 30000;
+        String timeout = _configDao.getValue(Config.SAMLTimeout.key());
+        if (timeout != null) {
+            tolerance = Integer.parseInt(timeout);
+        }
+
+        try {
+            HTTPMetadataProvider 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();
+                }
+            }
+            for (SingleLogoutService slos: 
idpEntityDescriptor.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleLogoutServices())
 {
+                if 
(slos.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
+                    this.idpSingleLogOutUrl = slos.getLocation();
+                }
+            }
+
+        } catch (MetadataProviderException e) {
+            s_logger.error("Unable to read SAML2 IDP MetaData URL, error:" + 
e.getMessage());
+            s_logger.error("SAML2 Authentication may be unavailable");
+        }
+
+        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");
+        }
+
+        return true;
+    }
+
+    @Override
+    public List<Class<?>> getAuthCommands() {
+        List<Class<?>> cmdList = new ArrayList<Class<?>>();
+        cmdList.add(SAML2LoginAPIAuthenticatorCmd.class);
+        cmdList.add(SAML2LogoutAPIAuthenticatorCmd.class);
+        return cmdList;
+    }
+
+    public String getServiceProviderId() {
+        return serviceProviderId;
+    }
+
+    public String getIdpSingleSignOnUrl() {
+        return this.idpSingleSignOnUrl;
+    }
+
+    public String getIdpSingleLogOutUrl() {
+        return this.idpSingleLogOutUrl;
+    }
+
+    public String getSpSingleSignOnUrl() {
+        return spSingleSignOnUrl;
+    }
+
+    public String getSpSingleLogOutUrl() {
+        return spSingleLogOutUrl;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/828f0d5f/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthServiceImpl.java
 
b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthServiceImpl.java
deleted file mode 100644
index 44e29ca..0000000
--- 
a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2AuthServiceImpl.java
+++ /dev/null
@@ -1,51 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-package org.apache.cloudstack.saml;
-
-import com.cloud.utils.component.AdapterBase;
-import org.apache.cloudstack.api.auth.PluggableAPIAuthenticator;
-import org.apache.cloudstack.api.command.SAML2LoginAPIAuthenticatorCmd;
-import org.apache.cloudstack.api.command.SAML2LogoutAPIAuthenticatorCmd;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
-import javax.ejb.Local;
-import java.util.ArrayList;
-import java.util.List;
-
-@Component
-@Local(value = PluggableAPIAuthenticator.class)
-public class SAML2AuthServiceImpl extends AdapterBase implements 
PluggableAPIAuthenticator {
-    private static final Logger s_logger = 
Logger.getLogger(SAML2AuthServiceImpl.class);
-
-    protected SAML2AuthServiceImpl() {
-        super();
-    }
-
-    @Override
-    public boolean start() {
-        return true;
-    }
-
-    @Override
-    public List<Class<?>> getAuthCommands() {
-        List<Class<?>> cmdList = new ArrayList<Class<?>>();
-        cmdList.add(SAML2LoginAPIAuthenticatorCmd.class);
-        cmdList.add(SAML2LogoutAPIAuthenticatorCmd.class);
-        return cmdList;
-    }
-}

Reply via email to