string Thumbprint(string kty, string e, string n) { return(Base64Url.Encode(Util.Sha256Hash(Encoding.ASCII.GetBytes( $"{{\"e\":\"{e}\",\"kty\":\"{kty}\",\"n\":\"{n}\"}}")))); }
public void SetSignature(byte[] signature) { Signature = Base64Url.Encode(signature); }
/// <summary> /// Creates the JWK document. /// </summary> public virtual async Task <IEnumerable <Models.JsonWebKey> > CreateJwkDocumentAsync() { var webKeys = new List <Models.JsonWebKey>(); foreach (var key in await Keys.GetValidationKeysAsync()) { if (key.Key is X509SecurityKey x509Key) { var cert64 = Convert.ToBase64String(x509Key.Certificate.RawData); var thumbprint = Base64Url.Encode(x509Key.Certificate.GetCertHash()); if (x509Key.PublicKey is RSA rsa) { var parameters = rsa.ExportParameters(false); var exponent = Base64Url.Encode(parameters.Exponent); var modulus = Base64Url.Encode(parameters.Modulus); var rsaJsonWebKey = new Models.JsonWebKey { kty = "RSA", use = "sig", kid = x509Key.KeyId, x5t = thumbprint, e = exponent, n = modulus, x5c = new[] { cert64 }, alg = key.SigningAlgorithm }; webKeys.Add(rsaJsonWebKey); } else if (x509Key.PublicKey is ECDsa ecdsa) { var parameters = ecdsa.ExportParameters(false); var x = Base64Url.Encode(parameters.Q.X); var y = Base64Url.Encode(parameters.Q.Y); var ecdsaJsonWebKey = new Models.JsonWebKey { kty = "EC", use = "sig", kid = x509Key.KeyId, x5t = thumbprint, x = x, y = y, crv = CryptoHelper.GetCrvValueFromCurve(parameters.Curve), x5c = new[] { cert64 }, alg = key.SigningAlgorithm }; webKeys.Add(ecdsaJsonWebKey); } else { throw new InvalidOperationException($"key type: {x509Key.PublicKey.GetType().Name} not supported."); } } else if (key.Key is RsaSecurityKey rsaKey) { var parameters = rsaKey.Rsa?.ExportParameters(false) ?? rsaKey.Parameters; var exponent = Base64Url.Encode(parameters.Exponent); var modulus = Base64Url.Encode(parameters.Modulus); var webKey = new Models.JsonWebKey { kty = "RSA", use = "sig", kid = rsaKey.KeyId, e = exponent, n = modulus, alg = key.SigningAlgorithm }; webKeys.Add(webKey); } else if (key.Key is ECDsaSecurityKey ecdsaKey) { var parameters = ecdsaKey.ECDsa.ExportParameters(false); var x = Base64Url.Encode(parameters.Q.X); var y = Base64Url.Encode(parameters.Q.Y); var ecdsaJsonWebKey = new Models.JsonWebKey { kty = "EC", use = "sig", kid = ecdsaKey.KeyId, x = x, y = y, crv = CryptoHelper.GetCrvValueFromCurve(parameters.Curve), alg = key.SigningAlgorithm }; webKeys.Add(ecdsaJsonWebKey); } else if (key.Key is JsonWebKey jsonWebKey) { var webKey = new Models.JsonWebKey { kty = jsonWebKey.Kty, use = jsonWebKey.Use ?? "sig", kid = jsonWebKey.Kid, x5t = jsonWebKey.X5t, e = jsonWebKey.E, n = jsonWebKey.N, x5c = jsonWebKey.X5c?.Count == 0 ? null : jsonWebKey.X5c.ToArray(), alg = jsonWebKey.Alg, crv = jsonWebKey.Crv, x = jsonWebKey.X, y = jsonWebKey.Y }; webKeys.Add(webKey); } } return(webKeys); }
public void ConfigureServices(IServiceCollection services) { services.AddHttpClient(); services.AddMvc(options => { var global = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(global)); }).SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1); services.AddAuthentication(options => { options.DefaultScheme = "cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("cookies", options => { options.AccessDeniedPath = "/account/denied"; }) .AddAutomaticTokenManagement() .AddOpenIdConnect("oidc", options => { options.Authority = "https://demo.identityserver.io"; options.ClientId = "native.code"; options.ClientSecret = "secret"; options.ResponseType = "code"; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("email"); options.Scope.Add("offline_access"); options.Scope.Add("api"); options.ClaimActions.MapAllExcept("iss", "nbf", "exp", "aud", "nonce", "iat", "c_hash", "at_hash"); options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = "role" }; options.Events.OnRedirectToIdentityProvider = context => { // only modify requests to the authorization endpoint if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication) { // generate code_verifier var codeVerifier = CryptoRandom.CreateUniqueId(32); // store codeVerifier for later use context.Properties.Items.Add(OidcConstants.TokenRequest.CodeVerifier, codeVerifier); // create code_challenge string codeChallenge; using (var sha256 = SHA256.Create()) { var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); codeChallenge = Base64Url.Encode(challengeBytes); } // add code_challenge and code_challenge_method to request context.ProtocolMessage.Parameters.Add(OidcConstants.AuthorizeRequest.CodeChallenge, codeChallenge); context.ProtocolMessage.Parameters.Add(OidcConstants.AuthorizeRequest.CodeChallengeMethod, OidcConstants.CodeChallengeMethods.Sha256); } return(Task.CompletedTask); }; options.Events.OnAuthorizationCodeReceived = context => { // only when authorization code is being swapped for tokens if (context.TokenEndpointRequest?.GrantType == OpenIdConnectGrantTypes.AuthorizationCode) { // get stored code_verifier if (context.Properties.Items.TryGetValue(OidcConstants.TokenRequest.CodeVerifier, out var codeVerifier)) { // add code_verifier to token request context.TokenEndpointRequest.Parameters.Add(OidcConstants.TokenRequest.CodeVerifier, codeVerifier); } } return(Task.CompletedTask); }; }); }
public void SetProtected(JsonWebSignatureProtected @protected) { Protected = Base64Url.Encode(JsonConvert.SerializeObject(@protected)); }
public FinalizeOrderRequest(string url, byte[] csr) { Url = url ?? throw new ArgumentNullException(nameof(url)); Csr = Base64Url.Encode(csr); }
/// <summary> /// Converts a JSON web key to a URL safe string. /// </summary> /// <param name="key">The key.</param> /// <returns></returns> public static string ToJwkString(this JsonWebKey key) { var json = JsonConvert.SerializeObject(key); return(Base64Url.Encode(Encoding.UTF8.GetBytes(json))); }
public JsonWebEncyption(string message, JsonHeader protectedHeader, string aad = null) { _message = Base64Url.Encode(message); _protectedHeader = protectedHeader; _aad = aad != null?Base64Url.Encode(aad) : null; }
/// <summary> /// Calculates the key id for a given x509 certificate /// </summary> /// <param name="certificate"></param> /// <returns>kid</returns> public Task <string> GetKidAsync(X509Certificate2 certificate) { return(Task.FromResult(Base64Url.Encode(certificate.GetCertHash()))); }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = "cookie"; options.DefaultSignInScheme = "cookie"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("cookie") .AddOpenIdConnect("oidc", options => { options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; // dev only options.ClientId = "pkce_client"; options.ClientSecret = "acf2ec6fb01a4b698ba240c2b10a0243"; options.ResponseType = "code"; options.ResponseMode = "form_post"; options.CallbackPath = "/signin-oidc"; options.Events.OnRedirectToIdentityProvider = context => { // only modify requests to the authorization endpoint if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication) { // generate code_verifier var codeVerifier = CryptoRandom.CreateUniqueId(32); // store codeVerifier for later use context.Properties.Items.Add("code_verifier", codeVerifier); // create code_challenge string codeChallenge; using (var sha256 = SHA256.Create()) { var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); codeChallenge = Base64Url.Encode(challengeBytes); } // add code_challenge and code_challenge_method to request context.ProtocolMessage.Parameters.Add("code_challenge", codeChallenge); context.ProtocolMessage.Parameters.Add("code_challenge_method", "S256"); } return(Task.CompletedTask); }; options.Events.OnAuthorizationCodeReceived = context => { // only when authorization code is being swapped for tokens if (context.TokenEndpointRequest?.GrantType == OpenIdConnectGrantTypes.AuthorizationCode) { // get stored code_verifier if (context.Properties.Items.TryGetValue("code_verifier", out var codeVerifier)) { // add code_verifier to token request context.TokenEndpointRequest.Parameters.Add("code_verifier", codeVerifier); } } return(Task.CompletedTask); }; }); }
public static string GetBase64UrlEncodedJson <T>(T instance) { byte[] utf8Bytes = JsonSerializer.SerializeToUtf8Bytes(instance, JSO.IgnoreNullValues); return(Base64Url.Encode(utf8Bytes)); }
/// <summary> /// Add custom authentication /// </summary> /// <param name="services">IServiceCollection</param> /// <param name="appSettings">AppSettings</param> /// <returns>Self</returns> public static IServiceCollection AddOpenIdAuthentication(this IServiceCollection services, AppSettings appSettings) { IdentityModelEventSource.ShowPII = true; JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; // "Cookies" options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; // "Cookies" options.DefaultChallengeScheme = "oidc"; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) .AddOpenIdConnect("oidc", options => { const string CODE_VERIFIER_KEY = "code_verifier"; const string CODE_CHALLENGE_KEY = "code_challenge"; const string CODE_CHALLENGE_METHOD_KEY = "code_challenge_method"; // Get config values from AppSetting file string oidcServerBaseUrl = appSettings?.Host.OidcServer; bool isRequireHttpsMetadata = !string.IsNullOrEmpty(oidcServerBaseUrl) && oidcServerBaseUrl.StartsWith("https"); options.Authority = string.IsNullOrEmpty(oidcServerBaseUrl) ? "https://localhost:6001" : oidcServerBaseUrl; options.RequireHttpsMetadata = isRequireHttpsMetadata; options.MetadataAddress = $"{oidcServerBaseUrl}/.well-known/openid-configuration"; options.BackchannelHttpHandler = AuthMetadataUtils.GetHttpHandler(); options.ClientId = "PkceCodeBackend"; options.ClientSecret = "secret"; options.ResponseType = "code"; options.ResponseMode = "form_post"; options.CallbackPath = "/signin-oidc"; options.SaveTokens = true; options.Scope.Add(appSettings?.AuthOptions?.Audience); options.Scope.Add("offline_access"); // Get refresh token options.Events.OnRedirectToIdentityProvider = context => { // only modify requests to the authorization endpoint if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication) { // generate code_verifier var codeVerifier = CryptoRandom.CreateUniqueId(32); // store codeVerifier for later use context.Properties.Items.Remove(CODE_VERIFIER_KEY); context.Properties.Items.Add(CODE_VERIFIER_KEY, codeVerifier); // create code_challenge string codeChallenge; using (var sha256 = SHA256.Create()) { var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); codeChallenge = Base64Url.Encode(challengeBytes); } // add code_challenge and code_challenge_method to request context.ProtocolMessage.Parameters.Remove(CODE_CHALLENGE_KEY); context.ProtocolMessage.Parameters.Remove(CODE_CHALLENGE_METHOD_KEY); context.ProtocolMessage.Parameters.Add(CODE_CHALLENGE_KEY, codeChallenge); context.ProtocolMessage.Parameters.Add(CODE_CHALLENGE_METHOD_KEY, "S256"); } return(Task.CompletedTask); }; options.Events.OnAuthorizationCodeReceived = context => { // only when authorization code is being swapped for tokens if (context.TokenEndpointRequest?.GrantType == OpenIdConnectGrantTypes.AuthorizationCode) { // get stored code_verifier if (context.Properties.Items.TryGetValue(CODE_VERIFIER_KEY, out var codeVerifier)) { // add code_verifier to token request context.TokenEndpointRequest.Parameters.Add(CODE_VERIFIER_KEY, codeVerifier); } } return(Task.CompletedTask); }; }); return(services); }
public void ConfigureServices(IServiceCollection services) { services.AddCors(); services.AddMvc(); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = "cookie"; options.DefaultSignInScheme = "cookie"; options.DefaultChallengeScheme = "oidc"; }).AddIdentityServerAuthentication(options => { options.Authority = "http://localhost:5000"; // auth server base endpoint (will use to search for disco doc) options.ApiName = "demo_api"; // required audience of access tokens options.RequireHttpsMetadata = false; // dev only! }) .AddCookie("cookie") .AddOpenIdConnect("oidc", options => { options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; // dev only options.ClientId = "demo_api_swagger"; options.ClientSecret = "acf2ec6fb01a4b698ba240c2b10a0243"; options.ResponseType = "code"; options.ResponseMode = "form_post"; options.CallbackPath = "/oauth2-redirect.html"; options.Events.OnRedirectToIdentityProvider = context => { // only modify requests to the authorization endpoint if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication) { // generate code_verifier var codeVerifier = CryptoRandom.CreateUniqueId(32); // store codeVerifier for later use context.Properties.Items.Add("code_verifier", codeVerifier); // create code_challenge string codeChallenge; using (var sha256 = SHA256.Create()) { var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); codeChallenge = Base64Url.Encode(challengeBytes); } // add code_challenge and code_challenge_method to request context.ProtocolMessage.Parameters.Add("code_challenge", codeChallenge); context.ProtocolMessage.Parameters.Add("code_challenge_method", "S256"); } return(Task.CompletedTask); }; options.Events.OnAuthorizationCodeReceived = context => { // only when authorization code is being swapped for tokens if (context.TokenEndpointRequest?.GrantType == OpenIdConnectGrantTypes.AuthorizationCode) { // get stored code_verifier if (context.Properties.Items.TryGetValue("code_verifier", out var codeVerifier)) { // add code_verifier to token request context.TokenEndpointRequest.Parameters.Add("code_verifier", codeVerifier); } } return(Task.CompletedTask); }; }); services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new Info { Title = "Protected API", Version = "v1" }); options.AddSecurityDefinition("oauth2", new OAuth2Scheme { Flow = "authorizationCode", // just get token via browser (suitable for swagger SPA) AuthorizationUrl = "http://localhost:5000/connect/authorize", TokenUrl = "http://localhost:5000/connect/token", Scopes = new Dictionary <string, string> { { "demo_api", "Demo API - full access" } }, }); options.OperationFilter <AuthorizeCheckOperationFilter>(); // Required to use access token }); }
public static byte[] EncodeSkinJwt(CngKey newKey) { byte[] t = ImportECDsaCngKeyFromCngKey(newKey.Export(CngKeyBlobFormat.EccPrivateBlob)); CngKey tk = CngKey.Import(t, CngKeyBlobFormat.EccPrivateBlob); ECDiffieHellmanCng ecKey = new ECDiffieHellmanCng(newKey); ecKey.HashAlgorithm = CngAlgorithm.Sha256; ecKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; var b64Key = Base64Url.Encode(ecKey.PublicKey.ToDerEncoded()); Skin skin = new Skin { Slim = false, SkinData = Encoding.Default.GetBytes(new string('Z', 8192)), SkinId = "Standard_Custom" }; string skin64 = Convert.ToBase64String(skin.SkinData); //{ // "ADRole": 2, // "ClientRandomId": 4670680294016914277, // "CurrentInputMode": 2, // "DefaultInputMode": 2, // "DeviceModel": "SAMSUNG GT-P5210", // "DeviceOS": 1, // "GameVersion": "1.1.0.4", // "GuiScale": 0, // "LanguageCode": "en_US", // "ServerAddress": "yodamine.com:19132", // "SkinData": "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79m9/+zUuP/v2r//8t/I//Ldwv/y3cL/7NS4/+zUuP/v2r//7NS4//LfyP/y3cL/8t3C/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkQSz/ZEEs/2RBLP9kQSz/KCgo/ygoKP8oKCj/KCgo/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6J1M/3q1d/96r3f/2LqU/+vTs//YupT/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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", // "SkinId": "Standard_Alex", // "TenantId": "", // "UIProfile": 1 //} string skinData = $@" {{ ""ADRole"": 0, ""ClientRandomId"": {new Random().Next()}, ""CurrentInputMode"": 1, ""DefaultInputMode"": 1, ""DeviceModel"": ""MINET CLIENT"", ""DeviceOS"": 7, ""GameVersion"": ""1.2.0.15"", ""GuiScale"": 0, ""LanguageCode"": ""en_US"", ""ServerAddress"": ""yodamine.com:19132"", ""SkinData"": ""{skin64}"", ""SkinId"": ""{skin.SkinId}"", ""TenantId"": ""75a3f792-a259-4428-9a8d-4e832fb960e4"", ""UIProfile"": 0 }}"; string val = JWT.Encode(skinData, tk, JwsAlgorithm.ES384, new Dictionary <string, object> { { "x5u", b64Key } }); return(Encoding.UTF8.GetBytes(val)); }
void IJsonSerializable.WriteProperties(Utf8JsonWriter json) { json.WriteString(s_valuePropertyNameBytes, Base64Url.Encode(Value)); }
public static string EncodeBase64Url(this byte[] input) { return(Base64Url.Encode(input)); }
/// <summary> /// Creates the JWK document. /// </summary> public virtual async Task <IEnumerable <Models.JsonWebKey> > CreateJwkDocumentAsync() { var webKeys = new List <Models.JsonWebKey>(); var signingCredentials = await Keys.GetSigningCredentialsAsync(); var algorithm = signingCredentials?.Algorithm ?? Constants.SigningAlgorithms.RSA_SHA_256; foreach (var key in await Keys.GetValidationKeysAsync()) { if (key is X509SecurityKey x509Key) { var cert64 = Convert.ToBase64String(x509Key.Certificate.RawData); var thumbprint = Base64Url.Encode(x509Key.Certificate.GetCertHash()); var pubKey = x509Key.PublicKey as RSA; var parameters = pubKey.ExportParameters(false); var exponent = Base64Url.Encode(parameters.Exponent); var modulus = Base64Url.Encode(parameters.Modulus); var webKey = new Models.JsonWebKey { kty = "RSA", use = "sig", kid = x509Key.KeyId, x5t = thumbprint, e = exponent, n = modulus, x5c = new[] { cert64 }, alg = algorithm }; webKeys.Add(webKey); continue; } if (key is RsaSecurityKey rsaKey) { var parameters = rsaKey.Rsa?.ExportParameters(false) ?? rsaKey.Parameters; var exponent = Base64Url.Encode(parameters.Exponent); var modulus = Base64Url.Encode(parameters.Modulus); var webKey = new Models.JsonWebKey { kty = "RSA", use = "sig", kid = rsaKey.KeyId, e = exponent, n = modulus, alg = algorithm }; webKeys.Add(webKey); } if (key is JsonWebKey jsonWebKey) { var webKey = new Models.JsonWebKey { kty = jsonWebKey.Kty, use = jsonWebKey.Use ?? "sig", kid = jsonWebKey.Kid, x5t = jsonWebKey.X5t, e = jsonWebKey.E, n = jsonWebKey.N, x5c = jsonWebKey.X5c?.Count == 0 ? null : jsonWebKey.X5c.ToArray(), alg = jsonWebKey.Alg }; webKeys.Add(webKey); } } return(webKeys); }
public void Configuration(IAppBuilder app) { app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = "cookie" }); app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { ClientId = "mvc.owin", Authority = "http://localhost:5000", RedirectUri = "http://localhost:5001/", Scope = "openid profile api1", SignInAsAuthenticationType = "cookie", RequireHttpsMetadata = false, UseTokenLifetime = false, RedeemCode = true, SaveTokens = true, ClientSecret = "secret", ResponseType = "code", ResponseMode = "query", Notifications = new OpenIdConnectAuthenticationNotifications { RedirectToIdentityProvider = n => { if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication) { // set PKCE parameters var codeVerifier = CryptoRandom.CreateUniqueId(32); string codeChallenge; using (var sha256 = SHA256.Create()) { var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); codeChallenge = Base64Url.Encode(challengeBytes); } n.ProtocolMessage.SetParameter("code_challenge", codeChallenge); n.ProtocolMessage.SetParameter("code_challenge_method", "S256"); // remember code_verifier (adapted from OWIN nonce cookie) RememberCodeVerifier(n, codeVerifier); } return(Task.CompletedTask); }, AuthorizationCodeReceived = n => { // get code_verifier var codeVerifier = RetrieveCodeVerifier(n); // attach code_verifier n.TokenEndpointRequest.SetParameter("code_verifier", codeVerifier); return(Task.CompletedTask); } } }); }
//For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 public void ConfigureAuth(IAppBuilder app) { // Workaround Middleware for Katana Bug #197 // Bug fix: Do not attempt to update cookies if headers have been sent. // https://github.com/Sustainsys/owin-cookie-saver app.UseKentorOwinCookieSaver(); app.UseCookieAuthentication(new CookieAuthenticationOptions { // uses the AuthenticationType defined by OpenIDConnect middleware. AuthenticationType = CookieAuthenticationDefaults.AuthenticationType, ExpireTimeSpan = TimeSpan.FromMinutes(30), SlidingExpiration = true }); // Authorization Code Flow with Proof Key for Code Exchange (PKCE) // https://auth0.com/docs/flows/concepts/auth-code-pkce app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { Authority = "https://idp.example.com/", ClientId = "myclient", RedirectUri = "https://localhost:44361", CallbackPath = new PathString("/"), // *** Critical to prevent infinite loop, when running in server *** Also dont forget to include virtual diretory name, if you have one. PostLogoutRedirectUri = "https://localhost:44361", // indicates idp to return authorization code. id_token is not returned, providing us the extra layer of security. ResponseType = OpenIdConnectResponseType.Code, // indicates idp to return code in querystring ResponseMode = OpenIdConnectResponseMode.Query, Scope = "openid profile partyAPI platformAPI offline_access", // this value determines the value of the AuthenticationType property of the ClaimsPrincipal/ClaimsIdentity generated from the incoming token. // if the cookie middleware finds this in an AuthenticationResponseGrant, that’s what the cookie middleware uses to determine whether such ClaimsPrincipal/ ClaimsIdentity should be used for creating a session. SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType, // default is true, set it to false to decouple the session validity time from the token expires time. UseTokenLifetime = false, // default is true, but we explicitly set it, so that when working with local idp, we can change to false. RequireHttpsMetadata = true, RedeemCode = true, // required for PKCE SaveTokens = true, Notifications = new OpenIdConnectAuthenticationNotifications { RedirectToIdentityProvider = async n => { if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication) { // generate code verifier and code challenge var codeVerifier = CryptoRandom.CreateUniqueId(32); string codeChallenge; using (var sha256 = SHA256.Create()) { var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); codeChallenge = Base64Url.Encode(challengeBytes); } // set code_challenge parameter on authorization request n.ProtocolMessage.SetParameter("code_challenge", codeChallenge); n.ProtocolMessage.SetParameter("code_challenge_method", "S256"); // remember code verifier in cookie (adapted from OWIN nonce cookie) n.RememberCodeVerifier(codeVerifier); } // if signing out, add the id_token_hint if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout) { var result = await n.OwinContext.Authentication.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationType); var idTokenHint = result.Properties.Dictionary[OpenIdConnectParameterNames.IdToken]; if (idTokenHint != null) { n.ProtocolMessage.IdTokenHint = idTokenHint; } } await Task.FromResult(0); }, AuthorizationCodeReceived = async n => { // get code verifier from cookie var codeVerifier = n.RetrieveCodeVerifier(); // attach code_verifier on token request n.TokenEndpointRequest.SetParameter("code_verifier", codeVerifier); await Task.FromResult(0); }, // after authentication, inject custom agent claims to the OWIN Identity SecurityTokenValidated = async n => { var accessToken = n.ProtocolMessage.AccessToken; // add custom claims var claimsIdentify = n.AuthenticationTicket.Identity; var customeClaims = new List <Claim> { new Claim(ClaimTypes.Role, "SystemAdmin"), }; claimsIdentify.AddClaims(customeClaims); await Task.FromResult(0); } } }); }
public void JwtHeaderEncode(string base64, string raw) { var encode = Base64Url.Encode(raw); encode.Should().Be(base64); }
/// <summary> /// Finalize order. /// </summary> /// <param name="AccountLocation">Account location.</param> /// <param name="FinalizeLocation">Finalize location.</param> /// <param name="CertificateRequest">Certificate request.</param> /// <returns>New order object.</returns> public async Task <AcmeOrder> FinalizeOrder(Uri AccountLocation, Uri FinalizeLocation, CertificateRequest CertificateRequest) { byte[] CSR = CertificateRequest.BuildCSR(); AcmeResponse Response = await this.POST(FinalizeLocation, AccountLocation, new KeyValuePair <string, object>("csr", Base64Url.Encode(CSR))); return(new AcmeOrder(this, AccountLocation, Response.Location, Response.Payload, Response.ResponseMessage)); }
private string BodyBase64() { return(Base64Url.Encode(Bytes.FromString(Configuration.Serializer.Serialize(this.BodyContent)))); }
public void TestJWTHandling() { CngKey newKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP384, null, new CngKeyCreationParameters() { ExportPolicy = CngExportPolicies.AllowPlaintextExport, KeyUsage = CngKeyUsages.AllUsages }); byte[] t = CryptoUtils.ImportECDsaCngKeyFromCngKey(newKey.Export(CngKeyBlobFormat.EccPrivateBlob)); CngKey tk = CngKey.Import(t, CngKeyBlobFormat.EccPrivateBlob); Assert.AreEqual(CngAlgorithmGroup.ECDsa, tk.AlgorithmGroup); ECDiffieHellmanCng ecKey = new ECDiffieHellmanCng(newKey); ecKey.HashAlgorithm = CngAlgorithm.Sha256; ecKey.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash; var b64Key = Base64Url.Encode(ecKey.PublicKey.GetDerEncoded()); string test = $@" {{ ""exp"": 1464983845, ""extraData"": {{ ""displayName"": ""gurunx"", ""identity"": ""af6f7c5e -fcea-3e43-bf3a-e005e400e578"" }}, ""identityPublicKey"": ""{b64Key}"", ""nbf"": 1464983844 }}"; CertificateData certificateData = new CertificateData { Exp = 1464983845, ExtraData = new ExtraData { DisplayName = "gurun", Identity = "af6f7c5e -fcea-3e43-bf3a-e005e400e578", }, IdentityPublicKey = b64Key, Nbf = 1464983844, }; JWT.JsonMapper = new NewtonsoftMapper(); string val = JWT.Encode(certificateData, tk, JwsAlgorithm.ES384, new Dictionary <string, object> { { "x5u", b64Key } }); Console.WriteLine(val); Assert.AreEqual(b64Key, JWT.Headers(val)["x5u"]); //Assert.AreEqual("", string.Join(";", JWT.Headers(val))); //Assert.AreEqual(test, JWT.Payload(val)); Console.WriteLine(JWT.Payload(val)); IDictionary <string, dynamic> headers = JWT.Headers(val); if (headers.ContainsKey("x5u")) { string certString = headers["x5u"]; // Validate CngKey importKey = CryptoUtils.ImportECDsaCngKeyFromString(certString); CertificateData data = JWT.Decode <CertificateData>(val, importKey); Assert.NotNull(data); Assert.AreEqual(certificateData.Exp, data.Exp); Assert.AreEqual(certificateData.IdentityPublicKey, data.IdentityPublicKey); Assert.AreEqual(certificateData.Nbf, data.Nbf); Assert.NotNull(data.ExtraData); Assert.AreEqual(certificateData.ExtraData.DisplayName, data.ExtraData.DisplayName); Assert.AreEqual(certificateData.ExtraData.Identity, data.ExtraData.Identity); } }
private string SignatureBase64() { return(Base64Url.Encode(this.SignatureData)); }
public void SetPayload(object payload) { Payload = Base64Url.Encode(JsonConvert.SerializeObject(payload)); }
public string Base64UrlEncode(byte[] arg) { return(Base64Url.Encode(arg)); }
private static string CreateUrl(string endpoint , string clientId , string scope , string redirectUri , string responseType , string responseMode , string maxAge , string codeVerifier , string state = null , string prompt = null , string nonce = null) { string str = string.Format("{0}?client_id={1}&scope={2}&redirect_uri={3}&response_type={4}" , endpoint , ApplicationSettings.UrlEncode(clientId) , ApplicationSettings.UrlEncode(scope) , ApplicationSettings.UrlEncode(redirectUri) , ApplicationSettings.UrlEncode(responseType)); var codeChallengeMethod = ApplicationSettings.CodeChallengeMethod; if (responseType.Contains("code") && codeChallengeMethod.ToLower() != "none") { var codeChallenge = codeVerifier; if (codeChallengeMethod == "S256") { using (var sha256 = SHA256.Create()) { var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); codeChallenge = Base64Url.Encode(challengeBytes); } } str = string.Format("{0}&code_challenge={1}&code_challenge_method={2}", str, ApplicationSettings.UrlEncode(codeChallenge), ApplicationSettings.UrlEncode(codeChallengeMethod)); } if (ApplicationSettings.UsingRequestObject != "true") { if (!string.IsNullOrEmpty(maxAge)) { str = string.Format("{0}&max_age={1}", str, ApplicationSettings.UrlEncode(maxAge)); } if (!string.IsNullOrEmpty(responseMode)) { str = string.Format("{0}&response_mode={1}", str, ApplicationSettings.UrlEncode(responseMode)); } if (!string.IsNullOrWhiteSpace(state)) { str = string.Format("{0}&state={1}", str, ApplicationSettings.UrlEncode(state)); } if (!string.IsNullOrWhiteSpace(prompt)) { str = string.Format("{0}&prompt={1}", str, ApplicationSettings.UrlEncode(prompt)); } if (!string.IsNullOrWhiteSpace(nonce)) { str = string.Format("{0}&nonce={1}", str, ApplicationSettings.UrlEncode(nonce)); } } else { var claimsIdentify = new ClaimsIdentity(); claimsIdentify.AddClaim(new Claim("client_id", clientId)); claimsIdentify.AddClaim(new Claim("response_type", responseType)); claimsIdentify.AddClaim(new Claim("scope", scope)); claimsIdentify.AddClaim(new Claim("redirect_uri", redirectUri)); claimsIdentify.AddClaim(new Claim("max_age", maxAge)); claimsIdentify.AddClaim(new Claim("response_mode", responseMode)); claimsIdentify.AddClaim(new Claim("state", state)); claimsIdentify.AddClaim(new Claim("prompt", prompt)); claimsIdentify.AddClaim(new Claim("nonce", nonce)); string token; if (ApplicationSettings.SignRequestObject == "true") { var securityTokenDescriptor = new SecurityTokenDescriptor { Subject = claimsIdentify, Issuer = clientId, IssuedAt = DateTime.UtcNow, Expires = DateTime.UtcNow.AddYears(10), Audience = endpoint }; var signingCertificate = LoadCertificate(StoreName.My, StoreLocation.LocalMachine, ApplicationSettings.ClientCertificate); securityTokenDescriptor.SigningCredentials = new X509SigningCredentials(signingCertificate, "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"); token = new JwtSecurityTokenHandler().CreateEncodedJwt(securityTokenDescriptor); } else { var jwtSecurityToken = new JwtSecurityTokenHandler().CreateJwtSecurityToken(clientId, endpoint, claimsIdentify, DateTime.UtcNow, DateTime.UtcNow.AddYears(10), DateTime.UtcNow); token = "eyJhbGciOiJub25lIn0" + "." + jwtSecurityToken.EncodedPayload + "."; } str += "&request=" + token; } return(str); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); services.AddControllersWithViews(); services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.Authority = "http://localhost:8000"; options.RequireHttpsMetadata = false; options.ClientId = "mvc"; options.ClientSecret = "mvc-secret"; options.ResponseType = "code"; options.UsePkce = true; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.Scope.Add("address"); options.ClaimActions.MapJsonKey("address", "address"); options.Scope.Add("security_info"); options.ClaimActions.MapJsonKey("sec_zone", "sec_zone"); options.ClaimActions.MapJsonKey("sec_exp", "sec_exp"); options.Scope.Add("offline_access"); options.Events = new OpenIdConnectEvents { OnRemoteFailure = ctx => { WriteLine(".....OnRemoteFailure"); WriteLine(ctx.Failure.Message); ctx.HandleResponse(); return(Task.FromResult(0)); }, OnRedirectToIdentityProvider = ctx => { // only modify requests to the authorization endpoint if (ctx.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication) { // generate code_verifier var codeVerifier = CryptoRandom.CreateUniqueId(32); // store codeVerifier for later use if (ctx.Properties.Items.ContainsKey("code_verifier")) { ctx.Properties.Items["code_verifier"] = codeVerifier; } else { ctx.Properties.Items.Add("code_verifier", codeVerifier); } // create code_challenge string codeChallenge; using (var sha256 = SHA256.Create()) { var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); codeChallenge = Base64Url.Encode(challengeBytes); } // add code_challenge and code_challenge_method to request if (ctx.ProtocolMessage.Parameters.ContainsKey("code_challenge")) { ctx.ProtocolMessage.Parameters["code_challenge"] = codeChallenge; ctx.ProtocolMessage.Parameters["code_challenge_method"] = "S256"; } else { ctx.ProtocolMessage.Parameters.Add("code_challenge", codeChallenge); ctx.ProtocolMessage.Parameters.Add("code_challenge_method", "S256"); } } return(Task.CompletedTask); }, OnAuthorizationCodeReceived = ctx => { // only when authorization code is being swapped for tokens if (ctx.TokenEndpointRequest?.GrantType == OpenIdConnectGrantTypes.AuthorizationCode) { // get stored code_verifier if (ctx.Properties.Items.TryGetValue("code_verifier", out var codeVerifier)) { // add code_verifier to token request ctx.TokenEndpointRequest.Parameters.Add("code_verifier", codeVerifier); } } return(Task.CompletedTask); } }; });
private async Task <IEndpointResult> ExecuteJwksAsync(HttpContext context) { _logger.LogDebug("Start key discovery request"); if (_options.DiscoveryOptions.ShowKeySet == false) { _logger.LogInformation("Key discovery disabled. 404."); return(new StatusCodeResult(404)); } var webKeys = new List <Models.JsonWebKey>(); foreach (var key in await _keys.GetKeysAsync()) { // todo //if (!(key is AsymmetricSecurityKey) && // !key.IsSupportedAlgorithm(SecurityAlgorithms.RsaSha256Signature)) //{ // var error = "signing key is not asymmetric and does not support RS256"; // _logger.LogError(error); // throw new InvalidOperationException(error); //} var x509Key = key as X509SecurityKey; if (x509Key != null) { var cert64 = Convert.ToBase64String(x509Key.Certificate.RawData); var thumbprint = Base64Url.Encode(x509Key.Certificate.GetCertHash()); var pubKey = x509Key.PublicKey as RSA; var parameters = pubKey.ExportParameters(false); var exponent = Base64Url.Encode(parameters.Exponent); var modulus = Base64Url.Encode(parameters.Modulus); var webKey = new Models.JsonWebKey { kty = "RSA", use = "sig", kid = x509Key.KeyId, x5t = thumbprint, e = exponent, n = modulus, x5c = new[] { cert64 } }; webKeys.Add(webKey); continue; } var rsaKey = key as RsaSecurityKey; if (rsaKey != null) { var parameters = rsaKey.Rsa.ExportParameters(false); var exponent = Base64Url.Encode(parameters.Exponent); var modulus = Base64Url.Encode(parameters.Modulus); var webKey = new Models.JsonWebKey { kty = "RSA", use = "sig", kid = rsaKey.KeyId, e = exponent, n = modulus, }; webKeys.Add(webKey); } } return(new JsonWebKeysResult(webKeys)); }
internal string GetKid() { RSAParameters parameters = mKey.ExportParameters(false); return(Thumbprint("RSA", Base64Url.Encode(parameters.Exponent), Base64Url.Encode(parameters.Modulus)).Substring(0, 5)); }