4

I have been looking around for a solution but can't find it.

This question is directly related to:

Here's the scenario I want to execute:

  1. authenticate to the SP using SAML2. Coded in PHP with SimpleSamlPhp.
  2. get an OAuth token from the API mgr endpoint, using the SAML2 assertion. (using URL http://api.gateway/token)
  3. call APIs over the API mgr's gateway, using the OAuth token.

I'm stuck at the instruction: get the SAML2 assertion token. Where do I find this token? In SimpleSamlPhp I can get attributes of the user, or their id, but I can't find any assertion.

I hacked SSP to get the last assertion, but don't know what to do with it. I was expecting a single value (like a token), but it's a complex structure. And one of the links above says I shouldn't be accessing it!

What do I send, encoded, to the token URL?


EDIT: adding some samples. My assert XML (edited):

<?xml version="1.0" encoding="UTF-8"?>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" ID="okdjgbm...jdbh" IssueInstant="2016-11-28T09:49:45.808Z" Version="2.0">
   <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://g...p.com:9443/samlsso</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="#okd...kejdbh">
            <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#" />
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
            <ds:DigestValue>RrGcR...cktFuH0=</ds:DigestValue>
         </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>b91j/k...Z7d4=</ds:SignatureValue>
      <ds:KeyInfo>
         <ds:X509Data>
            <ds:X509Certificate>MIICNT...Wq8uHSCo=</ds:X509Certificate>
         </ds:X509Data>
      </ds:KeyInfo>
   </ds:Signature>
   <saml2:Subject>
      <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">toto@titi.com</saml2:NameID>
      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
         <saml2:SubjectConfirmationData InResponseTo="_80258326a1...cd4bbd" NotOnOrAfter="2016-11-28T09:54:45.807Z" Recipient="http://1.2.3.4/simplesamlphp/www/module.php/saml/sp/saml2-acs.php/wso2-sp" />
      </saml2:SubjectConfirmation>
      <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
         <saml2:SubjectConfirmationData InResponseTo="_8025832...d4bbd" NotOnOrAfter="2016-11-28T09:54:45.807Z" Recipient="https://my.wso2.apim:8243/token" />
      </saml2:SubjectConfirmation>
   </saml2:Subject>
   <saml2:Conditions NotBefore="2016-11-28T09:49:45.808Z" NotOnOrAfter="2016-11-28T09:54:45.807Z">
      <saml2:AudienceRestriction>
         <saml2:Audience>mytestapp</saml2:Audience>
         <saml2:Audience>https://my.wso2.apim:8243/token</saml2:Audience>
      </saml2:AudienceRestriction>
   </saml2:Conditions>
   <saml2:AuthnStatement AuthnInstant="2016-11-28T09:49:45.815Z" SessionIndex="1f5192...b591">
      <saml2:AuthnContext>
         <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml2:AuthnContextClassRef>
      </saml2:AuthnContext>
   </saml2:AuthnStatement>
   <saml2:AttributeStatement />
</saml2:Assertion>

encode as base64-URL-encoded XML:

PHNhbWwyO...dGlvbj4,

using the method copied from another SO post

function base64_url_encode($input) {
 return strtr(base64_encode($input), '+/=', '-_,');
}

It's about 20 lines long (and yes, there's a comma at the end).

It doesn't work, I get the JSON result

{"error":"invalid_grant","error_description":"Provided Authorization Grant is invalid."}

In the traces:

TID: [0] [AM] [2016-11-29 11:04:50,297] DEBUG {org.wso2.carbon.identity.oauth2.token.handlers.grant.saml.SAML2BearerGrantHandler} -  SAML Token Issuer verification failed or Issuer not registered {org.wso2.carbon.identity.oauth2.token.handlers.grant.saml.SAML2BearerGrantHandler}
TID: [0] [AM] [2016-11-29 11:04:50,298] DEBUG {org.wso2.carbon.identity.oauth2.token.AccessTokenIssuer} -  Invalid Grant provided by the client, id=fkJa...Ohoa, user-name=null to application=myapp-subscriber_test_PRODUCTION {org.wso2.carbon.identity.oauth2.token.AccessTokenIssuer}
TID: [0] [AM] [2016-11-29 11:04:50,300] DEBUG {org.wso2.carbon.identity.oauth2.token.AccessTokenIssuer} -  OAuth-Error-Code=invalid_grant client-id=fkJa...hoa grant-type=urn:ietf:params:oauth:grant-type:saml2-bearer scope=PRODUCTION {org.wso2.carbon.identity.oauth2.token.AccessTokenIssuer}

I'm asking around to the configurators of the system. Seems to me there's something missing in the link between IDS, APIM and OAuth, some declaration. (I googled this, and came up with a stackoverflow exchange to check the issuer id in the assertion, which I did, but I can't identify anything wrong there)

Thanks for the help, I will come back if I have anything new. Except of course if I have overlooked something obvious!

JRobinss
  • 191
  • 1
  • 10
  • may be related to http://stackoverflow.com/questions/19866021/how-to-get-saml2-bearer-assertion-profile-for-oauth-within-wso2-api-manager-to-w?rq=1 – JRobinss Nov 29 '16 at 10:52
  • may be related to http://stackoverflow.com/questions/34738716/wso2-saml2bearergranthandler-saml-token-issuer-verification-failed-or-issuer-not – JRobinss Nov 29 '16 at 10:53

2 Answers2

2

When you login with SAML SSO, you get a SAML response with an Assertion in it. You can see a sample response/assertion here. You need this assertion to obtain an OAuth2 token. However, it looks like your php framework does not provide the SAML response to you directly. That's too bad because you need it here.

Anyway, since you have managed to obtain that, all you have to do now is to base64-URL encode the entire <Assertion>....</Assertion> tag and send with OAuth2 token request. Here is a nice online tool if you need to try manually.

Bee
  • 12,251
  • 11
  • 46
  • 73
  • thanks for the quick response. I will try with the hack I added to SSP, with the assertion I got. – JRobinss Nov 24 '16 at 13:18
  • I followed your advice: instead of looking for a single-value token, I took the whole assertion in XML, encoded it in base64-url-encode, and passed it as `assertion=...`.Didn't work, is there anything I did wrong, or do I just have some bad config in APIM? (see samples in the original question) – JRobinss Nov 28 '16 at 13:48
  • Yes, I checked them out, and it seems there's a problem in app registration. I will edit the original post to complete with this (because the comments editors is not up to the task!) – JRobinss Nov 29 '16 at 10:43
  • Looks like the issuer value is different in SP and the SAML Assertion. Please double check. – Bee Nov 29 '16 at 10:59
  • Several questions... can the authent happen when there is such an error? Also, what should I compare? "issuer" in SP config is the name of the app, whereas "issuer" in the SAML message is the URL of the IS (here, WSO2 IDS, separate from the APIM). Thanks! – JRobinss Nov 29 '16 at 13:03
  • Issuer name in SAML2 Assertion must be equals to “Identity Provider Entity Id” in IDP. See http://xacmlinfo.org/2014/10/31/saml2-bearer-assertion-profile-for-oauth-2-0/ – Bee Nov 29 '16 at 16:41
2

I have succeeded, so here are some indications for others who may have the same issue.

  1. I hacked simpleSamlPhp because they do not provide the SAML2 assertion (see https://github.com/simplesamlphp/simplesamlphp/issues/220). I did not do it in a nice way, because I only wanted to make it work. It's ugly but it works. Here's my hack, I put it at line 125 of saml2-acs.php:

    // ADDED to get SAML2 assertion in SP
    if (array_key_exists('SAMLResponse', $_POST)) {
        $attributes["samlresp"] = $_POST['SAMLResponse'];
    }
    
  2. In my PHP app, I then use this code:

    $authdata_array= $as->getAuthDataArray();
    $postSaml2Assert = $authdata_array["Attributes"]["samlresp"];
    $msg = base64_decode($postSaml2Assert);
    $document = new DOMDocument();
    $document->loadXML($msg);
    $assertion = $document->getElementsByTagNameNS ("urn:oasis:names:tc:SAML:2.0:assertion", "Assertion")->item(0);
    $saml2AssertionXml = $document->saveXML($assertion);
    
  3. I encode the assertion base64 and URL-encode. For this I used code from Passing base64 encoded strings in URL (thanks joeshmo!)

  4. in APIM / Entity Providers / list / myIdS / edit / Federated Authenticators / SAM2 web SSO... / Identity Provider entity ID I set the value to the expected IDS endpoint, https://myids:9443/samlsso. This solved my initial issue

  5. in the SP configuration (in the IDS) I added the oauth token both as audience and recipient, looks like https://myAPIM:9443/oauth2/token/. Caution, both as audience and recipient!

  6. Because I was debugging I had formatted the XML assertion, so it wasn't working, I ran into the problem detailed here WSO2 Identity Server OAuth2 Bearer SAML Assertion so I simply removed the formatting and used the XML string as-is. (I have of course removed this error from above)

  7. I had a last error easy to solve: the NotOnOrAfter flag was making trouble, because there was a delay between getting the SAML2 assertion and using it to generate a token. Lesson learned: The SAML2 assertion should be created just after logging in, not just before calling APIs.

Hope this helps others. Thanks @Bhathiya for helping!

Community
  • 1
  • 1
JRobinss
  • 191
  • 1
  • 10