//[Authorize] public Dictionary <string, string> RevokeToken(FormDataCollection formData) { // 戻り値(エラー) Dictionary <string, string> err = new Dictionary <string, string>(); // 変数 string[] temp = null; string token = formData[OAuth2AndOIDCConst.token]; string token_type_hint = formData[OAuth2AndOIDCConst.token_type_hint]; // クライアント認証 // クライアント識別子 string authHeader = HttpContext.Current.Request.Headers[OAuth2AndOIDCConst.HttpHeader_Authorization]; temp = authHeader.Split(' '); if (temp[0] == OAuth2AndOIDCConst.Basic) { temp = CustomEncode.ByteToString( CustomEncode.FromBase64String(temp[1]), CustomEncode.us_ascii).Split(':'); string clientId = temp[0]; string clientSecret = temp[1]; if (!(string.IsNullOrEmpty(clientId) && string.IsNullOrEmpty(clientSecret))) { // *.config or OAuth2Dataテーブルを参照してクライアント認証を行なう。 if (clientSecret == OAuth2Helper.GetInstance().GetClientSecret(clientId)) { // 検証完了 if (token_type_hint == OAuth2AndOIDCConst.AccessToken) { // 検証 AccessTokenFormatJwt verifier = new AccessTokenFormatJwt(); AuthenticationTicket ticket = verifier.Unprotect(token); if (ticket == null) { // 検証失敗 // 検証エラー err.Add("error", "invalid_request"); err.Add("error_description", "invalid token"); } else { // 検証成功 // jtiの取り出し Claim jti = ticket.Identity.Claims.Where( x => x.Type == OAuth2AndOIDCConst.Claim_JwtId).FirstOrDefault <Claim>(); // access_token取消 OAuth2RevocationProvider.GetInstance().Create(jti.Value); return(null); // 成功 } } else if (token_type_hint == OAuth2AndOIDCConst.RefreshToken) { // refresh_token取消 if (RefreshTokenProvider.DeleteDirectly(token)) { // 取り消し成功 return(null); // 成功 } else { // 取り消し失敗 err.Add("error", "invalid_request"); err.Add("error_description", "invalid token"); } } else { // token_type_hint パラメタ・エラー err.Add("error", "invalid_request"); err.Add("error_description", "invalid token_type_hint"); } } else { // クライアント認証エラー(Credential不正 err.Add("error", "invalid_client"); err.Add("error_description", "Invalid credential"); } } else { // クライアント認証エラー(Credential不正 err.Add("error", "invalid_client"); err.Add("error_description", "Invalid credential"); } } else { // クライアント認証エラー(ヘッダ不正 err.Add("error", "invalid_request"); err.Add("error_description", "Invalid authentication header"); } return(err); // 失敗 }
/// <summary>Unprotect</summary> /// <param name="jwt">JWT文字列</param> /// <returns>AuthenticationTicket</returns> public AuthenticationTicket Unprotect(string jwt) { // 空のケースあり。 if (string.IsNullOrEmpty(jwt)) { return(null); } // 検証 JWT_RS256 jwtRS256 = new JWT_RS256(ASPNETIdentityConfig.OAuthJWT_cer, ASPNETIdentityConfig.OAuthJWTPassword); if (jwtRS256.Verify(jwt)) { // 検証できた。 // デシリアライズ、 string[] temp = jwt.Split('.'); string json = CustomEncode.ByteToString(CustomEncode.FromBase64UrlString(temp[1]), CustomEncode.UTF_8); Dictionary <string, object> authTokenClaimSet = JsonConvert.DeserializeObject <Dictionary <string, object> >(json); // 以下の検証処理 // ★ "iss": accounts.google.com的な, // ★ "aud": client_id(クライアント識別子) // ★ "sub": ユーザーの一意識別子(uname, email) // ★ "exp": JWT の有効期限(Unix時間) // ☆ "jti": JWT のID(OAuth Token Revocation) DateTime?datetime = OAuth2RevocationProvider.GetInstance().Get((string)authTokenClaimSet["jti"]); if (datetime == null) { // authToken.iss, authToken.expの検証 if ((string)authTokenClaimSet["iss"] == ASPNETIdentityConfig.OAuthIssuerId && OAuth2Helper.GetInstance().GetClientSecret((string)authTokenClaimSet["aud"]) != null && long.Parse((string)authTokenClaimSet["exp"]) >= DateTimeOffset.Now.ToUnixTimeSeconds()) { // authToken.subの検証 // ApplicationUser を取得する。 ApplicationUserManager userManager = HttpContext.Current.GetOwinContext().GetUserManager <ApplicationUserManager>(); ApplicationUser user = userManager.FindByName((string)authTokenClaimSet["sub"]); // 同期版でOK。 if (user != null) { // User Accountの場合 // ユーザーに対応するClaimsIdentityを生成し、 ClaimsIdentity identity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ExternalBearer); // aud、scopes、nonceなどのClaimを追加する。 List <string> scopes = new List <string>(); foreach (string s in (JArray)authTokenClaimSet["scopes"]) { scopes.Add(s); } OAuth2Helper.AddClaim(identity, (string)authTokenClaimSet["aud"], "", scopes, (string) authTokenClaimSet["nonce"]); // その他、所定のClaimを追加する。 identity.AddClaim(new Claim(ASPNETIdentityConst.Claim_ExpirationTime, (string)authTokenClaimSet["exp"])); identity.AddClaim(new Claim(ASPNETIdentityConst.Claim_NotBefore, (string)authTokenClaimSet["nbf"])); identity.AddClaim(new Claim(ASPNETIdentityConst.Claim_IssuedAt, (string)authTokenClaimSet["iat"])); identity.AddClaim(new Claim(ASPNETIdentityConst.Claim_JwtId, (string)authTokenClaimSet["jti"])); // AuthenticationPropertiesの生成 AuthenticationProperties prop = new AuthenticationProperties(); prop.IssuedUtc = DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)authTokenClaimSet["iat"])); prop.ExpiresUtc = DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)authTokenClaimSet["exp"])); AuthenticationTicket auth = new AuthenticationTicket(identity, prop); // 認証結果を返す。 return(auth); } else { // Client Accountの場合 // ClaimとStoreのAudience(aud)に対応するSubject(sub)が一致するかを確認し、一致する場合のみ、認証する。 // ※ でないと、UserStoreから削除されたUser Accountが、Client Accountに化けることになる。 if ((string)authTokenClaimSet["sub"] == OAuth2Helper.GetInstance().GetClientName((string)authTokenClaimSet["aud"])) { // ClaimsIdentityを生成し、 ClaimsIdentity identity = new ClaimsIdentity(DefaultAuthenticationTypes.ExternalBearer); // sub(client_idに対応するclient_name)Claimを設定する。 identity.AddClaim(new Claim(ClaimTypes.Name, (string)authTokenClaimSet["sub"])); // aud、scopes、nonceなどのClaimを追加する。 List <string> scopes = new List <string>(); foreach (string s in (JArray)authTokenClaimSet["scopes"]) { scopes.Add(s); } OAuth2Helper.AddClaim(identity, (string)authTokenClaimSet["aud"], "", scopes, (string)authTokenClaimSet["nonce"]); // その他、所定のClaimを追加する。 identity.AddClaim(new Claim(ASPNETIdentityConst.Claim_ExpirationTime, (string)authTokenClaimSet["exp"])); identity.AddClaim(new Claim(ASPNETIdentityConst.Claim_NotBefore, (string)authTokenClaimSet["nbf"])); identity.AddClaim(new Claim(ASPNETIdentityConst.Claim_IssuedAt, (string)authTokenClaimSet["iat"])); identity.AddClaim(new Claim(ASPNETIdentityConst.Claim_JwtId, (string)authTokenClaimSet["jti"])); // AuthenticationPropertiesの生成 AuthenticationProperties prop = new AuthenticationProperties(); prop.IssuedUtc = DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)authTokenClaimSet["iat"])); prop.ExpiresUtc = DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)authTokenClaimSet["exp"])); AuthenticationTicket auth = new AuthenticationTicket(identity, prop); // 認証結果を返す。 return(auth); } } } else { // クレーム検証の失敗 } } else { // 取り消し済み } } else { // JWT署名検証の失敗 } // 検証、認証ナドナド、できなかった。 return(null); }