saml2: Fix plugin after refactoring

- Use opensaml version from root pom
- Add utils and api as explicit dependency
- Add org.apache.cloudstack.saml.SAML2AuthServiceImpl bean
- Fix imports in all source files and resource xmls
- Use methods available from SAMLUtils to encode/decode SAML request/response
- SAML logout api is not the global logout api

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

Branch: refs/heads/master
Commit: d45b303569af77c3c8c673bfb47ad6fdf21a8cbc
Parents: 591a686
Author: Rohit Yadav <rohit.ya...@shapeblue.com>
Authored: Sun Aug 24 16:01:22 2014 +0200
Committer: Rohit Yadav <rohit.ya...@shapeblue.com>
Committed: Thu Aug 28 19:45:23 2014 +0200

----------------------------------------------------------------------
 plugins/user-authenticators/saml2/pom.xml       |  12 +-
 .../cloudstack/saml2/spring-saml2-context.xml   |   6 +-
 .../command/SAML2LoginAPIAuthenticatorCmd.java  | 128 ++-----------------
 .../command/SAML2LogoutAPIAuthenticatorCmd.java |   2 +-
 .../cloudstack/saml/SAML2UserAuthenticator.java |   3 +-
 5 files changed, 27 insertions(+), 124 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d45b3035/plugins/user-authenticators/saml2/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/saml2/pom.xml 
b/plugins/user-authenticators/saml2/pom.xml
index a220dcf..df6aa45 100644
--- a/plugins/user-authenticators/saml2/pom.xml
+++ b/plugins/user-authenticators/saml2/pom.xml
@@ -35,7 +35,17 @@
     <dependency>
       <groupId>org.opensaml</groupId>
       <artifactId>opensaml</artifactId>
-      <version>2.6.1</version>
+      <version>${cs.opensaml.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-utils</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-api</artifactId>
+      <version>${project.version}</version>
     </dependency>
   </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d45b3035/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 f244292..15e085d 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
@@ -25,8 +25,12 @@
                       http://www.springframework.org/schema/context
                       
http://www.springframework.org/schema/context/spring-context-3.0.xsd";>
 
-    <bean id="SAML2UserAuthenticator" 
class="org.apache.cloudstack.SAML2UserAuthenticator">
+    <bean id="SAML2UserAuthenticator" 
class="org.apache.cloudstack.saml.SAML2UserAuthenticator">
         <property name="name" value="SAML2"/>
     </bean>
 
+    <bean id="SAML2Manager" 
class="org.apache.cloudstack.saml.SAML2AuthServiceImpl">
+        <property name="name" value="SAML2Auth"/>
+    </bean>
+
 </beans>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d45b3035/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 611c69b..463df7d 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
@@ -34,63 +34,35 @@ 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.utils.auth.SAMLUtils;
 import org.apache.log4j.Logger;
-import org.joda.time.DateTime;
-import org.opensaml.Configuration;
 import org.opensaml.DefaultBootstrap;
-import org.opensaml.common.SAMLVersion;
-import org.opensaml.common.xml.SAMLConstants;
 import org.opensaml.saml2.core.Assertion;
 import org.opensaml.saml2.core.Attribute;
 import org.opensaml.saml2.core.AttributeStatement;
-import org.opensaml.saml2.core.AuthnContextClassRef;
-import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration;
 import org.opensaml.saml2.core.AuthnRequest;
-import org.opensaml.saml2.core.Issuer;
 import org.opensaml.saml2.core.NameID;
-import org.opensaml.saml2.core.NameIDPolicy;
 import org.opensaml.saml2.core.NameIDType;
-import org.opensaml.saml2.core.RequestedAuthnContext;
 import org.opensaml.saml2.core.Response;
 import org.opensaml.saml2.core.StatusCode;
-import org.opensaml.saml2.core.impl.AuthnContextClassRefBuilder;
-import org.opensaml.saml2.core.impl.AuthnRequestBuilder;
-import org.opensaml.saml2.core.impl.IssuerBuilder;
-import org.opensaml.saml2.core.impl.NameIDPolicyBuilder;
-import org.opensaml.saml2.core.impl.RequestedAuthnContextBuilder;
 import org.opensaml.xml.ConfigurationException;
-import org.opensaml.xml.XMLObject;
-import org.opensaml.xml.io.Marshaller;
 import org.opensaml.xml.io.MarshallingException;
-import org.opensaml.xml.io.Unmarshaller;
-import org.opensaml.xml.io.UnmarshallerFactory;
 import org.opensaml.xml.io.UnmarshallingException;
 import org.opensaml.xml.signature.Signature;
-import org.opensaml.xml.util.Base64;
-import org.opensaml.xml.util.XMLHelper;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
 
 import javax.inject.Inject;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.stream.FactoryConfigurationError;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.StringWriter;
 import java.math.BigInteger;
 import java.net.URLEncoder;
 import java.security.SecureRandom;
 import java.util.List;
 import java.util.Map;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
 
 @APICommand(name = "samlsso", description = "SP initiated SAML Single Sign 
On", requestHasSensitiveInfo = true, responseObject = LoginCmdResponse.class, 
entityType = {})
 public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements 
APIAuthenticator {
@@ -142,107 +114,23 @@ public class SAML2LoginAPIAuthenticatorCmd extends 
BaseCmd implements APIAuthent
         String redirectUrl = "";
         try {
             DefaultBootstrap.bootstrap();
-            AuthnRequest authnRequest = this.buildAuthnRequestObject(randomId, 
spId, identityProviderUrl, consumerUrl);
-            redirectUrl = identityProviderUrl + "?SAMLRequest=" + 
encodeAuthnRequest(authnRequest);
+            AuthnRequest authnRequest = 
SAMLUtils.buildAuthnRequestObject(randomId, 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());
         }
         return redirectUrl;
     }
 
-    private AuthnRequest buildAuthnRequestObject(String authnId, String spId, 
String idpUrl, String consumerUrl) {
-        // Issuer object
-        IssuerBuilder issuerBuilder = new IssuerBuilder();
-        Issuer issuer = issuerBuilder.buildObject();
-        issuer.setValue(spId);
-
-        // NameIDPolicy
-        NameIDPolicyBuilder nameIdPolicyBuilder = new NameIDPolicyBuilder();
-        NameIDPolicy nameIdPolicy = nameIdPolicyBuilder.buildObject();
-        nameIdPolicy.setFormat(NameIDType.PERSISTENT);
-        nameIdPolicy.setSPNameQualifier("Apache CloudStack");
-        nameIdPolicy.setAllowCreate(true);
-
-        // AuthnContextClass
-        AuthnContextClassRefBuilder authnContextClassRefBuilder = new 
AuthnContextClassRefBuilder();
-        AuthnContextClassRef authnContextClassRef = 
authnContextClassRefBuilder.buildObject(
-                SAMLConstants.SAML20_NS,
-                "AuthnContextClassRef", "saml");
-        
authnContextClassRef.setAuthnContextClassRef("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport");
-
-        // AuthnContex
-        RequestedAuthnContextBuilder requestedAuthnContextBuilder = new 
RequestedAuthnContextBuilder();
-        RequestedAuthnContext requestedAuthnContext = 
requestedAuthnContextBuilder.buildObject();
-        requestedAuthnContext
-                .setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM);
-        requestedAuthnContext.getAuthnContextClassRefs().add(
-                authnContextClassRef);
-
-        // Creation of AuthRequestObject
-        AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder();
-        AuthnRequest authnRequest = authRequestBuilder.buildObject();
-        authnRequest.setID(authnId);
-        authnRequest.setDestination(idpUrl);
-        authnRequest.setVersion(SAMLVersion.VERSION_20);
-        authnRequest.setForceAuthn(true);
-        authnRequest.setIsPassive(false);
-        authnRequest.setIssuer(issuer);
-        authnRequest.setIssueInstant(new DateTime());
-        authnRequest.setProviderName("Apache CloudStack");
-        
authnRequest.setProtocolBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
-        authnRequest.setAssertionConsumerServiceURL(consumerUrl);
-        authnRequest.setNameIDPolicy(nameIdPolicy);
-        authnRequest.setRequestedAuthnContext(requestedAuthnContext);
-
-        return authnRequest;
-    }
-
-    private String encodeAuthnRequest(AuthnRequest authnRequest)
-            throws MarshallingException, IOException {
-        Marshaller marshaller = Configuration.getMarshallerFactory()
-                .getMarshaller(authnRequest);
-        Element authDOM = marshaller.marshall(authnRequest);
-        StringWriter requestWriter = new StringWriter();
-        XMLHelper.writeNode(authDOM, requestWriter);
-        String requestMessage = requestWriter.toString();
-        Deflater deflater = new Deflater(Deflater.DEFLATED, true);
-        ByteArrayOutputStream byteArrayOutputStream = new 
ByteArrayOutputStream();
-        DeflaterOutputStream deflaterOutputStream = new 
DeflaterOutputStream(byteArrayOutputStream, deflater);
-        deflaterOutputStream.write(requestMessage.getBytes());
-        deflaterOutputStream.close();
-        String encodedRequestMessage = 
Base64.encodeBytes(byteArrayOutputStream.toByteArray(), 
Base64.DONT_BREAK_LINES);
-        encodedRequestMessage = URLEncoder.encode(encodedRequestMessage, 
"UTF-8").trim();
-        return encodedRequestMessage;
-    }
-
     public Response processSAMLResponse(String responseMessage) {
-        XMLObject responseObject = null;
+        Response responseObject = null;
         try {
-            responseObject = this.unmarshall(responseMessage);
+            responseObject = SAMLUtils.decodeSAMLResponse(responseMessage);
 
         } catch (ConfigurationException | ParserConfigurationException | 
SAXException | IOException | UnmarshallingException e) {
             s_logger.error("SAMLResponse processing error: " + e.getMessage());
         }
-        return (Response) responseObject;
-    }
-
-    private XMLObject unmarshall(String responseMessage)
-            throws ConfigurationException, ParserConfigurationException,
-            SAXException, IOException, UnmarshallingException {
-        try {
-            DefaultBootstrap.bootstrap();
-        } catch (ConfigurationException | FactoryConfigurationError e) {
-            s_logger.error("SAML response message decoding error: " + 
e.getMessage());
-        }
-        DocumentBuilderFactory documentBuilderFactory = 
DocumentBuilderFactory.newInstance();
-        documentBuilderFactory.setNamespaceAware(true);
-        DocumentBuilder docBuilder = 
documentBuilderFactory.newDocumentBuilder();
-        byte[] base64DecodedResponse = Base64.decode(responseMessage);
-        Document document = docBuilder.parse(new 
ByteArrayInputStream(base64DecodedResponse));
-        Element element = document.getDocumentElement();
-        UnmarshallerFactory unmarshallerFactory = 
Configuration.getUnmarshallerFactory();
-        Unmarshaller unmarshaller = 
unmarshallerFactory.getUnmarshaller(element);
-        return unmarshaller.unmarshall(element);
+        return responseObject;
     }
 
     @Override
@@ -282,7 +170,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd 
implements APIAuthent
 
                 if (nameId.getFormat().equals(NameIDType.PERSISTENT) || 
nameId.getFormat().equals(NameIDType.EMAIL)) {
                     username = nameId.getValue();
-                    uniqueUserId = "saml-" + username;
+                    uniqueUserId = SAMLUtils.createSAMLId(username);
                     if (nameId.getFormat().equals(NameIDType.EMAIL)) {
                         email = username;
                     }
@@ -299,7 +187,7 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd 
implements APIAuthent
                     String attributeValue = 
attribute.getAttributeValues().get(0).getDOM().getTextContent();
                     if (attributeName.equalsIgnoreCase("uid") && uniqueUserId 
== null) {
                         username = attributeValue;
-                        uniqueUserId = "saml-" + username;
+                        uniqueUserId = SAMLUtils.createSAMLId(username);
                     } else if (attributeName.equalsIgnoreCase("givenName")) {
                         firstName = attributeValue;
                     } else if (attributeName.equalsIgnoreCase(("sn"))) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d45b3035/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 b82f2c8..32e2f99 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
@@ -31,7 +31,7 @@ import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import java.util.Map;
 
-@APICommand(name = "samlslo", description = "SAML Single Log Out API", 
responseObject = LogoutCmdResponse.class, entityType = {})
+@APICommand(name = "samlslo", description = "SAML Global Log Out API", 
responseObject = LogoutCmdResponse.class, entityType = {})
 public class SAML2LogoutAPIAuthenticatorCmd extends BaseCmd implements 
APIAuthenticator {
     public static final Logger s_logger = 
Logger.getLogger(SAML2LogoutAPIAuthenticatorCmd.class.getName());
     private static final String s_name = "logoutresponse";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d45b3035/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java
----------------------------------------------------------------------
diff --git 
a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java
 
b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java
index 1a37f65..a4902d1 100644
--- 
a/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java
+++ 
b/plugins/user-authenticators/saml2/src/org/apache/cloudstack/saml/SAML2UserAuthenticator.java
@@ -21,6 +21,7 @@ import com.cloud.user.UserAccount;
 import com.cloud.user.dao.UserAccountDao;
 import com.cloud.user.dao.UserDao;
 import com.cloud.utils.Pair;
+import org.apache.cloudstack.utils.auth.SAMLUtils;
 import org.apache.log4j.Logger;
 
 import javax.ejb.Local;
@@ -48,7 +49,7 @@ public class SAML2UserAuthenticator extends 
DefaultUserAuthenticator {
         } else {
             User user = _userDao.getUser(userAccount.getId());
             // TODO: check SAMLRequest, signature etc. from requestParameters
-            if (user != null && user.getUuid().startsWith("saml")) {
+            if (user != null && SAMLUtils.checkSAMLUserId(user.getUuid())) {
                 return new Pair<Boolean, ActionOnFailedAuthentication>(true, 
null);
             }
         }

Reply via email to