/// <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(""); }
/// <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 }
/// <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); } }
/// <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 }