Scenario for STS with symmetric signing key for a Relying party - wif

Please help me to understand the following scenario:
The web application is requesting a Token from STS. The STS is Thinktecture Identity server v2. STS is configured with following:
General Configuration
Only One Relying party
Both webapplication and STS have trust relationship established by installing required certificates .
The Web application uses WS-Trust protocol to request a token using following code:
WSTrustChannelFactory factory = new WSTrustChannelFactory(new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
string.Format(WS_TRUST_END_POINT, identityServer));
string relyingParty = "urn:test:symmetric";
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = username;
factory.Credentials.UserName.Password = password;
RequestSecurityToken rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
TokenType = TokenTypes.JsonWebToken,
AppliesTo = new EndpointReference(relyingParty),
};
GenericXmlSecurityToken xmlToken = factory.CreateChannel().Issue(rst) as GenericXmlSecurityToken;
handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
SecurityTokenHandlerCollection jwtToken = handlers.ReadToken(new XmlTextReader(new StringReader(xmlToken.TokenXml.OuterXml))) as JwtSecurityToken;
var Identity = handlers.ValidateToken(jwtToken);
The application web.config looks like following:
<system.identityModel>
<identityConfiguration saveBootstrapContext="true">
<audienceUris>
<add value="urn:test:symmetric"/>
</audienceUris>
<securityTokenHandlers>
<add type="System.IdentityModel.Tokens.JwtSecurityTokenHandler, System.IdentityModel.Tokens.Jwt, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089">
<sessionTokenRequirement lifetime="00:30:00"/>
</add>
<securityTokenHandlerConfiguration>
<issuerTokenResolver type="System.IdentityModel.Tokens.NamedKeyIssuerTokenResolver, System.IdentityModel.Tokens.JWT">
<securityKey symmetricKey="JDQLsrFL1VGBj5GZcAo0Xick4stoHyV5ah0B8RDBUoM=" name="TH_STS"/>
</issuerTokenResolver>
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<!-- STS Authority Nodes
-->
<authority name="TH_STS">
<keys>
<add symmetricKey="JDQLsrFL1VGBj5GZcAo0Xick4stoHyV5ah0B8RDBUoM="/>
</keys>
<validIssuers>
<add name="TH_STS"/>
</validIssuers>
</authority>
</issuerNameRegistry>
</securityTokenHandlerConfiguration>
</securityTokenHandlers>
</identityConfiguration>
</system.identityModel>
I read WIF concepts but I am still struggling to understand the flow. Am I correct to understand following:
The token requests works on https.
Trust is established between token requestor (web appplication ) and STS by installing proper certificate.
The web application requests a token over WS-Trust protocol by including details of username/password, relying party , keytype= bearer and tokentype = JSonwebtoken.
STS validates the user credentials and creates and sends a JWT token. The token is signed using a symmetric key configured in STS for the mentioned relying party. The claims are not encrypted.
On receiving the token, web application validates the token by verifying it is coming from the same STS and decrypts the token using the same symmetric key.
Does the above understanding seems correct? Am i missing anything here or anything wrong here?
Also the question is how the symmetric keys are generated ?

Related

Session cookie Unable to read the MachineKeySessionSecurityTokenHandler SessionSecurityToken in ASP.NET MVC APP

In my project setup, i don't have an Identity Provider, instead, I use one of the cookie value set by our internal system for authentication and transform that values as Claims Identity.
Once the Claims Identity created, I am planning to write the identity to Session Cookie of the application, using the SessionAuthenticationModule, and MachineKeySessionSecurityTokenHandler as below.
SessionSecurityToken token = new SessionSecurityToken(principal);
var handler = new MachineKeySessionSecurityTokenHandler(new TimeSpan(3, 30, 30));
var securityToken = handler.WriteToken(token);
SessionAuthenticationModule sam = new SessionAuthenticationModule();
sam.CookieHandler.RequireSsl = false; // This is required only for localhost to work
sam.CookieHandler.Write(securityToken, "Token", DateTime.Today.AddDays(1));
However, when reading back the cookie setup, I am unable to parse that back to SessionSecurityToken or Claims Identity. Any help to read this cookie and transform that to claims would be of great help.
I used the following code snippet to reading the cookie back, but I am getting error at handler.ReadToken method saying "
ID4008: 'SecurityTokenHandler' does not provide an implementation for 'ReadToken'." error message.
//Check if the CGX session cookie is available
SessionAuthenticationModule sam = new SessionAuthenticationModule();
sam.CookieHandler.Name = "Token";
sam.CookieHandler.RequireSsl = false;
var securityToken = sam.CookieHandler.Read(filterContext?.HttpContext.ApplicationInstance.Context);
if (securityToken != null)
{
var handler = new MachineKeySessionSecurityTokenHandler(new TimeSpan(3, 30, 30));
var tokenString = Convert.ToBase64String(securityToken);
var token = handler.ReadToken(tokenString) as SessionSecurityToken;
if (token != null) sam.AuthenticateSessionSecurityToken(token, true);
}
What would be the right approach to read and validate the cookie value which was set from the application. As I stated the MVC Application is responsible for creating the cookie and validating it on subsequent requests.
Finally, I've found a solution to get the claims identity working for my scenario.
This is to configure WIF 4.5 for mix of your custom or forms authentication, without having to setup Identity Providers (STS), your ASP.NET MVC application RP will setup the authentication and utilize it on subsequent requests on WebFarm Scenario.
Would like to add the answer so anyone in similar need can utilize this. Before I go to the code part, I will add the configurations that are critical in achieving the results as expected.
Add the following configs in the web.config.
This is to setup the identity related configurations for use,
<configSections>
<!--WIF 4.5 sections -->
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</configSections>
Below one's are for defining the Security Token Handler and Cookie Handler,
<system.identityModel>
<identityConfiguration>
<securityTokenHandlers>
<remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</securityTokenHandlers>
</identityConfiguration>
</system.identityModel>
<system.identityModel.services>
<federationConfiguration>
<cookieHandler name ="YourTokenName" mode="Default" requireSsl ="false">
<chunkedCookieHandler chunkSize="3000"/>
</cookieHandler>
</federationConfiguration>
</system.identityModel.services>
Add the following configs for setting up machine key as I am using the MachineKeySessionSecurityTokenHandler for WebFarm Scenario, and include the SessionAuthenticationModule in system.web section to make it work on localhost IIS Express VS2015 as of writing this answer.
<system.web>
<machineKey decryptionKey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" validationKey="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" />
<httpModules>
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</httpModules>
</system.web>
The following configs are for IIS 7.0 or above for Web Farm servers,
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</modules>
</system.webServer>
Once the configs are setup, now it's simple to access setup the Claims Identity, Claims Principal, Authentication, Security Token and Cookie. As follows,
If you use anti-forgery token for CORS in your web application you need to define the UniqueClaimTypeIdentifier set tell Anti-forgery token generator to use the unique identifier part of machine key encryption, otherwise anti-forgery wont work with Claims Identity.
In Global.asax
// Set Unique identifier for Antiforgery Token Generator
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
Place the below snippet in Login method or any code path where you kick start authentication,
// Step 1: Setup Identity
var appClaims = new List<Claim>{
new Claim(ClaimTypes.Name, "Your name claim"),
new Claim("UserId", "User ID claim"),
new Claim(ClaimTypes.NameIdentifier, "Name Identifier Claim Must"),
}
ClaimsIdentity identity = new ClaimsIdentity(appClaims,"Name Of Identity");
// Step 2: Setup Principal
ClaimsPrincipal principal = new ClaimsPrincipal(claimsIdentity);
//Step 3: The below code path sets the claims principal, using SessionAuthenticationModule, authenticates the principal and sets to httpcontext and current thread, sets the cookie in browser.
var authedCp = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager.Authenticate("Name", principal);
var token = FederatedAuthentication.SessionAuthenticationModule.CreateSessionSecurityToken(authedCp, "Issuer Name", DateTime.UtcNow, DateTime.UtcNow.AddHours(1), false);
// This is only for debug mode in localhost, to make cookie written for local http or for https set it true
FederatedAuthentication.SessionAuthenticationModule.CookieHandler.RequireSsl = false;
FederatedAuthentication.SessionAuthenticationModule.AuthenticateSessionSecurityToken(token, true);
Place this snippet, where you need to validate if the cookie contains the Claims details and authenticate again on subsequent requests (action filter maybe),
//Check if the session cookie is available
SessionAuthenticationModule sam = FederatedAuthentication.SessionAuthenticationModule;
sam.CookieHandler.Name = "Token Name";
sam.CookieHandler.RequireSsl = false; //for local host, https make it true
var securityToken = sam.CookieHandler.Read(filterContext?.HttpContext.ApplicationInstance.Context);
if (securityToken != null)
{
SessionSecurityToken sessionToken = null;
var readStatus = sam.TryReadSessionTokenFromCookie(out sessionToken);
if (sessionToken != null)
{
sam.AuthenticateSessionSecurityToken(sessionToken, true);
}
}
Now you have the Claims Principal and Claims Identity setup on your HttpContext and Thread from the cookie stored on subsequent requests. You can access it anytime within the request pipeline, watch out for the cookie size when you add more claims into the Identity.
I would like to thank Sander for his blog post https://itq.nl/mixing-forms-authentication-with-claims-based-authorisation-in-asp-net/ that helped me setup later pieces of accessing the tokens..

ID4175: The issuer of the security token was not recognized by the IssuerNameRegistry

I am trying to implement a Simple STS web site alongside my MVC application in a development environment. I was able to get this working properly on my local machine. I would navigate to my MVC app, kicked out to the STS web application, I login, then am redirected back to my MVC app. This is not using AFDS by the way.
When I migrated this to my Development environment, I see similar activity but I get the error below when I login. I have checked about 20 times that my thumbprint in the MVC app is the exact same as the cert.
(The login is working fine as I don't get redirected until the authentication succeeds.)
Any guesses?
Error message I recieve:
ID4175: The issuer of the security token was not recognized by the IssuerNameRegistry. To accept security tokens from this issuer, configure the IssuerNameRegistry to return a valid name for this issuer
web.config from STS website:
<appSettings>
<add key="IssuerName" value="STSTestCert"/>
<add key="SigningCertificateName" value="CN=STSTestCert"/>
<add key="EncryptingCertificateName" value=""/>
</appSettings>
web.config from MVC application:
<microsoft.identityModel>
<service>
<audienceUris>
<add value="http://localhost/" />
</audienceUris>
<federatedAuthentication>
<wsFederation passiveRedirectEnabled="true" issuer="http://localhost:57543/mySTS/" realm="http://localhost/" requireHttps="false" />
<cookieHandler requireSsl="false" />
</federatedAuthentication>
<applicationService>
<claimTypeRequired>
<!--Following are the claims offered by STS 'http://localhost:57543/mySTS/'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.-->
<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
</claimTypeRequired>
</applicationService>
<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<trustedIssuers>
<add thumbprint="‎11111" name="http://localhost:57543/mySTS/" />
</trustedIssuers>
</issuerNameRegistry>
</service>
</microsoft.identityModel>
Copying your thumbprint adds hidden unicode characters. Try typing it in.
As MJCoffman mentioned it is most probably because you copied the thumbprint with hidden character. You can find more details here.
In my case the problem was also that copying the thumbprint and pasting it was adding some characters that a regular text editor do not show. I found the following instructions very useful to remove the special characters (look #4). posted by Edwin Guru Singh
Do this to get rid of the special characters using Visual Studio:
Close the web.config
Right-click on it and open it with binary editor
Find where the thumbprint is and delete additional characters (everything that is not a number, usually dots).
Save and try again, it should work.

The password supplied is invalid. Passwords must conform to the password strength requirements configured for the default provider

How to prevent that error?
The password supplied is invalid. Passwords must conform to the
password strength requirements configured for the default provider.
I do migration users from the old ASP website to a new ASP .NET MVC 4 Website.
var newUser = System.Web.Security.Membership.CreateUser(oldUser.Login, oldUser.Password, userEMail);
web.config
<membership defaultProvider="DefaultMembershipProvider">
<providers>
<add connectionStringName="MembershipConnection" enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="3"
passwordStrengthRegularExpression=""
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
applicationName="MyCoolApplication"
name="DefaultMembershipProvider"
type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</providers>
</membership>
And it seems I need correct solution for some users who have incorrect password.
How I can manage it in a proper way?
Thanks!
Based on the assumption that you are using the same .NET MVC version. Why not skip C#, use the SQL knowledge we got from school?
Insert into [newDB].[table] (columns)
select [oldDB].[table].[columns]
from [newDB].[table]
If you upgraded MVC version, the password hash might not be compatible.
Lastly, you should be able to work around it by altering the password requirements in web.config

Using Microsoft Jwt handler with symmetric signing key using Oauth 2 resource owner flow

I'm trying to use an OAuth 2 Resource Owner Flow to authorize a mobile client against my Web Api services. I'm using Thinktecture IdentityServer to issue the jwt token with a symmetric signing key.
On the client side I'm using Thinktecture IdentityModel to help setup the token validation. My WebApiConfig looks like this:
var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
var mapping = new AuthenticationOptionMapping
{
// where to look for credentials
Options = AuthenticationOptions.ForAuthorizationHeader("bearer"),
// how to validate them
TokenHandler = new SecurityTokenHandlerCollection { jwtSecurityTokenHandler },
// which hint to give back if not successful
Scheme = AuthenticationScheme.SchemeOnly("bearer")
};
var authConfig = new AuthenticationConfiguration(){RequireSsl = false};
authConfig.AddMapping(mapping);
config.MessageHandlers.Add(new AuthenticationHandler(authConfig));
In my IdentityModel.config I have the following:
<system.identityModel>
<identityConfiguration>
<claimsAuthorizationManager type="PresentationHost.Claims.MobileClaimsAuthorizationManager, PresentationHost"/>
<audienceUris>
<add value="http://localhost:22674/" />
</audienceUris>
<securityTokenHandlers>
<add type="System.IdentityModel.Tokens.JwtSecurityTokenHandler, System.IdentityModel.Tokens.Jwt" />
</securityTokenHandlers>
<issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
<authority name="http://identityserver.v2.thinktecture.com/trust/auth">
<keys>
<add symmetricKey="tVNRmpweBgz3xeWvSXrSwLIE3DrxJ3aawgNxZKC1Od0"/>
</keys>
<validIssuers>
<add name="http://identityserver.v2.thinktecture.com/trust/auth" />
</validIssuers>
</authority>
</issuerNameRegistry>
<issuerTokenResolver type="System.IdentityModel.Tokens.NamedKeyIssuerTokenResolver, System.IdentityModel.Tokens.Jwt"/>
<securityKey symmetricKey="tVNRmpweBgz3xeWvSXrSwLIE3DrxJ3aawgNxZKC1Od0" name="http://identityserver.v2.thinktecture.com/trust/auth" />
<!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
<certificateValidation certificateValidationMode="None" />
Taken mostly from this link on http://leastprivilege.com/2013/07/16/identityserver-using-ws-federation-with-jwt-tokens-and-symmetric-signatures/ which I found via this Stack Overflow post: How to configure MIcrosoft JWT with symmetric key?
I attempted to use the derived class as found in that post, but when I attempted to run this line:
var resolver = (NamedKeyIssuerTokenResolver)this.Configuration.IssuerTokenResolver;
I get an InvalidCastException because the IssuerTokenResolver is of type X509CertificateStoreResolver and not of type NamedKeyIssuerTokenResolver.
It appears I'm still missing something from my configuration or code to get the correct TokenResolver configured. Does anyone have any thoughts?

Run WIF without LoadUserProfile = True is throwing null error

I am using WIF SSO for authentication in my website. Everything works perfect in development environment. But on deployment I got issue
Message: The data protection operation was unsuccessful. This may have
been caused by not having the user profile loaded for the current
thread's user context, which may be the case when the thread is
impersonating. ExceptionStackTrace: at
System.Security.Cryptography.ProtectedData.Protect(Byte[] userData,
Byte[] optionalEntropy, DataProtectionScope scope) at
Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Encode(Byte[]
value)
Searching abt this issue leads me to this stackoverflow question
Is it possible to run WIF without LoadUserProfile = True
I added the code mentioned but now I am getting
Value cannot be null
I am getting e.ServiceConfiguration.ServiceCertificate ServiceCertificate null. My question is what kind of certificate is this and where can I define this in my config. Do I need to place the same certificate on ACS.
here is my config section
<microsoft.identityModel>
<service>
<audienceUris>
<add value="http://localhost:9494/" />
</audienceUris>
<federatedAuthentication>
<wsFederation passiveRedirectEnabled="true" issuer="https://devworks-sb.accesscontrol.appfabriclabs.com/v2/wsfederation" realm="http://localhost:9494" requireHttps="false" />
<cookieHandler requireSsl="false" />
</federatedAuthentication>
<applicationService>
<claimTypeRequired>
<!--Following are the claims offered by STS 'https://devworks-sb.accesscontrol.appfabriclabs.com/'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.-->
<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
<!--<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" optional="true" />-->
<!--<claimType type="http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider" optional="true" />-->
</claimTypeRequired>
</applicationService>
<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<trustedIssuers>
<add thumbprint="BE9D0A516BEC2BC820C23D5C2EA79F068C094382" name="https://devworks-sb.accesscontrol.appfabriclabs.com/" />
</trustedIssuers>
</issuerNameRegistry>
</service> </microsoft.identityModel>
thanx
First thing you mentioned that the problem occurred after deployment, is that right? In your web.config have you changed the audienceUris to http://whatever_service_name.cloudapp.net?
<audienceUris>
<add value="http://localhost:9494/" /> <== This is wrong
</audienceUris>
Next your question about certificate is NULL at e.ServiceConfiguration.ServiceCertificate, please verify the following:
A. Endpoint is added in your application Service Definition:
B. Certificate thumbprint is set in Service Configuration
C. Certificate is set in web.config which is correct above
D. Finally added the following in your web.config so certificate can be search by thumbprint:
<serviceCertificate>
<certificateReference x509FindType="FindByThumbprint" findValue="CERT_THUMB" />
</serviceCertificate>
Study these two resources which will be very helpful:
http://www.jimandkatrin.com/CodeBlog/post/Troubleshooting-Azure-issues.aspx
http://blogs.msmvps.com/marcelmeijer/blog/2012/05/04/windows-azure-wif-access-control-acs/
The root cause is likely to be you’re using DPAPI (the default configuration of WIF). Please try to do a few modifications for the application to work in Windows Azure. I would like to suggest you to check http://msdn.microsoft.com/en-us/IdentityTrainingCourse_WIFonWAZLab2010 for a tutorial.
Best Regards,
Ming Xu.

Resources