public static async Task <ProviderInformation> LoadFromMetadataAsync(string authority) { var client = new HttpClient(); var url = authority.EnsureTrailingSlash() + ".well-known/openid-configuration"; var json = await client.GetStringAsync(url); var doc = JsonConvert.DeserializeObject <Dictionary <string, object> >(json); var info = new ProviderInformation { IssuerName = doc["issuer"].ToString(), AuthorizeEndpoint = doc["authorization_endpoint"].ToString(), TokenEndpoint = doc["token_endpoint"].ToString(), }; if (doc.ContainsKey("end_session_endpoint")) { info.EndSessionEndpoint = doc["end_session_endpoint"].ToString(); } if (doc.ContainsKey("userinfo_endpoint")) { info.UserInfoEndpoint = doc["userinfo_endpoint"].ToString(); } // parse web key set var jwksUri = doc["jwks_uri"].ToString(); var jwks = await client.GetStringAsync(jwksUri); info.KeySet = new JsonWebKeySet(jwks); return(info); }
/// <summary> /// Initializes a new instance of the <see cref="OidcClientOptions"/> class. /// </summary> /// <param name="authority">The authority.</param> /// <param name="clientId">The client identifier.</param> /// <param name="clientSecret">The client secret.</param> /// <param name="scope">The scope.</param> /// <param name="redirectUri">The redirect URI.</param> /// <param name="webView">The web view.</param> /// <param name="validator">The validator.</param> /// <exception cref="System.ArgumentNullException">authority</exception> public OidcClientOptions(string authority, string clientId, string clientSecret, string scope, string redirectUri, IWebView webView = null, IIdentityTokenValidator validator = null) : this(clientId, clientSecret, scope, redirectUri, webView, validator) { if (string.IsNullOrWhiteSpace(authority)) { throw new ArgumentNullException(nameof(authority)); } _providerInfo = new Lazy <Task <ProviderInformation> >(async() => await ProviderInformation.LoadFromMetadataAsync(authority, ValidateIssuerName, BackchannelHandler, (int)BackchannelTimeout.TotalSeconds)); }
/// <summary> /// Initializes a new instance of the <see cref="OidcClientOptions"/> class. /// </summary> /// <param name="info">The provider information.</param> /// <param name="clientId">The client id.</param> /// <param name="clientSecret">The client secret.</param> /// <param name="scope">The scope.</param> /// <param name="redirectUri">The redirect URI.</param> /// <param name="webView">The web view.</param> /// <param name="validator">The validator.</param> /// <exception cref="System.ArgumentNullException">info</exception> public OidcClientOptions(ProviderInformation info, string clientId, string clientSecret, string scope, string redirectUri, IWebView webView = null, IIdentityTokenValidator validator = null) : this(clientId, clientSecret, scope, redirectUri, webView, validator) { if (info == null) { throw new ArgumentNullException(nameof(info)); } info.Validate(); _providerInfo = new Lazy <Task <ProviderInformation> >(() => Task.FromResult(info)); }
public async Task <IdentityTokenValidationResult> ValidateAsync(string identityToken, string clientId, ProviderInformation providerInformation) { var client = new HttpClient(); var form = new Dictionary <string, string> { { "token", identityToken }, { "client_id", clientId } }; var response = await client.PostAsync( new Uri(_endpoint), new FormUrlEncodedContent(form)); if (!response.IsSuccessStatusCode) { return(new IdentityTokenValidationResult { Error = response.ReasonPhrase }); } var json = JObject.Parse(await response.Content.ReadAsStringAsync()); return(new IdentityTokenValidationResult { Claims = json.ToClaims(), SignatureAlgorithm = "RS256" }); }
/// <summary> /// Loads from metadata. /// </summary> /// <param name="authority">The authority.</param> /// <param name="validateIssuerName">if set to <c>true</c> the issuer name gets validated against the authority.</param> /// <returns>Provider information</returns> /// <exception cref="System.InvalidOperationException"> /// </exception> public static async Task <ProviderInformation> LoadFromMetadataAsync(string authority, bool validateIssuerName = true, HttpMessageHandler innerHandler = null, int timeout = 30) { var handler = innerHandler ?? new HttpClientHandler(); var client = new HttpClient(handler); client.Timeout = TimeSpan.FromSeconds(timeout); var url = authority.EnsureTrailingSlash() + ".well-known/openid-configuration"; Logger.Debug($"fetching discovery document from: {url}"); var response = await client.GetAsync(url).ConfigureAwait(false); if (!response.IsSuccessStatusCode) { var error = $"an error occurred while retrieving the discovery document ({url}): " + await FormatErrorAsync(response).ConfigureAwait(false); Logger.Error(error); throw new InvalidOperationException(error); } var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var doc = JsonConvert.DeserializeObject <Dictionary <string, object> >(json); var info = new ProviderInformation(); // issuer is required if (doc.ContainsKey("issuer")) { info.IssuerName = doc["issuer"].ToString(); Logger.Debug($"issuer name: {info.IssuerName}"); } else { var error = "issuer name is missing in discovery doc."; Logger.Error(error); throw new InvalidOperationException(error); } // validate issuer name against authority, if requested if (validateIssuerName) { if (!string.Equals(authority.RemoveTrailingSlash(), info.IssuerName.RemoveTrailingSlash(), StringComparison.OrdinalIgnoreCase)) { var error = $"issuer name of '{info.IssuerName}' does not match authority '{authority}'"; Logger.Error(error); throw new InvalidOperationException(error); } } // authorize endpoint is required if (doc.ContainsKey("authorization_endpoint")) { info.AuthorizeEndpoint = doc["authorization_endpoint"].ToString(); Logger.Debug($"authorization endpoint: {info.AuthorizeEndpoint}"); } else { var error = "authorization endpoint is missing in discovery doc."; Logger.Error(error); throw new InvalidOperationException(error); } // token endpoint is required if (doc.ContainsKey("token_endpoint")) { info.TokenEndpoint = doc["token_endpoint"].ToString(); Logger.Debug($"token endpoint: {info.TokenEndpoint}"); } else { var error = "token endpoint is missing in discovery doc."; Logger.Error(error); throw new InvalidOperationException(error); } // end_session endpoint is optional if (doc.ContainsKey("end_session_endpoint")) { info.EndSessionEndpoint = doc["end_session_endpoint"].ToString(); Logger.Debug($"end_session endpoint: {info.EndSessionEndpoint}"); } else { Logger.Debug("no end_session endpoint"); } // userinfo endpoint is optional, but required for the load profile feature if (doc.ContainsKey("userinfo_endpoint")) { info.UserInfoEndpoint = doc["userinfo_endpoint"].ToString(); Logger.Debug($"userinfo_endpoint: {info.UserInfoEndpoint}"); } else { Logger.Debug("no userinfo_endpoint"); } if (doc.ContainsKey("token_endpoint_auth_methods_supported")) { info.TokenEndPointAuthenticationMethods = ((JArray)doc["token_endpoint_auth_methods_supported"]).Select(x => (string)x).ToArray(); } // parse web key set if (doc.ContainsKey("jwks_uri")) { var jwksUri = doc["jwks_uri"].ToString(); var jwksResponse = await client.GetAsync(jwksUri).ConfigureAwait(false); if (!jwksResponse.IsSuccessStatusCode) { var error = $"an error occurred while retrieving the JWKS document ({jwksUri}) : " + await FormatErrorAsync(jwksResponse).ConfigureAwait(false); Logger.Error(error); throw new InvalidOperationException(error); } var jwks = await jwksResponse.Content.ReadAsStringAsync().ConfigureAwait(false); Logger.Debug($"jwks: {jwks}"); info.KeySet = new JsonWebKeySet(jwks); } else { var error = "jwks_uri is missing in discovery doc."; Logger.Error(error); throw new InvalidOperationException(error); } return(info); }