WCF: Federating WCF with WIF
Ask:
Federate WCF service via WIF
Traditional approach:
For normal web app or MVC app, we follow the concept of FedAuth cookie.
Client -> Federated Application, gets redirected to STS
Client -> STS, get claims
Client -> Federated Application validates claims and issue a Fed Auth Cookie.
Client -> This time call made with Fed Auth cookie and Federated application serves the request.
Approach for WCF Service:
WCF service by default uses the ws2007FederationHttpBinding.
This is a special binding designed to federate the WCF service. However, it does not work on above traditional approach. Rather this works on WCF Message Security principle.
Client -> Federated Application, get redirected to STS
Client -> Does Security Negotiation to get the SCT (Security Context Token) via RST/Issue Action.
Client (using SCT Token and Claims received via STS) -> Federated Application, here claims can be checked.
In above screen we can see that there is only one RST/Issue or SCT call made between two calls to “GetData()” method. Because with WCF federation, we work on concept of using the WCF channel or SCT token negotiated with STS. There is no concept of FedAuth cookie, because WCF Federation is all about using Message Security protocol.
https://msdn.microsoft.com/en-us/library/bb675187(v=vs.110).aspx
WsFederation2007HttpBindindm only support Message Level security.
<ws2007FederationBinding>
<binding >
<security mode="None/Message/TransportWithMessageCredential">
<message negotiateServiceCredential="Boolean"
algorithmSuite="Basic128/Basic192/Basic256/Basic128Rsa15/ Basic256Rsa15/TripleDes/TripleDesRsa15/Basic128Sha256/Basic192Sha256/TripleDesSha256/Basic128Sha256Rsa15/Basic192Sha256Rsa15/Basic256Sha256Rsa15/TripleDesSha256Rsa15"
defaultProtectionLevel="none/sign/EncryptAndSign"
issuedTokenType="string"
issuedKeyType="SymmetricKey/PublicKey"
</message>
</security>
</binding>
</ws2007FederationBinding>
From below screen shot, we can see client doing message security negotiation with the ADFS STS and not the actual Federated WCF application:
But, also check that the Body contains the actual address of the Federated WCF application or in other words our relying party address.
Once negotiation completes client received the SAML Assertion token from the ADFS or our custom STS.
Once received, client can now present the Claims along with the SCT token negotiated with the ADFS STS to the federated WCF application.
Unfortunately, WCF traces truncates the Claims in WCF traces, so we cannot see it. However, we can clearly see the SAML Assertion ID.
Simple WCF-WIF Federation sample can be created by following the below blog: https://blogs.msdn.microsoft.com/napegadie_kones_msft_blog/2015/02/09/claims-aware-wcf-using-wif-in-net-4-5/
Client application configuration: Caller to Federated WCF service
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logKnownPii="true" logMalformedMessages="true"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
</diagnostics>
<bindings>
<wsHttpBinding>
<binding name="https://adfs.contoso.com/adfs/services/trust/13/windowstransport">
<security mode="Transport" />
</binding>
</wsHttpBinding>
<ws2007FederationHttpBinding>
<binding name="WS2007FederationHttpBinding_IService1">
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false" negotiateServiceCredential="false">
<issuer address="https://adfs.contoso.com/adfs/services/trust/13/windowstransport"
binding="wsHttpBinding" bindingConfiguration="https://adfs.contoso.com/adfs/services/trust/13/windowstransport">
<identity>
<servicePrincipalName value="host/adfs.contoso.com" />
</identity>
</issuer>
<issuerMetadata address="https://adfs.contoso.com/adfs/services/trust/mex" />
<tokenRequestParameters>
<trust:SecondaryParameters xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:KeyType xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">https://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
<trust:KeySize xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">256</trust:KeySize>
<trust:KeyWrapAlgorithm xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">https://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</trust:KeyWrapAlgorithm>
<trust:EncryptWith xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">https://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptWith>
<trust:SignWith xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">https://www.w3.org/2000/09/xmldsig#hmac-sha1</trust:SignWith>
<trust:CanonicalizationAlgorithm xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">https://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
<trust:EncryptionAlgorithm xmlns:trust="https://docs.oasis-open.org/ws-sx/ws-trust/200512">https://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
</trust:SecondaryParameters>
</tokenRequestParameters>
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
</bindings>
<client>
<endpoint address="https://aadconnect.contoso.com/WcfService1/Service1.svc"
binding="ws2007FederationHttpBinding" bindingConfiguration="WS2007FederationHttpBinding_IService1"
contract="ServiceReference1.IService1" name="WS2007FederationHttpBinding_IService1" />
</client>
</system.serviceModel>
WCF Federated Service configuration:
<system.identityModel>
<identityConfiguration>
<audienceUris>
<add value="https://aadconnect.contoso.com/WcfService1/Service1.svc" />
</audienceUris>
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
<authority name="https://adfs.contoso.com/adfs/services/trust">
<keys>
<add thumbprint="FBB1052A9E412FFBEB0032D190DECE12E32C4689" />
</keys>
<validIssuers>
<add name="https://adfs.contoso.com/adfs/services/trust" />
</validIssuers>
</authority>
</issuerNameRegistry>
<!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
<certificateValidation certificateValidationMode="None" />
</identityConfiguration>
</system.identityModel>
<configSections>
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
<add key="ida:FederationMetadataLocation" value="https://adfs.contoso.com/federationmetadata/2007-06/federationmetadata.xml" />
<add key="ida:ProviderSelection" value="productionSTS" />
</appSettings>
<location path="FederationMetadata">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials useIdentityConfiguration="true">
<serviceCertificate findValue="CN=localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectDistinguishedName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="https" binding="ws2007FederationHttpBinding" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<ws2007FederationHttpBinding>
<binding name="">
<security mode="TransportWithMessageCredential">
<message establishSecurityContext="false" negotiateServiceCredential="false">
<issuerMetadata address="https://adfs.contoso.com/adfs/services/trust/mex" />
</message>
</security>
</binding>
</ws2007FederationHttpBinding>
</bindings>
</system.serviceModel>
Sample Application: https://1drv.ms/f/s!ArgnWb8iHXB6gqYXvg53egkGHFxdvw