In a claims-based identity scenario, tokens are issued by an Identity Provider (IP) and the user can access resources from a Service Provider or Relying Party (RP) using such claims. The following diagram illustrates the process flow:
However, in the world of claims, it is possible that an RP doesn't trust the IP if they are in discrete security domains. This recipe shows how federation can be used to build a Security Token Service for the IP (IP-STS) and the RP (RP-STS) to create a realm of trust across the security boundaries.
Windows Communication Foundation (WCF) exposes the WSFederationHttpBinding
class to support federation (WS-Federation). We will use this binding in our recipe solution to create a federated STS. The documentation provided at http://msdn.microsoft.com/en-us/library/aa347982.aspx will help you learn more about this binding configuration.
To create an STS, perform the following steps:
System.ServiceModel.Channels
namespace. ISecurityTokenService
service contract and define an operation contract that accepts the Message
request ( System.ServiceModel.Channels
) and returns a Message
response with the claims assigned by the issuer:[ServiceContract(Name = "SecurityTokenService", Namespace = "http://RelyingParty/v1")] public interface ISecurityTokenService { [OperationContract] Message ProcessRequestSecurityToken(Message message); }
SOAP
action for the reply message on the OperationContract
attribute:[OperationContract(Action = "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue", ReplyAction = "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue")]
The Action
and ReplyAction
properties must conform to the WS-Trust specification.
ISecurityTokenService
for the IP. In the implemented IdentityProviderSecurityTokenService
method, create an instance of RequestSecurityToken
using the request message header:RequestSecurityToken rst = RequestSecurityToken.CreateFrom(message.GetReaderAtBodyContents());
The RequestSecurityToken
class should comply with OASIS web security WS-Trust
standard specification. An equivalent XML representation will look like the following code:
<RequestSecurityToken> <RequestType> http://schemas.xmlsoap.org/ws/2005/02/trust/Issue </RequestType> <AppliesTo> <EndpointReference> <Address> http://localhost:8080/SecurityTokenService/IdentityProvider </Address> </EndpointReference> </AppliesTo> <TokenType> http://docs.oasis-open.org/wss/oasis-wss-saml-token- profile-1.1#SAMLV1.1 </TokenType> </RequestSecurityToken>
RequestSecurityToken
key retrieved from the RequestorEntropy
property and use the proof token, issuer token, and the claims to create a SamlSecurityToken
object with an encrypted proof key to be held by the subject of the SAML security token. Build a RequestSecurityResponse
instance using the SamlSecurityToken
object:BinarySecretSecurityToken proofToken = new BinarySecretSecurityToken(key); SamlSecurityToken samlToken = Saml11Helper.CreateSamlSecurityToken(issuer, proofToken, IssuerToken, ProofKeyEncryptionToken, samlConditions, samlAttributes); RequestSecurityTokenResponse rstr = GetRequestSecurityTokenResponse(rst, keySize, proofToken, samlToken, senderEntropy, stsEntropy);
senderEntropy
is the RequestorEntropy
key and stsEntropy
is an alternate random key.
RequestSecurityResponse
instance and message header action set to the WS-Trust reply action URI:Message responseMessage = Message.CreateMessage(message.Version, "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue", rstr);
responseMessage.Headers.RelatesTo = message.Headers.MessageId;
PeerOrChainTrust:
serviceHost.Credentials.IssuedTokenAuthentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
serviceCredentials
element:<serviceCertificate storeLocation ="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="IdentityProviderSTS" />
The binding element should be wsHttpBinding
. Also, make sure that a mex
endpoint is exposed for the purpose of metadata discovery.
ISecurityTokenService
for the RP. In the implemented method—RelyingPartySecurityTokenService
, verify that the issuer is the IP STS:List<ClaimSet> claimSets = new List<ClaimSet>(OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets); ClaimSet issuer = claimSets.Find((Predicate<ClaimSet>)delegate(ClaimSet target) { X509CertificateClaimSet issuerClaimSet = target.Issuer as X509CertificateClaimSet; return issuerClaimSet != null && issuerClaimSet.X509Certificate.Subject == "CN=IdentityProviderSTS"; });
In a more realistic scenario, the retrieved claim sets will be compared for matched thumbprints; however, for our recipe, we will settle for the certificate subject comparison with the IP. Notice that ClaimSet
is retrieved from the service's AuthorizationContext
. Also, copy over the identity claims retrieved from the IP realm to create an instance of SamlSecurityToken
for the response message.
serviceCredentials
element:<serviceCertificate storeLocation ="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="RelyingPartySTS" />
The binding element should be wsFederationHttpBinding
. The binding configuration should have message security mode set to Message
and the issuer/issuerMetadata
address pointing to the endpoint/mex endpoint address of the IP. A mex
endpoint should also be exposed in the RP service configuration for the purpose of metadata discovery.
<client> <endpoint name="" address="http://localhost:8080/RelyingParty/Service" binding="wsFederationHttpBinding" bindingConfiguration="FederationBinding" behaviorConfiguration="RelyingPartyServiceBehavior" contract="IResource"> <identity> <certificateReference storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="RelyingPartyService"/> </identity> </endpoint> </client>
To allow the users of the IP realm to access resources from the RP, a brokered trust is established using an STS on either side of the realm. In our recipe, the trust is established by sharing a common contract between the IP-STS and RP-STS. The RP expects that the user presents it with the claims to access the resources that are issued by the RP-STS. On the other hand, the RP-STS expects the user to present claims issued by the IP-STS. The successful handshake is achieved by verifying the issuer at each step. The following diagram illustrates this scenario:
The RP service can validate the client request using an implementation of ServiceAuthorizationManager
and validating the claims in the CheckAccess
method:
public class FedAuthorizationManager : ServiceAuthorizationManager { public override bool CheckAccess(OperationContext operationContext) { } }
A brief overview of the concept of federation is provided in the MSDN documentation at http://msdn.microsoft.com/en-us/library/ms730908.aspx. This recipe references the concepts mentioned in the article. A complete solution of the federation scenario sample can be downloaded from http://msdn.microsoft.com/en-us/library/aa355045.aspx.
Web browsers act as the passive requestors and there is no direct way of controlling the behavior. The WS-Federation Passive Requestor Profile provides a set of guidelines that can be used to make web applications provide identity services. Details of the guidelines can be found in the MSDN article at http://msdn.microsoft.com/en-us/library/bb608217.aspx.
If the trust boundaries are not discrete, a single realm STS could be used, where both the IP and the RP trust the STS. The following diagram illustrates this scenario:
In a single realm STS, the token service creates a token after authenticating the client credentials against an IP. The RP ensures that the issuer in the token is the STS and verifies the claims before accepting the client request.
18.118.16.81