Beispiel #1
0
        //[Authorize]
        public Dictionary <string, string> OAuth2BearerToken2(FormDataCollection formData)
        {
            // 戻り値
            // ・正常
            Dictionary <string, string> ret = new Dictionary <string, string>();
            // ・異常
            Dictionary <string, string> err = new Dictionary <string, string>();

            // 変数
            string grant_type = formData[OAuth2AndOIDCConst.grant_type];
            string assertion  = formData[OAuth2AndOIDCConst.assertion];

            // クライアント認証
            if (grant_type == OAuth2AndOIDCConst.JwtBearerTokenFlowGrantType)
            {
                Dictionary <string, string> dic = JsonConvert.DeserializeObject <Dictionary <string, string> >(
                    CustomEncode.ByteToString(CustomEncode.FromBase64UrlString(
                                                  assertion.Split('.')[1]), CustomEncode.us_ascii));

                string pubKey = OAuth2Helper.GetInstance().GetJwtAssertionPublickey(dic[OAuth2AndOIDCConst.iss]);
                pubKey = CustomEncode.ByteToString(CustomEncode.FromBase64String(pubKey), CustomEncode.us_ascii);

                if (!string.IsNullOrEmpty(pubKey))
                {
                    string  iss    = "";
                    string  aud    = "";
                    string  scopes = "";
                    JObject jobj   = null;

                    if (JwtAssertion.VerifyJwtBearerTokenFlowAssertion(assertion, out iss, out aud, out scopes, out jobj, pubKey))
                    {
                        // aud 検証
                        if (aud == ASPNETIdentityConfig.OAuth2AuthorizationServerEndpointsRootURI
                            + ASPNETIdentityConfig.OAuth2BearerTokenEndpoint2)
                        {
                            // ここからは、JwtAssertionではなく、JwtTokenを作るので、属性設定に注意。
                            ClaimsIdentity identity = OAuth2Helper.AddClaim(
                                new ClaimsIdentity(OAuthDefaults.AuthenticationType), iss, "", scopes.Split(' '), "");

                            AuthenticationProperties prop = new AuthenticationProperties();
                            prop.IssuedUtc  = DateTimeOffset.UtcNow;
                            prop.ExpiresUtc = DateTimeOffset.Now.Add(ASPNETIdentityConfig.OAuth2AccessTokenExpireTimeSpanFromMinutes);

                            // token_type
                            ret.Add(OAuth2AndOIDCConst.token_type, OAuth2AndOIDCConst.Bearer.ToLower());

                            // access_token
                            AccessTokenFormatJwt verifier = new AccessTokenFormatJwt();
                            string access_token           = verifier.Protect(new AuthenticationTicket(identity, prop));
                            ret.Add(OAuth2AndOIDCConst.AccessToken, access_token);

                            // expires_in
                            jobj = (JObject)JsonConvert.DeserializeObject(
                                CustomEncode.ByteToString(CustomEncode.FromBase64UrlString(
                                                              access_token.Split('.')[1]), CustomEncode.us_ascii));
                            ret.Add("expires_in", (long.Parse((string)jobj[OAuth2AndOIDCConst.exp]) - long.Parse((string)jobj[OAuth2AndOIDCConst.iat])).ToString());

                            // オペレーション・トレース・ログ出力
                            string clientName = OAuth2Helper.GetInstance().GetClientName(iss);
                            Logging.MyOperationTrace(string.Format(
                                                         "{0}({1}) passed the 'jwt bearer token flow' by {2}({3}).",
                                                         iss, clientName, iss, clientName));

                            return(ret); // 成功
                        }
                        else
                        {
                            // クライアント認証エラー(Credential(aud)不正
                            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
                {
                    // クライアント認証エラー(Credential(iss or pubKey)不正
                    err.Add("error", "invalid_client");
                    err.Add("error_description", "Invalid credential");
                }
            }
            else
            {
                // grant_type パラメタ・エラー
                err.Add("error", "invalid_request");
                err.Add("error_description", "invalid grant_type");
            }

            return(err); // 失敗
        }
Beispiel #2
0
        /// <summary>
        /// Resource Owner Password Credentials Grantのカスタム認証ロジック
        /// TokenEndpointPathへの grant_type = password アクセスは、こちらに到達する。
        /// ・context.Username および context.Password を検証する。
        /// ・クライアントは"access_token" および "refresh_token" を取得する。
        /// </summary>
        /// <param name="context">OAuthGrantResourceOwnerCredentialsContext</param>
        /// <returns>Task</returns>
        /// <see cref="https://msdn.microsoft.com/ja-jp/library/dn343587.aspx"/>
        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            if (!ASPNETIdentityConfig.EnableResourceOwnerPasswordCredentialsGrantType)
            {
                throw new NotSupportedException(Resources.ApplicationOAuthBearerTokenProvider.EnableResourceOwnerCredentialsGrantType);
            }

            // この実装は、ValidateClientAuthenticationの続きで、ClientのOAuth権限を確認する。
            // 権限がある場合、Resource Owner Password Credentialsグラント種別の処理フローを継続する。

            try
            {
                // ApplicationUser を取得する。
                ApplicationUserManager userManager
                    = HttpContext.Current.GetOwinContext().GetUserManager <ApplicationUserManager>();

                // username=ユーザ名&password=パスワードとして送付されたクレデンシャルを検証する。
                ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

                if (user != null)
                {
                    // ユーザーが見つかった場合。

                    try
                    {
                        // ユーザーに対応するClaimsIdentityを生成する。
                        ClaimsIdentity identity = await userManager.CreateIdentityAsync(user, OAuthDefaults.AuthenticationType);

                        // ClaimsIdentityに、その他、所定のClaimを追加する。
                        OAuth2Helper.AddClaim(identity, context.ClientId, "", context.Scope, "");

                        // 検証完了
                        context.Validated(identity);

                        // オペレーション・トレース・ログ出力
                        Logging.MyOperationTrace(string.Format("{0}({1}) passed the 'resource owner password credentials flow' by {2}({3}).",
                                                               user.Id, user.UserName, context.ClientId, OAuth2Helper.GetInstance().GetClientName(context.ClientId)));
                    }
                    catch
                    {
                        // ClaimManagerIdentityは、UserManagerで作成できませんでした。
                        context.SetError(
                            "server_error",
                            Resources.ApplicationOAuthBearerTokenProvider.server_error2);

                        // 拒否
                        context.Rejected();
                    }
                }
                else
                {
                    // ユーザーが見つからなかった場合。

                    // Resources Ownerの資格情報が無効であるか、Resources Ownerが存在しません。
                    context.SetError(
                        "access_denied",
                        Resources.ApplicationOAuthBearerTokenProvider.access_denied);

                    // 拒否
                    context.Rejected();
                }
            }
            catch
            {
                // ユーザーを取得できませんでした。
                context.SetError(
                    "server_error",
                    Resources.ApplicationOAuthBearerTokenProvider.server_error1);

                // 拒否
                context.Rejected();
            }
        }
Beispiel #3
0
        /// <summary>
        /// Client Credentialsグラント種別のカスタム認証ロジック
        /// TokenEndpointPathへの grant_type=client_credentials アクセスは、こちらに到達する。
        /// ・client_id, client_secret の検証は、(2) ValidateClientAuthenticationで済。
        /// ・クライアントは"access_token"を取得する。
        /// </summary>
        /// <param name="context">OAuthGrantClientCredentialsContext</param>
        /// <returns>Task</returns>
        /// <see cref="https://msdn.microsoft.com/ja-jp/library/dn343586.aspx"/>
        public override async Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
        {
            if (!ASPNETIdentityConfig.EnableClientCredentialsGrantType)
            {
                throw new NotSupportedException(Resources.ApplicationOAuthBearerTokenProvider.EnableClientCredentialsGrantType);
            }

            // ASP.Net MVC: Creating an OAuth client credentials grant type token endpoint
            // http://www.hackered.co.uk/articles/asp-net-mvc-creating-an-oauth-client-credentials-grant-type-token-endpoint
            // WEB API 2 OAuth Client Credentials Authentication, How to add additional parameters? - Stack Overflow
            // http://stackoverflow.com/questions/29132031/web-api-2-oauth-client-credentials-authentication-how-to-add-additional-paramet

            try
            {
                ApplicationUser        user = null;
                ApplicationUserManager userManager
                    = HttpContext.Current.GetOwinContext().GetUserManager <ApplicationUserManager>();

                // client_idに対応するApplicationUserを取得する。
                user = await userManager.FindByNameAsync(
                    OAuth2Helper.GetInstance().GetClientName(context.ClientId));

                // ClaimsIdentity
                ClaimsIdentity identity = null;
                if (user != null)
                {
                    // User Accountの場合、

                    // ユーザーに対応するClaimsIdentityを生成する。
                    identity = await userManager.CreateIdentityAsync(user, OAuthDefaults.AuthenticationType);

                    // ClaimsIdentityに、その他、所定のClaimを追加する。
                    identity = OAuth2Helper.AddClaim(identity, context.ClientId, "", context.Scope, "");

                    // オペレーション・トレース・ログ出力
                    Logging.MyOperationTrace(
                        string.Format("{0}({1}) passed the 'client credentials flow' by {2}({3}).",
                                      user.Id, user.UserName, context.ClientId, OAuth2Helper.GetInstance().GetClientName(context.ClientId)));

                    // 検証完了
                    context.Validated(identity);
                }
                else
                {
                    // Client Accountの場合、

                    string clientName = OAuth2Helper.GetInstance().GetClientName(context.ClientId);
                    if (string.IsNullOrEmpty(clientName))
                    {
                        // 検証失敗
                        context.Rejected();
                    }
                    else
                    {
                        // ClaimsIdentityを自前で生成する。
                        identity = new ClaimsIdentity(context.Options.AuthenticationType);
                        // Name Claimを追加
                        identity.AddClaim(new Claim(ClaimTypes.Name, OAuth2Helper.GetInstance().GetClientName(context.ClientId)));
                        // ClaimsIdentityに、その他、所定のClaimを追加する。
                        identity = OAuth2Helper.AddClaim(identity, context.ClientId, "", context.Scope, "");

                        // オペレーション・トレース・ログ出力
                        Logging.MyOperationTrace(string.Format(
                                                     "Passed the 'client credentials flow' by {0}({1}).", context.ClientId, clientName));

                        // 検証完了
                        context.Validated(identity);
                    }
                }
            }
            catch
            {
                // ユーザーを取得できませんでした。
                context.SetError(
                    "server_error",
                    Resources.ApplicationOAuthBearerTokenProvider.server_error1);

                // 拒否
                context.Rejected();
            }
        }
Beispiel #4
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);
        }