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) {
}