Obtaining an STS token from ADFS using Windows Authentication

This one has had me stumped for a bit now. An organisation where I work has an Office365 tenancy which is federated with an on-premises Active Directory. I have been working on an application which needs to authenticate to SharePoint Online to perform actions on behalf of users. The first version I wrote worked well, however it had a drawback in that it needed the user to enter their password on a Windows form before it could be used – the user principal name can be easily obtained from the session information.

I wanted to upgrade the application so that it would use integrated authentication to obtain a SAML token from ADFS and try to use this to authenticate before using the username/password combination as a fallback. Things weren’t straight forward, however, as a lot of the documentation around how to connect to ADFS in this manner is out of date. Microsoft have rolled a lot of the identity framework stuff into .NET natively from 4.5 onwards, so the old .NET 3.5 ways of doing things are no longer possible as the classes, properties and methods you need to create and manipulate are deprecated and not available in newer versions of .NET.

Some people may suggest that re-targeting the application at .NET 3.5 might have gotten around this, however I don’t like to go back to older versions of technology unless it’s absolutely necessary. To that end, I used the following code to pass through the currently logged on user’s information to ADFS and get a token back from the STS endpoint:

        public GenericXmlSecurityToken GetToken()
        {
            WS2007HttpBinding binding = new WS2007HttpBinding(SecurityMode.Transport);
            binding.Security.Message.EstablishSecurityContext = false;
            binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
            WSTrustChannelFactory factory = new WSTrustChannelFactory((binding), new EndpointAddress(stsEndpoint));
            factory.TrustVersion = TrustVersion.WSTrustFeb2005;
            factory.Credentials.SupportInteractive = false;
            var rst = new RequestSecurityToken
            {
                RequestType = RequestTypes.Issue,
                AppliesTo = new EndpointReference(realm),
                KeyType = KeyTypes.Bearer
            };
            IWSTrustChannelContract channel = factory.CreateChannel();
            return channel.Issue(rst) as GenericXmlSecurityToken;
        }

The stsEndpoint string is the link to your ADFS STS endpoint, e.g.: https://my.adfs.org/adfs/services/trust/2005/windowstransport for integrated authentication. The realm string is the link to Microsoft’s own STS server that secures Office365: https://login.microsoftonline.com/extSTS.srf

The method above returns a GenericXmlSecurityToken object which has a TokenXml property. Passing the GenericXmlSecurityToken.TokenXml.OuterXml property into a parametised SOAP request to the Office365 STS endpoint will allow you to pass through the user’s logged on details without needed to capture a password first.

Hope this helps anyone out there trying to do the same kind of thing.

Share and Enjoy:
  • Digg
  • StumbleUpon
  • Technorati
  • del.icio.us
  • Twitter
  • blogmarks
  • HackerNews
  • Tumblr
  • Posterous
  • email
Bookmark the permalink. Follow any comments here with the RSS feed for this post.
Post a comment or leave a trackback: Trackback URL.

Leave a Reply

Your email address will not be published. Required fields are marked *

This blog is kept spam free by WP-SpamFree.