Exemplo n.º 1
0
        /// <summary>
        /// ProtectFromAccessTokenPayload
        ///   Hybrid Flow対応(access_token_payloadを処理)
        /// </summary>
        /// <param name="access_token_payload">AccessTokenのPayload</param>
        /// <param name="customExp">Hybrid Flowのtokenに対応したexp</param>
        /// <returns>IdToken</returns>
        public static string ProtectFromAccessTokenPayload(string access_token_payload, ulong customExp)
        {
            string json = "";

            //string jws = "";

            // ticketの値を使用(これは、codeのexpっぽい。300秒になっているのでNG。)
            //authTokenClaimSet.Add(OAuth2AndOIDCConst.exp, ticket.Properties.ExpiresUtc.Value.ToUnixTimeSeconds().ToString());
            //authTokenClaimSet.Add(OAuth2AndOIDCConst.exp, DateTimeOffset.Now.AddSeconds(customExp).ToUnixTimeSeconds().ToString());

            #region JSON編集

            // access_token_payloadのDictionary化
            Dictionary <string, object> payload =
                JsonConvert.DeserializeObject <Dictionary <string, object> >(access_token_payload);

            // ★ customExpの値を使用する。
            payload[OAuth2AndOIDCConst.exp] = DateTimeOffset.Now.AddSeconds(customExp).ToUnixTimeSeconds().ToString();
            // ★ Hybrid Flow対応なので、scopeを制限してもイイ。
            payload[OAuth2AndOIDCConst.scopes] = payload[OAuth2AndOIDCConst.scopes];

            json = JsonConvert.SerializeObject(payload);

            #endregion

            #region JWS化

            JWS_RS256_X509 jwsRS256 = null;

            // 署名
            jwsRS256 = new JWS_RS256_X509(ASPNETIdentityConfig.OAuth2JWT_pfx, ASPNETIdentityConfig.OAuth2JWTPassword,
                                          X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

            // JWSHeaderのセット
            // kid : https://openid-foundation-japan.github.io/rfc7638.ja.html#Example
            Dictionary <string, string> jwk =
                JsonConvert.DeserializeObject <Dictionary <string, string> >(
                    RS256_KeyConverter.X509PfxToJwkPublicKey(ASPNETIdentityConfig.OAuth2JWT_pfx, ASPNETIdentityConfig.OAuth2JWTPassword));

            jwsRS256.JWSHeader.kid = jwk[JwtConst.kid];
            jwsRS256.JWSHeader.jku = ASPNETIdentityConfig.OAuth2AuthorizationServerEndpointsRootURI + OAuth2AndOIDCParams.JwkSetUri;

            return(jwsRS256.Create(json));

            //// 検証
            //jwsRS256 = new JWS_RS256_X509(OAuth2AndOIDCParams.RS256Cer, ASPNETIdentityConfig.OAuth2JWTPassword,
            //    X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

            //if (jwsRS256.Verify(jws))
            //{
            //    return jws; // 検証できた。
            //}
            //else
            //{
            //    return ""; // 検証できなかった。
            //}

            #endregion
        }
        static void Main(string[] args)
        {
            // 現在の証明書のJwk
            JObject jwkObject =
                JsonConvert.DeserializeObject <JObject>(
                    RS256_KeyConverter.X509CerToJwkPublicKey(OAuth2AndOIDCParams.RS256Cer));

            // JwkSet.jsonファイルの存在チェック
            if (!ResourceLoader.Exists(OAuth2AndOIDCParams.JwkSetFilePath, false))
            {
                // 新規
                File.Create(OAuth2AndOIDCParams.JwkSetFilePath).Close();
            }
            else
            {
                // 既存?
            }

            // JwkSet.jsonファイルのロード
            JwkSet jwkSetObject = JwkSet.LoadJwkSet(OAuth2AndOIDCParams.JwkSetFilePath);

            // 判定
            if (jwkSetObject == null)
            {
                // 新規
                jwkSetObject = new JwkSet();
                jwkSetObject.keys.Add(jwkObject);
            }
            else
            {
                // 既存

                // kidの重複確認
                JwkSet.AddJwkToJwkSet(jwkSetObject, jwkObject);
            }

            // jwkSetObjectのセーブ
            JwkSet.SaveJwkSet(OAuth2AndOIDCParams.JwkSetFilePath, jwkSetObject);
        }
Exemplo n.º 3
0
        /// <summary>ValidateSignature</summary>

        /// <param name="clientData">string</param>
        /// <param name="authenticatorData">string</param>
        /// <param name="signature">string</param>
        /// <returns>
        /// true  : valid
        /// false : invalid
        /// </returns>
        public bool ValidateSignature(
            string clientData, string authenticatorData, string signature)
        {
            bool ret = false;

            byte[] clientDataBytes        = CustomEncode.FromBase64UrlString(clientData);
            byte[] authenticatorDataBytes = CustomEncode.FromBase64UrlString(authenticatorData);
            byte[] signatureBytes         = CustomEncode.FromBase64UrlString(signature);

            // Challengeの一致を確認する。
            JObject clientJson = JObject.Parse(//Encoding.ASCII.GetString(clientDataBytes));
                Encoding.ASCII.GetString(clientDataBytes).Replace("\0", "").Trim());

            byte[] hashBytes = null;
            byte[] data      = null;
            hashBytes = GetHash.GetHashBytes(clientDataBytes, EnumHashAlgorithm.SHA256Managed, 0);
            data      = authenticatorDataBytes.Concat(hashBytes).ToArray();

            if ((string)clientJson["challenge"] == this.Challenge)
            {
                // Challengeの一致

                // Load public key
                RSACryptoServiceProvider rsaCryptoServiceProvider =
                    RS256_KeyConverter.JwkToProvider(this.PublicKey);

                // VerifyData
                ret = rsaCryptoServiceProvider.VerifyData(
                    data, signatureBytes,
                    HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

                return(ret);
            }
            else
            {
                // Challengeの不一致
                return(false);
            }
        }
Exemplo n.º 4
0
        /// <summary>JWT検証</summary>
        private void btnJWTVerify_Click(object sender, EventArgs e)
        {
            bool ret = false;

            if (rbnJWTHS256.Checked)
            {
                // HS256

                // 入力
                string[] temp = this.txtJWTSign.Text.Split('.');

                // 改変可能なフィールドから入力
                string newJWT =
                    CustomEncode.ToBase64UrlString(CustomEncode.StringToByte(this.txtJWTHeader.Text, CustomEncode.UTF_8))
                    + "." + CustomEncode.ToBase64UrlString(CustomEncode.StringToByte(this.txtJWTPayload.Text, CustomEncode.UTF_8))
                    + "." + temp[2];

                // 検証
                //JWT_HS256 jwtHS256 = new JWT_HS256(CustomEncode.StringToByte(this.txtJWTKey.Text, CustomEncode.UTF_8));
                JWT_HS256 jwtHS256 = new JWT_HS256(this.txtJWTJWK.Text);
                ret = jwtHS256.Verify(newJWT);
            }
            else if (rbnJWTRS256_XML.Checked)
            {
                // RS256 (XML)

                // 入力
                string[] temp = this.txtJWTSign.Text.Split('.');

                // 改変可能なフィールドから入力
                string newJWT =
                    CustomEncode.ToBase64UrlString(CustomEncode.StringToByte(this.txtJWTHeader.Text, CustomEncode.UTF_8))
                    + "." + CustomEncode.ToBase64UrlString(CustomEncode.StringToByte(this.txtJWTPayload.Text, CustomEncode.UTF_8))
                    + "." + temp[2];

                // 検証
                JWT_RS256_XML jwtRS256 = new JWT_RS256_XML(this.txtJWTKey.Text);
                ret = jwtRS256.Verify(newJWT);
            }
            else if (rbnJWTRS256_Param.Checked)
            {
                // RS256 (Param)

                // 入力
                string[] temp = this.txtJWTSign.Text.Split('.');

                // 改変可能なフィールドから入力
                string newJWT =
                    CustomEncode.ToBase64UrlString(CustomEncode.StringToByte(this.txtJWTHeader.Text, CustomEncode.UTF_8))
                    + "." + CustomEncode.ToBase64UrlString(CustomEncode.StringToByte(this.txtJWTPayload.Text, CustomEncode.UTF_8))
                    + "." + temp[2];

                // 検証
                //JWT_RS256_Param jwtRS256 = new JWT_RS256_Param(
                //    RS256_KeyConverter.XmlToProvider(this.txtJWTKey.Text).ExportParameters(false));
                JWT_RS256_Param jwtRS256 = new JWT_RS256_Param(
                    RS256_KeyConverter.JwkToProvider(this.txtJWTJWK.Text).ExportParameters(false));
                ret = jwtRS256.Verify(newJWT);
            }
            else
            {
                // RS256 (X509)

                // 入力
                string[] temp = this.txtJWTSign.Text.Split('.');

                // 改変可能なフィールドから入力
                string newJWT =
                    CustomEncode.ToBase64UrlString(CustomEncode.StringToByte(this.txtJWTHeader.Text, CustomEncode.UTF_8))
                    + "." + CustomEncode.ToBase64UrlString(CustomEncode.StringToByte(this.txtJWTPayload.Text, CustomEncode.UTF_8))
                    + "." + temp[2];

                // 検証
                JWT_RS256_X509 jwtRS256 = new JWT_RS256_X509(this.CertificateFilePath_cer, "");
                ret = jwtRS256.Verify(newJWT);
            }

            if (ret)
            {
                MessageBox.Show("検証成功");
            }
            else
            {
                MessageBox.Show("検証失敗");
            }
        }
Exemplo n.º 5
0
        /// <summary>JWT生成</summary>
        private void btnJWTSign_Click(object sender, EventArgs e)
        {
            if (rbnJWTHS256.Checked)
            {
                // HS256
                string    password = GetPassword.Generate(20, 10);
                JWT_HS256 jwtHS256 = new JWT_HS256(CustomEncode.StringToByte(password, CustomEncode.UTF_8));

                // 生成
                string jwt = jwtHS256.Create(this.txtJWTPayload.Text);

                // 出力
                this.txtJWTKey.Text  = password;
                this.txtJWTJWK.Text  = jwtHS256.JWK;
                this.txtJWTSign.Text = jwt;

                // 改竄可能なフィールドに出力
                string[] temp = jwt.Split('.');
                this.txtJWTHeader.Text = CustomEncode.ByteToString(
                    CustomEncode.FromBase64UrlString(temp[0]), CustomEncode.UTF_8);
                this.txtJWTPayload.Text = CustomEncode.ByteToString(
                    CustomEncode.FromBase64UrlString(temp[1]), CustomEncode.UTF_8);
            }
            else if (rbnJWTRS256_XML.Checked)
            {
                // RS256 (XML)
                JWT_RS256_XML jwtRS256 = new JWT_RS256_XML();

                // 生成
                string jwt = jwtRS256.Create(this.txtJWTPayload.Text);

                // 出力
                this.txtJWTKey.Text = jwtRS256.XMLPublicKey;

                this.txtJWTJWK.Text =
                    RS256_KeyConverter.ParamToJwkPublicKey(
                        RS256_KeyConverter.XmlToProvider(jwtRS256.XMLPublicKey).ExportParameters(false));

                this.txtJWTSign.Text = jwt;

                // 改竄可能なフィールドに出力
                string[] temp = jwt.Split('.');
                this.txtJWTHeader.Text = CustomEncode.ByteToString(
                    CustomEncode.FromBase64UrlString(temp[0]), CustomEncode.UTF_8);
                this.txtJWTPayload.Text = CustomEncode.ByteToString(
                    CustomEncode.FromBase64UrlString(temp[1]), CustomEncode.UTF_8);
            }
            else if (rbnJWTRS256_Param.Checked)
            {
                // RS256 (Param)
                JWT_RS256_Param jwtRS256 = new JWT_RS256_Param();

                // 生成
                string jwt = jwtRS256.Create(this.txtJWTPayload.Text);

                // 出力
                this.txtJWTKey.Text = RS256_KeyConverter.ParamToXmlPublicKey(jwtRS256.RsaPublicParameters);
                this.txtJWTJWK.Text = RS256_KeyConverter.ParamToJwkPublicKey(jwtRS256.RsaPublicParameters);

                this.txtJWTSign.Text = jwt;

                // 改竄可能なフィールドに出力
                string[] temp = jwt.Split('.');
                this.txtJWTHeader.Text = CustomEncode.ByteToString(
                    CustomEncode.FromBase64UrlString(temp[0]), CustomEncode.UTF_8);
                this.txtJWTPayload.Text = CustomEncode.ByteToString(
                    CustomEncode.FromBase64UrlString(temp[1]), CustomEncode.UTF_8);
            }
            else
            {
                // RS256 (X509)
                JWT_RS256_X509 jwtRS256 = new JWT_RS256_X509(this.CertificateFilePath_pfx, this.CertificateFilePassword,
                                                             X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

                // 生成
                string jwt = jwtRS256.Create(this.txtJWTPayload.Text);

                // 出力
                this.txtJWTKey.Text = jwtRS256.DigitalSignX509.X509PublicKey;

                this.txtJWTJWK.Text =
                    RS256_KeyConverter.ParamToJwkPublicKey(
                        RS256_KeyConverter.X509CerToProvider(
                            this.CertificateFilePath_cer).ExportParameters(false));

                this.txtJWTSign.Text = jwt;

                // 改竄可能なフィールドに出力
                string[] temp = jwt.Split('.');
                this.txtJWTHeader.Text = CustomEncode.ByteToString(
                    CustomEncode.FromBase64UrlString(temp[0]), CustomEncode.UTF_8);
                this.txtJWTPayload.Text = CustomEncode.ByteToString(
                    CustomEncode.FromBase64UrlString(temp[1]), CustomEncode.UTF_8);
            }
        }
        /// <summary>Protect</summary>
        /// <param name="ticket">AuthenticationTicket</param>
        /// <returns>JWT文字列</returns>
        public string Protect(AuthenticationTicket ticket)
        {
            string json = "";

            //string jws = "";

            // チェック
            if (ticket == null)
            {
                throw new ArgumentNullException("ticket");
            }

            ApplicationUserManager userManager
                = HttpContext.Current.GetOwinContext().GetUserManager <ApplicationUserManager>();

            ApplicationUser user = null;

            if (ticket.Identity.Name == null)
            {
                // Client認証の場合、
                user = null;
            }
            else
            {
                // Resource Owner認証の場合、
                user = userManager.FindByName(ticket.Identity.Name); // 同期版でOK。
            }

            #region ClaimSetの生成

            Dictionary <string, object> authTokenClaimSet = new Dictionary <string, object>();
            List <string> scopes = new List <string>();
            List <string> roles  = new List <string>();

            foreach (Claim c in ticket.Identity.Claims)
            {
                if (c.Type == OAuth2AndOIDCConst.Claim_Issuer)
                {
                    authTokenClaimSet.Add(OAuth2AndOIDCConst.iss, c.Value);
                }
                else if (c.Type == OAuth2AndOIDCConst.Claim_Audience)
                {
                    authTokenClaimSet.Add(OAuth2AndOIDCConst.aud, c.Value);
                }
                else if (c.Type == OAuth2AndOIDCConst.Claim_Nonce)
                {
                    authTokenClaimSet.Add(OAuth2AndOIDCConst.nonce, c.Value);
                }
                else if (c.Type == OAuth2AndOIDCConst.Claim_Scopes)
                {
                    scopes.Add(c.Value);
                }
                else if (c.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role")
                {
                    roles.Add(c.Value);
                }
            }

            if (ticket.Identity.Name == null)
            {
                // Client認証の場合、aud(client_id)に対応するClient名称
                authTokenClaimSet.Add(OAuth2AndOIDCConst.sub,
                                      OAuth2Helper.GetInstance().GetClientName((string)authTokenClaimSet[OAuth2AndOIDCConst.aud]));
            }
            else
            {
                // Resource Owner認証の場合、Resource Ownerの名称
                authTokenClaimSet.Add(OAuth2AndOIDCConst.sub, ticket.Identity.Name);
            }

            authTokenClaimSet.Add(OAuth2AndOIDCConst.exp, ticket.Properties.ExpiresUtc.Value.ToUnixTimeSeconds().ToString());
            authTokenClaimSet.Add(OAuth2AndOIDCConst.nbf, DateTimeOffset.Now.ToUnixTimeSeconds().ToString());
            authTokenClaimSet.Add(OAuth2AndOIDCConst.iat, ticket.Properties.IssuedUtc.Value.ToUnixTimeSeconds().ToString());
            authTokenClaimSet.Add(OAuth2AndOIDCConst.jti, Guid.NewGuid().ToString("N"));

            authTokenClaimSet.Add(OAuth2AndOIDCConst.scopes, scopes);

            // scope値によって、返す値を変更する。
            foreach (string scope in scopes)
            {
                if (user != null)
                {
                    // user == null では NG な Resource(Resource Owner の Resource)
                    switch (scope.ToLower())
                    {
                        #region OpenID Connect

                    case OAuth2AndOIDCConst.Scope_Profile:
                        // ・・・
                        break;

                    case OAuth2AndOIDCConst.Scope_Email:
                        authTokenClaimSet.Add(OAuth2AndOIDCConst.Scope_Email, user.Email);
                        authTokenClaimSet.Add(OAuth2AndOIDCConst.email_verified, user.EmailConfirmed.ToString());
                        break;

                    case OAuth2AndOIDCConst.Scope_Phone:
                        authTokenClaimSet.Add(OAuth2AndOIDCConst.phone_number, user.PhoneNumber);
                        authTokenClaimSet.Add(OAuth2AndOIDCConst.phone_number_verified, user.PhoneNumberConfirmed.ToString());
                        break;

                    case OAuth2AndOIDCConst.Scope_Address:
                        // ・・・
                        break;

                        #endregion

                        #region Else

                    case OAuth2AndOIDCConst.Scope_UserID:
                        authTokenClaimSet.Add(OAuth2AndOIDCConst.Scope_UserID, user.Id);
                        break;

                    case OAuth2AndOIDCConst.Scope_Roles:
                        authTokenClaimSet.Add(
                            OAuth2AndOIDCConst.Scope_Roles,
                            userManager.GetRolesAsync(user.Id).Result);
                        break;

                        #endregion
                    }
                }
                else
                {
                    // user == null でも OK な Resource
                }
            }

            json = JsonConvert.SerializeObject(authTokenClaimSet);

            #endregion

            #region JWS化

            JWS_RS256_X509 jwsRS256 = null;

            // JWT_RS256_X509
            jwsRS256 = new JWS_RS256_X509(ASPNETIdentityConfig.OAuth2JWT_pfx, ASPNETIdentityConfig.OAuth2JWTPassword,
                                          X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

            // JWSHeaderのセット
            // kid : https://openid-foundation-japan.github.io/rfc7638.ja.html#Example
            Dictionary <string, string> jwk =
                JsonConvert.DeserializeObject <Dictionary <string, string> >(
                    RS256_KeyConverter.X509PfxToJwkPublicKey(ASPNETIdentityConfig.OAuth2JWT_pfx, ASPNETIdentityConfig.OAuth2JWTPassword));

            jwsRS256.JWSHeader.kid = jwk[JwtConst.kid];
            jwsRS256.JWSHeader.jku = ASPNETIdentityConfig.OAuth2AuthorizationServerEndpointsRootURI + OAuth2AndOIDCParams.JwkSetUri;

            // 署名
            return(jwsRS256.Create(json));

            //// 検証
            //jwsRS256 = new JWS_RS256_X509(OAuth2AndOIDCParams.RS256Cer, ASPNETIdentityConfig.OAuth2JWTPassword,
            //    X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

            //if (jwsRS256.Verify(jws))
            //{
            //    return jws; // 検証できた。
            //}
            //else
            //{
            //    return ""; // 検証できなかった。
            //}

            #endregion
        }
        /// <summary>Unprotect</summary>
        /// <param name="jwt">JWT文字列</param>
        /// <returns>AuthenticationTicket</returns>
        public AuthenticationTicket Unprotect(string jwt)
        {
            // 空のケースあり。
            if (string.IsNullOrEmpty(jwt))
            {
                return(null);
            }

            // 検証
            JWS_RS256 jwsRS256 = null;

            // 証明書を使用するか、Jwkを使用するか判定
            Dictionary <string, string> header = JsonConvert.DeserializeObject <Dictionary <string, string> >(
                CustomEncode.ByteToString(CustomEncode.FromBase64UrlString(jwt.Split('.')[0]), CustomEncode.UTF_8));

            if (header.Keys.Any(s => s == JwtConst.kid))
            {
                if (string.IsNullOrEmpty(header[JwtConst.kid]))
                {
                    // 証明書を使用
                    jwsRS256 = new JWS_RS256_X509(OAuth2AndOIDCParams.RS256Cer, "");
                }
                else
                {
                    JwkSet  jwkSetObject = JwkSet.LoadJwkSet(OAuth2AndOIDCParams.JwkSetFilePath);
                    JObject jwkObject    = JwkSet.GetJwkObject(jwkSetObject, header[JwtConst.kid]);

                    if (jwkObject == null)
                    {
                        // 証明書を使用
                        jwsRS256 = new JWS_RS256_X509(OAuth2AndOIDCParams.RS256Cer, "");
                    }
                    else
                    {
                        // Jwkを使用
                        jwsRS256 = new JWS_RS256_Param(
                            RS256_KeyConverter.JwkToProvider(jwkObject).ExportParameters(false));
                    }
                }
            }

            if (jwsRS256.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[OAuth2AndOIDCConst.jti]);

                if (datetime == null)
                {
                    // authToken.iss, authToken.expの検証
                    if ((string)authTokenClaimSet[OAuth2AndOIDCConst.iss] == ASPNETIdentityConfig.OAuth2IssuerId &&
                        OAuth2Helper.GetInstance().GetClientSecret((string)authTokenClaimSet[OAuth2AndOIDCConst.aud]) != null &&
                        long.Parse((string)authTokenClaimSet[OAuth2AndOIDCConst.exp]) >= DateTimeOffset.Now.ToUnixTimeSeconds())
                    {
                        // authToken.subの検証
                        // ApplicationUser を取得する。
                        ApplicationUserManager userManager
                            = HttpContext.Current.GetOwinContext().GetUserManager <ApplicationUserManager>();
                        ApplicationUser user = userManager.FindByName((string)authTokenClaimSet[OAuth2AndOIDCConst.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[OAuth2AndOIDCConst.scopes])
                            {
                                scopes.Add(s);
                            }

                            OAuth2Helper.AddClaim(identity,
                                                  (string)authTokenClaimSet[OAuth2AndOIDCConst.aud], "", scopes,  (string) authTokenClaimSet[OAuth2AndOIDCConst.nonce]);

                            // その他、所定のClaimを追加する。
                            identity.AddClaim(new Claim(OAuth2AndOIDCConst.Claim_ExpirationTime, (string)authTokenClaimSet[OAuth2AndOIDCConst.exp]));
                            identity.AddClaim(new Claim(OAuth2AndOIDCConst.Claim_NotBefore, (string)authTokenClaimSet[OAuth2AndOIDCConst.nbf]));
                            identity.AddClaim(new Claim(OAuth2AndOIDCConst.Claim_IssuedAt, (string)authTokenClaimSet[OAuth2AndOIDCConst.iat]));
                            identity.AddClaim(new Claim(OAuth2AndOIDCConst.Claim_JwtId, (string)authTokenClaimSet[OAuth2AndOIDCConst.jti]));

                            // AuthenticationPropertiesの生成
                            AuthenticationProperties prop = new AuthenticationProperties();
                            prop.IssuedUtc  = DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)authTokenClaimSet[OAuth2AndOIDCConst.iat]));
                            prop.ExpiresUtc = DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)authTokenClaimSet[OAuth2AndOIDCConst.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[OAuth2AndOIDCConst.sub] == OAuth2Helper.GetInstance().GetClientName((string)authTokenClaimSet[OAuth2AndOIDCConst.aud]))
                            {
                                // ClaimsIdentityを生成し、
                                ClaimsIdentity identity = new ClaimsIdentity(DefaultAuthenticationTypes.ExternalBearer);

                                // sub(client_idに対応するclient_name)Claimを設定する。
                                identity.AddClaim(new Claim(ClaimTypes.Name, (string)authTokenClaimSet[OAuth2AndOIDCConst.sub]));

                                // aud、scopes、nonceなどのClaimを追加する。
                                List <string> scopes = new List <string>();
                                foreach (string s in (JArray)authTokenClaimSet[OAuth2AndOIDCConst.scopes])
                                {
                                    scopes.Add(s);
                                }

                                OAuth2Helper.AddClaim(identity,
                                                      (string)authTokenClaimSet[OAuth2AndOIDCConst.aud], "", scopes, (string)authTokenClaimSet[OAuth2AndOIDCConst.nonce]);

                                // その他、所定のClaimを追加する。
                                identity.AddClaim(new Claim(OAuth2AndOIDCConst.Claim_ExpirationTime, (string)authTokenClaimSet[OAuth2AndOIDCConst.exp]));
                                identity.AddClaim(new Claim(OAuth2AndOIDCConst.Claim_NotBefore, (string)authTokenClaimSet[OAuth2AndOIDCConst.nbf]));
                                identity.AddClaim(new Claim(OAuth2AndOIDCConst.Claim_IssuedAt, (string)authTokenClaimSet[OAuth2AndOIDCConst.iat]));
                                identity.AddClaim(new Claim(OAuth2AndOIDCConst.Claim_JwtId, (string)authTokenClaimSet[OAuth2AndOIDCConst.jti]));

                                // AuthenticationPropertiesの生成
                                AuthenticationProperties prop = new AuthenticationProperties();
                                prop.IssuedUtc  = DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)authTokenClaimSet[OAuth2AndOIDCConst.iat]));
                                prop.ExpiresUtc = DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)authTokenClaimSet[OAuth2AndOIDCConst.exp]));

                                AuthenticationTicket auth = new AuthenticationTicket(identity, prop);

                                // 認証結果を返す。
                                return(auth);
                            }
                        }
                    }
                    else
                    {
                        // クレーム検証の失敗
                    }
                }
                else
                {
                    // 取り消し済み
                }
            }
            else
            {
                // JWT署名検証の失敗
            }

            // 検証、認証ナドナド、できなかった。
            return(null);
        }