Keycloak as authentication service for Traefik has delay on logout - oauth-2.0

I have setup keycloak as authentication service and used it to protect some service using this guide:
https://github.com/ibuetler/docker-keycloak-traefik-workshop
the whole procedure seems to work correctly but when I call the logout route in keycloak OpenID configuration the session in keycloak sessions get deleted immediately but the traefik still route request to protected service for 30 second or so. After that I got redirected to login page to re-login. I think some sort of caching is happening in the traefik.
I expect that after calling the logout route which remove session in keycloak traefik immediately stop routing request to protected service but if I refresh the page with Ctrl+F5 it load the service for 30 second or so and after that It redirect me to login page. how can I fix it to do it without delay?

I found the problem.
I thought it was Traefik issue but it was Keycloak gatekeeper. It was my mistake in calling the logout URL. I called the Keycloak discovery logout URL but I should have called the gatekeeper logout URL. it was stated clearly in gatekeeper documentation. "/oauth/logout?redirect=url" route immediately logout user and close the session.

Related

Why OAuth do not redirect user to redirect url?

I created nodejs web application with react frontend. I have backend API assigned to api.domain.com.
In my api i have 4 endpoints.
/api/auth/login/google, /api/auth/login/facebook, /api/auth/redirect/google, /api/auth/redirect/facebook.
When i tried to login from domain.com via google or facebook my front end send request to api/auth/login/(google or facebook), then user redirects to google's login page and then it redirects me to the https://myaccount.google.com/?pli=1 or https://www.facebook.com/#_=_
How to solve this problem ?
I used default passport strategies for login with Nest.js
Plz help me)
It happends cause i tried to redirect my user back with res.redirect(req.headers['referrer']); - it redirects me to this pages

Azure App Gateway - Retain caller hostname in the user browser that calls App Gateway to prevent "possible CSRF detected - state parameter" error

Requesting for some help here. Kind of stuck with a use case. We are trying to integrate OneLogin with our app via Spring security.
The entry point to our application is Azure App Gateway that routes the requests to load balancer further routing to the VMs where the service is deployed. Everything works fine if we DONOT override the hostname in Backend settings for any incoming request, leading to the App Gateway host only getting passed for every request. Here the App Gateway URL being set as the redirect URI in Spring security auth endpoint call.
The problem appears when the Apigee is used as the entry point to our application. Apigee routes the request to App Gateway routing it further to load balancer and VMs. Here, we DO have to override the host as Apigee host name in order to authenticate the client to the OneLogin server. The Apigee endpoint is set as the redirect URI in the Spring security auth endpoint call.
However, the server responds back with "possible CSRF detected - state parameter was required but no state could be found" error. Tried different possible solutions from other SO links to resolve this error like providing a session cookie name, but did not help. Our OneLogin server and client application are also in different domains.
The only thing that works here is when we DONOT override the hostname in Azure App Gateway Backend settings and pass the App Gateway URL as the redirect URI in auth endpoint call. But the problem is it shows the App Gateway URL in the user browser, which we do not want because in an ideal scenario, the user should see only the Apigee host in the browser url and not the App Gateway host. So, is there any way to re-route/redirect/override the URL to Apigee URL in Azure App Gateway settings without the call being made to Apigee endpoint. Just the user sees the Apigee url in the browser, but internally all calls are made to App Gateway endpoint only.
Or the other solution could be to prevent the CSRF issue when Apigee hostname is used as the redirect URL in the auth endpoint instead of App Gateway host. But not sure how to resolve that.
• In your scenario, when you are not overriding the hostname in the Azure application gateway backend settings and pass the ‘Application Gateway’ URL as redirect URL in the ‘Authorization endpoint call’, the application gateway URL is shown in the user’s browser which is not desired since the Apigee host redirects the authentication requests to the ‘App gateway’ endpoint.
Therefore, without the call to be made to the ‘Apigee’ endpoint, you can surely redirect it to the Apigee redirect URL in the Azure application gateway settings by configuring the ‘Rewrite URI rules’ in the gateway. These rewrite rules will check for any presence of configured URLs or specific paths and will therefore, change the original URI path to the new path configured. As a result, please follow the below given snapshots as steps for configuring the same as stated above: -
Thus, as shown above, you can configure the ‘Rewrite rules’ in a ‘Standard V2’ SKU application gateway for redirecting response requests of ‘authorization endpoint call’ from application gateway URL to the Apigee endpoint hostname configured. In this way, when the application gateway URL is shown in the browser, it will be rewrited to the apigee endpoint hostname’s URL in the browser and accordingly the user at the receiving end will be able to see the Apigee endpoint hostname as a result fulfilling your requirement.
For more details regarding the above, kindly refer the below link: -
https://learn.microsoft.com/en-us/azure/application-gateway/rewrite-http-headers-url#modify-a-redirection-url

AccesDenied request is not forwarded to AuthenticationEntryPoint if multiple AuthenticationProvider exist

In a Spring Security project I have configured Keycloak via the regular KeycloakWebSecurityConfigurerAdapter method. Everything works fine with Keycloak itself.
I now have added one specific URL that needs to be authorized via basic-auth. For that, I have configured a second configuration, with an antMatcher to that URL that has higher priority than the Keycloak-configuration. This works fine, when I access that URL, basic auth is triggered and I can authenticate for it.
But after authenticating for this URL, I can no longer authenticate via my Keycloak-specific URL. The current logic is as follows: I have a Keycloak-login URL (/auth/login), which is handled by a controller in my project. The handling method is annotated with #Secured, requiring the user to have a role that he only gets after authenticating with Keycloak. So for the first login, the request to the /auth/login URL is denied, an AccessDeniedException is thrown.
What Spring then automatically does in ExceptionTranslationFilter: It delegates the request to the authentication entrypoint, which is a Keycloak specific implementation which does all the magic.
The problem in this specific case is, however, that in ExceptionTranslationFilter#handleSpringSecurityException Spring will not delegate to the authentication entry point, if the user is not "anonymous". Because the user has previously authenticated for a basic-auth URL, Spring finds this authentication object in the context and then does not consider the user as anonymous. I guess the logic here is that Spring considered this a failed login-attempt or something.
What can I do so that Spring also delegates the request to the configured authentication entry point if it finds some unrelated authentication in the context?

Attempting to connect to a IdentityServer4 login page fails

I have an existing website that I want to do a proof of concept with OAuth2 / OIDC. To this end I've configured a locally running IdentityServer4 MVC app as my demo OIDC server following the IdentityServer4 quick setup guidelines. This works fine and navigating to:
http://localhost:5000/.well-known/openid-configuration
Lets me see the discovery document.
I have created a fake login page on this OIDC app which consists of just a login button with no user credentials required.
There's no actual user database and I'm just hard coding some user details to return when the 'authentication' occurs.
In my pre-existing site I've added the OWIN middle wear and am configuring OIDC using the OpenIdConnectAuthenticationOptions. The clientId, scopes, secret etc all match as required and the authority is set to point to my locally running demo OIDC app (http://localhost:5000). The redirect url is set to return to my pre-existing site once authentication is complete.
This all appears to be fine but here's what I want to achieve and can't get working. On my pre-existing site when I navigate to any page that requires authentication I want the user to be redirected to the login page I created on OIDC app. They click the login button (no user details required) and are authenticated and redirected back to the original page.
Currently when I navigate to a protected page I am successfully redirected to the OIDC app but I am redirected to an error page and I don't know why. The error page gives me no detail, it's actually hard coded in the app.
When I look at the discovery document I see that the setting for the 'authorization_endpoint' is set to:
http://localhost:5000/connect/authorize
So I thought maybe I needed to either change that to point to Home/Login which is where I've created the dummy login form, or else I needed to actually create that connect/authorize endpoint and put my form there. Creating the end point makes no difference, it never gets hit and instead I just get the error page on my OIDC app. Changing it to home/login also appears to be ignored.
I am away from my main PC at the moment hence the lack of code snippets but essentially the set up is as per the IdentityServer4 quick setup guide and the OIDC app does appear to be working.
The issue is getting my pre-existing site to properly redirect to the login page.
I've been stuck on this for quite a while now and would like to even get to the stage of seeing the dummy login page. Any pointers are appreciated and again apologies for the lack of sample code.
UPDATE
I've got the login form appearing by setting the openidconfiguration like so:
Configuration = new OpenIdConnectConfiguration()
{
AuthorizationEndPoint = "http://localhost:5000/home/login"
}
However, this isn't logging me in when I click login. On that login action I'm doing this:
await HttpContext.SignInAsync("subjectId","username", authenticationProps);
And then redirecting back to my existing site. However it's not authenticating me and the redirect ends up being redirected back again to the login page.
UPDATE 2
I think the redirect URI should possibly be doing something more. Currently I do the following:
Try and access a restricted page -> Redirected to OIDC server -> Click Login (this sets the subject and user successfully) -> Am redirected to redirect URI which immediately bounces me back to the OIDC server.
So maybe the redirect URI is supposed to confirm login or otherwise do something?
So in the open id connect protocol, the authorize endpoint is used to validate the client information passed as query parameters (client_id, scopes, redirect_uri, etc). In your authentication server, none of that is being checked if all the endpoint does is return a form. Then again the validation can be tedious so keeping the authorize endpoint separate from the endpoint for logging in might be worth a thought.
The developers of Identity Server thought the same thing which is why they set up the endpoint (and endpoint validation) for you as part of the middleware. The validation uses the components that were injected (primarily the client_store, and your defined scopes) to be used by Identity Server.
After the framework validates your authorize request using your client store implementation, it will redirect the user to whichever login page you specify. The login page can be specified by changing it with the a delegate that can be passed in as the second parameter of 'AddIdentityServer' (that takes in something of type IdentityServerOptions that we'll refer to as just 'options'). In the delegate you can specify the login url of the page by changing the value of 'options.UserInteraction.LoginUrl' to the url of the login page.
After the user logs in and you call the signInAsync method on the HttpContext, you're actually supposed to redirect back to a query parameter passed to the login page referred to as the 'return_url' (which is basically the initial authorize endpoint request). This authorize endpoint further validates the cookie and will send the user back to the 'redirect_uri' (if consent on the client is set to false) with a code (if using the authorization code flow) or the id_token and optionally the access token (if using the implicit flow).
Assuming the implicit flow for simplicity, the tokens can be found in the request to the 'redirect_uri' and from there it's all up to you. Commonly the client will issue some kind of cookie (which can potentially contain the id or access token) to mark the successful authentication by the identity provider.

Spring Security "exceptionMappings"

Using Spring Security preauthentication, my web app re-directs to /login_disabled.html upon hitting a InsufficientAuthenticationException.
sample of applicationContext-security-preauth.xml
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop key="org.springframework.security.
InsufficientAuthenticationException">
/login_disabled.html
Based on this post, it seems that I should be able to re-direct the user to log in again.
Would I just need to re-direct the user to the webpage responsible for authentication?
It's not really clear for me what's the problem here. The redirection to the login page is automatically done without any further configuration if you have form-login set up. If the user tries to access a secured page without being authenticated, the ExceptionTranslationFilter invokes the AuthenticationEntryPoint to initiate authentication.
Using ExceptionMappingAuthenticationFailureHandler to map InsufficientAuthenticationException to a redirect-url won't work anyway because:
It's not indicating an authentication failre. It indicates the condition that the user is only anonymously authenticated while trying to access a secured resource. (As opposed to an auth failure such as entering bad credentials, or user has disabled status.)
It never even gets thrown. (Only instantiated and passed as a parameter in the above linked code.)

Resources