Esempio n. 1
0
        private static void ValidateOptions()
        {
            // Load web root path from config
            if (string.IsNullOrWhiteSpace(Options.VirtualDirectory))
            {
                Options.VirtualDirectory = "/";
            }
            Options.VirtualDirectory = NormalizeUrl(Options.VirtualDirectory);
            // Set default options
            if (string.IsNullOrWhiteSpace(Options.ResponseType))
            {
                Options.ResponseType = "code";
            }
            if (string.IsNullOrWhiteSpace(Options.Scope))
            {
                Options.Scope = "openid";
            }
            if (string.IsNullOrWhiteSpace(Options.CallbackPath))
            {
                Options.CallbackPath = $"{Options.VirtualDirectory}/owin/security/keycloak/{Uri.EscapeDataString(Options.AuthenticationScheme)}/callback";
            }
            if (string.IsNullOrWhiteSpace(Options.PostLogoutRedirectUrl))
            {
                Options.PostLogoutRedirectUrl = Options.VirtualDirectory;
            }

            if (Options.SignInAsAuthenticationSchema == null)
            {
                try
                {
                    //Options.SignInAsAuthenticationType = App.GetDefaultSignInAsAuthenticationType();
                    Options.SignInAsAuthenticationSchema = "";
                }
                catch (Exception)
                {
                    Options.SignInAsAuthenticationSchema = "";
                }
            }

            // Switch composite options

            if (Options.EnableWebApiMode)
            {
                Options.EnableBearerTokenAuth = true;
                Options.ForceBearerTokenAuth  = true;
            }

            // Validate other options

            if (Options.ForceBearerTokenAuth && !Options.EnableBearerTokenAuth)
            {
                Options.EnableBearerTokenAuth = true;
            }

            Options.KeycloakUrl  = NormalizeUrl(Options.KeycloakUrl);
            Options.CallbackPath = NormalizeUrlPath(Options.CallbackPath);

            // Final parameter validation
            KeycloakIdentity.ValidateParameters(Options);
        }
 private async Task LogoutRedirectAsync(AuthenticationProperties properties)
 {
     // Redirect response to logout
     Response.Redirect(
         (await KeycloakIdentity.GenerateLogoutUriAsync(Options, Request.Uri, new Uri(properties.RedirectUri)))
         .ToString());
 }
        private async Task ValidateSignInAsIdentities()
        {
            foreach (var origIdentity in Context.Authentication.User.Identities)
            {
                try
                {
                    if (!origIdentity.HasClaim(Constants.ClaimTypes.AuthenticationType, Options.AuthenticationType))
                    {
                        continue;
                    }
                    var kcIdentity = await KeycloakIdentity.ConvertFromClaimsIdentityAsync(Options, origIdentity);

                    if (!kcIdentity.IsTouched)
                    {
                        continue;
                    }

                    // Replace identity if expired
                    var identity = await kcIdentity.ToClaimsIdentityAsync();

                    Context.Authentication.User = new ClaimsPrincipal(identity);
                    SignInAsAuthentication(identity, null, Options.SignInAsAuthenticationType);
                }
                catch (AuthenticationException)
                {
                    Context.Authentication.SignOut(origIdentity.AuthenticationType);
                }
                catch (Exception)
                {
                    // TODO: Some kind of exception logging, maybe log the user out
                    throw;
                }
            }
        }
        public override async Task <bool> HandleRequestAsync()
        {
            // Check SignInAs identity for authentication update
            if (Context.User.Identity.IsAuthenticated)
            {
                await ValidateSignInAsIdentities();
            }
            var currUri = new Uri(CurrentUri);
            // Check for valid callback URI
            var callbackUri = await KeycloakIdentity.GenerateLoginCallbackUriAsync(Options, currUri);

            if (!Options.ForceBearerTokenAuth && currUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.Unescaped) == callbackUri.ToString())
            {
                // Create authorization result from query
                var authResult = new AuthorizationResponse(currUri.Query);
                try
                {
                    // Validate passed state
                    var stateData = ReturnState(authResult.State);
                    if (stateData == null)
                    {
                        throw new Exception("Invalid state: Please reattempt the request");
                    }

                    // Parse properties from state data
                    AuthenticationProperties properties;
                    if (stateData.TryGetValue(Constants.CacheTypes.AuthenticationProperties, out object authpprop))
                    {
                        properties = authpprop as AuthenticationProperties ?? new AuthenticationProperties();
                    }
                    else
                    {
                        properties = new AuthenticationProperties();
                    }

                    // Process response
                    var kcIdentity = await KeycloakIdentity.ConvertFromAuthResponseAsync(Options, authResult, currUri);

                    var identity = await kcIdentity.ToClaimsIdentityAsync();

                    Context.User.AddIdentity(identity);

                    SignInAsAuthentication(identity, properties, Options.SignInAsAuthenticationSchema);

                    // Redirect back to the original secured resource, if any
                    if (!string.IsNullOrWhiteSpace(properties.RedirectUri) && Uri.IsWellFormedUriString(properties.RedirectUri, UriKind.Absolute))
                    {
                        Response.Redirect(properties.RedirectUri);
                        return(true);
                    }
                }
                catch (Exception exception)
                {
                    await GenerateErrorResponseAsync(HttpStatusCode.BadRequest, "Bad Request", exception.Message);

                    return(true);
                }
            }
            return(false);
        }
        private async Task LogoutRedirectAsync()
        {
            // Redirect response to logout
            var temp = (await KeycloakIdentity.GenerateLogoutUriAsync(Options, Request.Uri)).ToString();

            Response.Redirect(temp);
        }
        /// <summary>
        /// Method logs generates the logout url for the realm and performs a user log out
        /// and issues a redirection to the login page for the user to enter credentials again.
        /// </summary>
        /// <param name="identity">Current identity signed in keycloak. It will be forced log out.</param>
        /// <returns>Redirection to login page</returns>
        private async Task ForceLogoutRedirectAsync(ClaimsIdentity identity)
        {
            // generate logout uri
            var uri = await KeycloakIdentity.GenerateLogoutUriAsync(Options, Request.Uri);

            //foreach (var claim in identity.Claims)
            //{
            //    _logger.Debug($"ForceLogoutRedirectAsync user claim {claim.Type} - {claim.Value}");
            //}

            _logger.Debug($"Force logout identity with isAuthenticated:{identity.IsAuthenticated}");

            Claim firstOrDefault = identity.Claims.FirstOrDefault(claim => claim.Type == "refresh_token");

            if (firstOrDefault != null)
            {
                await OidcDataManager.HttpLogoutPost(firstOrDefault.Value, Options, uri);
            }

            //redirect to relogin
            var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);

            if (challenge == null)
            {
                _logger.Debug($"Force logged out {identity.Name}.Challenge is null.Return.");
                return;
            }

            _logger.Debug($"Force logged out {identity.Name}.Redirecting from challenge properties.");
            await LoginRedirectAsync(challenge.Properties);
        }
Esempio n. 7
0
 private async Task LogoutRedirectAsync()
 {
     // Redirect response to logout
     Response.Redirect(
         (await
          KeycloakIdentity.GenerateLogoutUriAsync(Context, Options, Request.Uri))
         .ToString());
 }
        public override async Task <bool> InvokeAsync()
        {
            // Check SignInAs identity for authentication update
            if (Context.Authentication.User.Identity.IsAuthenticated)
            {
                await ValidateSignInAsIdentities();
            }

            // Check for valid callback URI
            var callbackUri = await KeycloakIdentity.GenerateLoginCallbackUriAsync(Options, Request.Uri);

            if (!Options.ForceBearerTokenAuth && Request.Uri.GetLeftPart(UriPartial.Path) == callbackUri.ToString())
            {
                // Create authorization result from query
                var authResult = new AuthorizationResponse(Request.Uri.Query);

                try
                {
                    // Validate passed state
                    var stateData = Global.StateCache.ReturnState(authResult.State);
                    if (stateData == null)
                    {
                        throw new BadRequestException("Invalid state: Please reattempt the request");
                    }

                    // Parse properties from state data
                    var properties =
                        stateData[Constants.CacheTypes.AuthenticationProperties] as AuthenticationProperties ??
                        new AuthenticationProperties();

                    // Process response
                    var kcIdentity =
                        await KeycloakIdentity.ConvertFromAuthResponseAsync(Options, authResult, Request.Uri);

                    var identity = await kcIdentity.ToClaimsIdentityAsync();

                    Context.Authentication.User.AddIdentity(identity);
                    SignInAsAuthentication(identity, properties, Options.SignInAsAuthenticationType);

                    // Redirect back to the original secured resource, if any
                    if (!string.IsNullOrWhiteSpace(properties.RedirectUri) &&
                        Uri.IsWellFormedUriString(properties.RedirectUri, UriKind.Absolute))
                    {
                        Response.Redirect(properties.RedirectUri);
                        return(true);
                    }
                }
                catch (BadRequestException exception)
                {
                    await GenerateErrorResponseAsync(HttpStatusCode.BadRequest, "Bad Request", exception.Message);

                    return(true);
                }
            }

            return(false);
        }
        private async Task LoginRedirectAsync(AuthenticationProperties properties)
        {
            if (string.IsNullOrEmpty(properties.RedirectUri))
            {
                properties.RedirectUri = Request.Uri.ToString();
            }

            // Create state
            var stateData = new Dictionary <string, object>
            {
                { Constants.CacheTypes.AuthenticationProperties, properties }
            };
            var state = Global.StateCache.CreateState(stateData);

            // Redirect response to login
            Response.Redirect((await KeycloakIdentity.GenerateLoginUriAsync(Options, Request.Uri, state)).ToString());
        }
        public override async Task <AuthenticationTicket> ExecuteAsync()
        {
            // Validate passed state
            var stateData = Global.StateCache.ReturnState(AuthResponse.State);

            if (stateData == null)
            {
                throw new BadRequestException("Invalid state: Please reattempt the request");
            }

            // Generate claims and create user information & authentication ticket
            var kcIdentity = new KeycloakIdentity(await ExecuteHttpRequestAsync());
            var properties = stateData[Constants.CacheTypes.AuthenticationProperties] as AuthenticationProperties ??
                             new AuthenticationProperties();

            return(new AuthenticationTicket(await kcIdentity.ValidateIdentity(Options), properties));
        }
        protected override async Task <AuthenticationTicket> AuthenticateCoreAsync()
        {
            // Bearer token authentication override
            if (Options.EnableBearerTokenAuth)
            {
                // Try to authenticate via bearer token auth
                if (Request.Headers.ContainsKey(Constants.BearerTokenHeader))
                {
                    var bearerAuthArr = Request.Headers[Constants.BearerTokenHeader].Trim().Split(new[] { ' ' }, 2);
                    if ((bearerAuthArr.Length == 2) && bearerAuthArr[0].ToLowerInvariant() == "bearer")
                    {
                        try
                        {
                            var authResponse = new TokenResponse(bearerAuthArr[1], null, null);
                            var kcIdentity   = await KeycloakIdentity.ConvertFromTokenResponseAsync(Options, authResponse);

                            var identity = await kcIdentity.ToClaimsIdentityAsync();

                            SignInAsAuthentication(identity, null, Options.SignInAsAuthenticationType);
                            return(new AuthenticationTicket(identity, new AuthenticationProperties()));
                        }
                        catch (Exception)
                        {
                            // ignored
                        }
                    }
                }

                // If bearer token auth is forced, skip standard auth
                if (Options.ForceBearerTokenAuth)
                {
                    return(null);
                }
            }

            return(null);
        }
Esempio n. 12
0
        public static async Task <ClaimsIdentity> GetKeycloakIdentityAsync(string username, string password)
        {
            if (Options == null)
            {
                throw new ArgumentNullException("options");
            }
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            {
                throw new InvalidCredentialException("username or password is empty.");
            }
            var uriManager = await OidcDataManager.GetCachedContextAsync(Options);

            var response = SendHttpPostRequest(uriManager.GetTokenEndpoint(), uriManager.BuildROPCAccessTokenEndpointContent(username, password));

            var result = await response.Content.ReadAsStringAsync();

            var tokenrespones = new TokenResponse(result);

            var claimidentity = await KeycloakIdentity.ConvertFromTokenResponseAsync(Options, tokenrespones);

            var identity = await claimidentity.ToClaimsIdentityAsync();

            return(new ClaimsIdentity(identity.Claims, Options.SignInAsAuthenticationSchema, identity.NameClaimType, identity.RoleClaimType));
        }
 private async Task LogoutRedirectAsync()
 {
     // Redirect response to logout
     Response.Redirect((await KeycloakIdentity.GenerateLogoutUriAsync(Options, new Uri(CurrentUri))).ToString());
 }
        public override async Task <bool> InvokeAsync()
        {
            // Check SignInAs identity for authentication update
            if (Context.Authentication.User.Identity.IsAuthenticated)
            {
                await ValidateSignInAsIdentities();
            }

            // Check for valid callback URI
            var callbackUri = await KeycloakIdentity.GenerateLoginCallbackUriAsync(Options, Request.Uri);

            if (!Options.ForceBearerTokenAuth && Request.Uri.GetLeftPart(UriPartial.Path) == callbackUri.ToString())
            {
                // Create authorization result from query
                var authResult = new AuthorizationResponse(Request.Uri.Query);
                _logger.Debug($"Request from {Request.Uri}");

                // If the authorization response returned a "error" query parameter (instead of "code" + "state"), redirect to a configured URL.
                // This could occur if the login is aborted by the user.
                if (!authResult.IsSuccessfulResponse())
                {
                    HandleAuthError(authResult);
                    return(true);
                }
                try
                {
                    // Validate passed state
                    var stateData = Global.StateCache.ReturnState(authResult.State) ?? new Dictionary <string, object>();
                    //throw new BadRequestException("Invalid state: Please reattempt the request");

                    // Process response and gather claims. If No state is found in cache we will log out the user from Keycloak and redirect him
                    //again for login. StateData must exist and match the oidc_state received from request
                    var kcIdentity =
                        await KeycloakIdentity.ConvertFromAuthResponseAsync(Options, authResult, Request.Uri);

                    var identity = await kcIdentity.ToClaimsIdentityAsync();

                    if (!stateData.ContainsKey(Constants.CacheTypes.AuthenticationProperties))
                    {
                        await ForceLogoutRedirectAsync(identity);

                        _logger.Debug($"State data is null.Logging out user and redirecting");
                        return(true);
                    }

                    // Parse properties from state data
                    var properties = stateData[Constants.CacheTypes.AuthenticationProperties] as AuthenticationProperties;

                    //everything is ok until here, sign in the user
                    Context.Authentication.User = new ClaimsPrincipal(identity);
                    SignInAsAuthentication(identity, properties, Options.SignInAsAuthenticationType);
                    _logger.Debug($"Signed in user {identity.Name} with state data.");

                    // Trigger OnAuthenticated?
                    var eventArgs = new OnAuthenticatedEventArgs {
                        RedirectUri = properties?.RedirectUri
                    };
                    Options.OnAuthenticated?.Invoke(Context, eventArgs);

                    // Redirect back to the original secured resource, if any
                    if (!string.IsNullOrWhiteSpace(eventArgs.RedirectUri) &&
                        Uri.IsWellFormedUriString(eventArgs.RedirectUri, UriKind.Absolute))
                    {
                        Response.Redirect(eventArgs.RedirectUri);
                        return(true);
                    }
                }
                catch (Exception exception)
                {
                    _logger.Debug($"Returning false for {exception.Message} {exception.StackTrace}");
                    await GenerateErrorResponseAsync(HttpStatusCode.InternalServerError, "Internal Server Error", exception.Message);

                    return(false);
                }
            }

            return(false);
        }
        private void ValidateOptions()
        {
            var logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            // Check to ensure authentication type isn't already used
            var authType = Options.AuthenticationType;

            if (!Global.KeycloakOptionStore.TryAdd(authType, Options))
            {
                logger.Error($"KeycloakAuthenticationOptions: Authentication type '{authType}' already used; required unique");
                throw new Exception(
                          $"KeycloakAuthenticationOptions: Authentication type '{authType}' already used; required unique");
            }

            // Verify required options
            if (Options.KeycloakUrl == null)
            {
                ThrowOptionNotFound(nameof(Options.KeycloakUrl));
            }
            if (Options.Realm == null)
            {
                ThrowOptionNotFound(nameof(Options.Realm));
            }

            // Load web root path from config
            if (string.IsNullOrWhiteSpace(Options.VirtualDirectory))
            {
                Options.VirtualDirectory = "/";
            }
            Options.VirtualDirectory = NormalizeUrl(Options.VirtualDirectory);
            if (!Uri.IsWellFormedUriString(Options.VirtualDirectory, UriKind.Relative))
            {
                ThrowInvalidOption(nameof(Options.VirtualDirectory));
            }

            // Set default options
            if (string.IsNullOrWhiteSpace(Options.ResponseType))
            {
                Options.ResponseType = "code";
            }
            if (string.IsNullOrWhiteSpace(Options.Scope))
            {
                Options.Scope = "openid";
            }
            if (string.IsNullOrWhiteSpace(Options.CallbackPath))
            {
                Options.CallbackPath =
                    $"{Options.VirtualDirectory}/owin/security/keycloak/{Uri.EscapeDataString(Options.AuthenticationType)}/callback";
            }
            if (string.IsNullOrWhiteSpace(Options.PostLogoutRedirectUrl))
            {
                Options.PostLogoutRedirectUrl = Options.VirtualDirectory;
            }

            if (Options.SignInAsAuthenticationType == null)
            {
                try
                {
                    Options.SignInAsAuthenticationType = App.GetDefaultSignInAsAuthenticationType();
                }
                catch (Exception)
                {
                    Options.SignInAsAuthenticationType = "";
                }
            }

            // Switch composite options

            if (Options.EnableWebApiMode)
            {
                Options.EnableBearerTokenAuth = true;
                Options.ForceBearerTokenAuth  = true;
            }

            // Validate other options

            if (Options.ForceBearerTokenAuth && !Options.EnableBearerTokenAuth)
            {
                Options.EnableBearerTokenAuth = true;
            }

            Options.KeycloakUrl  = NormalizeUrl(Options.KeycloakUrl);
            Options.CallbackPath = NormalizeUrlPath(Options.CallbackPath);

            //for more than 2 minutes set default value
            if (TimeSpan.Compare(Options.RefreshBeforeTokenExpiration.Duration(), TimeSpan.FromSeconds(120).Duration()) > 0)
            {
                Options.RefreshBeforeTokenExpiration = TimeSpan.FromSeconds(30);
            }

            // Final parameter validation
            KeycloakIdentity.ValidateParameters(Options);
        }
Esempio n. 16
0
        public override async Task <ClaimsIdentity> ExecuteAsync()
        {
            var newKcIdentity = new KeycloakIdentity(await ExecuteHttpRequestAsync(RefreshToken));

            return(await newKcIdentity.ValidateIdentity(Options));
        }
        private void ValidateOptions()
        {
            // Check to ensure authentication type isn't already used
            var authType = Options.AuthenticationType;

            if (!Global.KeycloakOptionStore.TryAdd(authType, Options))
            {
                throw new Exception(
                          $"KeycloakAuthenticationOptions: Authentication type '{authType}' already used; required unique");
            }

            // Verify required options
            if (Options.KeycloakUrl == null)
            {
                ThrowOptionNotFound(nameof(Options.KeycloakUrl));
            }
            if (Options.Realm == null)
            {
                ThrowOptionNotFound(nameof(Options.Realm));
            }

            // Load web root path from config
            if (string.IsNullOrWhiteSpace(Options.VirtualDirectory))
            {
                Options.VirtualDirectory = "/";
            }
            Options.VirtualDirectory = NormalizeUrl(Options.VirtualDirectory);
            if (!Uri.IsWellFormedUriString(Options.VirtualDirectory, UriKind.Relative))
            {
                ThrowInvalidOption(nameof(Options.VirtualDirectory));
            }

            // Set default options
            if (string.IsNullOrWhiteSpace(Options.ResponseType))
            {
                Options.ResponseType = "code";
            }
            if (string.IsNullOrWhiteSpace(Options.Scope))
            {
                Options.Scope = "openid";
            }
            if (string.IsNullOrWhiteSpace(Options.CallbackPath))
            {
                Options.CallbackPath =
                    $"{Options.VirtualDirectory}/owin/security/keycloak/{Uri.EscapeDataString(Options.AuthenticationType)}/callback";
            }
            if (string.IsNullOrWhiteSpace(Options.PostLogoutRedirectUrl))
            {
                Options.PostLogoutRedirectUrl = Options.VirtualDirectory;
            }

            if (Options.SignInAsAuthenticationType == null)
            {
                try
                {
                    Options.SignInAsAuthenticationType = App.GetDefaultSignInAsAuthenticationType();
                }
                catch (Exception)
                {
                    Options.SignInAsAuthenticationType = "";
                }
            }

            // Switch composite options

            if (Options.EnableWebApiMode)
            {
                Options.EnableBearerTokenAuth = true;
                Options.ForceBearerTokenAuth  = true;
            }

            // Validate other options

            if (Options.ForceBearerTokenAuth && !Options.EnableBearerTokenAuth)
            {
                Options.EnableBearerTokenAuth = true;
            }

            Options.KeycloakUrl  = NormalizeUrl(Options.KeycloakUrl);
            Options.CallbackPath = NormalizeUrlPath(Options.CallbackPath);

            // Final parameter validation
            KeycloakIdentity.ValidateParameters(Options);
        }