February 21st, 2012

Request a token from ADFS using WS-Trust from iOS, Objective-C, IPhone, IPad, Android, Java, Node.js or any platform or language

This is not just a SEO friendly name, in this post I want to show you a very easy way of providing Active Directory authentication in your apps, no matter the platform or language that you use, the only requirement is to be able to make an http post.

Request for a Security Token

To talk with ADFS we must be able to speak WS-Trust protocol, on the .NET platform this is a very easy thing to do thanks to WCF and Windows Identity Foundation frameworks, but regardless the platform make a WS-Trust call is not so hard.

The first thing that we need to know is that WS-Trust protocol defines an standard way of requesting security tokens, based on an XML structure known as Request Security Token or RST, this is an example of that structure:

<trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
  <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
    <a:EndpointReference>
      <a:Address>https://yourcompany.com</a:Address>
    </a:EndpointReference>
  </wsp:AppliesTo>
  <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
  <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
  <trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
</trust:RequestSecurityToken>

Focusing on the basics, there is a couple of fields that are important to us, inside of the RequestSecurityToken element you will find the AppliesTo tag where, using the WS-Addressing standard, we define the scope to which the token is valid, in this case: https://yourcompany.com.

RequestType specifies the action that you want to execute, in our case Issue, this means that we want that the (Security Token Service) STS issue a new token, but another option could be renewed an already issued token, in that case the RequestType would be Renew.

Finally, the TokenType specifies the type of the token that you want, in our case we are asking for a token based on the SAML 2.0 format.

Doesn’t looks very hard, isn’t? but where do we say who we are? well, one detail that adds a bit of complexity is the fact that all the WS-* protocols stack is build on top of SOAP, so we need to speak SOAP in order to send the token request. Once more, speak SOAP is not so hard, SOAP is also XML-Based, I’m not going to explain the whole SOAP protocol, but you can find the format for a soap message here: http://www.w3.org/2003/05/soap-envelope/

In our case, to talk with ADFS from a native client we going to use username and password security, so this is how the SOAP message will looks like: (I’ve cut some arguments to improve the presentation)

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
            xmlns:a="http://www.w3.org/2005/08/addressing"
            xmlns:u="...">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
    <a:To s:mustUnderstand="1">https://yourcompany.com/adfs/services/trust/13/UsernameMixed</a:To>
    <o:Security s:mustUnderstand="1" mlns:o="...">
      <o:UsernameToken u:Id="uuid-6a13a244-dac6-42c1-84c5-cbb345b0c4c4-1">
        <o:Username>Leandro Boffi</o:Username>
        <o:Password Type="...">P@ssw0rd!</o:Password>
      </o:UsernameToken>
    </o:Security>
  </s:Header>
  <s:Body>
    <trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
      <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
        <a:EndpointReference>
          <a:Address>https://yourcompany.com</a:Address>
        </a:EndpointReference>
      </wsp:AppliesTo>
      <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
      <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
      <trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
    </trust:RequestSecurityToken>
  </s:Body>
</s:Envelope>

To quickly understand the format, the SOAP envelop has two main tags: header and body. The body of our message contains the RST (Request for Security Token) message that we created before. In the header we can find context parameters like, the Uri of the service endpoint (To), the name of the action exposed in that endpoint that you want to execute (Action), remember that in SOAP you can have multiple actions in a single endpoint, and who we are (Security), in this case username and password.

To use UserName and Password authentication we need to look for the action Issue in the endpoint https://yourcompany.com/adfs/services/trust/13/UsernameMixed, so make sure that this endpoint is enabled on ADFS configuration.

Once we have the SOAP message, we just need to send it to the server using a regular HTTP POST, this is an example of how to do it on .NET, but it can be applied to any platform or language:

var client = new WebClient();

client.Headers.Add("Content-Type", "application/soap+xml; charset=utf-8");

var result = client.UploadString(
        address: "https://yourcompany.com/adfs/services/trust/13/UsernameMixed",
        method: "POST",
        data: soapMessage);

Make sure that you specify the Content-Type header to “application/soap+xml; charset=utf-8”, what you finally need to send to the server is this:

POST /adfs/services/trust/13/UsernameMixed HTTP/1.1

Connection: Keep-Alive
Content-Length: 1862
Content-Type: application/soap+xml; charset=utf-8
Accept-Encoding: gzip, deflate
Expect: 100-continue
Host: localhost

<s:Envelope ...> ... </s:Envelope>

I’ve added other headers to be consistent with the HTTP Protocol, but for ADFS just the Content-Type is required.

The Answer: Request Security Token Response

If your credentials were valid, and the scope Uri is the right one, you will get a SOAP response from ADFS. In the body of that message you will get something like this:

<trust:RequestSecurityTokenResponseCollection xmlns:trust="...">
  <trust:RequestSecurityTokenResponse>
    <trust:Lifetime>...</trust:Lifetime>
    <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">...</wsp:AppliesTo>
    <trust:RequestedSecurityToken>
      <Assertion ID="_fcf06a39-c495-4074-8f22-4a7df6e26513"
                 IssueInstant="2012-02-21T04:27:24.771Z"
                 Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
        <Issuer>http://yourcompany.com/adfs/services/trust</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/2001/04/xmldsig-more#rsa-sha256"/>
            <ds:Reference URI="#_fcf06a39-c495-4074-8f22-4a7df6e26513">
              <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/2001/04/xmlenc#sha256"/>
              <ds:DigestValue>...</ds:DigestValue>
            </ds:Reference>
          </ds:SignedInfo>
          <ds:SignatureValue>...</ds:SignatureValue>
          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <ds:X509Data>
              <ds:X509Certificate>...</ds:X509Certificate>
            </ds:X509Data>
          </KeyInfo>
        </ds:Signature>
        <Subject>
          <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
            <SubjectConfirmationData NotOnOrAfter="2012-02-21T04:32:24.771Z"/>
          </SubjectConfirmation>
        </Subject>
        <Conditions NotBefore="2012-02-21T04:27:24.756Z" NotOnOrAfter="2012-02-21T05:27:24.756Z">
          <AudienceRestriction>
            <Audience>https://yourcompany.com/</Audience>
          </AudienceRestriction>
        </Conditions>
        <AttributeStatement>
          <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
            <AttributeValue>Leandro Boffi</AttributeValue>
          </Attribute>
          <Attribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role">
            <AttributeValue>Administrator</AttributeValue>
            <AttributeValue>Mobile User</AttributeValue>
          </Attribute>
        </AttributeStatement>
        <AuthnStatement AuthnInstant="2012-02-21T04:27:24.724Z">
          <AuthnContext>
            <AuthnContextClassRef>
              urn:oasis:names:tc:SAML:2.0:ac:classes:Password
            </AuthnContextClassRef>
          </AuthnContext>
        </AuthnStatement>
      </Assertion>
    </trust:RequestedSecurityToken>
    <trust:RequestedAttachedReference>...</trust:RequestedAttachedReference>
    <trust:RequestedUnattachedReference>...</trust:RequestedUnattachedReference>
    <trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
    <trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
    <trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
  </trust:RequestSecurityTokenResponse>
</trust:RequestSecurityTokenResponseCollection>

This format is also specified in the WS-Trust protocol as Request Security Token Response or RSTR, but for you the most important section of the response is in RequestSecurityTokenResponseCollection/RequestSecurityToeknResponse/RequestedSecurityToken. The content of this tag is the security token, in our case a SAML 2.0 token:

<Assertion ID="_fcf06a39-c495-4074-8f22-4a7df6e26513" IssueInstant="2012-02-21T04:27:24.771Z"
                 Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
  <Issuer>http://yourcompany.com/adfs/services/trust</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/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference URI="#_fcf06a39-c495-4074-8f22-4a7df6e26513">
        <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/2001/04/xmlenc#sha256"/>
        <ds:DigestValue>...</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>...</ds:SignatureValue>
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
      <ds:X509Data>
        <ds:X509Certificate>...</ds:X509Certificate>
      </ds:X509Data>
    </KeyInfo>
  </ds:Signature>
  <Subject>
    <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
      <SubjectConfirmationData NotOnOrAfter="2012-02-21T04:32:24.771Z"/>
    </SubjectConfirmation>
  </Subject>
  <Conditions NotBefore="2012-02-21T04:27:24.756Z" NotOnOrAfter="2012-02-21T05:27:24.756Z">
    <AudienceRestriction>
      <Audience>https://yourcompany.com/</Audience>
    </AudienceRestriction>
  </Conditions>
  <AttributeStatement>
    <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
      <AttributeValue>Leandro Boffi</AttributeValue>
    </Attribute>
    <Attribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role">
      <AttributeValue>Administrator</AttributeValue>
      <AttributeValue>Mobile User</AttributeValue>
    </Attribute>
  </AttributeStatement>
  <AuthnStatement AuthnInstant="2012-02-21T04:27:24.724Z">
    <AuthnContext>
      <AuthnContextClassRef>
        urn:oasis:names:tc:SAML:2.0:ac:classes:Password
      </AuthnContextClassRef>
    </AuthnContext>
  </AuthnStatement>
</Assertion>

Once we extract the token from the response, everything gets simpler: Inside of the AttributeStatment section you will have a list of Attribute, this are the claims, information of the user, for example in this token we have three different claims:

  • Type: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
  • Value: Leandro Boffi
  • Type: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
  • Value: Administrator
  • Type: http://schemas.microsoft.com/ws/2008/06/identity/claims/role
  • Value: Mobile User

You can use those claims to perform authorization in your application, but also if your app needs to call webservices that rely on your ADFS, you will need to send the entire token in each request that you made to those services (I’ll explain this scenario in a future post).

Security Features

The token has some security features with which we can get us to make our application more secure. I’m not going to explain all the features in this post, but for example, if we want we can verify that no body has modified the token, because it is signed by the issuer (in our case, ADFS). You can find the signature on Assertion/Signature/SignatureValue. This signature is also based on a standard called XML Signature, you can find the specification here: http://www.w3.org/Signature/.

Also another very important feature is the fact that the token has a limited life time, to avoid that somebody use an old token, you can find that in the Assertion/Conditions/NotBefore and NotOnOrAfter.

Conclusion

Integrate the identity of our apps to Active Directory, no matter the platform or the language is possible due to ADFS is based on WS-Trust an standard protocol. If your language do not support WS-Trust natively it requires a bit more of effort, but as we saw in this post it’s not hard at all, you just need an XML template for the SOAP+RST call and an HTTP Post.

Download here the template for doing the SOAP-RST call, just replace the values in brackets with your values and start requesting tokens!

Hope has been useful!

  • prem nair

    We are trying to do an authentication using ADFS in our Cordova Project and suddenly Android KitKat started behaving weird. it works sometime and sometimes not. Any ideas?

    • http://leandrob.com leandrob

      It’s hard to say with that level of information, if you email me me@leandrob.com maybe I can help you!

  • Vinuta

    Which java library do you suggest for this interaction with ADFS to retrieve a SAML assertion token and WS-Trsut in general.

  • Samiboo

    Can you please post the complete SOAP request.

  • Praveen Addepally

    Thanks for the nice post… Got it worked on the first try itself!!!

    • http://leandrob.com/ Leandro Boffi

      You are welcome! It’s nice to hear that :)

  • Anil Sharma

    Hi Leandro,

    Thanks for your post, i got response from ADFS 2.0 STS.

    But RSTR is different. I suppose it is encrypted. Any idea how to fetch token from this :

    http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal–2014-09-18T07:03:39.646Z2014-09-18T07:08:39.646Z—+–https://10.164.44.89:8443/ems/verifyLogin.html———CN=localhost, OU=Sfnt, O=Safenet, L=Noida, S=UP, C=IN1407137793-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–_0e4b558f-eb92-475f-8b79-77e276937d59–_0e4b558f-eb92-475f-8b79-77e276937d59urn:oasis:names:tc:SAML:2.0:assertionhttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Issuehttp://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer

    • http://leandrob.com/ Leandro Boffi

      Anil, you are correct. As a security feature assertion can be encrypted to be opaque to the client, in this case the token is the whole content of encryptedassertion element.

      • Anil Sharma

        How can i validate this encrypted token. I have .pfx file which has private key. I assume i need to decrypt the token using that file only.What is function of key mentioned in encryted token xml above?

  • Akhil Agarwal

    Hi, Do you know what kind of configuration is required at ADFS end to accept this SOAP request other than exposing the endpoint? We currently have the configuration which will redirect all browser based request to a IIS hosted page which we would like to avoid and instead expecting a direct response from ADFS in the form of token.

    • http://leandrob.com/ Leandro Boffi

      You have to create a relying party trust.

  • o_m

    Hi,
    Thanks for easy to understand explanation. In my case I don’t have username/password but the have x509 certificate. How would I include it in the soapmessage?

  • Bob

    Hello. Great post! It helped me a lot. I am currently trying to authenticate against a Microsoft Dynamics server that has ADFS, using Java. I still haven’t figured it all out but at least now, with the help of your article I have been able to write a little program that connects and requests a security token.

    Now I just need to know how to send it along with each oData web service call. In your article you say:

    “you will need to send the entire token in each request that you made to those services (I’ll explain this scenario in a future post).”

    That was 2012. Any updates?

    • http://leandrob.com/ Leandro Boffi

      Bob, if you are using Microsoft Dynamics there is a very high chance that you need to use PoP tokens with Server and Client entropy. I’m currently writing a post on that, this is the first part http://leandrob.com/2015/01/ws-trust-proof-of-possession-pop-tokens-with-client-and-server-entropy-with-partial-keys-part-1/.

      If you don’t need PoP, you just need to insert the token in the security header of the SOAP envelope.

      Thanks for the comment, I hope this help!

      • Bob

        Hi again and thanks for the helpful info. I’m pretty much on my own with this problem; the people at the ws provider mostly use Miscrosoft tools to connect to their ws, so no one really knows how to do this with Java.

        I had a couple more questions:

        1. How do I know if the ws provider requires PoP tokens? I read a bit of your new article. It seems to say under the “Let’s start!” section that if you want to know what “keys” the service requires, you can find out by calling the wsdl. Is that how you know if PoP is needed or not?

        2. Assuming I don’t need PoP, you said all I need to do is “insert the token in the security header of the SOAP envelope”. So I’ve sent my request for a security token, and I got a response. When you say “token”, exactly which part of the response is the token? Everythning under “” ? And when you say “security header of the SOAP Envelope”, currently all there is under “” is a “” with “” and “”. So where does the token go?

        Sorry for the probably noob questions. I have never consumed an ADFS-protected web service before and literally have no idea.

  • Marcelo

    Hi Leandro,

    I have everything setup with ADFS and I am getting a wresult with t:RequestSecurityTokenResponse and all the details that you’ve mentioned. I would like to read this token using a Backbone.js application. Any thoughts?

    Thank you,

    Marcelo

    • http://leandrob.com/ Leandro Boffi

      Marcelo, in your case, if you are using a webapp, you need to use passive authentication (WS-Federation) not active (WS-Trust). From security standpoint validate the token client side is no secure at all.

      • Marcelo

        Thanks for the repply Leandro.

        Is there any node module that I can use with backbone in order to validate the token that I am getting back after a successful authentication? I’ve used this in the past: https://simplesamlphp.org/ with PHP. I would read the token, check the validity and kick the user in if valid. How can I use passive authentication on my scenario?

        Thanks,

        Marcelo

  • Ram prathap

    i am using xamarin Mono project(Mac project).Could you please let me know how to generate the RST as System.Identitymodel Namespace is not supported for Mono project.Kindly send me some sample code to achieve it.Please note the above project NOT supported WS-Trust

    • http://leandrob.com/ Leandro Boffi

      That is exactly what I explain on the post, how to generate the RST, what is your doubt?

      • Ram prathap

        I am getting response as BAD request when i send the above xml file to our server.Also dilemma part is that we are not aware about the authentication logic which is built in our end server.We are also not aware the complete URL to send the request.Is it mandatory to know the correct URL to send the request (For Ex; i cannot send the above xml to http://www.ourserver.com URL,i am sure the URL which we required to send request should like http://www.ourserver.com/login/checkuser?id=xxxxxx&&&Token=XXXXXX.Am i ryt?)

        • http://leandrob.com/ Leandro Boffi

          Is your server using WS-Trust? The URL depends on the WS-Trust endpoint for your server, if you are using ADFS the url would be https://yourcompany.com/adfs/services/trust/13/UsernameMixed

          • Ram prathap

            So in applies to attattribuin the xml file ,i have to give the above url..am i right?i shpuld not give yourcompany.com simply

          • http://leandrob.com/ Leandro Boffi

            I’m not sure of understanding the question. The RequestSecurityToken structure is part of the WS-Trust standard. In the post I show to to create that.

          • Ram prathap

            Do we have any other option to generate RequestSecurityToken with out using WS-Trust logic?What is the format to generate RST key whether it belongs to Encoding/Encryption/Hash code format?Please help.

  • Tiago Costa

    Can I use the RequestedSecurityToken section as a bearer token to do a call to ASP.NET web api?

    Something like: headers: { “Authorization”: “Bearer ” + token }

    Thanks

    • http://leandrob.com/ Leandro Boffi

      Sure. That is not a common case, because REST services usually use Json Web Tokens because they are more light that the huge XML in which is based the SAML token that you will get here.

      In that case, you need to send only the SAML token, that is the “Assertion” that you will find inside of the RequestedSecurityToken, and you will need to implement the logic to validate the SAML token using WIF framework, checkout this link http://stackoverflow.com/questions/17277996/using-wif-with-web-api

  • Praju

    Can you please tell how can i request token and get authenticated for ajaxify wcf call? application-json content type? I get Service undefined error

    • http://leandrob.com/ Leandro Boffi

      You can do that just like I explain in the article.

  • th

    Hi there, thanks for your informative post. Any ideas when it comes to encoding usernames/passwords – if a password contains < or & in my case, I get either a 400 response or 500. Thanks :)

  • Chad Brouwer

    This was working great with ADFS 2.0 but I just migrated to ADFS 3.0 (Server 2012 R2) and now I get an error “Connection reset by
    peer” when I make the service call. Has something changed with ADFS 3.0?

    • http://leandrob.com/ Leandro Boffi

      I haven’t tested with ADFS 3.0, but I’m pretty sure that this should work. Make sure that the endpoint is enabled in ADFS configuration because it could be disabled.

      • Chad Brouwer

        Thanks for the quick response. The endpoint is enabled. I will do some more testing and see what else I can come up with. It’s difficult because the “connection reset” error isn’t very helpful and nothing shows up in the ADFS logs.

        • http://leandrob.com/ Leandro Boffi

          Connection reset seems more a like a network problem, make sure you have connectivity to the ADFS, you can try that downloading the metadata file in /federationmetadata/2007-06/federationmetadata.xml

          • Chad Brouwer

            We found that it ended up being an authentication problem. ADFS 3.0 wanted username in domainusername format whereas ADFS 2.0 was fine with just username.

  • Alessio

    Dear Leandro,
    very useful… thanks!
    You say “[…] You can use those claims to perform authorization in your application, but also if your app needs to call webservices that rely on your ADFS, you will need to send the entire token in each request that you made to those services (I’ll explain this scenario in a future post). […]”, well, this is exactly my scenario.
    I have some aspx/vb web services behind adfs authentication and I perform ajax calls from an iOS application, using Cordova, so I’m writing in javascript.
    Those webservices return json data.
    I do, with success, this call:

    $.ajax({
    url: wsAuthUrl,
    cache: false,
    contentType: “application/soap+xml; charset=utf-8″,
    method: “POST”,
    data: requestToken, //the token formed as you suggested in your post
    success: function (authToken) {
    //”authToken” should be my valid authorization token, how can I use it?
    },
    error: function (jqXHR, textStatus, errorThrown) {
    alert(“ERROR”);
    },
    });

    I understand I have to put the authorization token, as you mentioned in your article, in each $.ajax call I make, but I cannot figure out I can do it: do you have any advice, please?

    Thank you very much for your help.

    • Alessio

      Any ideas? :)

      • http://leandrob.com/ Leandro Boffi

        It is very hard to say with this information.

        It looks like you are trying to call a REST service, but you use content-type for SOAP service.

        If you are trying to call a SOAP service, you need to include the SAML assertion in the header of the SOAP envelope, using WS-Security standard.

        If your service is a REST-like service there is no standard for sending the token, the common practice is to use the http authorization header to provide the token to the service, but as there is not an standard for doing that it depends on how the service is implemented.

        • Alessio

          Hi Leandro,
          thank you for the reply.
          I’m not calling rest webservices but some ws created ad hoc, I do some specific calls passing some parameters to aspx pages and I have some json data as result (ex: http://siteurl.com/jsonWs.aspx?func=clientList&clientid=client1…).
          Reading your answer I guess if I’m missing some parts, my thought was:
          1) I request the authorization token as you wrote in your article, by the SOAP request
          2) I embed this token to all the future ajax requests I will perform to my websevices as I do with the Form Authentication, IIS (or the ADFS server) will be in charge to extract the token from the request and recognize my request as a valid request.
          Did I misunderstood something?

          Thanks again, regards.

          • http://leandrob.com/ Leandro Boffi

            What you describe is not a very well-made architecture, but let me walk you thru what is happening (or at least from what I understood):

            You have a website made on ASP.NET that is using ADFS Forms Authentication. The way this works is that when you login to ADFS, ADFS sends (POSTs) a token to your site, your site checks the token and creates a cookie for you. Now on, you use that cookie in any of the calls you make to the site, to any page with the browser (the browser sends the cookie automatically). The important thing here is that the token is not used any more, just the first time to create the cookie (this is called Passive Authentication).

            Now, to call any endpoint (or aspx page) secured in that way from a native app (cordova or whatever) you need to identify yourself in any call you make. With the browser that happens with the cookie, in your case, you don’t have a cookie mechanism, so you have two options:

            1) You can simulate the browser process: get the token from ADFS like I showed in the post, POST that token to the site using WS-Federation like form, get the cookie that the site will send you, and send that cookie in each request you make manually.

            2) You can prepare your site to accept tokens in each call (Active Authetication), in this scenario, that is the one I recommend, you would need to change you site to be able of receiving the token in each request, maybe in the HTTP Authorization Header, validate the token signature and create the IPrincipal for that Identity.

            Hope that helps!

  • Rene Van Der Kooi

    I’m so lost… i got the envelope sample, filled out everything… i keep getting error “ID3242: The security token could not be authenticated or authorized.” or ” An error occurred when verifying security for the message.”… I even used the envelope the provider gave me with the exact settings… I am 100% sure the username and password are correct. The error switches when I play with the timestamp. I’m completely lost.

    • http://leandrob.com/ Leandro Boffi
      • Rene Van Der Kooi

        yes

        • http://leandrob.com/ Leandro Boffi

          You may need to check the logs from the ADFS server. Some tips:

          Make sure that:
          – You are using username in domainusername
          – The endpoint for username mixed auth (/adfs/services/trust/13/UsernameMixed) is enabled on the ADFS configuration
          – You are sending HTTP header for content-type: application/soap+xml; charset=utf-8

          If that doesn’t work, please paste here the request you are doing with all HTTP headers to see if I can help!

          • Rene Van Der Kooi

            I tried posting the code, but it keeps disappearing somehow…
            You’re help would be greatly appreciated…

            I have no access to the server or the logs. It’s a service I’m trying to connect to, but keeps failing.

            can I contact you in any way to send you some files? Buy you a beer if you get me to fix this…

          • http://leandrob.com/ Leandro Boffi

            sure, email the files me at me@leandrob.com