Comment configurer MIcrosoft JWT avec la clé symétrique?
j'essaie de configurer mon ASP.NET application pour accepter un JSON Web Token (JWT) qui est signé avec une clé symétrique. Le STS n'est pas capable d'utiliser des certificats pour cela, donc nous utilisons leur support de clé symétrique.
de mon côté, j'utilise Microsoft JWT Developer Preview. Malheureusement, je n'ai vu aucun exemple d'utilisation d'une clé symétrique. Après avoir creusé un peu autour avec divers outils, j'ai trouvé le NamedKeyIssuerTokenResolver
et j'ai découvert que j' configurer pour utiliser une clé symétrique. Par exemple:
<securityTokenHandlers>
<add type="Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler,Microsoft.IdentityModel.Tokens.JWT" />
<securityTokenHandlerConfiguration>
<certificateValidation certificateValidationMode="PeerTrust" />
<issuerTokenResolver
type="Microsoft.IdentityModel.Tokens.JWT.NamedKeyIssuerTokenResolver,
Microsoft.IdentityModel.Tokens.JWT">
<securityKey
symmetricKey="+zqf97FD/xyzzyplugh42ploverFeeFieFoeFooxqjE="
name="https://localhost/TestRelyingParty" />
</issuerTokenResolver>
</securityTokenHandlerConfiguration>
</securityTokenHandlers>
je ne suis pas entièrement sûr de ce que je suis censé utiliser pour le name
il n'. Devrait-il S'agir de L'URI du public, peut-être de l'émetteur? En tout cas, je sais que si je n'inclue pas un name
, j'obtiens une exception lorsque mon programme démarre, car le securityKey
l'élément nécessite cet attribut.
quoi qu'il en soit, cela ne résout toujours pas le problème. Après m'être authentifié contre les STS, j'obtiens le exception suivante:
[SecurityTokenValidationException: JWT10310: Unable to validate signature. validationParameters.SigningTokenResolver type: 'Microsoft.IdentityModel.Tokens.JWT.NamedKeyIssuerTokenResolver', was unable to resolve key to a token.
The SecurityKeyIdentifier is:
'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = Microsoft.IdentityModel.Tokens.JWT.NamedKeyIdentifierClause
)
'. validationParameters.SigningToken was null.]
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateSignature(JWTSecurityToken jwt, TokenValidationParameters validationParameters) +2111
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateToken(JWTSecurityToken jwt, TokenValidationParameters validationParameters) +138
Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler.ValidateToken(SecurityToken token) +599
System.IdentityModel.Tokens.SecurityTokenHandlerCollection.ValidateToken(SecurityToken token) +135
System.IdentityModel.Services.TokenReceiver.AuthenticateToken(SecurityToken token, Boolean ensureBearerToken, String endpointUri) +117
System.IdentityModel.Services.WSFederationAuthenticationModule.SignInWithResponseMessage(HttpRequestBase request) +698
System.IdentityModel.Services.WSFederationAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs args) +123924
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165
est-ce que je manque une autre étape de configuration? Est-ce que je mets la mauvaise chose dans le name
l'attribut? Ou est-ce un bug connu dans la Preview du développeur JWT?
5 réponses
mise à Jour 2014/02/13:
http://leastprivilege.com/2013/07/16/identityserver-using-ws-federation-with-jwt-tokens-and-symmetric-signatures/.notez que la réponse originale ci-dessous était pour la version Beta, Microsoft.IdentityModel.Jeton.JWT. La mise à niveau vers la version la version, le Système.IdentityModel.Jeton.Jwt, il fallait juste un peu plus de travail. Voir ci-dessous.
Le principal problème s'avère être que la méthode JWTSecurityTokenHandler.ValidateToken(token)
ne remplit pas entièrement le TokenValidationParameters
qu'il passe à JWTSecurityTokenHandler.ValidateToken(token, validationParameters)
. En particulier, il ne peuplera pas le SigningToken
membre ou le ValidIssuers
(ou ValidIssuer
).
fait intéressant, la configuration que j'ai montrée dans ma question originale est en fait chargée par le résolveur de jeton, et est disponible à l'exécution, comme vous pouvez le voir dans le le code ci-dessous.
Je ne sais pas comment spécifier la chaîne valide de l'émetteur dans le fichier de configuration, cependant. Je soupçonne fortement qu'il y ait un endroit pour mettre cette information, mais je n'ai pas encore trouvé où elle devrait être.
La solution à mon problème est de créer un jeton de sécurité gestionnaire qui en dérive JWTSecurityTokenHandler
. Primordial ValidateToken(token, validationParameters)
me donne l'occasion de définir les paramètres dont j'ai besoin, et puis appeler la classe de base ValidateToken
méthode.
public class CustomJwtSecurityTokenHandler: JWTSecurityTokenHandler
{
// Override ValidateSignature so that it gets the SigningToken from the configuration if it doesn't exist in
// the validationParameters object.
private const string KeyName = "https://localhost/TestRelyingParty";
private const string ValidIssuerString = "https://mySTSname/trust";
public override ClaimsPrincipal ValidateToken(JWTSecurityToken jwt, TokenValidationParameters validationParameters)
{
// set up valid issuers
if ((validationParameters.ValidIssuer == null) &&
(validationParameters.ValidIssuers == null || !validationParameters.ValidIssuers.Any()))
{
validationParameters.ValidIssuers = new List<string> {ValidIssuerString};
}
// and signing token.
if (validationParameters.SigningToken == null)
{
var resolver = (NamedKeyIssuerTokenResolver)this.Configuration.IssuerTokenResolver;
if (resolver.SecurityKeys != null)
{
List<SecurityKey> skeys;
if (resolver.SecurityKeys.TryGetValue(KeyName, out skeys))
{
var tok = new NamedKeySecurityToken(KeyName, skeys);
validationParameters.SigningToken = tok;
}
}
}
return base.ValidateToken(jwt, validationParameters);
}
}
dans ma toile.config, j'ai juste eu à changer le jeton de sécurité gestionnaire de:
<securityTokenHandlers>
<!--<add type="Microsoft.IdentityModel.Tokens.JWT.JWTSecurityTokenHandler,Microsoft.IdentityModel.Tokens.JWT" />-->
<!-- replaces the default JWTSecurityTokenHandler -->
<add type="TestRelyingParty.CustomJwtSecurityTokenHandler,TestRelyingParty" />
rien de tel que de passer trois ou quatre jours à faire des recherches sur un problème qui est résolu avec quelques douzaines de lignes de code . . .
ajout pour la nouvelle version
en juin 2013, Microsoft a officiellement publié leur JWT. Ils ont changé le namespace en System.IdentityModel.Jeton.Jwt. Après la mise à niveau, la solution ci-dessus a cessé de fonctionner. De obtenir ce travail, j'ai dû ajouter ce qui suit à mon CustomJwtSecurityTokenHandler
. En plus le code existant.
public override ClaimsPrincipal ValidateToken(JwtSecurityToken jwt)
{
var vparms = new TokenValidationParameters
{
AllowedAudiences = Configuration.AudienceRestriction.AllowedAudienceUris.Select(s => s.ToString())
};
return ValidateToken(jwt, vparms);
}
voici un exemple d'utilisation de cette bibliothèque avec .Net 4.5 qui émet et valide un JWT signé avec la clé symétrique basée sur HMAC SHA256 (tout en code et sans WIF):
string jwtIssuer = "MyIssuer";
string jwtAudience = "MyAudience";
// Generate symmetric key for HMAC-SHA256 signature
RNGCryptoServiceProvider cryptoProvider = new RNGCryptoServiceProvider();
byte[] keyForHmacSha256 = new byte[64];
cryptoProvider.GetNonZeroBytes(keyForHmacSha256);
///////////////////////////////////////////////////////////////////
// Create signing credentials for the signed JWT.
// This object is used to cryptographically sign the JWT by the issuer.
SigningCredentials sc = new SigningCredentials(
new InMemorySymmetricSecurityKey(keyForHmacSha256),
"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"http://www.w3.org/2001/04/xmlenc#sha256");
///////////////////////////////////////////////////////////////////
// Create token validation parameters for the signed JWT
// This object will be used to verify the cryptographic signature of the received JWT
TokenValidationParameters validationParams =
new TokenValidationParameters()
{
AllowedAudience = s_jwtAudience,
ValidIssuer = s_jwtIssuer,
ValidateExpiration = true,
ValidateNotBefore = true,
ValidateIssuer = true,
ValidateSignature = true,
SigningToken = new BinarySecretSecurityToken(keyForHmacSha256),
};
///////////////////////////////////////////////////////////////////
// Create JWT handler
// This object is used to write/sign/decode/validate JWTs
JWTSecurityTokenHandler jwtHandler = new JWTSecurityTokenHandler();
// Create a simple JWT claim set
IList<Claim> payloadClaims = new List<Claim>() { new Claim("clm1", "clm1 value"), };
// Create a JWT with signing credentials and lifetime of 12 hours
JWTSecurityToken jwt =
new JWTSecurityToken(jwtIssuer, jwtAudience, payloadClaims, sc, DateTime.UtcNow, DateTime.UtcNow.AddHours(12.0));
// Serialize the JWT
// This is how our JWT looks on the wire: <Base64UrlEncoded header>.<Base64UrlEncoded body>.<signature>
string jwtOnTheWire = jwtHandler.WriteToken(jwt);
// Validate the token signature (we provide the shared symmetric key in `validationParams`)
// This will throw if the signature does not validate
jwtHandler.ValidateToken(jwtOnTheWire, validationParams);
// Parse JWT from the Base64UrlEncoded wire form (<Base64UrlEncoded header>.<Base64UrlEncoded body>.<signature>)
JWTSecurityToken parsedJwt = jwtHandler.ReadToken(jwtOnTheWire) as JWTSecurityToken;
Jim,
Merci d'avoir essayé la preview, désolé que vous ayez eu des problèmes qui n'étaient pas évidents : - (.
NamedKeyIssuerTokenResolver
est né de deux idées:
- la nécessité d'associer une clé pour la vérification de la signature d'un secret partagé;
- plusieurs clés valides pourraient être utilisées en même temps.
Il a été conçu pour fonctionner avec le NamedKeySecurityToken
qui a un nom et un certain nombre de touches. NKITR
peut retourner un NKST
qui simplifie la vérification d'une signature lorsque plusieurs clés sont en jeu.
un but pour le NKITR
était de fournir un mappage entre le JWT iss
demande (dans l'en-tête) et une clé. Quand il est temps de vérifier la signature, le JWTHandler
vérifie:
TokenValidationParamerter.SigningToken
, si trouvé l'utiliser;SecurityKeyIdentifier
obtenu à partir deJWT.Header.SigningKeyIdentifier
(actuellement seul x5t est pris en charge) est envoyé auINR
;NamedKeyIdentifierClause
est créé à partir de laJwt.Issuer
et envoyé au courantINR
.
Depuis SecurityToken
peut contenir plusieurs clés, chaque commande est utilisée pour vérifier la signature, premier succès s'arrête et le JWT.SigningToken
contient SecurityToken
qui a validé la signature.
Jim et Willy,
Désolé pour la confusion avec l' ValidateToken(SecurityToken)
méthode de surcharge. Les paramètres sont déplacés à partir de Configuration
ValidationParameters
, mais pas les propriétés comme ValidIssuer
qui ont un seul élément, mais
IssuerNameRegistry -> VP.IssuerNameRegistry
IssuerTokenResolver -> VP.SigningTokenResolver
AllowedAudienceUris -> VP.AllowedAudiences
CertificateValidator -> VP.CertificateValidator
SaveBootStrapContext -> VP.SaveBootStrapContext
Brent
AFAIK, le JWtSecurityTokenHandler n'est pas encore prêt à être utilisé à partir d'un fichier de configuration. L'exemple donné par Vittorio Bertocci est aussi un "exemple de code". En cela, il appelle explicitement le ValidateToken surchargé avec le paramètre tokenValidationParameters supplémentaire qui contient toutes les choses nécessaires pour faire la validation (comme la clé symétrique).
Malheureusement, cette surcharge n'est pas appelée par le pipeline WIF normal (il appelle le ValidateToken avec juste le jeton comme un paramètre)
J'ai résolu de sous-classer le gestionnaire de jwtsecurity, de surcharger LoadCustomConfiguration pour charger manuellement les choses nécessaires pour créer un objet tokenValidationParemeter (j'ai dû créer quelques objets de configuration pour cela). Puis j'ai fait un override de validateToken pour explicitement appeler la surcharge avec le paramètre supplémentaire (que je pouvais créer à la volée avec les paramètres que j'ai lus à partir de la config). Tous très encombrants à faire mais le seul moyen d'exploiter le pouvoir de la tokenValidationparameters. (mais j'ai peut-être tort, bien sûr)
<issuerTokenResolver type="Microsoft.IdentityModel.Tokens.JWT.NamedKeyIssuerTokenResolver, Microsoft.IdentityModel.Tokens.JWT">
<securityKey symmetricKey="01234567890123456789012345678901" name="MyIssuer"/>
</issuerTokenResolver>
<securityTokenHandlers>
Voici comment cela fonctionne avec la version RTM du gestionnaire JWT: http://leastprivilege.com/2013/07/16/identityserver-using-ws-federation-with-jwt-tokens-and-symmetric-signatures/