By default, Geneva STS developers are quite shielded from the SAML creation process – you simply derive from SecurityTokenService and implement GetScope and GetOutputClaimsIdentity, and the rest gets done by the framework. But if you need more control over the generated tokens, it’s worthwhile to have a closer look.
Internally the SecurityTokenService class drives a “token information gathering” pipeline which results in the construction of a SecurityTokenDescriptor (a token neutral description) of the token to be issued. After that the descriptor is passed on to a SecurityTokenHandler that creates the security token. In the last step, the generated token is wrapped in an RSTR and sent back.
In the current bits, the STS pipeline looks like this:
- GetScope
Must be implemented. Determines scope specific information like signing and encrypting credentials – usually based on the AppliesTo header. - CreateSecurityDescriptor
Creates a default descriptor based on the scope from step 1. This is one option to modify the descriptor manually. - GetSecurityTokenHandler
Creates the security token handler that is later used for creating the token. The handler is determined based on the TokenType property of the RST. - GetIssuerName
Returns the issuer for the token. By default the issuer from the SecurityTokenServiceConfiguration is used. - GetTokenLifetime
Returns the life time of the token. By default the default life time from SecurityTokenServiceConfiguration is used (which is 10 hours). - GetProofToken
Creates a ProofTokenDescriptor that describes the proof token (asymmetric, symmetric or none). By default the information from the RST and the scope are used here. - GetOutputClaimsIdentity
Must be implemented. Returns the identity that describes the subject. - SecurityTokenHandler.CreateToken
The token handler creates the token and returns it to the token service (more details later) - GetDisplayToken
Returns the claims that should be client visible (e.g. for an identity selector) - GetResponse
Creates the RSTR. This is a popular hook for looking at the generated response before sending it back.
You can override any of these methods to modify the shape of the output token. This pipeline is always the same regardless of the token type. Token specific processing is done in the security token handler.
Security token handlers also have a pipeline that drives token creation. Since they are token specific, you have more control here over the output token details. For the purpose of this post, I will describe the SAML 1.1 token creation. The details differ for other token types.
- CreateStatements
Creates the SAML subject, attribute and authentication statements. This method calls out to:- CreateSamlSubject
Looks for a name identifier claim and uses this to create the SAML subject. Additionally if this claim has properties that describe the name format and qualifier these values will be added to the subject. The last step is to set the proof key identifier and subject confirmation method (holder of key / bearer) - CreateAttributeStatement
Creates the attribute statement based on the claims from the token service. - CreateAuthenticationStatementFromAuthenticationInformation
Creates the authentication statement based on the authentication information in the token descriptor. This method only gets called if such information is present – so be sure to populate the AuthenticationInformation collection on the descriptor at some earlier point.
- CreateSamlSubject
- CreateConditions
Sets the token lifetime and audience URIs restrictions. - CreateAdvice
Creates the SAML advice. By default no advice is created. - CreateAssertion
Creates the SAML assertion based on the statements, the conditions and the advice. - GetSigningCredentials
Returns the credential used to sign the token. - GetEncryptingCredentials
Returns the credential used to encrypt the token. If this method returns null, the token will not be encrypted.
Again you can override any of these methods.
OK – that was a lot of information. Where would you now plug in when you want to modify token creation? You basically have two options. Either you override the methods in SecurityTokenService to shape the token descriptor that gets passed to the handler. Of, if you need more control, you derive from one of the token handlers (e.g. Saml11SecurityTokenHandler) and override some of the methods that create the token details.
If you choose to write a custom handler, you can wire up the handler to the token service by overriding the SecurityTokenService.GetSecurityTokenHandler method.
HTH