use of org.wso2.carbon.identity.saml.common.util.exception.IdentityUnmarshallingException in project identity-inbound-auth-oauth by wso2-extensions.
the class SAML2BearerGrantHandlerTest method validateGrantExceptionDataProvider.
@DataProvider(name = "validateGrantExceptionDataProvider")
public Object[][] validateGrantExceptionDataProvider() throws Exception {
NameID nameId1 = (new NameIDBuilder()).buildObject();
nameId1.setValue("nameIdValue");
Subject subject1 = (new SubjectBuilder()).buildObject();
subject1.setNameID(nameId1);
NameID nameId2 = (new NameIDBuilder()).buildObject();
nameId2.setValue(null);
Subject subject2 = (new SubjectBuilder()).buildObject();
subject2.setNameID(nameId2);
DateTime validOnOrAfter = new DateTime(System.currentTimeMillis() + 10000000L);
DateTime expiredOnOrAfter = new DateTime(System.currentTimeMillis() - 10000000L);
return new Object[][] { { validOnOrAfter, "LOCAL", true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, new IdentityUnmarshallingException("Error"), "Error while unmashalling" }, { validOnOrAfter, "FED", true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, new IdentityProviderManagementException("Error"), "Error while retrieving identity provider" }, { validOnOrAfter, "FED", true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, new SignatureException(), "Error while validating the signature" }, { validOnOrAfter, "LOCAL", true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, new IdentityApplicationManagementException("Error"), "Error while retrieving service provider" }, { validOnOrAfter, "LOCAL", true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, new UserStoreException(), "Error while building local user" }, { validOnOrAfter, "FED", true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, new CertificateException(), "Error occurred while decoding public certificate" }, { validOnOrAfter, "LOCAL", true, false, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, null, "User not found" }, { validOnOrAfter, "LOCAL", false, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, null, "Non SaaS app" }, { validOnOrAfter, "LOCAL", true, true, "invalidAudience", TestConstants.LOACALHOST_DOMAIN, null, "Audience Restriction validation failed" }, { validOnOrAfter, "LOCAL", true, true, "", TestConstants.LOACALHOST_DOMAIN, null, "Token Endpoint alias has not been configured" }, { validOnOrAfter, "FED", true, true, "invalidAudience", TestConstants.LOACALHOST_DOMAIN, null, "Audience Restriction validation failed" }, { validOnOrAfter, null, true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, null, "Identity provider is null" }, { expiredOnOrAfter, "LOCAL", true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, null, "Assertion is not valid" }, { null, "LOCAL", true, true, TestConstants.OAUTH2_TOKEN_EP, TestConstants.LOACALHOST_DOMAIN, null, "Cannot find valid NotOnOrAfter" } };
}
use of org.wso2.carbon.identity.saml.common.util.exception.IdentityUnmarshallingException in project identity-inbound-auth-oauth by wso2-extensions.
the class SAML2BearerGrantHandlerTest method testValidateGrantException.
@Test(dataProvider = "validateGrantExceptionDataProvider")
public void testValidateGrantException(Object dateTimeObj, String idpName, boolean isSaas, boolean isUserExist, String audience, String idpEntityId, Exception e, String expected) throws Exception {
DateTime notOnOrAfter = (DateTime) dateTimeObj;
initAssertion(OAuthConstants.UserType.LEGACY_USER_TYPE, idpName, notOnOrAfter);
IdentityProvider idp = initIdentityProviderManager(idpName, audience);
initFederatedAuthConfig(idp);
initSignatureValidator();
mockOAuthComponents();
prepareForGetSAMLSSOServiceProvider();
serviceProvider.setSaasApp(isSaas);
when(realmService.getTenantUserRealm(anyInt())).thenReturn(userRealm);
when(identityProviderManager.getIdPByAuthenticatorPropertyValue(anyString(), anyString(), anyString(), anyString(), anyBoolean())).thenReturn(idp);
when(IdentityApplicationManagementUtil.getProperty(oauthConfig.getProperties(), IdentityApplicationConstants.Authenticator.OIDC.OAUTH2_TOKEN_URL)).thenReturn(getProperty(IdentityApplicationConstants.Authenticator.OIDC.OAUTH2_TOKEN_URL, audience));
when(IdentityApplicationManagementUtil.getProperty(samlConfig.getProperties(), IdentityApplicationConstants.Authenticator.SAML2SSO.IDP_ENTITY_ID)).thenReturn(getProperty("samlsso", idpEntityId));
when(userRealm.getUserStoreManager()).thenReturn(userStoreManager);
when(userStoreManager.isExistingUser(anyString())).thenReturn(isUserExist);
if (e instanceof IdentityProviderManagementException) {
when(identityProviderManager.getIdPByAuthenticatorPropertyValue(anyString(), anyString(), anyString(), anyString(), anyBoolean())).thenThrow(e);
} else if (e instanceof IdentityUnmarshallingException) {
when(UnmarshallUtils.unmarshall(anyString())).thenThrow(e);
} else if (e instanceof SignatureException) {
PowerMockito.mockStatic(SignatureValidator.class);
PowerMockito.doThrow(e).when(SignatureValidator.class, "validate", Matchers.any(Signature.class), Matchers.any(X509Credential.class));
} else if (e instanceof IdentityApplicationManagementException) {
when(applicationManagementService.getServiceProviderByClientId(anyString(), anyString(), anyString())).thenThrow(e);
} else if (e instanceof UserStoreException) {
when(realmService.getTenantUserRealm(anyInt())).thenThrow(e);
} else if (e instanceof CertificateException) {
when(IdentityApplicationManagementUtil.decodeCertificate(anyString())).thenThrow(e);
}
try {
saml2BearerGrantHandler.validateGrant(tokReqMsgCtx);
fail("Expected error not thrown");
} catch (IdentityOAuth2Exception ex) {
assertTrue(ex.getMessage().contains(expected));
}
}
use of org.wso2.carbon.identity.saml.common.util.exception.IdentityUnmarshallingException in project identity-inbound-auth-oauth by wso2-extensions.
the class SAML2BearerGrantHandler method getAssertionObject.
private Assertion getAssertionObject(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {
try {
XMLObject samlObject = UnmarshallUtils.unmarshall(new String(Base64.decodeBase64(tokReqMsgCtx.getOauth2AccessTokenReqDTO().getAssertion()), StandardCharsets.UTF_8));
validateAssertionList(samlObject);
return getAssertion(samlObject);
} catch (IdentityUnmarshallingException e) {
if (log.isDebugEnabled()) {
log.debug("Error while unmashalling the assertion", e);
}
throw new IdentityOAuth2Exception("Error while unmashalling the assertion", e);
}
}
use of org.wso2.carbon.identity.saml.common.util.exception.IdentityUnmarshallingException in project identity-inbound-auth-oauth by wso2-extensions.
the class SAML1BearerGrantHandler method validateGrant.
/**
* 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%3Asaml1-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
public boolean validateGrant(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {
boolean validGrant = super.validateGrant(tokReqMsgCtx);
Assertion assertion;
IdentityProvider identityProvider = null;
String tokenEndpointAlias = null;
String tenantDomain = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getTenantDomain();
if (tenantDomain == null || "".equals(tenantDomain)) {
tenantDomain = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
}
RequestParameter[] requestParameters = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getRequestParameters();
for (RequestParameter requestParameter : requestParameters) {
if (requestParameter.getKey().equals("assertion")) {
String[] values = requestParameter.getValue();
tokReqMsgCtx.getOauth2AccessTokenReqDTO().setAssertion(values[0]);
break;
}
}
if (log.isDebugEnabled() && IdentityUtil.isTokenLoggable(IdentityConstants.IdentityTokens.SAML_ASSERTION)) {
log.debug("Received SAML assertion : " + new String(Base64.decodeBase64(tokReqMsgCtx.getOauth2AccessTokenReqDTO().getAssertion()), StandardCharsets.UTF_8));
}
try {
XMLObject samlObject = UnmarshallUtils.unmarshall(new String(Base64.decodeBase64(tokReqMsgCtx.getOauth2AccessTokenReqDTO().getAssertion()), StandardCharsets.UTF_8));
// Validating for multiple assertions
NodeList assertionList = samlObject.getDOM().getElementsByTagNameNS(SAMLConstants.SAML1_NS, "Assertion");
if (assertionList.getLength() > 0) {
if (log.isDebugEnabled()) {
log.debug("Invalid schema for SAML Assertion. Nested assertions detected.");
}
return false;
}
if (samlObject instanceof Assertion) {
assertion = (Assertion) samlObject;
} else {
if (log.isDebugEnabled()) {
log.debug("Only Assertion objects are validated in SAML1Bearer Grant Type");
}
return false;
}
} catch (IdentityUnmarshallingException e) {
if (log.isDebugEnabled()) {
log.debug("Error occurred while unmarshalling SAML1.0 assertion", e);
}
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>.
*/
List<AuthenticationStatement> authenticationStatements = assertion.getAuthenticationStatements();
Subject subject;
if (authenticationStatements != null && authenticationStatements.size() > 0) {
AuthenticationStatement authenticationStatement = authenticationStatements.get(0);
subject = authenticationStatement.getSubject();
if (subject != null) {
String resourceOwnerUserName = subject.getNameIdentifier().getNameIdentifier();
if (resourceOwnerUserName == null || resourceOwnerUserName.equals("")) {
if (log.isDebugEnabled()) {
log.debug("NameID in Assertion cannot be empty");
}
return false;
}
AuthenticatedUser user = OAuth2Util.getUserFromUserName(resourceOwnerUserName);
user.setAuthenticatedSubjectIdentifier(resourceOwnerUserName);
user.setFederatedUser(true);
tokReqMsgCtx.setAuthorizedUser(user);
if (log.isDebugEnabled()) {
log.debug("Resource Owner User Name is set to " + resourceOwnerUserName);
}
} else {
if (log.isDebugEnabled()) {
log.debug("Subject element cannot be empty.");
}
return false;
}
} else {
if (log.isDebugEnabled()) {
log.debug("Authentication Statement cannot be empty");
}
return false;
}
if (assertion.getIssuer() == null || assertion.getIssuer().isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("Issuer is empty in the SAML assertion");
}
return false;
} else {
try {
if (log.isDebugEnabled()) {
log.debug("Issuer is :" + assertion.getIssuer());
}
identityProvider = IdentityProviderManager.getInstance().getIdPByAuthenticatorPropertyValue("IdPEntityId", assertion.getIssuer(), tenantDomain, false);
// resident IDP entitiID == 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().equals(idpEntityId)) {
if (log.isDebugEnabled()) {
log.debug("SAML Token Issuer verification failed or Issuer not registered");
}
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 verification failed or Issuer not registered");
}
return false;
}
} catch (IdentityProviderManagementException e) {
if (log.isDebugEnabled()) {
log.debug("Error while getting Federated Identity Provider ", e);
}
}
}
if (audienceRestrictionValidationEnabled) {
if (tokenEndpointAlias == null || tokenEndpointAlias.equals("")) {
String errorMsg = "Token Endpoint alias of the local Identity Provider has not been " + "configured for " + identityProvider.getIdentityProviderName();
if (log.isDebugEnabled()) {
log.debug(errorMsg);
}
return false;
}
Conditions conditions = assertion.getConditions();
if (conditions != null) {
List<AudienceRestrictionCondition> audienceRestrictions = conditions.getAudienceRestrictionConditions();
if (audienceRestrictions != null && !audienceRestrictions.isEmpty()) {
boolean audienceFound = false;
for (AudienceRestrictionCondition audienceRestriction : audienceRestrictions) {
if (audienceRestriction.getAudiences() != null && audienceRestriction.getAudiences().size() > 0) {
for (Audience audience : audienceRestriction.getAudiences()) {
if (audience.getUri().equals(tokenEndpointAlias)) {
audienceFound = true;
break;
}
}
}
if (audienceFound) {
break;
}
}
if (!audienceFound) {
if (log.isDebugEnabled()) {
log.debug("SAML Assertion Audience Restriction validation failed");
}
return false;
}
} else {
if (log.isDebugEnabled()) {
log.debug("SAML Assertion doesn't contain AudienceRestrictions");
}
return false;
}
} else {
if (log.isDebugEnabled()) {
log.debug("SAML Assertion doesn't contain Conditions");
}
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:1.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.
* 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;
Set<DateTime> notOnOrAfterFromSubjectConfirmations = new HashSet<DateTime>();
boolean bearerFound = false;
if (assertion.getConditions() != null && assertion.getConditions().getNotOnOrAfter() != null) {
notOnOrAfterFromConditions = assertion.getConditions().getNotOnOrAfter();
}
SubjectConfirmation subjectConfirmation = subject.getSubjectConfirmation();
List<ConfirmationMethod> confirmationMethods = subjectConfirmation.getConfirmationMethods();
for (ConfirmationMethod confirmationMethod : confirmationMethods) {
if (OAuthConstants.OAUTH_SAML1_BEARER_METHOD.equals(confirmationMethod.getConfirmationMethod())) {
bearerFound = true;
}
}
if (!bearerFound) {
if (log.isDebugEnabled()) {
log.debug("Cannot find a subject confirmation with method " + OAuthConstants.OAUTH_SAML1_BEARER_METHOD + " in subject confirmation " + subject.getSubjectConfirmation());
}
return false;
}
XMLObject confirmationData = subject.getSubjectConfirmation().getSubjectConfirmationData();
if (confirmationData == null) {
log.warn("Subject confirmation data is missing.");
}
/*
* 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.
*/
long timestampSkewInMillis = OAuthServerConfiguration.getInstance().getTimeStampSkewInSeconds() * 1000;
if (notOnOrAfterFromConditions != null && notOnOrAfterFromConditions.plus(timestampSkewInMillis).isBeforeNow()) {
// notOnOrAfter is an expired timestamp
if (log.isDebugEnabled()) {
log.debug("NotOnOrAfter is having an expired timestamp in Conditions element");
}
return false;
}
boolean validSubjectConfirmationDataExists = false;
if (!notOnOrAfterFromSubjectConfirmations.isEmpty()) {
for (DateTime entry : notOnOrAfterFromSubjectConfirmations) {
if (entry.plus(timestampSkewInMillis).isAfterNow()) {
validSubjectConfirmationDataExists = true;
}
}
}
if (notOnOrAfterFromConditions == null && !validSubjectConfirmationDataExists) {
if (log.isDebugEnabled()) {
log.debug("No valid NotOnOrAfter element found in SubjectConfirmations");
}
return false;
}
try {
profileValidator.validate(assertion.getSignature());
} catch (SignatureException e) {
// Indicates signature did not conform to SAML1.0 Signature profile
if (log.isDebugEnabled()) {
log.debug("Signature did not conform to SAML1.0 Signature profile", e);
}
return false;
}
X509Certificate x509Certificate = null;
try {
x509Certificate = (X509Certificate) IdentityApplicationManagementUtil.decodeCertificate(identityProvider.getCertificate());
} catch (CertificateException e) {
String message = "Error occurred while decoding public certificate of Identity Provider " + identityProvider.getIdentityProviderName() + " for tenant domain " + tenantDomain;
throw new IdentityOAuth2Exception(message, e);
}
try {
X509Credential x509Credential = new X509CredentialImpl(x509Certificate);
SignatureValidator.validate(assertion.getSignature(), x509Credential);
if (log.isDebugEnabled()) {
log.debug("Signature validation successful");
}
} catch (SignatureException e) {
if (log.isDebugEnabled()) {
log.debug("Signature validation failure:" + e.getMessage(), e);
}
return false;
}
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 validGrant;
}
Aggregations