WCF service using Azure relay and ADFS authentication (2/2)

In the second part of this article (read part 1 here), we’re going to extend our relayed service with AD (Active Directory) authentication. In most cases you’ll need authentication to provide some security for your business data. In this example, we’re keeping it simple; just using a valid domain account to access the data. All (enabled) accounts are valid. But with some extending, you can quite easily adapt this code to work with AD groups for instance, making sure only certain users can get to the data. This is done by using claims, perhaps I’ll cover that in a third article.

Let’s sum up the things we’ll need to get this working:

  1. An ADFS server is required to validate the authentication requests. This server needs to be accessible via the Internet, so usually it will live inside a DMZ zone of some kind. Let me clarify that I am not an authentication / ADFS expert and that I did not configure our sever (actually, I don’t even have access). So you might need the help of a colleague here as I did.
  2. You need to setup Azures ACS (Access Control Service). How to do that, I will describe in this article.
  3. You need to alter your client and server code to authenticate themselves using ADFS instead of the previously used shared access key.

The authentication flow will go as follows:

  1. Your client sends an authentication request to the ADFS server.
  2. The ADFS server replies with a SAML token when the credentials supplied were valid. This token is encrypted.
  3. Your client decrypts the token using the decryption certificate.
  4. The decrypted token is used to create a TokenProvider object, which is then passed to the relay binding endpoint.
  5. Because of the trust setup between ACS and ADFS, ACS will recognized the passed along token and provide access based on it.

Behind the scenes there’s much more going on, but these are the basics. This differs from what I first had in mind myself; I thought ACS would contact ADFS and handle the security. It’s important to realize it doesn’t work that way; YOU need to provide the ADFS token. Perhaps they’ll change that in de future? Don’t know. It would be great if you could just send credentials to ACS and tell it to verify them at the ADFS server. But until that happens, this is what you’ll need to do.

ADFS Requirements

First, we’re going to setup ADFS. I’m going to assume you’ll won’t be doing that yourself (I didn’t). If you’re going to contact your ADFS administrator, you’ll need the following things:

  • The URL of the FederationMetadata.xml. This is usually found at:
    https://adfs.company.com/FederationMetadata/2007-06/FederationMetadata.xmlThese XML’s are great because they automate a part of the setup.
  • The token decryption certificate
    Which you’ll need to decrypt the token (duh), otherwise you won’t be able to use it.
  • His ok to configure a relying party
    The administrator will need to configure ACS as a relying party in ADFS as well. Sure make sure you get the approvals for that when needed.
  • Enabled usernamemixed endpoint
    Ask the administrator to verify that the usernamemixed endpoint is enabled and ask for the URL. Normally it would be:
    https://adfs.company.com/adfs/services/trust/13/usernamemixed

In return, you can provide the ADFS administrator with the metadata XML URL for ACS. He can use that to configure a relying party in ADFS. The URL is found in the ACS management portal, under “Application Development”. It will be something like: https://calculator-sb.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml.
Note: you’ll need the –sb URL (also see “Setting up ACS”)!

Setting up ADFS

I’m not going to elaborate on how to setup ADFS since I’m not a specialist. I can however point you to this article: http://msdn.microsoft.com/en-us/library/jj136813.aspx. It clearly describes what to do. I used it as guidance on this entire project, but it doesn’t use username/password type credentials, so don’t copy/paste the code!

Setting up ACS

Setting up ACS is described in the article as well, but I want to elaborate on that a bit. First important thing to realize is that your service bus has a separate ACS! That fooled me for a while; I would open up the Azure management portal, click Active Directory, select my instance and select “Manage”. But in that case, Service Bus won’t be there as a relying party! To open up the correct one, go to “Service Bus”, click “Access Key” and then click the “Open ACS Management Portal” link. Or you can browse to “https://namespace-sb.accesscontrol.windows.net“, replace namespace with your own of course.

If your ADFS administrator gave you the FederationMetadata URL, setting up is easy.

  • Click “Identity Providers”
  • Select “WS-Federation identity provider”
  • Choose a name and insert the metadata URL
  • Under “Used by” select “Service Bus”. This will hook up this identity provider to the service bus.

Done! Using the metadata from the XML, the rest is configured pretty much automagically. Again, for more detail check out this article.

Setting up the client and server

Now it’s back to code again. For both the server and the client, we will have to switch out the TokenProvider. In the relay example we were using TokenProvider.CreateSharedSecretTokenProvider, now we will use TokenProvider.CreateSamlTokenProvider instead. For that, we’ll need a SAML token which we will get from ADFS.

The samples are a bit too big to all publish, so please just download the solution file (see bottom). I will highlight a few things.

  • For connecting to the ADFS instance, we use the UserNameWSTrustBinding binding.
  • That binding is used in a WSTrustChannelFactory instance, in which we need to set the credentials of the user. Note that for both client and server it doesn’t matter what you put in here, as long as the account is a valid one. But you can implement more control later, requesting certain claims for instance. I need to figure out how before I blog about it 😉
  • Another thing to note is the value we put into the “AppliesTo” property of the RequestSecurityToken. The value needs to be present in the “relying party identifiers” list of ADFS. If it’s not, you’ll won’t receive a token.

So that all boils down to:

string samlToken = GetTokenFromADFS.GetIssuedToken(Constants.adfsTrust13UsernameMixed, Constants.acsEndpoint, Constants.adfsX509CertificateSubjectName, Constants.domainUser, Constants.domainPassword);

var cf = new ChannelFactory<ICalculatorChannel>(
             new BasicHttpRelayBinding(),
             new EndpointAddress(ServiceBusEnvironment.CreateServiceUri("https", Constants.sbNamespace, Constants.sbServicePath)));

cf.Endpoint.Behaviors.Add(new
    TransportClientEndpointBehavior {
        TokenProvider = TokenProvider.CreateSamlTokenProvider(samlToken)
});

To be absolutely honest, the GetTokenFromADFS.GetIssuedToken
I mostly got from a very kind Microsoft engineer who helped me on this. If you want to create and understand that yourself, you got some reading to do about the authentication flow (spnego). I just know it works and have a general understanding of what it does. That suffices too 😉

By the way, Microsoft guys, why not stick a method like GetTokenFromADFS.GetIssuedToken in the IdentityProvider framework dll’s?

As you can see, the code is not that different from what it was. And that’s the beauty of it. Apart from the “fetch SAML token” code, most stuff is done by the Azure ServiceBus SDK bits. So once you understand the trick, it’s easy to implement, also for existing WCF services you might want to expose.

And then… finally… here’s the code! Make sure you alter the values in constants.cs (shared) and eventually create a configuration file of course.

http://sdrv.ms/1cLznnZ

Hope you like it (and it works). If not, please use the comments below!

,

Related posts

Long Term Support… or not?

In the second part of this article (read part 1 here), we're going to extend our relayed service with AD (Active Directory) authentication. In most cases you'll need authentication to provide some security for your business data. In this example, we're keeping it simple; just using a valid domain account to access the data. All (enabled) accounts are valid. But with some extending, you can quite easily adapt this code to work with AD groups for instance, making sure only certain users can get to the data. This is done by using claims, perhaps I'll cover that in a third article.

[DevOps] Should you migrate onto YAML release pipelines?

In the second part of this article (read part 1 here), we're going to extend our relayed service with AD (Active Directory) authentication. In most cases you'll need authentication to provide some security for your business data. In this example, we're keeping it simple; just using a valid domain account to access the data. All (enabled) accounts are valid. But with some extending, you can quite easily adapt this code to work with AD groups for instance, making sure only certain users can get to the data. This is done by using claims, perhaps I'll cover that in a third article.

Latest posts

Long Term Support… or not?

In the second part of this article (read part 1 here), we're going to extend our relayed service with AD (Active Directory) authentication. In most cases you'll need authentication to provide some security for your business data. In this example, we're keeping it simple; just using a valid domain account to access the data. All (enabled) accounts are valid. But with some extending, you can quite easily adapt this code to work with AD groups for instance, making sure only certain users can get to the data. This is done by using claims, perhaps I'll cover that in a third article.

[DevOps] Should you migrate onto YAML release pipelines?

In the second part of this article (read part 1 here), we're going to extend our relayed service with AD (Active Directory) authentication. In most cases you'll need authentication to provide some security for your business data. In this example, we're keeping it simple; just using a valid domain account to access the data. All (enabled) accounts are valid. But with some extending, you can quite easily adapt this code to work with AD groups for instance, making sure only certain users can get to the data. This is done by using claims, perhaps I'll cover that in a third article.

Leave a Comment

Leave a Reply

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