SAML2 Bearer grant type is one of the popular profile in OAuth 2.0. Once end user login in to a web application using SAML2 SSO and if web application needs to call an OAuth secured API behalf of the user, SAML2 Bearer grant type would be the ideal way to do it. With this profile, Web application can easily exchange an OAuth token by providing SAML2 Assertion.
Identity Server supports this profile and let see how we can try out it. Basically lets grant an OAuth access token by providing a SAML2 Assertion. Therefore Identity Server acts an authorization server who can grant OAuth token according to the SAML2 Bearer specification.
Step 1. Let assume that you find a SAML Assertion.
As Identity Server can act as SAML2 SSO IDP, you can find valid SAML2 Assertion as follows.
You can go through my previous blog post on configuring SAML2 SSO with Identity Server and also it is recommend to read this to capture a SAML Assertion for trying out. (Debug logs would be the ideal way to capture it)
Sample SAML Assertion that has been captured.
<saml2:Assertion ID="bpmnofnofoiejbeljpdidnkhmnmddgmbadkjkebh" IssueInstant="2014-10-29T12:26:11.870Z" Version="2.0" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">ssoidp.com</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#bpmnofnofoiejbeljpdidnkhmnmddgmbadkjkebh"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces PrefixList="xs" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>DFn+PkMiGv1QSOh0phyp2MOyWR0=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>F6mV8lkr23Df+pJ1rdLsJuNnUZev7rNhrojgsl1DJ44uam7AXN+QQ2MXEpB9XWFzTD3Ja7tVU2rCe3NxPpTIsigJJ7CAgNWZT6djPx9FRFmXXZMCTrGiWB8AKEAQeoH+vJnwgDamcxNkDW5tKMhmsnZb4ogvtAmuKR+6YinGprE=</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIICNTCCAZ6gAwIBAgIES343gjANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxDTALBgNVBAoMBFdTTzIxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xMDAyMTkwNzAyMjZaFw0zNTAyMTMwNzAyMjZaMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzENMAsGA1UECgwEV1NPMjESMBAGA1UEAwwJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUp/oV1vWc8/TkQSiAvTousMzOM4asB2iltr2QKozni5aVFu818MpOLZIr8LMnTzWllJvvaA5RAAdpbECb+48FjbBe0hseUdN5HpwvnH/DW8ZccGvk53I6Orq7hLCv1ZHtuOCokghz/ATrhyPq+QktMfXnRS4HrKGJTzxaCcU7OQIDAQABoxIwEDAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEFBQADgYEAW5wPR7cr1LAdq+IrR44iQlRG5ITCZXY9hI0PygLP2rHANh+PYfTmxbuOnykNGyhM6FjFLbW2uZHQTY1jMrPprjOrmyK5sjJRO4d1DeGHT/YnIjs9JogRKv4XHECwLtIVdAbIdWHEtVZJyMSktcyysFcvuhPQK8Qc/E/Wq8uHSCo=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">asela</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData InResponseTo="0" NotOnOrAfter="2014-10-29T12:56:11.870Z" Recipient="http://localhost:8080/travelocity.com/home.jsp"/></saml2:SubjectConfirmation><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData InResponseTo="0" NotOnOrAfter="2014-10-29T12:56:11.870Z" Recipient="https://oauthidm.com/oauth/token"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2014-10-29T12:26:11.870Z" NotOnOrAfter="2014-10-29T12:56:11.870Z"><saml2:AudienceRestriction><saml2:Audience>travelocity.com</saml2:Audience><saml2:Audience>https://oauthidm.com/oauth/token</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2014-10-29T12:26:11.870Z" SessionIndex="f58108ac-da02-4f22-9ed2-ecf2f8848947"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement><saml2:Attribute Name="http://wso2.org/claims/role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Pathberiya</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name="http://wso2.org/claims/emailaddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">[email protected]</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion>
Step 2. Register a service provider in Identity Server with OAuth in-bound authentication.
Important : If you are using WSO2 APIM, You do not need this step. Once you subscribe to application, API Store would register an OAuth subscription automatically.
You can find the steps from following the screen shots.
Step 3. Register the SAML2 IDP that is issuing the SAML Assertion as Federated IDP in Identity Server.
Note : If SAML2 SSO IDP is same Identity Server, you also do not need to register a separate IDP. It means that if you use same instance of WSO2IS for SAML2 SSO and OAuth2, then you do not need to configure this step.. It will explain under the topic “Using Same Instance of WSO2IS or Key Manager as SAML2 SSO IDP and OAuth2 Authorization server”
When we are registering IDP, we need to consider following according to SAML2 Bearer specification.
1. You can provide any value for “Identity Provider Name:” This can be any unique value…
2. Upload “Identity Provider Public Certificate”. It is the certificate that contains in the SAML Assertion. Basically the certificate that has been used to sign the SAML Assertion. You can find the certificate from SAML2 Assertion or you need to import the certificate from the SAML2 SSO IDP which generates the SAML2 Asertion
In spec, It says “The Assertion MUST be digitally signed”
3. Configure Alias. There are few things to consider here.
AudienceRestriction
In Spec, It says. The Assertion MUST contain a <Conditions> element with an <AudienceRestriction> element with an <Audience> element that identifies the authorization server as an intended audience.
You can find this as follows
<saml2:AudienceRestriction> <saml2:Audience>travelocity.com</saml2:Audience> <saml2:Audience>https://oauthidm.com/oauth/token</saml2:Audience> </saml2:AudienceRestriction>
Recipient Value
You need to configure Recipient value that is contain in the SubjectConfirmation element with “urn:oasis:names:tc:SAML:2.0:cm:bearer”. In Spec it says. The <Subject> element MUST contain at least one <SubjectConfirmation> element that has a Method attribute with avalue of “urn:oasis:names:tc:SAML:2.0:cm:bearer”. <SubjectConfirmationData> element MUST have a Recipient attribute with a value indicating the token endpoint URL of the authorization server (or an acceptable alias). You can find this as follows
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml2:SubjectConfirmationData InResponseTo="0" NotOnOrAfter="2014-09-17T06:32:14.918Z" Recipient="https://oauthidm.com/oauth/token"/> </saml2:SubjectConfirmation>
However finally, SAML Assertion must contain equal values for both AudienceRestriction and Recipient. The value must be configured as Alias.
4. Configure “Identity Provider Entity Id:” value under SAML2 SSO federated authenticator configuration. It must be the issuer name in the SAML Assertion.
In spec, It says “The Assertion’s <Issuer> element MUST contain a unique identifier for the entity that issued the Assertion”
You can find it in SAML Assertion
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">ssoidp.com</saml2:Issuer>
Now your done with the configurations.
Please note, Authorization server is validate the Assertion validity period using “NotOnOrAfter” value in the “Condition” and “SubjectConfirmation” elements
Step 4. Building our request to grant an Access Token.
Authorization grant Request must be something like following
POST /token.oauth2 HTTP/1.1 Host: authz.example.net Content-Type: application/x-www-form-urlencoded grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2- bearer&assertion=PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU [...omitted for brevity...]aG5TdGF0ZW1lbnQ-PC9Bc3NlcnRpb24-
Here SAML Assertion must be base64url encoded. It means that you need to convert it to Base64 and then it must be URL encoded. You can find many online tool to do it. I used this tool..
Sample curl request would be as follows.
curl -X POST -k -u "4ppy0unf2TGPUyAbHgwBgM2Enfoa:nLmLl06rRHEgX0C9yxxD1rxyEUQa" -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" -d "grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer&assertion={Base64 URL encoded Assertion}" https://localhost:9443/oauth2/token
Important : If there any issue while granting access token. Please make sure to enable debug log in OAuth 2.0 component and verify. Then you can see the exact issue with the access token granting. More detail on enabling debug logs can be found from here
log4j.logger.org.wso2.carbon.identity.oauth2=DEBUG
Using Same Instance of WSO2IS or Key Manager as SAML2 SSO IDP and OAuth2 Authorization server.
If you are using the same instance of WSO2IS as SAML2 SSO IDP and OAuth2, then you can skip the 3rd step by registering the federated IDP. Then how SAML2 Assertion is validated ?
WSO2IS has a default Identity Provider called “Resident IDP” This IDP contains the default configurations… By using these configurations, SAML2 Assertion is validated.
- Identity Provider Name is “LOCAL“
- Alias value is “Token Endpoint URL” which is equals to “https://{HOSTNAME}:{PORT}/oauth2/token”
- Identity Provider Entity Id is set to hostname by default. This can be configured.
- Public Certificate is the certificate of the primary keystore in the tenant (This is certificate which signs the SAML2 Assertion as well.)
You can see the Resident IDP configuration from following.. and currently you can configure the Identity Provider Entity Id as well
How we can build the SAML2 Assertion which validates with Resident IDP configurations ? You need to consider above following facts..
1. Issuer name in SAML2 Assertion must be equals to “Identity Provider Entity Id”. Yes.. it would be equal by default, Because when SAML2 Assertion is created, Issuer value is read from “Identity Provider Entity Id” configuration and when it is validates, it would be validated with the same configuration.
2. SAML2 Assertion must be signed.. Yes.. it would be signed by the primary keystore in the tenant. So, there is no issue because Resident IDP can validates it.
3. Alias value must be equals to both AudienceRestriction and Recipient. Now, Alias value is set to “https://{HOSTNAME}:{PORT}/oauth2/token”. We need to configure same values in SAML2 SSO issuer configurations as well as in following.
Try out with Sample Web Application
If you are using SAML2 SSO sample web application that is described here. You can try out the SAML2 bearer assertion profile using sample web application as well.
You can configure the sample web application with SAML2 SSO IDP (WSO2 Identity Server) as described in here. Then you can login to the web application using SAML2 SSO Web browser based profile. Here, web application would received a SAML2 assertion from the SAML2 SSO IDP. Web application can retrieve an OAuth2 access token by exchaging the received SAML2 Assertion.
Please note to try out the SAML2 Bearer profile using sample web application, You need to configure following properties in the travelocity.properties file, which can be found inside the travelocity.com/WEB-INF/classes directory of the sample web application.
EnableSAML2Grant=true
OAuth2 token endpoint URL
SAML.OAuth2TokenEndpoint=https://localhost:9443/oauth2/token
OAuth2 Client ID
SAML.OAuth2ClientID=4ppy0unf2TGPUyAbHgwBgM2Enfoa
OAuth2 Client Secret
SAML.OAuth2ClientSecret=nLmLl06rRHEgX0C9yxxD1rxyEUQa
Once you login to sample web application, you will see a link to get the access token.