3
votes

I have a working implementation of a Claims based authentication system implemented with WIF and .NET 4.5. It contains the usual pieces:

  • Custom STS with Passive and Active endpoints
  • Backend WCF service
  • Frontend MVC application
  • Frontend WebApi application

The calls from the frontend applications to the backedn WCF service use Delegated authentication, so the user authenticates in the Frontend app, the app requests a new token with ActAs=BootstrapToken and then calls the WCF service.

This is all working correctly with SAML tokens.

Now I want to use a JWT token to talk to the WebApi, so I installed the JSON Web Token Handler For the Microsoft .Net Framework 4.5 Nuget package in my STS and WebApi projects.

So I have my STS correctly issuing signed JWT tokens and my WebApi Relying Party validating the same token. All fine.

The problem:

If I use the JWT token in the ActAs field of my RST, it will be sent without the signature, so its naturally rejected by the STS. It seems that the token returned by the SecurityTokenHandler.ReadToken() method returns a token without any signature info.

Now my dilemma is this: Is this a supported scenario for a JWT token? As far as I understand, a JWT token doesn't carry all the information to validate the signature, as opposed to a SAML token, so is there any other limitations?

On the other hand, if this is indeed supported, does anyone implemented this before, or has any ideas? This is a developer preview, so could it be a bug?

Edit

This is a sample to illustrate the issue. The code produces the same results when run in the STS (with access to the signing key) and on a Relying Party (with access to the certificate's public key:

System.Diagnostics.Debug.WriteLine("Raw Token       : {0}", (object)rawToken);

var readToken = this.identityConfiguration.SecurityTokenHandlers.ReadToken(rawToken);

this.identityConfiguration.SecurityTokenHandlers.ValidateToken(readToken);

var serializedToken = this.identityConfiguration.SecurityTokenHandlers.WriteToken(readToken);

System.Diagnostics.Debug.WriteLine("Serialized Token: {0}", (object)serializedToken);

Produces the following

Raw Token       : eyJAi(...)x3a9.eyJvYXB(...)DYzWiJ9.y-lT(...)PyBUTw
Serialized Token: eyJAi(...)x3a9.eyJvYXB(...)DYzWiJ9.

So, clearly, a Read/Write roundtrip loses the signing information. I could understand why this happens in the RP, but not in the STS.

Edit 2

So here's the current JWTSecurityTokenHandler.WriteToken(SecurityToken token) implementation:

public override string WriteToken(SecurityToken token)
{
    Utility.VerifyNonNullArgument("token", token);
    JWTSecurityToken jWTSecurityToken = token as JWTSecurityToken;
    if (jWTSecurityToken == null)
    {
        throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, "JWT10200: This instance of JWTSecurityTokenHandler can only write SecurityTokens of type '{0}', a SecurityToken of type '{1}' was received.", new object[]
        {
            typeof(JWTSecurityToken),
            token.GetType()
        }));
    }
    string text = string.Empty;
    string text2 = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
    {
        jWTSecurityToken.EncodedHeader,
        jWTSecurityToken.EncodedPayload
    });
    if (jWTSecurityToken.SigningCredentials != null)
    {
        text = this.Sign(text2, jWTSecurityToken.SigningCredentials);
    }
    return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
    {
        text2,
        text
    });
}

By looking into it, it's clear that the written token will never have its signature when in a RP, as we don't have the Signing Credentials. So this doesn't look like a bug, but rather an implementation decision. I just don't understand why.

Thanks

3
Sorry just to be clear when the token goes in to ReadToken does it look like this "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9. eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt cGxlLmNvbS9pc19yb290Ijp0cnVlfQ." with a trailing empty "."? or does it have a 3rd part going in to ReadToken?Mark Jones
The issued token by the STS has the 3 parts. The input string I use for SecurityTokenHandler.ReadToken(string) also has the 3 parts. But the token that gets to the STS arrives without the signature (last part)Pedro
Please see my edit with sample codePedro
The only location Write can produce a JWT with signature is the issuing point. Any other scenario would be a security bug. I'm not sure I understand exactly what you want to achieve, but any party other than the token issuer is not supposed to try to re-create it (that's what you mean by Read-Write roundtrip). When you receive a signed JWT you can only Validate and Read it. You are free to retransmit the original JWT as is, but you won't be able to "properly" reconstruct it, as you are not the issuer.Vladik Branevich
I can't see how that can be a security bug. You don't have the private key to generate a new signature, so you cannot change the contents of the token. The STS (or any recipient) has all the needed information to validate the token. Correct me if I'm wrong, but when you attach a SAML token to a RST, you need to write it (you are attaching a SecurityToken instance that has been read before). Before attaching that token to the RST, WIF needs to write the token back to XML, including the signature for which the RP doesn't have the corresponding private key.Pedro

3 Answers

3
votes

This is neither a security (or any other) bug, nor implementation decision. The only location Write can produce a JWT with signature is the issuing point. Any party other than the token issuer is not supposed to try to re-create it (that's what you mean by Read-Write roundtrip). When you receive a signed JWT you can only Validate and Read it. You are free to re-transmit the original JWT as is, but you won't be able to "properly" reconstruct it, as you are not the issuer and do not have the appropriate signing key.

This is the very reason behind signing the token: only the original issuer can properly sign it.

If you like, I can try to help you design the correct scenario with security tokens and STS, but for that, please share the sequence diagram of the scenario you are implementing.

2
votes

I wouldn't be surprise if this is a bug - the JWT handler is still in preview mode.

But maybe you don't want to do the full blow ActAs for Web API services - have a look here:

http://blogs.msdn.com/b/vbertocci/archive/2013/01/09/using-the-jwt-handler-for-implementing-poor-man-s-delegation-actas.aspx

0
votes

Have a look at JWTSecurityToken.RawData. That contains the original encodedToken. And should have the signature from the original issuer.