You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by bh...@apache.org on 2015/05/29 15:44:02 UTC

[10/11] git commit: updated refs/heads/saml-production-grade to 89a290f

CLOUDSTACK-8463: Use username attribute specified in global setting

Use username attribute defined by admin from a global setting
In case of encrypted assertion/attributes:
- Decrypt them
- Check signature if provided to check authenticity of message using IdP's
  public key and SP's private key
- Loop through attributes to find the username

Signed-off-by: Rohit Yadav <ro...@shapeblue.com>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/89a290f2
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/89a290f2
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/89a290f2

Branch: refs/heads/saml-production-grade
Commit: 89a290f2b6cce80b19ae567e91d4052e43e33894
Parents: f2466e3
Author: Rohit Yadav <ro...@shapeblue.com>
Authored: Fri May 29 15:39:31 2015 +0200
Committer: Rohit Yadav <ro...@shapeblue.com>
Committed: Fri May 29 15:43:33 2015 +0200

----------------------------------------------------------------------
 .../command/SAML2LoginAPIAuthenticatorCmd.java  | 103 ++++++++++++++-----
 1 file changed, 77 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/89a290f2/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 108a5c7..cabb730 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
@@ -47,13 +47,19 @@ import org.opensaml.saml2.core.Assertion;
 import org.opensaml.saml2.core.Attribute;
 import org.opensaml.saml2.core.AttributeStatement;
 import org.opensaml.saml2.core.AuthnRequest;
-import org.opensaml.saml2.core.NameID;
-import org.opensaml.saml2.core.NameIDType;
+import org.opensaml.saml2.core.EncryptedAssertion;
 import org.opensaml.saml2.core.Response;
 import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.encryption.Decrypter;
 import org.opensaml.xml.ConfigurationException;
+import org.opensaml.xml.encryption.DecryptionException;
+import org.opensaml.xml.encryption.EncryptedKeyResolver;
+import org.opensaml.xml.encryption.InlineEncryptedKeyResolver;
 import org.opensaml.xml.io.MarshallingException;
 import org.opensaml.xml.io.UnmarshallingException;
+import org.opensaml.xml.security.SecurityHelper;
+import org.opensaml.xml.security.credential.Credential;
+import org.opensaml.xml.security.keyinfo.StaticKeyInfoCredentialResolver;
 import org.opensaml.xml.security.x509.BasicX509Credential;
 import org.opensaml.xml.signature.SignatureValidator;
 import org.opensaml.xml.validation.ValidationException;
@@ -69,6 +75,7 @@ import javax.xml.stream.FactoryConfigurationError;
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.security.InvalidKeyException;
+import java.security.KeyPair;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.util.List;
@@ -188,8 +195,8 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
                             params, responseType));
                 }
 
-                if (_samlAuthManager.getIdpSigningKey() != null) {
-                    org.opensaml.xml.signature.Signature sig = processedSAMLResponse.getSignature();
+                org.opensaml.xml.signature.Signature sig = processedSAMLResponse.getSignature();
+                if (_samlAuthManager.getIdpSigningKey() != null && sig != null) {
                     BasicX509Credential credential = new BasicX509Credential();
                     credential.setEntityCertificate(_samlAuthManager.getIdpSigningKey());
                     SignatureValidator validator = new SignatureValidator(credential);
@@ -219,30 +226,75 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
                     s_logger.error("The default domain ID for SAML users is not set correct, it should be a UUID. ROOT domain will be used.");
                 }
 
-                String username = null;
-
-                Assertion assertion = processedSAMLResponse.getAssertions().get(0);
-                NameID nameId = assertion.getSubject().getNameID();
-                String sessionIndex = assertion.getAuthnStatements().get(0).getSessionIndex();
-                session.setAttribute(SAMLUtils.SAML_NAMEID, nameId);
-                session.setAttribute(SAMLUtils.SAML_SESSION, sessionIndex);
+                KeyPair spKeyPair = _samlAuthManager.getSpKeyPair();
+                Credential credential = SecurityHelper.getSimpleCredential(_samlAuthManager.getIdpEncryptionKey().getPublicKey(), spKeyPair.getPrivate());
+                StaticKeyInfoCredentialResolver keyInfoResolver = new StaticKeyInfoCredentialResolver(credential);
+                EncryptedKeyResolver keyResolver = new InlineEncryptedKeyResolver();
+                Decrypter decrypter = new Decrypter(null, keyInfoResolver, keyResolver);
+                decrypter.setRootInNewDocument(true);
 
-                if (nameId.getFormat().equals(NameIDType.PERSISTENT) || nameId.getFormat().equals(NameIDType.EMAIL)) {
-                    username = nameId.getValue();
+                String username = null;
+                String usernameAttributeName = SAML2AuthManager.SAMLUserAttributeName.value();
+                List<EncryptedAssertion> encryptedAssertions = processedSAMLResponse.getEncryptedAssertions();
+                if (encryptedAssertions != null) {
+                    for (EncryptedAssertion encryptedAssertion : encryptedAssertions) {
+                        try {
+                            Assertion assertion = decrypter.decrypt(encryptedAssertion);
+                            sig = assertion.getSignature();
+                            if (_samlAuthManager.getIdpSigningKey() != null && sig != null) {
+                                BasicX509Credential sigCredential = new BasicX509Credential();
+                                sigCredential.setEntityCertificate(_samlAuthManager.getIdpSigningKey());
+                                SignatureValidator validator = new SignatureValidator(sigCredential);
+                                try {
+                                    validator.validate(sig);
+                                } catch (ValidationException e) {
+                                    s_logger.error("SAML Response's signature failed to be validated by IDP signing key:" + e.getMessage());
+                                    throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.ACCOUNT_ERROR.getHttpCode(),
+                                            "SAML Response's signature failed to be validated by IDP signing key",
+                                            params, responseType));
+                                }
+                            }
+                            List<AttributeStatement> attributeStatements = assertion.getAttributeStatements();
+                            if (attributeStatements != null && attributeStatements.size() > 0) {
+                                for (AttributeStatement attributeStatement : attributeStatements) {
+                                    if (attributeStatement == null) {
+                                        continue;
+                                    }
+                                    if (username != null) {
+                                        break;
+                                    }
+                                    for (Attribute attribute : attributeStatement.getAttributes()) {
+                                        if (usernameAttributeName.equalsIgnoreCase(attribute.getName()) ||
+                                                usernameAttributeName.equalsIgnoreCase(attribute.getFriendlyName())) {
+                                            if (attribute.getAttributeValues().size() > 0) {
+                                                username = attribute.getAttributeValues().get(0).getDOM().getTextContent();
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        } catch (DecryptionException e) {
+                            s_logger.warn("SAML EncryptedAssertion error: " + e.toString());
+                        }
+                    }
                 }
 
-                List<AttributeStatement> attributeStatements = assertion.getAttributeStatements();
-                if (attributeStatements != null && attributeStatements.size() > 0) {
-                    for (AttributeStatement attributeStatement: attributeStatements) {
-                        if (attributeStatement == null) {
-                            continue;
-                        }
-                        // Try capturing standard LDAP attributes
-                        for (Attribute attribute: attributeStatement.getAttributes()) {
-                            String attributeName = attribute.getName();
-                            String attributeValue = attribute.getAttributeValues().get(0).getDOM().getTextContent();
-                            if (attributeName.equalsIgnoreCase(SAML2AuthManager.SAMLUserAttributeName.value()) && username == null) {
-                                username = attributeValue;
+                List<Assertion> assertions = processedSAMLResponse.getAssertions();
+                if (assertions != null) {
+                    for (Assertion assertion : assertions) {
+                        List<AttributeStatement> attributeStatements = assertion.getAttributeStatements();
+                        if (attributeStatements != null && attributeStatements.size() > 0) {
+                            for (AttributeStatement attributeStatement : attributeStatements) {
+                                if (attributeStatement == null) {
+                                    continue;
+                                }
+                                for (Attribute attribute : attributeStatement.getAttributes()) {
+                                    String attributeName = attribute.getName();
+                                    String attributeValue = attribute.getAttributeValues().get(0).getDOM().getTextContent();
+                                    if (attributeName.equalsIgnoreCase(SAML2AuthManager.SAMLUserAttributeName.value()) && username == null) {
+                                        username = attributeValue;
+                                    }
+                                }
                             }
                         }
                     }
@@ -270,7 +322,6 @@ public class SAML2LoginAPIAuthenticatorCmd extends BaseCmd implements APIAuthent
                             resp.addCookie(new Cookie("userfullname", URLEncoder.encode(loginResponse.getFirstName() + " " + loginResponse.getLastName(), HttpUtils.UTF_8).replace("+", "%20")));
                             resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value());
                             return ApiResponseSerializer.toSerializedString(loginResponse, responseType);
-
                         }
                     } catch (final CloudAuthenticationException ignored) {
                     }