public SecurityToken ValidateToken(string jwt, IKeycloakParameters options, OidcDataManager uriManager, bool isRefreshToken = false) { var tokenValidationParameters = new TokenValidationParameters { ValidateLifetime = true, RequireExpirationTime = true, ValidateIssuer = !options.DisableIssuerValidation, ValidateAudience = !options.DisableAudienceValidation, ValidateIssuerSigningKey = !options.DisableTokenSignatureValidation, RequireSignedTokens = !options.AllowUnsignedTokens, ValidIssuer = uriManager.GetIssuer(), ClockSkew = options.TokenClockSkew, ValidAudiences = new List <string> { "null", options.ClientId }, IssuerSigningKeys = uriManager.GetJsonWebKeys().GetSigningKeys(), AuthenticationType = options.AuthenticationType // Not used }; bool disableAllValidation = isRefreshToken && options.DisableAllRefreshTokenValidation; if (disableAllValidation) { return(ReadJwtToken(jwt)); } bool disableOnlySignatureValidation = isRefreshToken && options.DisableRefreshTokenSignatureValidation; return(ValidateToken(jwt, tokenValidationParameters, disableOnlySignatureValidation)); }
/// <summary> /// Validates an IKeycloakParameters object for completeness and correctness /// </summary> /// <param name="parameters"></param> /// <returns></returns> public static void ValidateParameters(IKeycloakParameters parameters) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } // Verify required parameters if (parameters.KeycloakUrl == null) { throw new ArgumentNullException(nameof(parameters.KeycloakUrl)); } if (parameters.Realm == null) { throw new ArgumentNullException(nameof(parameters.Realm)); } // Set default parameters if (string.IsNullOrWhiteSpace(parameters.ResponseType)) { throw new ArgumentNullException(nameof(parameters.ResponseType)); } if (string.IsNullOrWhiteSpace(parameters.Scope)) { throw new ArgumentNullException(nameof(parameters.Scope)); } if (string.IsNullOrWhiteSpace(parameters.CallbackPath)) { throw new ArgumentNullException(nameof(parameters.CallbackPath)); } // Validate other parameters if (!Uri.IsWellFormedUriString(parameters.KeycloakUrl, UriKind.Absolute)) { throw new ArgumentException(nameof(parameters.KeycloakUrl)); } if (!Uri.IsWellFormedUriString(parameters.CallbackPath, UriKind.Relative) && parameters.CallbackPath != Constants.KeycloakParameters.NoCallbackUri) { throw new ArgumentException(nameof(parameters.CallbackPath)); } if (parameters.PostLogoutRedirectUrl != null && !Uri.IsWellFormedUriString(parameters.PostLogoutRedirectUrl, UriKind.RelativeOrAbsolute)) { throw new ArgumentException(nameof(parameters.PostLogoutRedirectUrl)); } var logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); // Attempt to refresh OIDC metadata from endpoint (on separate thread) try { Task.Run(() => OidcDataManager.GetCachedContextAsync(parameters)).Wait(); } catch (Exception exception) { logger.Error($"Invalid Keycloak server parameters specified: See inner for server error: {exception.InnerException}"); throw new ArgumentException("Invalid Keycloak server parameters specified: See inner for server error", exception); } }
/// <summary> /// Converts a set of JWTs into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="accessToken"></param> /// <param name="refreshToken"></param> /// <param name="idToken"></param> /// <returns></returns> public static async Task <KeycloakIdentity> ConvertFromJwtAsync(IKeycloakParameters parameters, string accessToken, string refreshToken = null, string idToken = null) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (accessToken == null) { throw new ArgumentNullException(nameof(accessToken)); } var kcIdentity = new KeycloakIdentity(parameters); try { await kcIdentity.CopyFromJwt(accessToken, refreshToken, idToken); } catch (SecurityTokenExpiredException) { // Load new identity from token endpoint via refresh token (if possible) await kcIdentity.RefreshIdentity(refreshToken); } return(kcIdentity); }
/// <summary> /// Generates the OpenID Connect compliant Keycloak logout URL /// </summary> /// <param name="parameters"></param> /// <param name="baseUri"></param> /// <param name="redirectUri"></param> /// <returns></returns> public static async Task <Uri> GenerateLogoutUriAsync(IKeycloakParameters parameters, Uri baseUri, Uri redirectUri) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (baseUri == null) { throw new ArgumentNullException(nameof(baseUri)); } if (redirectUri == null) { throw new ArgumentNullException(nameof(redirectUri)); } // Generate logout URI and data var uriManager = await OidcDataManager.GetCachedContextAsync(parameters); var logoutParams = uriManager.BuildEndSessionEndpointContent(baseUri, null, redirectUri.ToString()); var logoutUrl = uriManager.GetEndSessionEndpoint(); // Return logout URI var logoutQueryString = await logoutParams.ReadAsStringAsync(); return(new Uri(logoutUrl + (!string.IsNullOrEmpty(logoutQueryString) ? "?" + logoutQueryString : ""))); }
/// <summary> /// Perform logout of the User entity with the specified <param name="refreshToken"></param> /// </summary> /// <param name="refreshToken">Claims refresh token</param> /// <param name="options"></param> /// <param name="uri"></param> /// <returns></returns> public static async Task <string> HttpLogoutPost(string refreshToken, IKeycloakParameters options, Uri uri) { var logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); var httpClient = new HttpClient(); StringContent authContent = new StringContent("refresh_token=" + refreshToken, Encoding.UTF8, "application/x-www-form-urlencoded"); httpClient.DefaultRequestHeaders.Remove("Authorization"); httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + Convert.ToBase64String( Encoding.UTF8.GetBytes( $"{options.ClientId}:{options.ClientSecret}"))); logger.Debug($"HttpLogoutPost options.ClientId {options.ClientId} to uri {uri}"); var response = await httpClient.PostAsync(uri, authContent); // Fail on unreachable destination if (!response.IsSuccessStatusCode) { logger.Error($"HttpLogoutPost Logging out user: HTTP address unreachable ('{uri}')"); throw new Exception( $"Logging out user: HTTP address unreachable ('{uri}')"); } httpClient.Dispose(); logger.Debug("HttpLogoutPost success.disposed client."); return(await response.Content.ReadAsStringAsync()); }
protected GenericMessage(IKeycloakParameters options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } Options = options; }
protected OidcDataManager(IKeycloakParameters options) { _options = options; _nextCachedRefreshTime = DateTime.Now; Authority = _options.KeycloakUrl + "/realms/" + _options.Realm; MetadataEndpoint = new Uri(Authority + "/" + OpenIdProviderMetadataNames.Discovery); TokenValidationEndpoint = new Uri(Authority + "/tokens/validate"); }
public RefreshAccessTokenMessage(IKeycloakParameters options, string refreshToken) : base(options) { if (refreshToken == null) { throw new ArgumentNullException(); } RefreshToken = refreshToken; }
/// <summary> /// Load a new Keycloak-based identity from a claims identity /// </summary> /// <param name="parameters"></param> protected KeycloakIdentity(IKeycloakParameters parameters) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } ValidateParameters(parameters); _parameters = parameters; }
protected OidcDataManager(IOwinContext context, IKeycloakParameters options) { _options = options; _nextCachedRefreshTime = DateTime.Now; var realm = MultiTenantRealmSelector != null?MultiTenantRealmSelector(context) : options.Realm; Authority = _options.KeycloakUrl + "/realms/" + realm; MetadataEndpoint = new Uri(Authority + "/" + OpenIdProviderMetadataNames.Discovery); TokenValidationEndpoint = new Uri(Authority + "/tokens/validate"); }
/// <summary> /// Converts a JWT token-response endpoint message into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="message"></param> /// <returns></returns> public static Task <KeycloakIdentity> ConvertFromTokenResponseAsync(IKeycloakParameters parameters, TokenResponse message) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } return(ConvertFromJwtAsync(parameters, message.AccessToken, message.RefreshToken, message.IdToken)); }
/// <summary> /// Converts a keycloak-generated claims identity into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="identity"></param> /// <returns></returns> public static Task <KeycloakIdentity> ConvertFromClaimsIdentityAsync(IKeycloakParameters parameters, ClaimsIdentity identity) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (identity == null) { throw new ArgumentNullException(nameof(identity)); } return(ConvertFromClaimsAsync(parameters, identity.Claims)); }
/// <summary> /// Trys to validate an IKeycloakParameters object for completeness and correctness /// </summary> /// <param name="parameters"></param> /// <returns></returns> public static bool TryValidateParameters(IKeycloakParameters parameters) { try { ValidateParameters(parameters); return(true); } catch (Exception) { return(false); } }
public static async Task <OidcDataManager> CreateCachedContext(IKeycloakParameters options, bool preload = true) { var newContext = new OidcDataManager(options); OidcManagerCache[options.AuthenticationType + CachedContextPostfix] = newContext; if (preload) { await newContext.ValidateCachedContextAsync(); } return(newContext); }
/// <summary> /// Converts a set of JWTs into a Keycloak identity /// If the access token of the identity is about to expire the identity gets refreshed /// If a <see cref="SecurityTokenExpiredException"/> is thrown when converting the set of jwts, the identity /// gets refreshed. /// </summary> /// <param name="parameters"></param> /// <param name="accessToken"></param> /// <param name="refreshToken"></param> /// <param name="idToken"></param> /// <returns>The identity is returned</returns> public static async Task <KeycloakIdentity> ConvertFromJwtAsync(IKeycloakParameters parameters, string accessToken, string refreshToken = null, string idToken = null) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (accessToken == null) { throw new ArgumentNullException(nameof(accessToken)); } var kcIdentity = new KeycloakIdentity(parameters); try { await kcIdentity.CopyFromJwt(accessToken, refreshToken, idToken); //check if identity is about to expire in 30 secs (default). If yes refresh identity! DateTime?accessValidTo = DateTimeExtension.ParseClaimsDateToFormat( kcIdentity.Claims?.FirstOrDefault(c => c.Type == Constants.ClaimTypes.AccessTokenExpiration)? .Value); DateTime?refreshValidTo = DateTimeExtension.ParseClaimsDateToFormat( kcIdentity.Claims?.FirstOrDefault(c => c.Type == Constants.ClaimTypes.RefreshTokenExpiration)? .Value); var utcNow = DateTime.UtcNow; //_logger.Debug($"access {accessValidToX?.ToUniversalTime()} " + // $"utcnow {utcNow} refresh {refreshValidToX?.ToUniversalTime()}."); if (utcNow >= accessValidTo?.Subtract(parameters.RefreshBeforeTokenExpiration).ToUniversalTime() && utcNow <= refreshValidTo?.Subtract(parameters.RefreshBeforeTokenExpiration).ToUniversalTime()) { _logger.Debug( $"{kcIdentity.Name} access token will expire in less then {parameters.RefreshBeforeTokenExpiration} seconds. Refresh identity."); await kcIdentity.RefreshIdentity(refreshToken); } } catch (SecurityTokenExpiredException) { _logger.Debug($"SecurityTokenExpiredException was thrown.Refreshing identity with refresh token"); // Load new identity from token endpoint via refresh token (if possible) await kcIdentity.RefreshIdentity(refreshToken); } catch (ArgumentOutOfRangeException) { _logger.Debug($"ArgumentOutOfRangeException was thrown when calculating acces token expiration timeframe. No refreshing of identity. User is out of luck."); } return(kcIdentity); }
/// <summary> /// Generates the local URL on which to accept OIDC callbacks from Keycloak /// </summary> /// <param name="parameters"></param> /// <param name="baseUri"></param> /// <returns></returns> public static async Task <Uri> GenerateLoginCallbackUriAsync(IKeycloakParameters parameters, Uri baseUri) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (baseUri == null) { throw new ArgumentNullException(nameof(baseUri)); } return((await OidcDataManager.GetCachedContextAsync(parameters)).GetCallbackUri(baseUri)); }
public bool TryValidateToken(string jwt, IKeycloakParameters options, OidcDataManager uriManager, out SecurityToken rToken) { try { rToken = ValidateToken(jwt, options, uriManager); return true; } catch (Exception) { rToken = null; return false; } }
public bool TryValidateToken(string jwt, IKeycloakParameters options, OidcDataManager uriManager, out SecurityToken rToken, bool isRefreshToken = false) { try { rToken = ValidateToken(jwt, options, uriManager, isRefreshToken); return(true); } catch (Exception) { rToken = null; return(false); } }
public RequestAccessTokenMessage(Uri baseUri, IKeycloakParameters options, AuthorizationResponse authResponse) : base(options) { if (baseUri == null) { throw new ArgumentNullException(nameof(baseUri)); } if (authResponse == null) { throw new ArgumentNullException(nameof(authResponse)); } BaseUri = baseUri; AuthResponse = authResponse; }
/// <summary> /// Validates an IKeycloakParameters object for completeness and correctness /// </summary> /// <param name="parameters"></param> /// <returns></returns> public static void ValidateParameters(IKeycloakParameters parameters) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } // Verify required parameters if (parameters.KeycloakUrl == null) { throw new ArgumentNullException(nameof(parameters.KeycloakUrl)); } if (parameters.Realm == null && parameters.MultiTenantRealmSelector == null) { throw new ArgumentNullException(nameof(parameters.Realm)); } // Set default parameters if (string.IsNullOrWhiteSpace(parameters.ResponseType)) { throw new ArgumentNullException(nameof(parameters.ResponseType)); } if (string.IsNullOrWhiteSpace(parameters.Scope)) { throw new ArgumentNullException(nameof(parameters.Scope)); } if (string.IsNullOrWhiteSpace(parameters.CallbackPath)) { throw new ArgumentNullException(nameof(parameters.CallbackPath)); } // Validate other parameters if (!Uri.IsWellFormedUriString(parameters.KeycloakUrl, UriKind.Absolute)) { throw new ArgumentException(nameof(parameters.KeycloakUrl)); } if (!Uri.IsWellFormedUriString(parameters.CallbackPath, UriKind.Relative) && parameters.CallbackPath != Constants.KeycloakParameters.NoCallbackUri) { throw new ArgumentException(nameof(parameters.CallbackPath)); } if (parameters.PostLogoutRedirectUrl != null && !Uri.IsWellFormedUriString(parameters.PostLogoutRedirectUrl, UriKind.RelativeOrAbsolute)) { throw new ArgumentException(nameof(parameters.PostLogoutRedirectUrl)); } }
/// <summary> /// Converts a keycloak-generated claims list into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="claims"></param> /// <returns></returns> public static Task <KeycloakIdentity> ConvertFromClaimsAsync(IKeycloakParameters parameters, IEnumerable <Claim> claims) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (claims == null) { throw new ArgumentNullException(nameof(claims)); } var claimLookup = claims.ToLookup(c => c.Type, c => c.Value); var idToken = claimLookup[Constants.ClaimTypes.IdToken].FirstOrDefault(); var accessToken = claimLookup[Constants.ClaimTypes.AccessToken].FirstOrDefault(); var refreshToken = claimLookup[Constants.ClaimTypes.RefreshToken].FirstOrDefault(); return(ConvertFromJwtAsync(parameters, accessToken, refreshToken, idToken)); }
public SecurityToken ValidateToken(string jwt, IKeycloakParameters options, OidcDataManager uriManager) { var tokenValidationParameters = new TokenValidationParameters { ValidateLifetime = true, RequireExpirationTime = true, ValidateIssuer = !options.DisableIssuerValidation, ValidateAudience = !options.DisableAudienceValidation, ValidateIssuerSigningKey = !options.DisableTokenSignatureValidation, RequireSignedTokens = !options.AllowUnsignedTokens, ValidIssuer = uriManager.GetIssuer(), ClockSkew = options.TokenClockSkew, ValidAudiences = new List<string> {"null", options.ClientId}, IssuerSigningTokens = uriManager.GetJsonWebKeys().GetSigningTokens(), AuthenticationType = options.AuthenticationType // Not used }; return ValidateToken(jwt, tokenValidationParameters); }
public SecurityToken ValidateToken(string jwt, IKeycloakParameters options, OidcDataManager uriManager) { var tokenValidationParameters = new TokenValidationParameters { ValidateLifetime = true, RequireExpirationTime = true, ValidateIssuer = !options.DisableIssuerValidation, ValidateAudience = !options.DisableAudienceValidation, ValidateIssuerSigningKey = !options.DisableTokenSignatureValidation, RequireSignedTokens = !options.AllowUnsignedTokens, ValidIssuer = uriManager.GetIssuer(), ClockSkew = options.TokenClockSkew, ValidAudiences = new List <string> { "null", options.ClientId }, IssuerSigningKeys = uriManager.GetJsonWebKeys().GetSigningKeys(), }; return(ValidateToken(jwt, tokenValidationParameters)); }
/// <summary> /// Converts a JWT token-response endpoint message into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="response"></param> /// <param name="baseUri"></param> /// <returns></returns> public static async Task <KeycloakIdentity> ConvertFromAuthResponseAsync(IKeycloakParameters parameters, AuthorizationResponse response, Uri baseUri) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (response == null) { throw new ArgumentNullException(nameof(response)); } if (baseUri == null) { throw new ArgumentNullException(nameof(baseUri)); } response.ThrowIfError(); var message = new RequestAccessTokenMessage(baseUri, parameters, response); return(await ConvertFromTokenResponseAsync(parameters, await message.ExecuteAsync())); }
/// <summary> /// Generates the OpenID Connect compliant Keycloak login URL /// </summary> /// <param name="parameters"></param> /// <param name="baseUri"></param> /// <param name="state"></param> /// <returns></returns> public static async Task <Uri> GenerateLoginUriAsync(IKeycloakParameters parameters, Uri baseUri, string state = null) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (baseUri == null) { throw new ArgumentNullException(nameof(baseUri)); } // Generate login URI and data var uriManager = await OidcDataManager.GetCachedContextAsync(parameters); var loginParams = uriManager.BuildAuthorizationEndpointContent(baseUri, state ?? Guid.NewGuid().ToString()); var loginUrl = uriManager.GetAuthorizationEndpoint(); // Return login URI var loginQueryString = await loginParams.ReadAsStringAsync(); return(new Uri(loginUrl + (!string.IsNullOrEmpty(loginQueryString) ? "?" + loginQueryString : ""))); }
public static async Task<OidcDataManager> CreateCachedContext(IKeycloakParameters options, bool preload = true) { var newContext = new OidcDataManager(options); OidcManagerCache[options.AuthenticationType + CachedContextPostfix] = newContext; if (preload) await newContext.ValidateCachedContextAsync(); return newContext; }
/// <summary> /// Converts a JWT token-response endpoint message into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="response"></param> /// <param name="baseUri"></param> /// <returns></returns> public static async Task<KeycloakIdentity> ConvertFromAuthResponseAsync(IKeycloakParameters parameters, AuthorizationResponse response, Uri baseUri) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (response == null) throw new ArgumentNullException(nameof(response)); if (baseUri == null) throw new ArgumentNullException(nameof(baseUri)); response.ThrowIfError(); var message = new RequestAccessTokenMessage(baseUri, parameters, response); return await ConvertFromTokenResponseAsync(parameters, await message.ExecuteAsync()); }
public static OidcDataManager GetCachedContext(IKeycloakParameters options) { return(GetCachedContext(options.AuthenticationType)); }
/// <summary> /// Converts a set of JWTs into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="accessToken"></param> /// <param name="refreshToken"></param> /// <param name="idToken"></param> /// <returns></returns> public static async Task<KeycloakIdentity> ConvertFromJwtAsync(IKeycloakParameters parameters, string accessToken, string refreshToken = null, string idToken = null) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (accessToken == null) throw new ArgumentNullException(nameof(accessToken)); var kcIdentity = new KeycloakIdentity(parameters); try { await kcIdentity.CopyFromJwt(accessToken, refreshToken, idToken); } catch (SecurityTokenExpiredException) { // Load new identity from token endpoint via refresh token (if possible) await kcIdentity.RefreshIdentity(refreshToken); } return kcIdentity; }
public async Task<SecurityToken> ValidateTokenAsync(string jwt, IKeycloakParameters options) { var uriManager = await OidcDataManager.GetCachedContextAsync(options); return ValidateToken(jwt, options, uriManager); }
public static Task ValidateCachedContextAsync(IKeycloakParameters options) { var context = GetCachedContext(options.AuthenticationType); return(context.ValidateCachedContextAsync()); }
public static Task<OidcDataManager> GetCachedContextAsync(IKeycloakParameters options) { var context = GetCachedContextSafe(options.AuthenticationType); return context != null ? Task.FromResult(context) : CreateCachedContext(options); }
/// <summary> /// Converts a keycloak-generated claims list into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="claims"></param> /// <returns></returns> public static Task<KeycloakIdentity> ConvertFromClaimsAsync(IKeycloakParameters parameters, IEnumerable<Claim> claims) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (claims == null) throw new ArgumentNullException(nameof(claims)); var claimLookup = claims.ToLookup(c => c.Type, c => c.Value); var idToken = claimLookup[Constants.ClaimTypes.IdToken].FirstOrDefault(); var accessToken = claimLookup[Constants.ClaimTypes.AccessToken].FirstOrDefault(); var refreshToken = claimLookup[Constants.ClaimTypes.RefreshToken].FirstOrDefault(); return ConvertFromJwtAsync(parameters, accessToken, refreshToken, idToken); }
/// <summary> /// Converts a keycloak-generated claims identity into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="identity"></param> /// <returns></returns> public static Task<KeycloakIdentity> ConvertFromClaimsIdentityAsync(IKeycloakParameters parameters, ClaimsIdentity identity) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (identity == null) throw new ArgumentNullException(nameof(identity)); return ConvertFromClaimsAsync(parameters, identity.Claims); }
public static Task ValidateCachedContextAsync(IKeycloakParameters options) { var context = GetCachedContext(options.AuthenticationType); return context.ValidateCachedContextAsync(); }
public static Task ValidateCachedContextAsync(IOwinContext context, IKeycloakParameters options) { return(GetCachedContext(context, options.AuthenticationType) .ValidateCachedContextAsync()); }
public static async Task <SecurityToken> ValidateTokenRemote(string jwt, IKeycloakParameters options) { var uriManager = await OidcDataManager.GetCachedContextAsync(options); return(await ValidateTokenRemote(jwt, uriManager)); }
/// <summary> /// Generates the local URL on which to accept OIDC callbacks from Keycloak /// </summary> /// <param name="parameters"></param> /// <param name="baseUri"></param> /// <returns></returns> public static async Task<Uri> GenerateLoginCallbackUriAsync(IKeycloakParameters parameters, Uri baseUri) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (baseUri == null) throw new ArgumentNullException(nameof(baseUri)); return (await OidcDataManager.GetCachedContextAsync(parameters)).GetCallbackUri(baseUri); }
/// <summary> /// Generates the OpenID Connect compliant Keycloak logout URL /// </summary> /// <param name="parameters"></param> /// <param name="baseUri"></param> /// <param name="redirectUrl"></param> /// <returns></returns> public static async Task<Uri> GenerateLogoutUriAsync(IKeycloakParameters parameters, Uri baseUri, string redirectUrl = null) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (baseUri == null) throw new ArgumentNullException(nameof(baseUri)); // Generate logout URI and data var uriManager = await OidcDataManager.GetCachedContextAsync(parameters); var logoutParams = uriManager.BuildEndSessionEndpointContent(baseUri, null, redirectUrl); var logoutUrl = uriManager.GetEndSessionEndpoint(); // Return logout URI var logoutQueryString = await logoutParams.ReadAsStringAsync(); return new Uri(logoutUrl + (!string.IsNullOrEmpty(logoutQueryString) ? "?" + logoutQueryString : "")); }
/// <summary> /// Load a new Keycloak-based identity from a claims identity /// </summary> /// <param name="parameters"></param> protected KeycloakIdentity(IKeycloakParameters parameters) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); ValidateParameters(parameters); _parameters = parameters; }
public static OidcDataManager GetCachedContext(IKeycloakParameters options) { return GetCachedContext(options.AuthenticationType); }
public static Task <OidcDataManager> GetCachedContextAsync(IKeycloakParameters options) { var context = GetCachedContextSafe(options.AuthenticationType); return(context != null?Task.FromResult(context) : CreateCachedContext(options)); }
/// <summary> /// Converts a JWT token-response endpoint message into a Keycloak identity /// </summary> /// <param name="parameters"></param> /// <param name="message"></param> /// <returns></returns> public static Task<KeycloakIdentity> ConvertFromTokenResponseAsync(IKeycloakParameters parameters, TokenResponse message) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (message == null) throw new ArgumentNullException(nameof(message)); return ConvertFromJwtAsync(parameters, message.AccessToken, message.RefreshToken, message.IdToken); }
/// <summary> /// Generates the OpenID Connect compliant Keycloak login URL /// </summary> /// <param name="parameters"></param> /// <param name="baseUri"></param> /// <param name="state"></param> /// <returns></returns> public static async Task<Uri> GenerateLoginUriAsync(IKeycloakParameters parameters, Uri baseUri, string state = null) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (baseUri == null) throw new ArgumentNullException(nameof(baseUri)); // Generate login URI and data var uriManager = await OidcDataManager.GetCachedContextAsync(parameters); var loginParams = uriManager.BuildAuthorizationEndpointContent(baseUri, state ?? Guid.NewGuid().ToString()); var loginUrl = uriManager.GetAuthorizationEndpoint(); // Return login URI var loginQueryString = await loginParams.ReadAsStringAsync(); return new Uri(loginUrl + (!string.IsNullOrEmpty(loginQueryString) ? "?" + loginQueryString : "")); }
public async Task <SecurityToken> ValidateTokenAsync(IOwinContext context, string jwt, IKeycloakParameters options) { var uriManager = await OidcDataManager.GetCachedContextAsync(context, options); return(ValidateToken(jwt, options, uriManager)); }
/// <summary> /// Trys to validate an IKeycloakParameters object for completeness and correctness /// </summary> /// <param name="parameters"></param> /// <returns></returns> public static bool TryValidateParameters(IKeycloakParameters parameters) { try { ValidateParameters(parameters); return true; } catch (Exception) { return false; } }
/// <summary> /// Validates an IKeycloakParameters object for completeness and correctness /// </summary> /// <param name="parameters"></param> /// <returns></returns> public static void ValidateParameters(IKeycloakParameters parameters) { if (parameters == null) throw new ArgumentNullException(nameof(parameters)); // Verify required parameters if (parameters.KeycloakUrl == null) throw new ArgumentNullException(nameof(parameters.KeycloakUrl)); if (parameters.Realm == null) throw new ArgumentNullException(nameof(parameters.Realm)); // Set default parameters if (string.IsNullOrWhiteSpace(parameters.ResponseType)) throw new ArgumentNullException(nameof(parameters.ResponseType)); if (string.IsNullOrWhiteSpace(parameters.Scope)) throw new ArgumentNullException(nameof(parameters.Scope)); if (string.IsNullOrWhiteSpace(parameters.CallbackPath)) throw new ArgumentNullException(nameof(parameters.CallbackPath)); // Validate other parameters if (!Uri.IsWellFormedUriString(parameters.KeycloakUrl, UriKind.Absolute)) throw new ArgumentException(nameof(parameters.KeycloakUrl)); if (!Uri.IsWellFormedUriString(parameters.CallbackPath, UriKind.Relative) && parameters.CallbackPath != Constants.KeycloakParameters.NoCallbackUri) throw new ArgumentException(nameof(parameters.CallbackPath)); if (parameters.PostLogoutRedirectUrl != null && !Uri.IsWellFormedUriString(parameters.PostLogoutRedirectUrl, UriKind.RelativeOrAbsolute)) throw new ArgumentException(nameof(parameters.PostLogoutRedirectUrl)); // Attempt to refresh OIDC metadata from endpoint (on separate thread) try { Task.Run(() => OidcDataManager.GetCachedContextAsync(parameters)).Wait(); } catch (Exception exception) { throw new ArgumentException("Invalid Keycloak server parameters specified: See inner for server error", exception); } }
public async Task <SecurityToken> ValidateTokenAsync(string jwt, IKeycloakParameters options, bool isRefreshToken = false) { var uriManager = await OidcDataManager.GetCachedContextAsync(options); return(ValidateToken(jwt, options, uriManager, isRefreshToken)); }