WIF, ADFS 2 and WCF–Part 2: The Service
- by Your DisplayName here!
OK – so let’s first start with a simple WCF service and connect that to ADFS 2 for
authentication.
The service itself simply echoes back the user’s claims – just so we can make sure
it actually works and to see how the ADFS 2 issuance rules emit claims for the service:
[ServiceContract(Namespace
= "urn:leastprivilege:samples")]
public interface IService
{
[OperationContract]
List<ViewClaim>
GetClaims();
}
public class Service : IService
{
public List<ViewClaim>
GetClaims()
{
var id
= Thread.CurrentPrincipal.Identity as IClaimsIdentity;
return (from c in id.Claims
select new ViewClaim
{
ClaimType
= c.ClaimType,
Value
= c.Value,
Issuer
= c.Issuer,
OriginalIssuer
= c.OriginalIssuer
}).ToList();
}
}
The ViewClaim data contract is simply a DTO that holds the claim information.
Next is the WCF configuration – let’s have a look step by step. First I mapped all
my http based services to the federation binding. This is achieved by using .NET 4.0’s
protocol mapping feature (this can be also done the 3.x way – but in that scenario
all services will be federated):
<protocolMapping>
<add scheme="http" binding="ws2007FederationHttpBinding" />
</protocolMapping>
Next, I provide a standard configuration for the federation binding:
<bindings>
<ws2007FederationHttpBinding>
<binding>
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false">
<issuerMetadata address="https://server/adfs/services/trust/mex" />
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
</bindings>
This binding points to our ADFS 2 installation metadata endpoint. This is all that
is needed for svcutil (aka “Add Service Reference”) to generate the required client
configuration. I also chose mixed mode security (SSL + basic message credential) for
best performance. This binding also disables session – you can control that via the establishSecurityContext setting
on the binding. This has its pros and cons. Something for a separate blog post, I
guess.
Next, the behavior section adds support for metadata and WIF:
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpsGetEnabled="true" />
<federatedServiceHostConfiguration />
</behavior>
</serviceBehaviors>
</behaviors>
The next step is to add the WIF specific configuration (in <microsoft.identityModel
/>). First we need to specify the key material that we will use to decrypt
the incoming tokens. This is optional for web applications but for web services you
need to protect the proof key – so this is mandatory (at least for symmetric proof
keys, which is the default):
<serviceCertificate>
<certificateReference storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectDistinguishedName"
findValue="CN=Service" />
</serviceCertificate>
You also have to specify which incoming tokens you trust. This is accomplished by
registering the thumbprint of the signing keys you want to accept. You get this information
from the signing certificate configured in ADFS 2:
<issuerNameRegistry type="...ConfigurationBasedIssuerNameRegistry">
<trustedIssuers>
<add thumbprint="d1
… db"
name="ADFS" />
</trustedIssuers>
</issuerNameRegistry>
The last step (promised) is to add the allowed audience URIs to the configuration
– WCF clients use (by default – and we’ll come back to this) the endpoint address
of the service:
<audienceUris>
<add value="https://machine/soapadfs/service.svc" />
</audienceUris>
OK – that’s it – now we have a basic WCF service that uses ADFS 2 for authentication.
The next step will be to set-up ADFS to issue tokens for this service. Afterwards
we can explore various options on how to use this service from a client.
Stay tuned…
(if you want to have a look at the full source code or peek at the upcoming parts
– you can download the complete solution here)