SessionAuthenticationModule "validFrom" appears invalid with ThinkTecture - session-cookies

I have an ASP.NET website with two IDP servers running ThinkTecture software authenticating the users using WS-FED.
When I login with IDP server #1, I can login fine, the IDP issues the token to my website and I get a session token as expected and I can access the website perfectly fine.
When I login with into the IDP server #2, I can login fine and the IDP redirects me back to my website, presumably with a SAML token which it tries to convert into a Session token. Unfortunately, at this point, from my website I see this error:
Specified argument was out of the range of valid values.
Parameter name: validFrom
and stack trace:
System.IdentityModel.Tokens.SessionSecurityToken..ctor(ClaimsPrincipal claimsPrincipal, UniqueId contextId, String id, String context, Byte[] key, String endpointId, Nullable`1 validFrom, Nullable`1 validTo, UniqueId keyGeneration, Nullable`1 keyEffectiveTime, Nullable`1 keyExpirationTime, SctAuthorizationPolicy sctAuthorizationPolicy, Uri securityContextSecurityTokenWrapperSecureConversationVersion) +1011230
System.IdentityModel.Tokens.SessionSecurityToken..ctor(ClaimsPrincipal claimsPrincipal, UniqueId contextId, String context, String endpointId, Nullable`1 validFrom, Nullable`1 validTo, SymmetricSecurityKey key) +317
System.IdentityModel.Tokens.SessionSecurityTokenHandler.CreateSessionSecurityToken(ClaimsPrincipal principal, String context, String endpointId, DateTime validFrom, DateTime validTo) +306
System.IdentityModel.Services.SessionAuthenticationModule.CreateSessionSecurityToken(ClaimsPrincipal principal, String context, DateTime validFrom, DateTime validTo, Boolean isPersistent) +313
System.IdentityModel.Services.WSFederationAuthenticationModule.SignInWithResponseMessage(HttpRequestBase request) +1079
System.IdentityModel.Services.WSFederationAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs args) +123940
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165
After a period of time (approx 10 mins) I start to see this error:
ID4148: The Saml2SecurityToken is rejected because the SAML2:Assertion's NotOnOrAfter condition is not satisfied.
NotOnOrAfter: '17/07/2014 17:01:07'
Current time: '17/07/2014 17:10:08'
I am using the sliding session code as suggested by the ThinkTecture guys:
protected void Application_Start()
{
PassiveModuleConfiguration.EnableSlidingSessionExpirations();
}
and as you refresh the page the NotOnOrAfter just remains the same for several hours.
As one IDP server works fine and the other does not, I can only assume that the configuration on the 2nd IDP server is in some way different. The token lifetime on the 2nd IDP is set to 10 hours.
All 3 servers have the same time.
I thought the SAML assertion was set by the IDP, rather than the web server (IIS)?
Any ideas?

Related

ADFS SAML Identity provider redirects to service provider with status "Responder"

I am using omniauth-saml to authenticate users on a Ruby on Rails application.
Authentication has worked well, until we stated attempting to work with companies using ADFS (Windows Active Directory).
Our Application is able to route to the ADFS log-in screen, the log-in operation takes place, and when ADFS redirects back to our application, we are presented with the error message:
The status code of the Response was not Success, was Responder
debugging, we can see that omniauth-saml is what generates this message.
digging though the payload sent to our application, the "SAMLResponse" attribute contains a xml document with the following part:
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder" /></samlp:Status>
which we believe is related to the error message presented by omniauth-saml.
ADFS is noticeable hard to debug, but we believe the following error messages is what is behind this ordeal:
Additional Data
Protocol Name:
Saml
Relying Party:
https://our-domain/users/auth/saml/metadata?attr1=123&attr2=432
Exception details:
Microsoft.IdentityModel.SecurityTokenService.InvalidScopeException: MSIS3055: The requested relying party trust 'https://our-domain/users/auth/saml/metadata' is unspecified or unsupported. If a relying party trust was specified, it is possible the user does not have permission to access the relying party trust. ---> Microsoft.IdentityServer.Service.Policy.PolicyServer.Engine.ScopeNotFoundPolicyRequestException: MSIS3020: The relying party trust with identifier 'https://our-domain/users/auth/saml/metadata' could not be located.
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Threading.AsyncResult.End(IAsyncResult result)
at Microsoft.IdentityModel.Threading.TypedAsyncResult`1.End(IAsyncResult result)
at Microsoft.IdentityServer.Web.WSTrust.SecurityTokenServiceManager.Issue(RequestSecurityToken request, IList`1& identityClaimSet, List`1 additionalClaims)
at Microsoft.IdentityServer.Web.WSTrust.SecurityTokenServiceManager.Issue(RequestSecurityToken request, List`1 additionalClaims)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolManager.Issue(HttpSamlRequestMessage httpSamlRequestMessage, SecurityTokenElement onBehalfOf, String sessionState, String relayState, String& newSamlSession, String& samlpAuthenticationProvider, Boolean isUrlTranslationNeeded, WrappedHttpListenerContext context, Boolean isKmsiRequested)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolHandler.RequestBearerToken(WrappedHttpListenerContext context, HttpSamlRequestMessage httpSamlRequest, SecurityTokenElement onBehalfOf, String relyingPartyIdentifier, Boolean isKmsiRequested, Boolean isApplicationProxyTokenRequired, String& samlpSessionState, String& samlpAuthenticationProvider)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolHandler.BuildSignInResponseCoreWithSerializedToken(HttpSamlRequestMessage httpSamlRequest, WrappedHttpListenerContext context, String relyingPartyIdentifier, SecurityTokenElement signOnTokenElement, Boolean isKmsiRequested, Boolean isApplicationProxyTokenRequired)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolHandler.BuildSignInResponseCoreWithSecurityToken(SamlSignInContext context, SecurityToken securityToken, SecurityToken deviceSecurityToken)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolHandler.Process(ProtocolContext context)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.ProcessProtocolRequest(ProtocolContext protocolContext, PassiveProtocolHandler protocolHandler)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.OnGetContext(WrappedHttpListenerContext context)
Microsoft.IdentityServer.Service.Policy.PolicyServer.Engine.ScopeNotFoundPolicyRequestException: MSIS3020: The relying party trust with identifier 'https://our-domain/users/auth/saml/metadata' could not be located.
Event Xml:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
<Provider Name="AD FS" Guid="{2ffb687a-1571-4ace-8550-47ab5ccae2bc}" />
<EventID>364</EventID>
<Version>0</Version>
<Level>2</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000001</Keywords>
<TimeCreated SystemTime="2019-10-15T23:15:19.254339300Z" />
<EventRecordID>1512764</EventRecordID>
<Correlation ActivityID="{19de3423-ee29-40a8-890d-0080000000bf}" />
<Execution ProcessID="752" ThreadID="4076" />
<Channel>AD FS/Admin</Channel>
<Computer>serve-name.domain</Computer>
<Security UserID="S-1-5-21-1708537768-1844237615-682003330-107716" />
</System>
<UserData>
<Event xmlns="http://schemas.microsoft.com/ActiveDirectoryFederationServices/2.0/Events">
<EventData>
<Data>Saml</Data>
<Data>https://our-domain/users/auth/saml/metadata?attr1=123&attr2=432</Data>
<Data>Microsoft.IdentityModel.SecurityTokenService.InvalidScopeException: MSIS3055: The requested relying party trust 'https://our-domain/users/auth/saml/metadata' is unspecified or unsupported. If a relying party trust was specified, it is possible the user does not have permission to access the relying party trust. ---> Microsoft.IdentityServer.Service.Policy.PolicyServer.Engine.ScopeNotFoundPolicyRequestException: MSIS3020: The relying party trust with identifier 'https://our-domain/users/auth/saml/metadata' could not be located.
--- End of inner exception stack trace ---
at Microsoft.IdentityModel.Threading.AsyncResult.End(IAsyncResult result)
at Microsoft.IdentityModel.Threading.TypedAsyncResult`1.End(IAsyncResult result)
at Microsoft.IdentityServer.Web.WSTrust.SecurityTokenServiceManager.Issue(RequestSecurityToken request, IList`1& identityClaimSet, List`1 additionalClaims)
at Microsoft.IdentityServer.Web.WSTrust.SecurityTokenServiceManager.Issue(RequestSecurityToken request, List`1 additionalClaims)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolManager.Issue(HttpSamlRequestMessage httpSamlRequestMessage, SecurityTokenElement onBehalfOf, String sessionState, String relayState, String& newSamlSession, String& samlpAuthenticationProvider, Boolean isUrlTranslationNeeded, WrappedHttpListenerContext context, Boolean isKmsiRequested)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolHandler.RequestBearerToken(WrappedHttpListenerContext context, HttpSamlRequestMessage httpSamlRequest, SecurityTokenElement onBehalfOf, String relyingPartyIdentifier, Boolean isKmsiRequested, Boolean isApplicationProxyTokenRequired, String& samlpSessionState, String& samlpAuthenticationProvider)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolHandler.BuildSignInResponseCoreWithSerializedToken(HttpSamlRequestMessage httpSamlRequest, WrappedHttpListenerContext context, String relyingPartyIdentifier, SecurityTokenElement signOnTokenElement, Boolean isKmsiRequested, Boolean isApplicationProxyTokenRequired)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolHandler.BuildSignInResponseCoreWithSecurityToken(SamlSignInContext context, SecurityToken securityToken, SecurityToken deviceSecurityToken)
at Microsoft.IdentityServer.Web.Protocols.Saml.SamlProtocolHandler.Process(ProtocolContext context)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.ProcessProtocolRequest(ProtocolContext protocolContext, PassiveProtocolHandler protocolHandler)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.OnGetContext(WrappedHttpListenerContext context)
Microsoft.IdentityServer.Service.Policy.PolicyServer.Engine.ScopeNotFoundPolicyRequestException: MSIS3020: The relying party trust with identifier 'https://our-domain/users/auth/saml/metadata' could not be located.
</Data>
</EventData>
</Event>
</UserData>
</Event>
My understanding of ADFS is limited, so I'm not sure if the errors were caused by ADFS misconfiguration or by something specific we would need to add to our application to make it work with ADFS...
Your help would be appreciated!
The RP with identifier "https://our-domain/users/auth/saml/metadata" does not exist in ADFS.
How did you configure the ADFS RP? Did you use metadata?
The RP should have the above identifier in the "Identifier" tab when you view it via the ADFS wizard.
As it turns out the answer was to provide an alternative url for ADFS to retrieve the SAML metadata file from our system.
It seems ADFS cannot handle having query strings into its "relying party trust" "Federation metadata file location" (this ADFS jargon is killing me ...)
anyway, once the url could be used without query strings, all worked fine.
We moved the parameters to be part of the url:
instead of
https://our-domain/users/auth/saml/metadata?attr1=123&attr2=432
we monkey-patched omniauth-saml and used a new url so we could provide the same functionality with the alternative url:
https://our-domain/users/auth/saml/:attr1/:attr2/metadata

How can I propagate an identity from an asp.net mvc application in order to access a tfs server?

I am developing an asp.net mvc application to extract some data from a TFS server.
Right now I am having problems with authentication on the TFS server. When I run the app from my local machine everything works fine, since it propagates my windows identity to the server, but when I deploy the app to my IIS8 server, since there's no user logged on, it won't work.
I would like to avoid using windows authentication on the IIS8 server, since I do not want to maintain the user control with windows groups. Instead I would like only to authenticate the user on my AD, store the identity info and propagate it to the TFS server, but I am clueless on how to do that.
Can you guys help me out? Right now my asp.net mvc app has no authentication and I get the following message:
[UnauthorizedAccessException: Access to the registry key 'HKEY_CURRENT_USER\Software\Microsoft\VSCommon\12.0\ClientServices\TokenStorage\VisualStudio' is denied.]
Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str) +4325774
Microsoft.Win32.RegistryKey.CreateSubKeyInternal(String subkey, RegistryKeyPermissionCheck permissionCheck, Object registrySecurityObj, RegistryOptions registryOptions) +10872754
Microsoft.Win32.RegistryKey.CreateSubKey(String subkey, RegistryKeyPermissionCheck permissionCheck, RegistryOptions options) +14
Microsoft.VisualStudio.Services.Common.TokenStorage.RegistryTokenStorageHelper.GetRootKey(String subkeyName) +50
Microsoft.VisualStudio.Services.Common.TokenStorage.RegistryTokenStorage.RetrieveToken(VssTokenKey tokenKey) +57
Microsoft.VisualStudio.Services.Common.TokenStorage.VssTokenStorage.Retrieve(VssTokenKey tokenKey) +15
Microsoft.TeamFoundation.Client.TfsClientCredentialStorage.RetrieveToken(Uri serverUrl, VssCredentialsType credentialType) +58
Microsoft.TeamFoundation.Client.CookieCredential.OnCreateTokenProvider(Uri serverUrl, HttpWebResponse response) +127
Microsoft.TeamFoundation.Client.IssuedTokenCredential.CreateTokenProvider(Uri serverUrl, HttpWebResponse response, IssuedToken failedToken) +45
Microsoft.TeamFoundation.Client.TfsClientCredentials.TryGetTokenProvider(Uri serverUrl, IssuedTokenProvider& provider) +95
Microsoft.TeamFoundation.Client.Channels.TfsHttpRequestHelpers.PrepareWebRequest(HttpWebRequest webRequest, Guid sessionId, String operationName, CultureInfo cultureInfo, TfsRequestSettings settings, TfsClientCredentials credentials, IdentityDescriptor impersonate, IssuedToken& currentToken, IssuedTokenProvider& tokenProvider) +136
Microsoft.TeamFoundation.Client.Channels.TfsHttpRequestHelpers.CreateSoapRequest(Uri requestUri, Guid sessionId, String soapAction, String operationName, CultureInfo cultureInfo, TfsRequestSettings settings, TfsClientCredentials credentials, IdentityDescriptor impersonate, IssuedToken& currentToken, IssuedTokenProvider& tokenProvider) +106
Microsoft.TeamFoundation.Client.Channels.TfsHttpWebRequest.CreateWebRequest() +154
Microsoft.TeamFoundation.Client.Channels.TfsHttpWebRequest.SendRequest() +599
Microsoft.TeamFoundation.Client.Channels.TfsHttpRequestChannel.Request(TfsMessage message, TimeSpan timeout) +243
Microsoft.TeamFoundation.Client.Channels.TfsHttpClientBase.Invoke(TfsClientOperation operation, Object[] parameters, TimeSpan timeout, Object[]& outputs) +91
Microsoft.TeamFoundation.Framework.Client.LocationWebService.Connect(Int32 connectOptions, Int32 lastChangeId, Int32 features) +175
Microsoft.TeamFoundation.Framework.Client.FrameworkServerDataProvider.Connect(ConnectOptions connectOptions) +92
Microsoft.TeamFoundation.Client.TfsConnection.EnsureProviderConnected() +723
Microsoft.TeamFoundation.Client.TfsConnection.EnsureAuthenticated() +25
Your first issue is that your need to make the account that the website is running under an administrator on your web server. Current permissions are not going to cut the mustered.
Additionally you are going to hit a double hop authentication issue with Kerberos ( security is a pain) and you need to configure an SPN for the account to show it to proxy Kerberos authentication tokens to the TFS server. User SetSPN to configure it, and you will likely need the help of a domain admin.

No Fedauth cookie are sent back as SAML token after reaching STS seems to miss XML tags. Happens only on Firefox

I am scratching my head over a peculiar problem that seems to work on IE and Chrome.
We have a custom passive STS which serves a RP. All is well till i authenticate via my custom authentication service and then STS returns token which i can see in my temp folder. The POST operation which then sends the SAML 1.0 token hangs and silently dies instead of getting back the FedAuth cookie which would normally redirect me the RP
Note : RP and IP are hosted on web server that is behind a reverse proxy server (Nginx). Reverse proxy is hosted over SSL and all traffic to and fro proxy server and webserver is non SSL
The following get logged on the webserver
Event code: 3005
Event message: An unhandled exception has occurred.
Event time: 12/11/2013 5:16:33 PM
Event time (UTC): 12/11/2013 5:16:33 PM
Event ID: eef80ad2bffe425780dd46e5f28c0306
Event sequence: 2
Event occurrence: 1
Event detail code: 0
Exception information:
Exception type: XmlException
Exception message: **Unexpected end of file. Following elements are not closed: RequestedUnattachedReference, RequestSecurityTokenResponse,** RequestSecurityTokenResponseCollection. Line 1, position 5852.
at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3)
at System.Xml.XmlExceptionHelper.ThrowUnexpectedEndOfFile(XmlDictionaryReader reader)
at System.Xml.XmlBufferReader.GetByteHard()
at System.Xml.XmlBufferReader.GetByte()
at System.Xml.XmlUTF8TextReader.ReadStartElement()
at System.Xml.XmlUTF8TextReader.Read()
at System.Xml.XmlBaseReader.ReadEndElement()
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.ReadRSTRXml(XmlReader reader, RequestSecurityTokenResponse rstr, WSTrustSerializationContext context, WSTrustConstantsAdapter trustConstants)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13ResponseSerializer.ReadXmlElement(XmlReader reader, RequestSecurityTokenResponse rstr, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustSerializationHelper.CreateResponse(XmlReader reader, WSTrustSerializationContext context, WSTrustResponseSerializer responseSerializer, WSTrustConstantsAdapter trustConstants)
at Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13ResponseSerializer.ReadXml(XmlReader reader, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Protocols.WSFederation.WSFederationSerializer.CreateResponse(WSFederationMessage message, WSTrustSerializationContext context)
at Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.GetXmlTokenFromMessage(SignInResponseMessage message, WSFederationSerializer federationSerializer)
at Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.GetXmlTokenFromMessage(SignInResponseMessage message)
at Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.GetXmlTokenFromMessage(SignInResponseMessage message, WSFederationSerializer federationSerializer)
at Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.GetSecurityToken(SignInResponseMessage message)
at Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.GetSecurityToken(HttpRequest request)
at Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.SignInWithResponseMessage(HttpRequest request)
at Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs args)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
I dont understand why just for FF i get this problem. Is there a limitation on the size of the content that is sent in the header for FF?
Another question is : I have installed two different certificates one at proxy server (SSL)and one at webserver(STS) to signing the token. Can i use the same certificate? Should i?
According to the top voted answer on the question Can HTTP headers be too big for a browser, Firefox does have the lowest individual header-size (or at least did back in FF3.6). The accepted answer may help you though as you've mentioned you're behind a proxy.

JWT Handler for .NET 4.5 throws error: GetIssuerName with single parameter is not supported

I've just implemented this JSON Web Token Handler for .Net 4.5 library described here:
http://www.cloudidentity.com/blog/2012/11/20/introducing-the-developer-preview-of-the-json-web-token-handler-for-the-microsoft-net-framework-4-5-2/
I have an ACS service that's supposed to be returning a JWT token to my application. However, at the point when I should be getting the token returned to my app (when the browser is redirected to my relying party's return uri), I instead get this exception:
WIF10200: GetIssuerName with single parameter is not supported. Call:
'GetIssuerName( SecurityToken securityToken, string issuer )'.
I don't think this is a problem directly with my code; because if I do a solution-wide search, "GetIssuerName" is not in my solution. I think it might have something to do with the certificate issuers WIF wants to trust, but I've followed the instructions in the article I linked above about importing the certificate from the ACS site's FederationMetadata... and I'm utterly stumped on this one.
Strangely enough, when I change my Relying Party token type from JWT to SAML 1 or 2, my relying party's Return Uri is never hit, I'm just redirected back to my realm error free. I would expect to finally land on my Return Uri. If someone could explain either phenomenon to me, it would help tremendously!
UPDATE
The GetIssuerName method in .NET 4.5 is part of the System.IdentityModel.Tokens.ValidatingIssuerNameRegistry class (there's also a System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry class with the same method, but that's not the one I'm working with).
From looking at the metadata, there are 2 overridden methods with this name in the class:
public override string GetIssuerName(SecurityToken securityToken);
public override string GetIssuerName(SecurityToken securityToken, string requestedIssuerName);
The error I'm getting from WIF seems to be coming directly from the first method listed there, as you can see from the stack trace below. With my relying party returning JWT, something somewhere is supposed to be calling the second method, whose signature has a second parameter, but is calling the first. I wish I knew how to change it.
[NotSupportedException: WIF10200: GetIssuerName with single parameter
is not supported. Call: 'GetIssuerName( SecurityToken securityToken,
string issuer )'.]
System.IdentityModel.Tokens.ValidatingIssuerNameRegistry.GetIssuerName(SecurityToken
securityToken) +156
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateIssuer(JWTSecurityToken
jwt, TokenValidationParameters validationParameters) +1303
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateToken(JWTSecurityToken
jwt, TokenValidationParameters validationParameters) +278
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateToken(SecurityToken
token) +2248
System.IdentityModel.Tokens.SecurityTokenHandlerCollection.ValidateToken(SecurityToken
token) +135
System.IdentityModel.Services.TokenReceiver.AuthenticateToken(SecurityToken
token, Boolean ensureBearerToken, String endpointUri) +502
System.IdentityModel.Services.WSFederationAuthenticationModule.SignInWithResponseMessage(HttpRequestBase
request) +1508
System.IdentityModel.Services.WSFederationAuthenticationModule.OnAuthenticateRequest(Object
sender, EventArgs args) +700
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
+80 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165

WIF: ID1014: The signature is not valid. The data may have been tampered with

We've built a Relying Party application based on the Windows Identity Foundation. We followed the advice in Vittorio's book and created a custom set of cookie transforms to use RSA to encrypt/sign the token.
private void OnServiceConfigurationCreated( object sender, ServiceConfigurationCreatedEventArgs e )
{
List<CookieTransform> sessionTransforms = new List<CookieTransform>( new CookieTransform[]
{
new DeflateCookieTransform(),
new RsaEncryptionCookieTransform( e.ServiceConfiguration.ServiceCertificate ),
new RsaSignatureCookieTransform( e.ServiceConfiguration.ServiceCertificate )
} );
SessionSecurityTokenHandler sessionHandler =
new SessionSecurityTokenHandler( sessionTransforms.AsReadOnly() );
e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace( sessionHandler );
}
We configured a in the web.config.
<microsoft.identityModel>
<service>
<serviceCertificate>
<certificateReference x509FindType="FindByThumbprint" findValue="C7FD338059CCB374798923A915BC91B718814A8E" storeLocation="LocalMachine" storeName="TrustedPeople" />
</serviceCertificate>
</service>
</microsoft.identityModel>
I know the code in the OnServiceConfigurationCreated is executing because if I put a garbage thumbprint value into the config file the OnServiceConfigurationCreated throws an exception.
Unfortunately we are frequently getting the following exception showing up in our logs.
System.Security.Cryptography.CryptographicException: ID1014: The signature is not valid. The data may have been tampered with.
at Microsoft.IdentityModel.Web.RsaSignatureCookieTransform.Decode(Byte[] encoded)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver)
at Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken)
at Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
We believe this exception is causing other problems in the system but can't figure out why it's occurring. We have three web servers and we've triple-checked that they are all configured to use the same certificate thumbprint and that the certificate is installed in the same place on all three servers.
We are also using a custom SessionAuthenticationModule to handle sliding session expiration. I thought that maybe when that code (below) was reissuing the cookie it might be using a different encryption/signing approach but I'm pretty sure I've tested it and that doesn't seem to be the case. I'm including it only in the interest of full disclosure.
void CustomSessionAuthenticationModule_SessionSecurityTokenReceived( object sender, SessionSecurityTokenReceivedEventArgs e )
{
DateTime now = DateTime.UtcNow;
DateTime validFrom = e.SessionToken.ValidFrom;
DateTime validTo = e.SessionToken.ValidTo;
double tokenLifetime = (validTo - validFrom).TotalMinutes;
SessionAuthenticationModule sam = sender as SessionAuthenticationModule;
if( now < validTo && now > validFrom.AddMinutes( tokenLifetime / 2 ) )
{
e.SessionToken = sam.CreateSessionSecurityToken(
e.SessionToken.ClaimsPrincipal, e.SessionToken.Context,
now, now.AddMinutes( tokenLifetime ), e.SessionToken.IsPersistent );
e.ReissueCookie = true;
}
}
From what we can tell we've done everything the docs/blogs/etc have said but we're still getting this exception. Any tips/pointers/educated guesses would be helpful at this point.
You might want to check the total size of cookie data your application sets. If you include lots of claims, the cookies grow accordingly unless you use session mode. E.g. Safari has a 4K limit on total cookie data size. If you break this limit you'd start losing cookies, which could mean you'd lose a cookie with part of the signature.
As a side note, if you can move to WIF 4.5 you have the option of using the MachineKeySessionSecurityTokenHandler instead of doing the certficate based cookie encryption.

Resources