Work in progress | |
---|---|
This document is not finished yet. When it gets finished this box will be removed. |
This document should describe how should developers configure and use the Atomia Identity Security Token Service (STS) from their applications.
By looking at the image above we could distinguish two different Authentication paths:
Authenticating user to use web application (steps 1, 2, 3, 4) - To be able to use the web application user must authenticate to the STS, providing the username and password. Then the user gets the SAML token key containing the set of claims those identify the user to the Web Application.
Authenticating web application to use WCF service (with identity delegation) (steps 6, 7, 3, 8) - In order to use the WCF service through the web application, web application needs to delegate user's credentials to the STS by providing the user's token (given to the user in the previous iteration) and its certificate. Then the WCF service has the identity information about the logged user and its delegate (web application).
We are starting from conficuration like this:
<configuration> <system.serviceModel> <services> <service behaviorConfiguration="CoreServiceBehavior" name="Service.CoreService"> <endpoint address="" binding="wsHttpBinding" contract="Service.ICoreService"> <identity> <dns value="localhost" /> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:8700/CoreService/" /> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior name="CoreServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
As we can see we are starting with one WCF service
ICoreService
that does not need any authentication.
To enable authentication using
Atomia Identity
in this file we will add config section for
microsoft.identity
<!-- NEW --> <configSections> <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </configSections> <microsoft.identityModel> <service> <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedIssuers> <add name="CN=Atomia Identity" thumbprint="72071a7a2b933bd5b73bbb4b026c575ccb2d2ca4"/> </trustedIssuers> </issuerNameRegistry> <securityTokenHandlers> <remove type="Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add type="Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <samlSecurityTokenRequirement> <nameClaimType value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"/> <roleClaimType value="http://schemas.troxo.com/ucp/2009/04/ucpcore/claims/groups"/> </samlSecurityTokenRequirement> </add> </securityTokenHandlers> </service> </microsoft.identityModel>
In this config file few things are important to note:
line 09 - We define with which issuer our WCF application has trusted relation.
line 17 - Defines value of which token type will be interpreted as username
line 18 - Defines value of which token type will be interpreted as users role
Now, we should configure our service to use federated authentication
<system.serviceModel> <services> <service behaviorConfiguration="CoreServiceBehavior" name="Service.CoreService"> <endpoint address="" binding="wsFederationHttpBinding" contract="Service.ICoreService" bindingConfiguration="wsFed" > </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:8700/CoreService/" /> </baseAddresses> </host> </service> </services> <bindings> <wsFederationHttpBinding> <binding name="wsFed" > <security mode="Message"> <message issuedKeyType="SymmetricKey" issuedTokenType=""> <claimTypeRequirements> <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="false"/> <add claimType="http://schemas.troxo.com/ucp/2009/04/ucpcore/claims/groups" isOptional="true"/> </claimTypeRequirements> <issuer address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/username/" /> <issuerMetadata address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/mex" /> </message> </security> </binding> </wsFederationHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="CoreServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> <serviceAuthorization principalPermissionMode="None"/> <serviceCredentials> <issuedTokenAuthentication allowUntrustedRsaIssuers="false" certificateValidationMode="PeerOrChainTrust" audienceUriMode="Never" revocationMode="Online" trustedStoreLocation="LocalMachine"> <knownCertificates> <add findValue="UCP Authorization Service" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/> </knownCertificates> </issuedTokenAuthentication> <serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="UCP Core"> </serviceCertificate> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
Line 06 - Defines that we use now wsFederationHttpBinding
Lines 19 to 31 - Describes federated http bindings setting
Lines 23 to 26 - What claim types we are requesting from
Atomia Identity
for our WCF
Lines 27 and 28 - Defines location of identity provider for
On the STS side we should add RP (Rely party) certificate and inform STS that for given URI should use that certificate. This is done in two steps:
1. Set which RpCertProvider to use for given RP URI
<type type="IRpCertProvider" mapTo="AtomiaRpCertificateProvider" name="http://localhost:8700/CoreService/"></type>
2. For AtomiaRpCertProvider set how to find certificate
<add storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" findValue="CN=MyWebService" rpAddress="http://localhost:8700/CoreService/" />
Of course, you will have to install that certificate on given location.
If we now update service reference on client side Visual Studio will generate config file like:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <wsFederationHttpBinding> <binding name="WSFederationHttpBinding_ICoreService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Message"> <message algorithmSuite="Default" issuedKeyType="SymmetricKey" negotiateServiceCredential="true"> <claimTypeRequirements> <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="false" /> <add claimType="http://schemas.troxo.com/ucp/2009/04/ucpcore/claims/groups" isOptional="true" /> </claimTypeRequirements> <issuer address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/username/" /> <issuerMetadata address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/mex" /> </message> </security> </binding> </wsFederationHttpBinding> </bindings> <client> <endpoint address="http://localhost:8700/CoreService/" binding="wsFederationHttpBinding" bindingConfiguration="WSFederationHttpBinding_ICoreService" contract="CoreServiceNamespace.ICoreService" name="WSFederationHttpBinding_ICoreService"> <identity> <dns value="localhost" /> </identity> </endpoint> </client> </system.serviceModel> </configuration>
If you look line 24 you will see that is set what is address of STS server but its not set how to authenticate to this service. We will need to update that line like:
<issuer address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/username/" binding="wsHttpBinding" bindingConfiguration="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/username/"> <identity> <certificate encodedValue="AwAAAAEAAAAUAAAAu0r+Dvx..." /> </identity> </issuer>
Now we should add new bindingConfiguration:
<wsHttpBinding> <binding name="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/username/" closeTimeout="00:01:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Message"> <message clientCredentialType="UserName" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" /> </security> </binding> </wsHttpBinding>
With this binding configuration we have set how the client will be authenticated to the STS.
If we assume that certificate for Atomia Identity is
AtomiaIdentity.cer
and certificates for RP are
WCFService.cer
and
WCFService.pfx
locations for them will be:
On STS Side:
WCFService.cer => LocalComputer|TrustedPeople
On RP Side:
AtomiaIdentity.cer => LocalComputer|Trusted root certificate authorities
AtomiaIdentity.cer => LocalComputer|Trusted people
WCFService.pfx => LocalComputer|Personal
On client side
WCFService.cer => LocalComputer|Trusted root certificate authorities
In order that STS could identify the user for the web application it should be hosted on the web server and provide some login page where your application will redirect for logging in. When you log in SAML token with claims has been created by the STS and you will be redirected back to your application. To make the service to be able to create a token it must contain the page that needs to check if the user need to be redirected to the login page and to translate SAML token(in our example that page will be titled as PassiveStsEndPoint.aspx ).
Also in the web.config of the Atomia Identity (STS) we need to define relaying party application address:
<relyingPartyConfiguration> <relyingParty> ... <add storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" findValue="CN=UCP Core" rpAddress="http://localhost/MvcIdentity"/> </relyingParty> </relyingPartyConfiguration>
For the Atomia Identity (STS) we must set which Certificate Provider to use for our web application URI:
<type type="IRpCertProvider" mapTo="AtomiaRpCertificateProvider" name="http://localhost/MvcIdentity"> </type>
We should also set what claims types will need to provide Atomia Identity for our web application
In element with xpath
configuration\atomiaSTSConfig\passiveRpClaimRequests
should be added element that looks like:
<realm address="http://localhost:63340/"> <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"/> <add claimType="http://schemas.atomia.com/atomia/2009/04/identity/claims/groups"/> </realm>
In order to reference and use the Atomia Identity (STS), one should have Microsoft Geneva Framework installed and referenced as a dll (Microsoft.IdentityModel.dll). You can download and install from this url - download Geneva Framework .
In order to use Atomia Identity (STS) there are also some config sections should be implemented in web.config file.
<configSections> ... <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> .. </configSections> ... <microsoft.identityModel> <service> <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedIssuers> <add name="CN=UCP Authorization Service" thumbprint="bb4afe0efc6ab35a1006355c231e5b3a5d829625"/> </trustedIssuers> </issuerNameRegistry> <audienceUris> <add value="http://localhost/MvcIdentity"/> </audienceUris> <securityTokenHandlers> <add type="Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> </add> </securityTokenHandlers> <federatedAuthentication> <wsFederation requireHttps="false" passiveRedirectEnabled="true" issuer="http://localhost:50680/AtomiaIdentityStS/PassiveStsEndpoint.aspx" realm="http://localhost/MvcIdentity" ></wsFederation> <cookieHandler requireSsl="false"/> </federatedAuthentication> <serviceCertificate> <certificateReference x509FindType="FindBySubjectName" findValue="UCP Core" storeLocation="LocalMachine" storeName="My"/> </serviceCertificate> </service> </microsoft.identityModel> ... <system.web> ... <authentication mode="None"/> ... <httpModules> ... <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> ... </httpModules> </system.web> ... <system.webServer> <modules> <add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" preCondition="managedHandler"/> ...
First section is the microsoft.identityModel
in the configSections copy the section tag that adds the microsoft.identityModel configuration.
take the whole section microsoft.identityModel and copy to the web.config.
in trustedIssuers section you add the issuer you trust (name of the STS service and the thumbprint of its certificate).
in audienceUris set your url identification.
federatedAuthentication/wsFederation attribute issuer set the url of the STS' page that accepts authentication request and translates the SAML token into set of claims (in above - STS configuration section - we used to call that page PassiveStsEndPoint.aspx ).
system.web section
For the authentication tag set the attribute mode to None since we are using external STS authentication service.
The next step inserts 2 new HttpModules in the pipeline.
In the system.webServer/modules need to add same two modules as in the previous httpModules section.
Set the attribute enabled to false in the <roleManager> tag.
When all above is set the web application is ready to use the STS as an authentication provider. No other membership providers or authentication section need to be defined in the configuration file.
The usage of the application after this configuration is quite easy.
Define pages those need the authorization (using web.config or using ClassAttributes [UCP:Authorize] before methods definitions in the MVC controllers classes).
In ASP.NET web forms for the current directory in web.config you need to set
<authorization> <deny users="?" /> </authorization>
In ASP.NET MVC, above the method definition in the controller class that do some action you need to put the attribute class [UCP:Authorize]
[Authorize] public ActionResult Management() { return View(); }
In both cases above when the user tries to access pages those require to be authorized he will be redirected to the STS Login page.
When the web application is being authenticated we are able to read claims provided by the STS.
IClaimsIdentity contains property Claims represents the ClaimsCollection.
Every claim in collection is of type Claim which contains basic claim property as ClaimType and Value.
Therefore Relaying Party (RP) service by the given set of claims could authorize the user for some actions.
IClaimsIdentity claimsIdentity = Thread.CurrentPrincipal.Identity as IClaimsIdentity; foreach (Claim claim in claimsIdentity.Claims) { Console.WriteLine(claim.ClaimType); Console.WriteLine(claim.Value); }
or if it is asp.net web form page
IClaimsIdentity ci = User.Identity as IClaimsIdentity; foreach (var claim in ci.Claims) { Response.Write(string.Format("<div>Clam type: {0}; Claim value: {1}; Claim issuer: {2}</div>", claim.ClaimType, claim.Value, claim.Issuer)); }
The STS should be aware of the web application's certificate via which the web application will authenticate to the STS.
Add the information about your web application's certificate to the
web.config
of the STS within the
microsoft.identityModel
section:
<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedIssuers> <add name="CN=Your Web Application Certificate Name" thumbprint="14f8d3701f0121e20a934baf140d712b4d83550d"/> </trustedIssuers> </issuerNameRegistry>
The same element should be added in element with xpath
configuration\microsoft.identityModel\service\securityTokenHandlers\securityTokenHandlerConfiguration\issuerNameRegistry\trustedIssuers
Change the following properties in the above example:
XML Section |
Property |
Description |
Example |
issuerNameRegistry -> trustedIssuer |
|
CN value of your web application's certificate |
CN=Your Web Application Certificate Name |
issuerNameRegistry -> trustedIssuer |
|
Thumbprint of your web application's certificate |
14f8d3701f0121e20a934baf140d712b4d83550d |
To view details of your web application's certificate use Microsoft Management Console application ( mmc ).
There's one additional setting that needs to be added to the
web.config
within the
relyingParty
section :
<add storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" findValue="CN=Your Web Application Certificate Name" rpAddress="Your Web Application's address"/>
For the Atomia Identity (STS) we must set which Certificate Provider to use for our web application URI:
<type type="IRpCertProvider" mapTo="AtomiaRpCertificateProvider" name="http://localhost/MvcIdentity"> </type>
Change the following properties in the above example:
XML Section |
Property |
Description |
Example |
relyingParty -> add |
|
CN value of your web application's certificate |
CN=Your Web Application Certificate Name |
relyingParty -> add |
|
The address of your web application |
Add the reference to Microsoft.Identity.dll in the WCF application.
Add the microsoft.Identity config section in the WCF application's web.config file:
<configSections> .... <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> .... </configSections>
Add a new section in the WCF application's web.config file within the
configuration
section:
<microsoft.identityModel> <service> <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <trustedIssuers> <add name="CN=UCP Authorization Service" thumbprint="72071a7a2b933bd5b73bbb4b026c575ccb2d2ca4"/> </trustedIssuers> </issuerNameRegistry> <securityTokenHandlers> <remove type="Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> <add type="Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"> <samlSecurityTokenRequirement audienceUriMode="Never"> <nameClaimType value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"/> <roleClaimType value="http://schemas.troxo.com/ucp/2009/04/ucpcore/claims/groups"/> </samlSecurityTokenRequirement> </add> </securityTokenHandlers> </service> </microsoft.identityModel>
Change the following properties in the above example:
XML Section |
Property |
Description |
Example |
issuerNameRegistry -> trustedIssuer |
|
CN value of the trusted application that issued the token |
CN=UCP Authorization Service |
issuerNameRegistry -> trustedIssuer |
|
Thumbprint of the certificate from the trusted application that issued the token |
72071a7a2b933bd5b73bbb4b026c575ccb2d2ca4 |
securityTokenHandlers |
|
The class(with assembly info) that is handling the STS token |
Microsoft.IdentityModel.Tokens.Saml11.Saml11SecurityTokenHandler, Microsoft.IdentityModel, Version=0.6.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 |
securityTokenHandlers-> samlSecurityTokenRequirement |
|
List of claims that are contained in the token |
<nameClaimType value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"/> <roleClaimTypes> <add value="http://schemas.troxo.com/ucp/2009/04/ucpcore/claims/groups"/> </roleClaimTypes> |
Add a section in the WCF application's web.config file within the
<system.serviceModel>
section:
<services> <service behaviorConfiguration="UCPAuthPrototype.TestService.CoreServiceBehavior" name="UCPAuthPrototype.TestService.CoreService"> <endpoint address="" binding="wsFederationHttpBinding" contract="UCPAuthPrototype.TestService.ICoreService" bindingConfiguration="STSBindingConfiguration"> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:8700/CoreService/" /> </baseAddresses> </host> </service> </services> <bindings> <wsFederationHttpBinding> <binding name="STSBindingConfiguration" > <security mode="Message"> <message issuedKeyType="SymmetricKey" issuedTokenType=""> <claimTypeRequirements> <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="false"/> <add claimType="http://schemas.microsoft.com/ws/2006/04/identity/claims/role" isOptional="true"/> </claimTypeRequirements> <issuer address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/cert/" /> <issuerMetadata address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/mex" /> </message> </security> </binding> </wsFederationHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="UCPAuthPrototype.TestService.CoreServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> <serviceAuthorization principalPermissionMode="None"/> <serviceCredentials> <issuedTokenAuthentication allowUntrustedRsaIssuers="false" certificateValidationMode="PeerTrust" audienceUriMode="Never" revocationMode="Online" trustedStoreLocation="LocalMachine"> <knownCertificates> <add findValue="UCP Authorization Service" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/> </knownCertificates> </issuedTokenAuthentication> <serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="UCP Core"/> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors>
Let's explain the
service
,
bindings
and
behaviors
sections separately - let's start from the
bindings
section:
<bindings> <wsFederationHttpBinding> <binding name="STSBindingConfiguration" > <security mode="Message"> <message issuedKeyType="SymmetricKey" issuedTokenType=""> <claimTypeRequirements> <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="false"/> <add claimType="http://schemas.microsoft.com/ws/2006/04/identity/claims/role" isOptional="true"/> </claimTypeRequirements> <issuer address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/cert/" /> <issuerMetadata address="http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/mex" /> </message> </security> </binding> </wsFederationHttpBinding> </bindings>
The binding defines the way of communication between the WCF service and the Web application that wants to use the WCF service. This element holds a collection of standard and custom bindings which are is identified by their name. So, the communication will be done through wsFederationHttpBinding - a binding that supports WS-Federation.
These are the settings that can be changed in the above section:
XML Section |
Property |
Description |
Example |
wsFederationHttpBinding -> binding |
|
Binding identifier |
STSBindingConfiguration |
message |
{{claimTypeRequirements }} |
The list of claims the web application needs to provide in order to use the WCF service |
<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="false"/> <add claimType="http://schemas.microsoft.com/ws/2006/04/identity/claims/role" isOptional="true"/> |
message -> issuer |
|
The address of the STS where the web application should obtain the claims from |
http://localhost:50680/AtomiaIdentityStS/AtomiaSts.svc/cert/ |
message -> issuerMetadata |
|
The address of the STS's metadata |
The
behavior
section defines behavior elements consumed by services. Each behavior element is identified by its unique name attribute.
<behaviors> <serviceBehaviors> <behavior name="UCPAuthPrototype.TestService.CoreServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> <serviceAuthorization principalPermissionMode="None"/> <serviceCredentials> <issuedTokenAuthentication allowUntrustedRsaIssuers="false" certificateValidationMode="PeerTrust" audienceUriMode="Never" revocationMode="Online" trustedStoreLocation="LocalMachine"> <knownCertificates> <add findValue="UCP Authorization Service" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/> </knownCertificates> </issuedTokenAuthentication> <serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" findValue="UCP Core"/> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors>
We can customize these settings:
XML Section |
Property |
Description |
Example |
serviceBehaviors -> behavior |
|
Behavior identifier |
UCPAuthPrototype.TestService.CoreServiceBehavior |
issuedTokenAuthentication -> knownCertificates |
|
A string in the X.509 certificate store that contains the certificate used by the STS for signing and encrypting the tokens issued to web application (so the WCF service can authenticate the web application) |
UCP Authorization Service |
serviceCertificate |
|
A string in the X.509 certificate store that contains the certificate used for signing and encrypting messages from a web application to the WCF service |
UCP Core |
Finally, the
service
section contains the settings for a Windows Communication Foundation (WCF) service. It also contains endpoints that expose the service.
<service behaviorConfiguration="UCPAuthPrototype.TestService.CoreServiceBehavior" name="UCPAuthPrototype.TestService.CoreService"> <endpoint address="" binding="wsFederationHttpBinding" contract="UCPAuthPrototype.TestService.ICoreService" bindingConfiguration="STSBindingConfiguration"> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:8700/CoreService/" /> </baseAddresses> </host> </service>
These settings need to be customized so the service will use the binding ad behavior defined above:
XML Section |
Property |
Description |
Example |
service |
|
Specifies the type of the service to be instantiated. The format should be Namespace.Class. |
UCPAuthPrototype.TestService.CoreService |
service |
|
A string that contains the behavior name of the behavior to be used to instantiate the service |
UCPAuthPrototype.TestService.CoreServiceBehavior |
host |
|
A string that specifies a base address used by the service host. |
|
endpoint |
|
Specifies the type of binding to use. |
wsFederationHttpBinding |
endpoint |
|
A string that specifies the binding name of the binding to use when the endpoint is instantiated |
STSBindingConfiguration |
This part is for developers of web applications who want to use WCF services with Atomia Identity authorization. It will show you how a web application can issue calls to WCF service with the privileges of the user who authenticated to that web application. This mechanism is called Identity Delegation . In the Identity Delegation mechanism, web application is able to use WCF by providing the appropriate SAML token to the WCF service.
This token should contain:
identity claims and
delegation information
Add a service reference to the Web application
After adding a service reference to the web application, the
web.config
file is automatically updated - we have a new section within
configuration
:
<system.serviceModel> <bindings> <wsFederationHttpBinding> <binding name="WSFederationHttpBinding_IUcpCoreService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Message"> <message algorithmSuite="Default" issuedKeyType="SymmetricKey" negotiateServiceCredential="true"> <claimTypeRequirements> <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="false" /> <add claimType="http://schemas.microsoft.com/ws/2006/04/identity/claims/role" isOptional="true" /> </claimTypeRequirements> <issuer address="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/username/" /> <issuerMetadata address="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/mex" /> </message> </security> </binding> </wsFederationHttpBinding> </bindings> <client> <endpoint address="http://t098/UCP/UcpCoreService.svc" binding="wsFederationHttpBinding" bindingConfiguration="WSFederationHttpBinding_IUcpCoreService" contract="UcpCoreService.IUcpCoreService" name="WSFederationHttpBinding_IUcpCoreService"> <identity> <certificate encodedValue="AwAAAAEAAAAUAAAAkI...." /> </identity> </endpoint> </client> </system.serviceModel>
We need to adjust Web Application's
web.config
file in order to use Token delegation to the WCF service. First, we need to change the
issuer
section within the
security->message
tag in our
binding
section - our web application will be authenticated on the STS via certificate instead of username/password combination. So, instead of:
<issuer address="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/username/" />
we should have this kind of section:
<issuer address="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/cert/" binding="wsHttpBinding" bindingConfiguration="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/cert/"> <identity> <certificate encodedValue="MIIByzCCATSgAwIBAgIQ2PtXByKML5dI68y5...." /> </identity> </issuer>
XML Section |
Property |
Description |
Example |
identity-> certificate |
|
The certificate (public key) web application is using to sign and encrypt messages to STS (can be found at STS's wsdl) |
MIIByzCCATSgAwIBAgIQ2PtXByKML5dI68y5.... |
Since we're specifying the way of communication between the web application and the STS via the
binding
and
bindingConfiguration
attributes, we need define this binding within the
bindings
section :
<wsHttpBinding> <binding name="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/cert/" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Message"> <message clientCredentialType="Certificate" /> </security> </binding> </wsHttpBinding>
where the part
<security mode="Message"> <message clientCredentialType="Certificate" /> </security>
defines that the web application will be authenticated at the STS via its own certificate.
The next thing we need to do is to define where web application's certificate can be found. Let's add behaviorConfiguration="ClientCertificateBehavior" attribute to the <endpoint> tag of our WCF service:
<endpoint address="http://t098/UCP/UcpCoreService.svc" behaviorConfiguration="ClientCertificateBehavior" binding="wsFederationHttpBinding" bindingConfiguration="WSFederationHttpBinding_IUcpCoreService" contract="UcpCoreService.IUcpCoreService" name="WSFederationHttpBinding_IUcpCoreService"> <identity> <certificate encodedValue="AwAAAAEAAAAUAAAAkI0urWJG...." /> </identity> </endpoint>
and a
behaviors
section above the
client
section :
<behaviors> <endpointBehaviors> <behavior name="ClientCertificateBehavior"> <clientCredentials> <clientCertificate findValue="My web application" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /> </clientCredentials> </behavior> </endpointBehaviors> </behaviors>
where the following setting needs to be adjusted
XML Section |
Property |
Description |
Example |
clientCertificate |
|
A string in the X.509 certificate store that contains the certificate used for authenticating web application at the STS |
My web application |
The last thing we need to do is to modify the
serviceCertificate
within
microsoft.identityModel
section in
web.config
file :
<serviceCertificate> <certificateReference x509FindType="FindBySubjectName" findValue="Your Application Name" storeLocation="LocalMachine" storeName="My"/> </serviceCertificate>
Change the following properties :
XML Section |
Property |
Description |
Example |
serviceCertificate-> certificateReference |
|
A string in the X.509 certificate store that contains the certificate STS for encrypting the issued tokens for the web application |
Your Application Name |
This step is just an overview what the
web.config
system.serviceModel
section should look like:
<system.serviceModel> <bindings> <wsFederationHttpBinding> <binding name="WSFederationHttpBinding_IUcpCoreService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Message"> <message algorithmSuite="Default" issuedKeyType="SymmetricKey" negotiateServiceCredential="true"> <claimTypeRequirements> <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="false" /> <add claimType="http://schemas.microsoft.com/ws/2006/04/identity/claims/role" isOptional="true" /> </claimTypeRequirements> <issuer address="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/cert/" binding="wsHttpBinding" bindingConfiguration="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/cert/"> <identity> <certificate encodedValue="MIIByzCCATSgAwIBAgIQ2PtXByKML5dI68y5ADms+DANBgkqhkiG9w0BAQUFADAkMSIwIAYDVQQDExlVQ1AgQXV0aG9yaXphdGlvbiBTZXJ2aWNlMB4XDTA5MDYwMTExMDEyOFoXDTM5MDYwMTExMDEyOFowJDEiMCAGA1UEAxMZVUNQIEF1dGhvcml6YXRpb24gU2VydmljZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAkT+edt1kwnjNE0JU0Yq4n2WHz/NK3O5a4h6V7kfG3D1iixvPEqzgbCaNw8OpM6+lLEMFoFvTRIMhSr3vM7Y9AxaoaXCY8oQ9oJgnK6XEnuh4zh234jAFokkvkiUx1t/E/J6vAgGmTdm84SrAK+0Lc7pONW8qnNnJzv18EglVkrcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQAYlziJ46RFEWtarXbZlscFAOwyu8VQaafKrNLTMDfvv9i1rVCHeQZZK9DmyWHsgtreinVXr09Sio8djaKIroPXBod6HaeRLKaJT8xlqTJncc3zUn+NCNEDGr1OXcyeuldd3ckTZRzc9Up7jIi1kQjDnfe3A51IRGYc2dX9WwWE7Q==" /> </identity> </issuer> <issuerMetadata address="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/mex" /> </message> </security> </binding> </wsFederationHttpBinding> <wsHttpBinding> <binding name="http://localhost/AtomiaIdentityStS/AtomiaSts.svc/cert/" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Message"> <message clientCredentialType="Certificate" /> </security> </binding> </wsHttpBinding> </bindings> <behaviors> <endpointBehaviors> <behavior name="ClientCertificateBehavior"> <clientCredentials> <clientCertificate findValue="Atomia Web Frame" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> <client> <endpoint address="http://t098/UCP/UcpCoreService.svc" binding="wsFederationHttpBinding" bindingConfiguration="WSFederationHttpBinding_IUcpCoreService" behaviorConfiguration="ClientCertificateBehavior" contract="UcpCoreService.IUcpCoreService" name="WSFederationHttpBinding_IUcpCoreService"> <identity> <certificate encodedValue="AwAAAAEAAAAUAAAAkI0urWJGQQsCDdWMWI4QlfxNP6kgAAAAAQAAAK0BAAAwggGpMIIBEqADAgECAhApKYqxXRgmq0D335zyfiZeMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNVBAMTCFVDUCBDb3JlMB4XDTA5MDYwMTExMDEyOVoXDTM5MDYwMTExMDEyOVowEzERMA8GA1UEAxMIVUNQIENvcmUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMqLb1jz9bB2AZpnASVmvxCB4iWxBb1IbvmPwfPDJTVuvbvAtihO34lt77z4SNa8ivxUOi1EFsj7V8DBiHGHiCc8Cgp6B2WT6fiOaKUXHKWHbEqVNfi6fKYidfjXtK6axIZH3sw1rceGYIHCHNO3n/Iq7Av7vNVU9GSAMhZ2qQqVAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAMJFJWpNirhnHhzws7O80V3dvV0XHWuhJIeGg8Ds35MUNO4y4K2aE/l9QtzH8De3+TECarAOabaD3iz8K+aBqgem1VfkIB+bWgckRYkdwimCpGuxKqSDO9xEOcSaQitUphmj63as/ddi7ccUTlHAGwtLMRJcD4iHiA144w3sD+Ms=" /> </identity> </endpoint> </client> </system.serviceModel>
There are few things need to be done in the code in order to use the Identity delegation.
Open the Global.asax.cs of your web application
public static readonly string CachedChannelFactory = "WFE_CachedChannelFactory"; void SessionAuthenticationModule_ConfigurationLoaded(object sender, EventArgs e) { ChannelFactory<UCPAuthPrototype.WebMvcApplication.CoreService.ICoreService> service2CF = new ChannelFactory<UCPAuthPrototype.WebMvcApplication.CoreService.ICoreService>("WSFederationHttpBinding_ICoreService"); FederatedClientCredentials.ConfigureChannelFactory<UCPAuthPrototype.WebMvcApplication.CoreService.ICoreService>(service2CF); Application[CachedChannelFactory] = service2CF; }
copy the code above
here we initialize the ChannelFactory instance for the service we will use UCPAuthPrototype.WebMvcApplication.CoreService.ICoreService - here you provide the proxy class of your service.
put that instance in the global Application dictionary.
Before the you call of the method of some service you need to initialize it first:
// Get the caller's token from custom state SessionSecurityToken sessionToken = null; if (System.Web.HttpContext.Current.Items.Contains(typeof(SessionSecurityToken).AssemblyQualifiedName)) { sessionToken = System.Web.HttpContext.Current.Items[typeof(SessionSecurityToken).AssemblyQualifiedName] as SessionSecurityToken; } SecurityToken callerToken = null; // We expect only one token to be specified during Bootstrap. if ((sessionToken != null) && (sessionToken.BootstrapTokens.Count == 1)) { callerToken = sessionToken.BootstrapTokens[0]; } if (callerToken == null) { // We lost the session state but the user still has the federated ticket // Let's sign the user off and start again FederatedAuthentication.SignOut(); return LogOff(); } // Get the channel factory to the backend service from the application state ChannelFactory<ICoreService> factory = (ChannelFactory<ICoreService>)System.Web.HttpContext.Current.Application[MvcApplication.CachedChannelFactory]; // Create and setup channel to talk to the backend service ICoreService channel; lock (factory) { // Setup the ActAs to point to the caller's token so that we perform a delegated call to the backend service // on behalf of the original caller. channel = factory.CreateChannelActingAs<ICoreService>(callerToken); //factory.Credentials.IssuedToken = callerToken; //channel = factory.CreateChannel(); }
first need to get callerToken (it represents the SAML token of the currently authenticated user)
then in the line: take the factory instance - initialized in the previous code section in the Global.asax.cs
use the factory instance to create the Channel for your service
channel = factory.CreateChannelActingAs<ICoreService>(callerToken);
Change ICoreService to the interface of your service
you can call your service method
var UcpAccounts = channel.ListAccounts();
Web.config file of Atomia Identity update with:
On element with xpath
configuration\microsoft.identityModel\service\issuerNameRegistry\trustedIssuers
add line like:
<add name="CN=MyWebApplication" thumbprint="1C18704DF16069DCDD90CE6C6D2FFDE3002E2929" />
On element with xpath
configuration\microsoft.identityModel\service\securityTokenHandlers\securityTokenHandlerConfiguration\issuerNameRegistry\trustedIssuers
add line like:
<add name="CN=MyWebApplication" thumbprint="1C18704DF16069DCDD90CE6C6D2FFDE3002E2929" />