made it use the default saml grant type

4.x.x
ayyoob 8 years ago
parent 38f61adf94
commit 4ec7762a5c

@ -19,10 +19,10 @@
"owner": "admin@carbon.super", "owner": "admin@carbon.super",
"dynamicClientAppRegistrationServiceURL": "%https.ip%/dynamic-client-web/register", "dynamicClientAppRegistrationServiceURL": "%https.ip%/dynamic-client-web/register",
"apiManagerClientAppRegistrationServiceURL": "https://%iot.gateway.host%:%iot.gateway.https.port%/api-application-registration/register/tenants", "apiManagerClientAppRegistrationServiceURL": "https://%iot.gateway.host%:%iot.gateway.https.port%/api-application-registration/register/tenants",
"grantType": "password refresh_token urn:ietf:params:oauth:grant-type:saml2-carbon urn:ietf:params:oauth:grant-type:jwt-bearer", "grantType": "password refresh_token urn:ietf:params:oauth:grant-type:saml2-bearer urn:ietf:params:oauth:grant-type:jwt-bearer",
"tokenScope": "admin", "tokenScope": "admin",
"callbackUrl": "%https.ip%/api/device-mgt/v1.0", "callbackUrl": "%https.ip%/api/device-mgt/v1.0",
"samlGrantTypeName": "urn:ietf:carbon:signed:grant-type:saml2-bearer" "samlGrantTypeName": "urn:ietf:params:oauth:grant-type:saml2-bearer"
}, },
"tokenServiceURL": "https://%iot.gateway.host%:%iot.gateway.https.port%/token" "tokenServiceURL": "https://%iot.gateway.host%:%iot.gateway.https.port%/token"
}, },

@ -83,48 +83,24 @@
org.wso2.carbon.device.mgt.oauth.extensions.* org.wso2.carbon.device.mgt.oauth.extensions.*
</Export-Package> </Export-Package>
<Import-Package> <Import-Package>
javax.security.auth.*,
org.apache.commons.logging, org.apache.commons.logging,
org.osgi.service.component, org.osgi.service.component,
org.wso2.carbon.device.mgt.oauth.extensions.*,
org.wso2.carbon.identity.application.common.model;version="${carbon.identity.framework.version.range}", org.wso2.carbon.identity.application.common.model;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth.callback;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth2;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth2.model;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth2.validators;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.user.api, org.wso2.carbon.user.api,
org.wso2.carbon.user.core.service, org.wso2.carbon.user.core.service,
org.wso2.carbon.user.core.tenant, org.wso2.carbon.user.core.tenant,
org.json.simple, org.json.simple,
javax.cache, javax.cache,
org.wso2.carbon.identity.core.util;version="${carbon.identity.framework.version.range}", org.wso2.carbon.identity.core.util;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth2.dto;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth2.token;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.utils, org.wso2.carbon.utils,
org.wso2.carbon.context, org.wso2.carbon.context,
org.wso2.carbon.identity.oauth.cache;version="${carbon.identity.framework.version.range}", org.wso2.carbon.identity.oauth.*;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth.config;version="${carbon.identity.framework.version.range}", org.wso2.carbon.apimgt.keymgt.*;version="${carbon.api.mgt.version.range}",
org.wso2.carbon.identity.oauth2.dao;version="${carbon.identity.framework.version.range}", org.wso2.carbon.base,
org.wso2.carbon.utils.multitenancy, org.wso2.carbon.identity.application.authentication.framework.model;version="${carbon.identity.framework.version.range}",
org.apache.commons.codec.binary;version="${commons-codec.wso2.osgi.version.range}",
org.wso2.carbon.identity.application.authentication.framework.model;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.base,
org.apache.commons.collections,
org.apache.commons.lang,
org.joda.time,
org.opensaml.saml2.core,
org.opensaml.security,
org.opensaml.xml.*,
org.w3c.dom,
org.wso2.carbon.identity.application.common.util;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.base;version="${carbon.identity.framework.version.range}", org.wso2.carbon.identity.base;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth2.token.handlers.grant.*;version="${carbon.identity.framework.version.range}", org.wso2.carbon.identity.oauth2.*;version="${carbon.identity.framework.version.range}",
org.wso2.carbon.identity.oauth2.util;version="${carbon.identity.framework.version.range}", org.wso2.carbon.utils.multitenancy
org.wso2.carbon.idp.mgt;version="${carbon.identity.framework.version.range}",
org.opensaml.common.xml,
org.wso2.carbon.identity.oauth.common;version="${carbon.identity.framework.version.range}",
org.opensaml,
org.wso2.carbon.apimgt.keymgt.*;version="${carbon.api.mgt.version.range}"
</Import-Package> </Import-Package>
</instructions> </instructions>
</configuration> </configuration>

@ -18,552 +18,34 @@
package org.wso2.carbon.device.mgt.oauth.extensions.handlers.grant; package org.wso2.carbon.device.mgt.oauth.extensions.handlers.grant;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.opensaml.DefaultBootstrap;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.Audience;
import org.opensaml.saml2.core.AudienceRestriction;
import org.opensaml.saml2.core.Conditions;
import org.opensaml.saml2.core.SubjectConfirmation;
import org.opensaml.security.SAMLSignatureProfileValidator;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.security.x509.X509Credential;
import org.opensaml.xml.signature.SignatureValidator;
import org.opensaml.xml.validation.ValidationException;
import org.w3c.dom.NodeList;
import org.wso2.carbon.apimgt.keymgt.ScopesIssuer; import org.wso2.carbon.apimgt.keymgt.ScopesIssuer;
import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser;
import org.wso2.carbon.identity.application.common.model.FederatedAuthenticatorConfig;
import org.wso2.carbon.identity.application.common.model.IdentityProvider;
import org.wso2.carbon.identity.application.common.model.Property;
import org.wso2.carbon.identity.application.common.util.IdentityApplicationConstants;
import org.wso2.carbon.identity.application.common.util.IdentityApplicationManagementUtil;
import org.wso2.carbon.identity.base.IdentityConstants;
import org.wso2.carbon.identity.base.IdentityException;
import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.oauth.common.OAuthConstants;
import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.model.RequestParameter;
import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext;
import org.wso2.carbon.identity.oauth2.token.handlers.grant.AbstractAuthorizationGrantHandler; import org.wso2.carbon.identity.oauth2.token.handlers.grant.saml.SAML2BearerGrantHandler;
import org.wso2.carbon.identity.oauth2.token.handlers.grant.saml.SAML2TokenCallbackHandler;
import org.wso2.carbon.identity.oauth2.util.X509CredentialImpl;
import org.wso2.carbon.idp.mgt.IdentityProviderManagementException;
import org.wso2.carbon.idp.mgt.IdentityProviderManager;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* This looks up for idp in supertenant space. * This sets up user with tenant aware username.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class ExtendedSAML2BearerGrantHandler extends AbstractAuthorizationGrantHandler { public class ExtendedSAML2BearerGrantHandler extends SAML2BearerGrantHandler {
private static Log log = LogFactory.getLog(ExtendedSAML2BearerGrantHandler.class); private static Log log = LogFactory.getLog(ExtendedSAML2BearerGrantHandler.class);
SAMLSignatureProfileValidator profileValidator = null;
private static final String ASSERTION_IDENTIFIER = "assertion";
@Override
public void init() throws IdentityOAuth2Exception {
super.init();
Thread thread = Thread.currentThread();
ClassLoader loader = thread.getContextClassLoader();
thread.setContextClassLoader(this.getClass().getClassLoader());
try {
DefaultBootstrap.bootstrap();
} catch (ConfigurationException e) {
log.error("Error in bootstrapping the OpenSAML2 library", e);
throw new IdentityOAuth2Exception("Error in bootstrapping the OpenSAML2 library");
} finally {
thread.setContextClassLoader(loader);
}
profileValidator = new SAMLSignatureProfileValidator();
}
@Override @Override
public boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) { public boolean validateScope(OAuthTokenReqMessageContext tokReqMsgCtx) {
return ScopesIssuer.getInstance().setScopes(tokReqMsgCtx); return ScopesIssuer.getInstance().setScopes(tokReqMsgCtx);
} }
/**
* We're validating the SAML token that we receive from the request. Through the assertion parameter is the POST
* request. A request format that we handle here looks like,
* <p/>
* POST /token.oauth2 HTTP/1.1
* Host: as.example.com
* Content-Type: application/x-www-form-urlencoded
* <p/>
* grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2-bearer&
* assertion=PHNhbWxwOl...[omitted for brevity]...ZT4
*
* @param tokReqMsgCtx Token message request context
* @return true if validation is successful, false otherwise
* @throws org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception
*/
@Override @Override
public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception { public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {
RequestParameter[] parameters = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getRequestParameters();
for (RequestParameter parameter : parameters) {
if (ASSERTION_IDENTIFIER.equals(parameter.getKey())) {
tokReqMsgCtx.getOauth2AccessTokenReqDTO().setAssertion(parameter.getValue()[0]);
}
}
if(!super.validateGrant(tokReqMsgCtx)){ if(!super.validateGrant(tokReqMsgCtx)){
return false; return false;
} }
AuthenticatedUser authenticatedUser = tokReqMsgCtx.getAuthorizedUser();
Assertion assertion = null; authenticatedUser.setUserName(MultitenantUtils.getTenantAwareUsername(authenticatedUser.getUserName()));
IdentityProvider identityProvider = null;
String tokenEndpointAlias = null;
String tenantDomain = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getTenantDomain();
if (tenantDomain == null || "".equals(tenantDomain)) {
tenantDomain = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
}
// Logging the SAML token
if (log.isDebugEnabled() && IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.SAML_ASSERTION)) {
log.debug("Received SAML assertion : " +
new String(Base64.decodeBase64(tokReqMsgCtx.getOauth2AccessTokenReqDTO().getAssertion()))
);
}
try {
XMLObject samlObject = IdentityUtil.unmarshall(new String(Base64.decodeBase64(
tokReqMsgCtx.getOauth2AccessTokenReqDTO().getAssertion())));
// Validating for multiple assertions
NodeList assertionList = samlObject.getDOM().getElementsByTagNameNS(SAMLConstants.SAML20_NS, "Assertion");
if (assertionList.getLength() > 0) {
log.error("Invalid schema for SAML2 Assertion. Nested assertions detected.");
return false;
}
if (samlObject instanceof Assertion) {
assertion = (Assertion) samlObject;
} else {
log.error("Only Assertion objects are validated in SAML2Bearer Grant Type");
return false;
}
} catch (IdentityException e) {
// fault in the saml2 assertion
if(log.isDebugEnabled()){
log.debug("Error while unmashalling the assertion", e);
}
return false;
}
if (assertion == null) {
log.debug("Assertion is null, cannot continue");
return false;
}
/*
The Assertion MUST contain a <Subject> element. The subject MAY identify the resource owner for whom
the access token is being requested. For client authentication, the Subject MUST be the "client_id"
of the OAuth client. When using an Assertion as an authorization grant, the Subject SHOULD identify
an authorized accessor for whom the access token is being requested (typically the resource owner, or
an authorized delegate). Additional information identifying the subject/principal of the transaction
MAY be included in an <AttributeStatement>.
*/
if (assertion.getSubject() != null) {
String subjectIdentifier = assertion.getSubject().getNameID().getValue();
if (StringUtils.isBlank(subjectIdentifier)) {
if (log.isDebugEnabled()){
log.debug("NameID in Assertion cannot be empty");
}
return false;
}
AuthenticatedUser user =
AuthenticatedUser.createFederateAuthenticatedUserFromSubjectIdentifier(subjectIdentifier);
user.setUserName(MultitenantUtils.getTenantAwareUsername(subjectIdentifier));
// we take a tenant domain of the authorized user to be the tenant domain of the OAuth app
user.setTenantDomain(tenantDomain);
tokReqMsgCtx.setAuthorizedUser(user);
tenantDomain = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
} else {
if (log.isDebugEnabled()) {
log.debug("Cannot find a Subject in the Assertion");
}
return false;
}
if (assertion.getIssuer() == null || "".equals(assertion.getIssuer().getValue())) {
if (log.isDebugEnabled()) {
log.debug("Issuer is empty in the SAML assertion");
}
return false;
} else {
try {
identityProvider = IdentityProviderManager.getInstance().
getIdPByAuthenticatorPropertyValue("IdPEntityId",
assertion.getIssuer().getValue(), tenantDomain, false);
// IF Federated IDP not found get the resident IDP and check,
// resident IDP entityID == issuer
if (identityProvider != null) {
if (IdentityApplicationConstants.RESIDENT_IDP_RESERVED_NAME.equals(
identityProvider.getIdentityProviderName())) {
identityProvider = IdentityProviderManager.getInstance().getResidentIdP(tenantDomain);
FederatedAuthenticatorConfig[] fedAuthnConfigs =
identityProvider.getFederatedAuthenticatorConfigs();
String idpEntityId = null;
// Get SAML authenticator
FederatedAuthenticatorConfig samlAuthenticatorConfig =
IdentityApplicationManagementUtil.getFederatedAuthenticator(fedAuthnConfigs,
IdentityApplicationConstants.Authenticator.SAML2SSO.NAME);
// Get Entity ID from SAML authenticator
Property samlProperty = IdentityApplicationManagementUtil.getProperty(
samlAuthenticatorConfig.getProperties(),
IdentityApplicationConstants.Authenticator.SAML2SSO.IDP_ENTITY_ID);
if (samlProperty != null) {
idpEntityId = samlProperty.getValue();
}
if (idpEntityId == null || !assertion.getIssuer().getValue().equals(idpEntityId)) {
if(log.isDebugEnabled()) {
log.debug("SAML Token Issuer verification failed against resident Identity Provider " +
"in tenant : " + tenantDomain + ". Received : " +
assertion.getIssuer().getValue() + ", Expected : " + idpEntityId);
}
return false;
}
// Get OpenIDConnect authenticator == OAuth
// authenticator
FederatedAuthenticatorConfig oauthAuthenticatorConfig =
IdentityApplicationManagementUtil.getFederatedAuthenticator(fedAuthnConfigs,
IdentityApplicationConstants.Authenticator.OIDC.NAME);
// Get OAuth token endpoint
Property oauthProperty = IdentityApplicationManagementUtil.getProperty(
oauthAuthenticatorConfig.getProperties(),
IdentityApplicationConstants.Authenticator.OIDC.OAUTH2_TOKEN_URL);
if (oauthProperty != null) {
tokenEndpointAlias = oauthProperty.getValue();
}
} else {
// Get Alias from Federated IDP
tokenEndpointAlias = identityProvider.getAlias();
}
} else {
if(log.isDebugEnabled()) {
log.debug("SAML Token Issuer : " + assertion.getIssuer().getValue() +
" not registered as a local Identity Provider in tenant : " + tenantDomain);
}
return false;
}
} catch (IdentityProviderManagementException e) {
throw new IdentityOAuth2Exception("Error while getting an Identity Provider for issuer value : " +
assertion.getIssuer().getValue(), e);
}
}
/*
The Assertion MUST contain <Conditions> element with an <AudienceRestriction> element with an <Audience>
element containing a URI reference that identifies the authorization server, or the service provider
SAML entity of its controlling domain, as an intended audience. The token endpoint URL of the
authorization server MAY be used as an acceptable value for an <Audience> element. The authorization
server MUST verify that it is an intended audience for the Assertion.
*/
if (StringUtils.isBlank(tokenEndpointAlias)) {
if (log.isDebugEnabled()){
String errorMsg = "Token Endpoint alias has not been configured in the Identity Provider : "
+ identityProvider.getIdentityProviderName() + " in tenant : " + tenantDomain;
log.debug(errorMsg);
}
return false;
}
Conditions conditions = assertion.getConditions();
if (conditions != null) {
//Set validity period extracted from SAML Assertion
long curTimeInMillis = Calendar.getInstance().getTimeInMillis();
tokReqMsgCtx.setValidityPeriod(conditions.getNotOnOrAfter().getMillis() - curTimeInMillis);
List<AudienceRestriction> audienceRestrictions = conditions.getAudienceRestrictions();
if (audienceRestrictions != null && !audienceRestrictions.isEmpty()) {
boolean audienceFound = false;
for (AudienceRestriction audienceRestriction : audienceRestrictions) {
if (CollectionUtils.isNotEmpty(audienceRestriction.getAudiences())) {
for (Audience audience : audienceRestriction.getAudiences()) {
if (audience.getAudienceURI().equals(tokenEndpointAlias)) {
audienceFound = true;
break;
}
}
}
if (audienceFound) {
break;
}
}
if (!audienceFound) {
if (log.isDebugEnabled()) {
log.debug("SAML Assertion Audience Restriction validation failed against the Audience : " +
tokenEndpointAlias + " of Identity Provider : " +
identityProvider.getIdentityProviderName() + " in tenant : " + tenantDomain);
}
return false;
}
} else {
if (log.isDebugEnabled()) {
String message = "SAML Assertion doesn't contain AudienceRestrictions";
log.debug(message);
}
return false;
}
} else {
if (log.isDebugEnabled()) {
String message = "SAML Assertion doesn't contain Conditions";
log.debug(message);
}
return false;
}
/*
The Assertion MUST have an expiry that limits the time window during which it can be used. The expiry
can be expressed either as the NotOnOrAfter attribute of the <Conditions> element or as the NotOnOrAfter
attribute of a suitable <SubjectConfirmationData> element.
*/
/*
The <Subject> element MUST contain at least one <SubjectConfirmation> element that allows the
authorization server to confirm it as a Bearer Assertion. Such a <SubjectConfirmation> element MUST
have a Method attribute with a value of "urn:oasis:names:tc:SAML:2.0:cm:bearer". The
<SubjectConfirmation> element MUST contain a <SubjectConfirmationData> element, unless the Assertion
has a suitable NotOnOrAfter attribute on the <Conditions> element, in which case the
<SubjectConfirmationData> element MAY be omitted. When present, the <SubjectConfirmationData> element
MUST have a Recipient attribute with a value indicating the token endpoint URL of the authorization
server (or an acceptable alias). The authorization server MUST verify that the value of the Recipient
attribute matches the token endpoint URL (or an acceptable alias) to which the Assertion was delivered.
The <SubjectConfirmationData> element MUST have a NotOnOrAfter attribute that limits the window during
which the Assertion can be confirmed. The <SubjectConfirmationData> element MAY also contain an Address
attribute limiting the client address from which the Assertion can be delivered. Verification of the
Address is at the discretion of the authorization server.
*/
DateTime notOnOrAfterFromConditions = null;
Map<DateTime,DateTime> notOnOrAfterFromAndNotBeforeSubjectConfirmations = new HashMap<>();
boolean bearerFound = false;
List<String> recipientURLS = new ArrayList<>();
if (assertion.getConditions() != null && assertion.getConditions().getNotOnOrAfter() != null) {
notOnOrAfterFromConditions = assertion.getConditions().getNotOnOrAfter();
}
DateTime notBeforeConditions = null;
if (assertion.getConditions() != null && assertion.getConditions().getNotBefore() != null) {
notBeforeConditions = assertion.getConditions().getNotBefore();
}
List<SubjectConfirmation> subjectConfirmations = assertion.getSubject().getSubjectConfirmations();
if (subjectConfirmations != null && !subjectConfirmations.isEmpty()) {
for (SubjectConfirmation s : subjectConfirmations) {
if (s.getMethod() != null) {
if (s.getMethod().equals(OAuthConstants.OAUTH_SAML2_BEARER_METHOD)) {
bearerFound = true;
}
} else {
if (log.isDebugEnabled()){
log.debug("Cannot find Method attribute in SubjectConfirmation " + s.toString());
}
return false;
}
if (s.getSubjectConfirmationData() != null) {
if (s.getSubjectConfirmationData().getRecipient() != null) {
recipientURLS.add(s.getSubjectConfirmationData().getRecipient());
}
if (s.getSubjectConfirmationData().getNotOnOrAfter() != null || s.getSubjectConfirmationData()
.getNotBefore() != null) {
notOnOrAfterFromAndNotBeforeSubjectConfirmations.put(s.getSubjectConfirmationData().getNotOnOrAfter(),
s.getSubjectConfirmationData().getNotBefore());
} else {
if (log.isDebugEnabled()){
log.debug("Cannot find NotOnOrAfter and NotBefore attributes in " +
"SubjectConfirmationData " +
s.getSubjectConfirmationData().toString());
}
}
} else {
if (s.getSubjectConfirmationData() == null && notOnOrAfterFromConditions == null) {
if (log.isDebugEnabled()){
log.debug("Neither can find NotOnOrAfter attribute in Conditions nor SubjectConfirmationData" +
"in SubjectConfirmation " + s.toString());
}
return false;
}
if (s.getSubjectConfirmationData() == null && notBeforeConditions == null) {
if (log.isDebugEnabled()){
log.debug("Neither can find NotBefore attribute in Conditions nor SubjectConfirmationData" +
"in SubjectConfirmation " + s.toString());
}
return false;
}
}
}
} else {
if (log.isDebugEnabled()){
log.debug("No SubjectConfirmation exist in Assertion");
}
return false;
}
if (!bearerFound) {
if (log.isDebugEnabled()){
log.debug("Failed to find a SubjectConfirmation with a Method attribute having : " +
OAuthConstants.OAUTH_SAML2_BEARER_METHOD);
}
return false;
}
if (CollectionUtils.isNotEmpty(recipientURLS) && !recipientURLS.contains(tokenEndpointAlias)) {
if (log.isDebugEnabled()){
log.debug("None of the recipient URLs match against the token endpoint alias : " + tokenEndpointAlias +
" of Identity Provider " + identityProvider.getIdentityProviderName() + " in tenant : " +
tenantDomain);
}
return false;
}
/*
The authorization server MUST verify that the NotOnOrAfter instant has not passed, subject to allowable
clock skew between systems. An invalid NotOnOrAfter instant on the <Conditions> element invalidates
the entire Assertion. An invalid NotOnOrAfter instant on a <SubjectConfirmationData> element only
invalidates the individual <SubjectConfirmation>. The authorization server MAY reject Assertions with
a NotOnOrAfter instant that is unreasonably far in the future. The authorization server MAY ensure
that Bearer Assertions are not replayed, by maintaining the set of used ID values for the length of
time for which the Assertion would be considered valid based on the applicable NotOnOrAfter instant.
*/
if (notOnOrAfterFromConditions != null && notOnOrAfterFromConditions.compareTo(new DateTime()) < 1) {
// notOnOrAfter is an expired timestamp
if (log.isDebugEnabled()){
log.debug("NotOnOrAfter is having an expired timestamp in Conditions element");
}
return false;
}
if (notBeforeConditions != null && notBeforeConditions.compareTo(new DateTime()) >= 1) {
// notBefore is an early timestamp
if (log.isDebugEnabled()){
log.debug("NotBefore is having an early timestamp in Conditions element");
}
return false;
}
boolean validSubjectConfirmationDataExists = false;
if (!notOnOrAfterFromAndNotBeforeSubjectConfirmations.isEmpty()) {
for (Map.Entry<DateTime, DateTime> entry : notOnOrAfterFromAndNotBeforeSubjectConfirmations.entrySet()) {
if (entry.getKey() != null) {
if (entry.getKey().compareTo(new DateTime()) >= 1) {
validSubjectConfirmationDataExists = true;
}
}
if (entry.getValue() != null) {
if (entry.getValue().compareTo(new DateTime()) < 1) {
validSubjectConfirmationDataExists = true;
}
}
}
}
if (notOnOrAfterFromConditions == null && !validSubjectConfirmationDataExists) {
if (log.isDebugEnabled()){
log.debug("No valid NotOnOrAfter element found in SubjectConfirmations");
}
return false;
}
if (notBeforeConditions == null && !validSubjectConfirmationDataExists) {
if (log.isDebugEnabled()){
log.debug("No valid NotBefore element found in SubjectConfirmations");
}
return false;
}
/*
The Assertion MUST be digitally signed by the issuer and the authorization server MUST verify the
signature.
*/
try {
profileValidator.validate(assertion.getSignature());
} catch (ValidationException e) {
// Indicates signature did not conform to SAML Signature profile
log.error("Signature do not confirm to SAML signature profile.", e);
return false;
}
X509Certificate x509Certificate = null;
try {
x509Certificate = (X509Certificate) IdentityApplicationManagementUtil
.decodeCertificate(identityProvider.getCertificate());
} catch (CertificateException e) {
throw new IdentityOAuth2Exception("Error occurred while decoding public certificate of Identity Provider "
+ identityProvider.getIdentityProviderName() + " for tenant domain " + tenantDomain, e);
}
try {
X509Credential x509Credential = new X509CredentialImpl(x509Certificate);
SignatureValidator signatureValidator = new SignatureValidator(x509Credential);
signatureValidator.validate(assertion.getSignature());
if (log.isDebugEnabled()){
log.debug("Signature validation successful");
}
} catch (ValidationException e) {
log.error("Error while validating the signature.", e);
return false;
}
/*
The authorization server MUST verify that the Assertion is valid in all other respects per
[OASIS.saml-core-2.0-os], such as (but not limited to) evaluating all content within the Conditions
element including the NotOnOrAfter and NotBefore attributes, rejecting unknown condition types, etc.
[OASIS.saml-core-2.0-os] - http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
*/
// TODO: Throw the SAML request through the general SAML2 validation routines
tokReqMsgCtx.setScope(tokReqMsgCtx.getOauth2AccessTokenReqDTO().getScope());
// Storing the Assertion. This will be used in OpenID Connect for example
tokReqMsgCtx.addProperty(OAuthConstants.OAUTH_SAML2_ASSERTION, assertion);
// Invoking extension
SAML2TokenCallbackHandler callback =
OAuthServerConfiguration.getInstance()
.getSAML2TokenCallbackHandler();
if (callback != null) {
if (log.isDebugEnabled()){
log.debug("Invoking the SAML2 Token callback handler ");
}
callback.handleSAML2Token(tokReqMsgCtx);
}
return true; return true;
} }

Loading…
Cancel
Save