Пример #1
0
        /// <summary>ChangeToIdTokenFromJwt</summary>
        /// <param name="access_token">Jwt (string)</param>
        /// <returns>IdToken (string)</returns>
        public static string ChangeToIdTokenFromJwt(string access_token)
        {
            if (access_token.Contains("."))
            {
                string[] temp = access_token.Split('.');
                string   json = CustomEncode.ByteToString(CustomEncode.FromBase64UrlString(temp[1]), CustomEncode.UTF_8);
                Dictionary <string, object> authTokenClaimSet = JsonConvert.DeserializeObject <Dictionary <string, object> >(json);

                // ・access_tokenがJWTで、payloadに"nonce" and "scope=openidクレームが存在する場合、
                if (authTokenClaimSet.ContainsKey("nonce") &&
                    authTokenClaimSet.ContainsKey("scopes"))
                {
                    JArray scopes = (JArray)authTokenClaimSet["scopes"];

                    // ・OpenID Connect : response_type=codeに対応する。
                    if (scopes.Any(x => x.ToString() == ASPNETIdentityConst.Scope_Openid))
                    {
                        //・payloadからscopeを削除する。
                        authTokenClaimSet.Remove("scopes");
                        //・編集したpayloadを再度JWTとして署名する。
                        string    newPayload = JsonConvert.SerializeObject(authTokenClaimSet);
                        JWT_RS256 jwtRS256   = null;

                        // 署名
                        jwtRS256 = new JWT_RS256(ASPNETIdentityConfig.OAuthJWT_pfx, ASPNETIdentityConfig.OAuthJWTPassword,
                                                 X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

                        string id_token = jwtRS256.Create(newPayload);

                        // 検証
                        jwtRS256 = new JWT_RS256(ASPNETIdentityConfig.OAuthJWT_cer, ASPNETIdentityConfig.OAuthJWTPassword,
                                                 X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

                        if (jwtRS256.Verify(id_token))
                        {
                            // 検証できた。
                            return(id_token);
                        }
                        else
                        {
                            // 検証できなかった。
                        }
                    }
                    else
                    {
                        // OIDCでない。
                    }
                }
                else
                {
                    // OIDCでない。
                }
            }
            else
            {
                // JWTでない。
            }

            return("");
        }
Пример #2
0
        /// <summary>
        /// ProtectFromPayload
        ///   Hybrid Flow対応(access_token_payloadを処理)
        /// </summary>
        /// <param name="access_token_payload">AccessTokenのPayload</param>
        /// <param name="customExp">Hybrid Flowのtokenに対応したexp</param>
        /// <returns></returns>
        public static string ProtectFromPayload(string access_token_payload, ulong customExp)
        {
            string json = "";
            string jwt  = "";

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

            #region JSON編集

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

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

            json = JsonConvert.SerializeObject(dic);

            #endregion

            #region JWT化

            JWT_RS256 jwtRS256 = null;

            // 署名
            jwtRS256 = new JWT_RS256(ASPNETIdentityConfig.OAuthJWT_pfx, ASPNETIdentityConfig.OAuthJWTPassword,
                                     X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

            jwt = jwtRS256.Create(json);

            // 検証
            jwtRS256 = new JWT_RS256(ASPNETIdentityConfig.OAuthJWT_cer, ASPNETIdentityConfig.OAuthJWTPassword,
                                     X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

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

            #endregion
        }
Пример #3
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));
                ret = jwtHS256.Verify(newJWT);
            }
            else
            {
                // RS256 (X509Cer)

                // 入力
                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 jwtRS256 = new JWT_RS256(this.CertificateFilePath_cer, "");
                ret = jwtRS256.Verify(newJWT);
            }

            if (ret)
            {
                MessageBox.Show("検証成功");
            }
            else
            {
                MessageBox.Show("検証失敗");
            }
        }
Пример #4
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
            {
                // RS256 (X509Cer)
                JWT_RS256 jwtRS256 = new JWT_RS256(this.CertificateFilePath_pfx, this.CertificateFilePassword);

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

                // 出力
                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);
            }
        }
Пример #5
0
        /// <summary>Protect</summary>
        /// <param name="ticket">AuthenticationTicket</param>
        /// <returns>JWT文字列</returns>
        public string Protect(AuthenticationTicket ticket)
        {
            string json = "";
            string jwt  = "";

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

            ApplicationUserManager userManager
                = HttpContext.Current.GetOwinContext().GetUserManager <ApplicationUserManager>();
            ApplicationUser 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 == ASPNETIdentityConst.Claim_Issuer)
                {
                    authTokenClaimSet.Add("iss", c.Value);
                }
                else if (c.Type == ASPNETIdentityConst.Claim_Audience)
                {
                    authTokenClaimSet.Add("aud", c.Value);
                }
                else if (c.Type == ASPNETIdentityConst.Claim_Nonce)
                {
                    authTokenClaimSet.Add("nonce", c.Value);
                }
                else if (c.Type == ASPNETIdentityConst.Claim_Scope)
                {
                    scopes.Add(c.Value);
                }
                else if (c.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role")
                {
                    roles.Add(c.Value);
                }
            }

            authTokenClaimSet.Add("sub", ticket.Identity.Name);
            authTokenClaimSet.Add("iat", ticket.Properties.IssuedUtc.Value.ToUnixTimeSeconds().ToString());
            authTokenClaimSet.Add("exp", ticket.Properties.ExpiresUtc.Value.ToUnixTimeSeconds().ToString());

            // scope値によって、返す値を変更する。
            foreach (string scope in scopes)
            {
                switch (scope.ToLower())
                {
                    #region OpenID Connect
                case ASPNETIdentityConst.Scope_Profile:
                    // ・・・
                    break;

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

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

                case ASPNETIdentityConst.Scope_Address:
                    // ・・・
                    break;
                    #endregion

                    #region Else

                case ASPNETIdentityConst.Scope_Userid:
                    authTokenClaimSet.Add(ASPNETIdentityConst.Scope_Userid, user.Id);
                    break;

                case ASPNETIdentityConst.Scope_Roles:
                    authTokenClaimSet.Add(ASPNETIdentityConst.Scope_Roles, roles);
                    break;

                    #endregion
                }
            }

            authTokenClaimSet.Add("scopes", scopes);

            json = JsonConvert.SerializeObject(authTokenClaimSet);

            #endregion

            #region JWT化

            JWT_RS256 jwtRS256 = null;

            // 署名
            jwtRS256 = new JWT_RS256(ASPNETIdentityConfig.OAuthJWT_pfx, ASPNETIdentityConfig.OAuthJWTPassword,
                                     X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

            jwt = jwtRS256.Create(json);

            // 検証
            jwtRS256 = new JWT_RS256(ASPNETIdentityConfig.OAuthJWT_cer, ASPNETIdentityConfig.OAuthJWTPassword,
                                     X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

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

            #endregion
        }
Пример #6
0
        /// <summary>Unprotect</summary>
        /// <param name="jwt">JWT文字列</param>
        /// <returns>AuthenticationTicket</returns>
        public AuthenticationTicket Unprotect(string jwt)
        {
            // 検証
            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":"クライアント識別子.apps.googleusercontent.com",
                //  ★ "sub":"ユーザーの一意識別子",
                //  ★ "exp":JWT の有効期限(Unix時間)
                //  ☆ "nonce":Implicitで必須

                // authToken.iss, authToken.expの検証
                if ((string)authTokenClaimSet["iss"] == ASPNETIdentityConfig.OAuthIssuerId &&
                    OAuth2ProviderHelper.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);

                        // ClaimsIdentityに、その他、所定のClaimを追加する。
                        List <string> scopes = new List <string>();
                        foreach (string s in (JArray)authTokenClaimSet["scopes"])
                        {
                            scopes.Add(s);
                        }
                        OAuth2ProviderHelper.AddClaim(identity,
                                                      (string)authTokenClaimSet["aud"],
                                                      "", (string)authTokenClaimSet["nonce"], scopes);

                        // AuthenticationPropertiesの生成
                        AuthenticationProperties prop = new AuthenticationProperties();

                        // AuthenticationTicketに格納不要
                        //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に対応するSubjectが一致するかを確認し、一致する場合のみ、認証する。
                        // でないと、UserStoreから削除されたUser Accountが、Client Accountに化けることになる。
                        if ((string)authTokenClaimSet["sub"] == OAuth2ProviderHelper.GetInstance().GetClientName((string)authTokenClaimSet["aud"]))
                        {
                            // ClaimsIdentityを生成し、
                            ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);

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

                            // ClaimsIdentityに、その他、所定のClaimを追加する。
                            List <string> scopes = new List <string>();
                            foreach (string s in (JArray)authTokenClaimSet["scopes"])
                            {
                                scopes.Add(s);
                            }

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

                            // AuthenticationPropertiesの生成
                            AuthenticationProperties prop = new AuthenticationProperties();

                            // AuthenticationTicketに格納不要
                            //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);
                        }
                    }
                }
            }

            // 検証、認証ナドナド、できなかった。
            return(null);
        }
Пример #7
0
        /// <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);
        }