How to disable auto login redirect in Spring Boot Keycloak Adapter - spring-boot

I am writing an API in Spring Boot that I want to secure using Keycloak.
After doing some setting up, I managed to get the keycloak adapter to work. While I was expecting a 403 on any non-authenticated request, I get an HTTP 302 redirect to login page instead.
As I am working on an API, how can I disable the auto login-redirect and provide a 403 error message, so that I could add some frontend logic to start on the login process?

In your config, you do
http.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint())
It will start returning 403 on every failed call and you can then catch it and whatever logic you need.

You need to add the propery keycloak.bearer-only: true in the application.properties or application.yml to avoid redirect to login page when there is one error
You will get one 401 error

Related

Issue while running the Spring boot application with Cloud run

In Springboot application we are facing issue after authentication with AD and while doing redirection.
We have added the below redirection in application.properties file:
aad.redirectHomeUri=https://icaps-userhelpertool-dev-cloudrun-kwyk47pogq-ez.a.run.app/resetpassword
Above url is cloud run url where we have deployed our code and same url we have added in AD also . But after authentication its not redirecting and we are getting below error.
19-01-2023 10:08:07.259 ERROR c.m.a.m.ConfidentialClientApplication - [Correlation ID: b396dc37-982d-4f56-ac5d-a754f24f4f53] Execution of class com.microsoft.aad.msal4j.AcquireTokenByAuthorizationGrantSupplier failed.
com.microsoft.aad.msal4j.MsalServiceException: AADSTS500112: The reply address 'http://icaps-userhelpertool-dev-cloudrun-kwyk47pogq-ez.a.run.app/resetpassword' does not match the reply address 'https://icaps-userhelpertool-dev-cloudrun-kwyk47pogq-ez.a.run.app/resetpassword' provided when requesting Authorization code.
I tried to reproduce the same in my environment
Received the error:
AADSTS50011: The redirect URI 'http://xxx/signin-oidc' specified in the request does not match the redirect URIs configured for the application '50065a5f-d3e4-426f-a4f4-1e6fbd2ed06e'. Make sure the redirect URI sent in the request matches one added to your application in the Azure portal.
This error occurred as in my code ,the http protocol it used is http But the one registered in portal is https .
This can be set properly with HttpsRedirection middleware configuration
In spring ,this occurs when your Tomcat server is behind a proxy which redirects to http protocol.
Set the below configurations in application.properties with the proper url in registered-redirect-uri and x-forwarded-proto as mentioned here spring-boot-application-with-azure-ad-throws-reply-url-does-not-match | StackOverflow
application.properties
security.oauth2.client.pre-established-redirect-uri=https://yourappurl.net/login
security.oauth2.client.registered-redirect-uri=https://yourappurl.net/login
security.oauth2.client.use-current-uri=false
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto
server.tomcat.use-relative-redirects=true
server.use-forward-headers=true
server.tomcat.internal-proxies=.*
and Add server.forward-headers-strategy=native
Reference : spring-redirect-happening-to-http-login-instead-of-https-login | Stack Overflow

Spring Boot Security and Keycloak - receive 403 forbidden /sso/login after successfull login when using HTTPS

I have a Spring Boot App using Spring Security and Keycloak as IDP.
Keycloak is available under https://auth.example.com, having a realm backo with a client backo-core and a testuser configured with the required roles.
If I configure my local app, using
keycloak.enabled=true
keycloak.auth-server-url=https://auth.example.com/auth
keycloak.realm=backo
keycloak.public-client=true
keycloak.resource=backo-core
keycloak.ssl-required=external
keycloak.confidential-port=443
Everything works fine.
If I deploy it to my DEV environment under https://backo.example.com/backo with https://backo.example.com/sso/login, when accessing the app I get redirect to the Keycloak login. After successful login I get redirected to the redirect URL with the state, session-state and code parameters but receive 403.
https://backo.example.com/sso/login?state=...&session_state=...&code=...
with request initiator chain coming from https://auth.example.com/auth/realms/backo/login-action/authenticate?...
If I set locally keycloak.ssl-required=all, the redirect_url parameter when accessing the login page is https://localhost/sso/login, so I can change it manually to http://localhost:8080/sso/login. After a successful login I have the exact same problem with a 403 Forbidden response for
http://localhost:8080/sso/login?state=...&session_state=...&code=...
with request initiator chain coming from https://auth.example.com/auth/realms/backo/login-action/authenticate?...
This is how my security config looks like
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers("/backo").hasAnyRole(ROLE_ADMIN, ROLE_BACKOFFICE)
.anyRequest().permitAll();
http.csrf().disable();
http.headers().frameOptions().disable(); // otherwise Vaadin doesn't work properly
http
.logout()
.addLogoutHandler(keycloakLogoutHandler())
.logoutUrl("/sso/logout").permitAll()
.logoutSuccessUrl("/");
}
You can ignore this Vaadin workaround, as it fails in /sso/login already.
http.csrf().disable(); is required to prevent other 403 Forbidden errors on post request while authorization.
One thing that could be worth mentioning:
The Spring Boot App has no HTTPS enabled, in our dev environment it sits behind an AWS Application loadbalancer ALB. HTTPS is terminated in the ALB.
We have faced the similar problem three days ago with spring boot thymeleaf application. We have used keycloak adapter (13.0.1) for spring boot.
After successful login it was redirecting to /sso/login page with 403 error.
After lots of effort we finally got the configuration required to fix this issue. you need to use the below application properties :
server.use-forward-headers=true
keycloak.public-client=true
keycloak.ssl-required=all
keycloak.confidential-port=443

How to make spring webclient follow redirect with access token/authorization header?

We are using spring boot 2.4.5 with webflux and calling a service with client credentials grant type. What we noticed is that webclient is not following redirects.
How can we enable webclient to follow redirects where it can continue passing access token until it get the http 200?
Adding following code snippet does not pass the access token to redirected url and it is returning 401.
WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create().followRedirect(true)
))
The sensitive headers like the Authorization are removed from the initialized request when redirecting to a different domain.
You can use the following variant of followRedirect(boolean):
followRedirect(boolean followRedirect, Consumer<HttpClientRequest> redirectRequestConsumer)
In order to re-add the Authorization header using redirectRequestConsumer.
For more details see the Javadoc here and Reactor Netty documentation here.

How to handle 401 unauthorized error in Springboot app

I need to log 401 unauthorized errors in my Springboot application.
I wanted to log this for a certain end point in my app since its unauthorized error I know this attempt will be caught when invoking the api at the beginning itself.
Are there anyways I can keep track of this in spring boot?
I tried through WebSecurityConfig but didnt help.
I am using springboot 2.
Thanks in advance.
There are 2 ways I can think of, but probably there are more
use custom #ExceptionHandler method in your controller and make it sensitive to UnauthorizedException.class
Use Filter to introspect into request/response - and log whatever you want in case of response beeing 401.
You can get hold of the authentication entry point and handle some 401 logic in the http
security config:
.authenticationEntryPoint((httpServletRequest, httpServletResponse, e) -> {
log.warn(e.getMessage());
httpServletResponse.setStatus(401);
httpServletResponse.getWriter().print(e.getMessage());
})

404 when do logout in Spring Security Rest Plugin for Grails

I'm setting the security system on my project (Grails - Angularjs) with Spring Security Rest Plugin v1.5.4 (using spring security core 2.0.0) for Grails 2.4.4. Doc about this plugin can be found here.
I'm testing the login and logout with postman chrome rest client and I'm able to do a login OK, but I'm getting a 404 when I do logout.
In the documentation clearly says:
The logout filter exposes an endpoint for deleting tokens. It will
read the token from an HTTP header. If found, will delete it from the
storage, sending a 200 response. Otherwise, it will send a 404
response
You can configure it in Config.groovy using this properties:
Config key...................................................................................Default
value
grails.plugin.springsecurity.rest.logout.endpointUrl....................../api/logout
grails.plugin.springsecurity.rest.token.validation.headerName....X-Auth-Token
So, after doing a login successfully, I tried to do a logout to that url (my_host_url/api/logout) with a GET method and sending a header X-Auth-Token with the token I got previously from login.
But I keep getting a 404. See image below
Edit: I'm setting the chain map like this (in order to get a stateless behavior):
grails.plugin.springsecurity.filterChain.chainMap = [
'/api/**': 'JOINED_FILTERS,-exceptionTranslationFilter,-authenticationProcessingFilter,-securityContextPersistenceFilter,-rememberMeAuthenticationFilter', // Stateless chain
'/**': 'JOINED_FILTERS,-restTokenValidationFilter,-restExceptionTranslationFilter' // Traditional chain
]
So. What am I doing wrong here, or what am I missing?
Thanks in advance!
You missed another excerpt from the docs. It's a warning message literally before the chunk you quoted, and says:
Logout is not possible when using JWT tokens (the default strategy), as no state is kept in the server.
If you still want to have logout, you can provide your own implementation by creating a subclass of JwtTokenStorageService and overriding the methods storeToken and removeToken. Then, register your implementation in resources.groovy as tokenStorageService.

Resources