Ask Learn
Preview
Please sign in to use this experience.
Sign inThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
In this blog post I am going to walkthrough the steps required to secure a WCF service with ADFS 2.0, as well as how to call this service from a client. The aim of this article is to provide an outline of the general principals and steps, not to explain how to set up a fully secured scenario (everything in this post was tested across a couple of VMs on a development machine).
With federated security, there are two modes of authentication:
This walkthrough was carried out on two VMs.
To set up ADFS 2.0, you first need to download it from https://www.microsoft.com/download/en/details.aspx?displaylang=en&id=10909. Once download, run through the following steps…
After it has installed, you now need to configure it
On server 2, the WIF run time and SDK first needs to be installed.
Next, if your not using a DNS server (i.e. you’re on a dev enviroment), edit C:\Windows\System32\drivers\etc\hosts and add the following entries:
Next, create a website to host the WCF service:
Next, we need to set up a trusted certificate for our new site. We will follow the steps as per server 1 to do this. My SelfSSL command is as follows: SelfSSL /N:CN=services.testdomain.dev /V:365 /S:2
Also, set IE to accept certificates as above to both services.testdomain.dev and adfs.testdomain.dev (as per server 1).
1: public string GetData()
2: {
3: var id = Thread.CurrentPrincipal.Identity as IClaimsIdentity;
4: return string.Format("Hello {0}", id.Claims[0].Value);
5: }
Now the service has been created, it now needs to be altered to use ADFS 2.0.
Edit Claim Rules
Set the namespace to MyTestService and click ok.
Add a couple of references:
Add a new class called Token.cs to the project. This actively obtains the token from ADFS 2.0 (the secure token store). Add the following code to this class…
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.IdentityModel.Tokens;
6: using System.Net;
7: using Microsoft.IdentityModel.Protocols.WSTrust;
8: using System.ServiceModel;
9: using System.ServiceModel.Security;
10:
11: namespace WCFClient
12: {
13: internal class Token
14: {
15: public static SecurityToken GetToken(string username, string password, string appliesTo, out RequestSecurityTokenResponse rsts)
16: {
17: WS2007HttpBinding binding = new WS2007HttpBinding();
18: binding.Security.Message.EstablishSecurityContext = false;
19: binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
20: binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
21: binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
22:
23: WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory(binding, new EndpointAddress("https://adfs.testdomain.dev/adfs/services/trust/13/usernamemixed"));
24: trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
25: trustChannelFactory.Credentials.UserName.UserName = username;
26: trustChannelFactory.Credentials.UserName.Password = password;
27: trustChannelFactory.ConfigureChannelFactory();
28:
29: // Create issuance issuance and get security token
30: RequestSecurityToken requestToken = new RequestSecurityToken(WSTrust13Constants.RequestTypes.Issue);
31: requestToken.AppliesTo = new EndpointAddress(appliesTo);
32: WSTrustChannel tokenClient = (WSTrustChannel)trustChannelFactory.CreateChannel();
33: SecurityToken token = tokenClient.Issue(requestToken, out rsts);
34: return token;
35: }
36: }
37: }
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.ServiceModel;
6: using System.IdentityModel.Tokens;
7: using Microsoft.IdentityModel.Protocols.WSTrust;
8:
9: namespace WCFClient
10: {
11: public class FederatedWCFClient<T>
12: {
13: private SecurityToken token;
14: private ChannelFactory<T> factory;
15:
16: public FederatedWCFClient(SecurityToken securityToken, string binding)
17: {
18: this.token = securityToken;
19: this.factory = new ChannelFactory<T>(binding);
20: this.factory.ConfigureChannelFactory<T>();
21: }
22:
23: public void Close()
24: {
25: this.factory.Close();
26: }
27:
28: public T Client
29: {
30: get
31: {
32: return this.factory.CreateChannelWithIssuedToken(token);
33: }
34: }
35:
36: public T ClientActAs
37: {
38: get
39: {
40: return this.factory.CreateChannelActingAs(this.token);
41: }
42: }
43: }
44: }
Finally, update our main method in Program.cs as follows (ensure that the binding name, endpoint and credentials are set up correctly).
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5: using System.Net;
6: using Microsoft.IdentityModel.Protocols.WSTrust;
7:
8: namespace WCFClient
9: {
10: class Program
11: {
12: static void Main(string[] args)
13: {
14: var requestTokenResponse = new RequestSecurityTokenResponse();
15: var token = Token.GetToken(@"mydomain\testuser", "p@ssw0rd", "https://services.testdomain.dev/wcfservice/Service.svc", out requestTokenResponse);
16:
17: var wcfClient = new FederatedWCFClient<MyTestService.IService>(token, "WS2007FederationHttpBinding_IService"); // This must match the app.config
18: var client = wcfClient.Client as MyTestService.IService;
19: var result = client.GetData();
20: Console.WriteLine(result);
21: wcfClient.Close();
22: }
23: }
24: }
Now when you run the program, the client app will do the following
Thanks to Bradley Cotier for his debugging assistance
Written by Rob Nowik
Anonymous
October 02, 2012
Following your post, I have made WCF working without SSL; however, the process seems broken for SSL (https) based WCF. Do you have a post for WCF with SSL protected by AD FS 2.0?
Anonymous
March 04, 2014
Following all the steps I am getting Exception wsTrustSearializationException with message:
ID3135: The element 'KeyType' with namespace 'docs.oasis-open.org/.../200512& has value '2' which is not an absolute URI.
Searched for same but not getting any idea. Any help on this appreciated.
Anonymous
November 20, 2014
Very confusing guidance... Lost between server names and what you were doing where and why !
Anonymous
June 11, 2015
How to use WIF 4.5 framework for the same with ADFS 3.0
Anonymous
December 22, 2015
Bob,
The exception message is:
ID3242: The security token could not be authenticated or authorized.
I did get conflicts in the Token class. Are the below the right namespaces?
using System.ServiceModel.Security;
using System.Web;
using System.IdentityModel.Tokens;
using System.IdentityModel.Protocols.WSTrust;
//using Microsoft.IdentityModel.Protocols.WSTrust;
Please sign in to use this experience.
Sign in