WIF, ADFS 2 and WCF–Part 2: The Service

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)

This entry was posted in IdentityModel. Bookmark the permalink.

21 Responses to WIF, ADFS 2 and WCF–Part 2: The Service

  1. lockszmith says:

    get a 404 when trying to download the binary, can you provide another link for it? thanks.

  2. KitKat says:

    Where in the archives? I cannot find it. Thank you.

  3. william says:

    When we add an entry to the trustedIssuers, does a certificate with that thumbprint need to be on the RP’s machine? It seems not. But if not, then how does the RP validate the signature? Thanks for your help with this complex topic.

  4. Mark Shyn says:

    Dominick,

    First of all, thanks for posting this 6-part series on WIF, ADFS 2, and WCF. It’s very informative.
    I have a question about the need to configure the thumbPrint for the token-signing certificate. If I am implementing an active, federated scenario using the manual approach, won’t I still need to specify the thumbPrint (either in my code or through configuration) so that the call to validateToken() will succeed?

    • Mark Shyn says:

      I’ve seen one example, on Gavin Draper’s blog, where a class derived from IssuerNameRegistry is defined and which is used to verify that the subject name specified in the cert matches the expected name. So, I suppose this is an alternative to using a thumbPrint?

      But it seems to me that all of this depends on the RSTR message containing a certificate chain with a trusted cert at the end of the chain. Otherwise, a phony cert/public-key could be transmitted.

      • yea – well – all Gavin is doing is to make sure the name of the cert is what he expects…anybody could craft a cert with a given name..maybe someone should tell him that ;)

    • The issuer name registry is how you establish trust with an issuer. You register the thumbprint of the issuing cert and map it to a logical issuer name.

      • Mark Shyn says:

        The MSDN article at this url: http://msdn.microsoft.com/en-us/library/ee748479.aspx
        makes the statement: “Although the IssuerNameRegistry is the logical place to reject untrusted, unknown, or invalid issuers, keep in mind that the token handlers enforce PeerOrChainTrust validity on issuer certificates by default, so any similar checks in the IssuerNameRegistry will be redundant.”

        So, in other words, it seems the authenticity of the cert is already established and the purpose of checking the registry is to simply verify that the cert comes from someone that you expected. Am I mistaken on this?

  5. It’s the other way round – the issuer name registry makes sure (at least the default one) that the token is signed by an expected issuer.

    In addtion (and optionally) you can validate the cert (expiration, chain trust etc).

  6. Mark Shyn says:

    Well, I may be mistaken Dominick, but it would seem that before you check that the issuer identified on the certificate was someone from whom you were expecting to receive the token, you would have to validate the certificate since (as you said yourself in one of your earlier replies up above), the issuer could be falsified.

  7. Well – when using a thumbprint – the issuer cannot be falsified. The thumbprint is a unique value (hash of the cert). Using just the issuer name is not enought – in that case you need to check the trust chain.

    So – either check thumbprint only. Or check common name plus trust chain.

    • Mark Shyn says:

      Since the transmitted certificate does not contain the private key, an imposter could replicate the entire certificate. The thumbprint, since it is computed using a well-known hash function, would match the expected value.
      I do not think the thumbprint check eliminates the need for chain-of-trust certificate validation. The thumbprint provides a way to uniquely identify the certificate and nothing more.
      Suppose the STS you’re dealing with has a dozen different certs that they could use (depending perhaps on which of your applications they are communicating with) to sign the token. For a given application, you might want to accept only one of those certs. The issuer could be the same for all 12 certs, so something more precise is needed. The thumbprint, being a hash of the entire cert, serves that purpose.
      Perhaps I’m misinformed, but this is my understanding.

  8. Well – actually . you are misinformed.

    The thumbprint is the hash over the cert – including its public key – and only this public key can be used to verify the signature of the token (which can only be signed by the corresponding private key). So no – you can’t “clone” the thumbprint.

  9. Chris says:

    Dominick, where is the sample project code located now? The link above which points here: “https://leastprivilege.com/content/binary/soapadfs.zip” is broken.

  10. Rani Y. says:

    I am probably missing something, since the full project downloaded from the archive does not contain any endpoint, or explanation about what is starting the serviceModel of the server.
    Is it supposed to be set on IIS ? hosted on console application for example whould suffice.
    Moreover, I can’t figure out if the service is supposed to be exposed as https (with ssl certificates which are not explained here), or as http.
    Meaning if I try to compile the given solution (with project) I cannot raise a hosted service and use the addServiceReference to update the automatic client.
    A lot of stuff seems to be missing, like the endpoint configuration, the ssl-certificate for the https, and more.
    Is there a complete solution out there to be tested ?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s