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:
Must be implemented. Determines scope specific information like signing and encrypting credentials – usually based on the AppliesTo header.
Creates a default descriptor based on the scope from step 1. This is one option to modify the descriptor manually.
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.
Returns the issuer for the token. By default the issuer from the SecurityTokenServiceConfiguration is used.
Returns the life time of the token. By default the default life time from SecurityTokenServiceConfiguration is used (which is 10 hours).
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.
Must be implemented. Returns the identity that describes the subject.
The token handler creates the token and returns it to the token service (more details later)
Returns the claims that should be client visible (e.g. for an identity selector)
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.
Creates the SAML subject, attribute and authentication statements. This method calls out to:
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)
Creates the attribute statement based on the claims from the token service.
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.
Sets the token lifetime and audience URIs restrictions.
Creates the SAML advice. By default no advice is created.
Creates the SAML assertion based on the statements, the conditions and the advice.
Returns the credential used to sign the token.
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.