Example #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
        }
        /// <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
        }