Spring Security in Grails runnable jar redirects to HTTP - spring

I'm using a grails 3 runnable jar with spring Security behind a reverse proxy handling https to http traffic (and https to http redirects), forwarding it to http://my-host:8080
For all my /login/** calls , grails is sending "302 redirect" to http
For example a /login/authenticate XHR is redirected with the header
Location: http://my-big-ip/login/ajaxSuccess, etc.
It's not using the serverURL parameter that I set in application.yml to https://my-big-ip
My jar is using embedded tomcat since I have this in my build.gradle
compile "org.springframework.boot:spring-boot-starter-tomcat"
The logs I get about this redirect
2019-03-27 15:56:34,415 DEBUG http-nio-8088-exec-5 org.springframework.security.web.savedrequest.HttpSessionRequestCache - Removing DefaultSavedRequest from session if present
2019-03-27 15:56:34,415 DEBUG http-nio-8088-exec-5 grails.plugin.springsecurity.web.authentication.AjaxAwareAuthenticationSuccessHandler - Redirecting to Ajax Success Url: /login/ajaxSuccess
2019-03-27 15:56:34,415 DEBUG http-nio-8088-exec-5 grails.plugin.springsecurity.web.GrailsRedirectStrategy - Redirecting to '/login/ajaxSuccess'

I believe that you will need to add this to your application/runtime.(groovy|yml):
server."use-forward-headers" = true
There is a good bit of documentation (about this and other things) here https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html that may be helpful if you are interested in additional details.

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

How to disable auto login redirect in Spring Boot Keycloak Adapter

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

How to configure Spring Boot to use OIDC while app is behind an SSL termination proxy

I am trying to configure a Spring Boot app to use OIDC. The server is behind an SSL termination proxy.
Here are the properties I use:
spring:
security:
oauth2:
client:
provider:
oidc:
authorization-uri: https://example.org/oidc/oauth2/authorize
token-uri: https://example.org/oidc/oauth2/access_token
user-info-uri: https://example.org/oidc/oauth2/userinfo
jwk-set-uri: https://example.org/oidc/oauth2/connect/jwk_uri
custom-params: param_name1,param_value1,param_name2,param_value2,nonce,123456789
registration:
oidc:
client-id: myclientid
client-secret: myclientsecret
authorization-grant-type: authorization_code
scope:
- openid
- email
- profile
redirect-uri: https://mydomain/myapp/login/oauth2/code/oidc
Here's where it goes wrong:
1. The OIDC server requires a nonce param to be added to the request URL
I have solved this by using a custom OAuth2AuthorizationRequest that reads the custom-params property and appends those values to the request URL
2. The OidcAuthorizationCodeAuthenticationProvider throws an exception caused by invalid_redirect_uri_parameter
I have tried many approaches to fix this.
I have tried creating a filter that adds the X-Forwarded-Proto to the request (because the proxy doesn't handle that).
The headers are added, I have also added the following properties:
server:
forward-headers-strategy: native
tomcat.protocol-header: x-forwarded-proto
But it doesn't seem to work.
OidcAuthorizationCodeAuthenticationProvider still throws an exception because this condition is false:
!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())
I have debugged the code and the only difference is one being http and the other https.
I have found a VERY hacky solution that I don't like at all, which is another filter that modifies the URL just for that particular URL.
I would prefer a more elegant solution.
3. When using the custom nonce parameter, the OidcAuthorizationCodeAuthenticationProvider throws an exception cause by invalid_nonce
Now I am stuck. I considered writing my own Authentication Provider, but I have no guarantee that mine will be picked up before the OIDC one provided by Spring.
And with the nonce, it's a catch 22:
if I don't use the custom param, I couldn't find a way to make Spring add the nonce to the request
if I use that one, Spring doesn't recognize it when it's part of the JWT and freaks out
Any help would be GREATLY appreciated, as this has been driving me nuts for days if not weeks.
Thank you.
EDIT
The 2 urls that are compared in case 2 come from:
OAuth2AuthorizationRequest
OAuth2AuthorizationResponse
OAuth2AuthorizationRequest is built in the
OAuth2AuthorizationRequestRedirectFilter at the following line:
OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestResolver.resolve(request);
The redirect uri is built in DefaultOAuth2AuthorizationRequestResolver.expandRedirectUri() which calls
UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
OAuth2AuthorizationResponse is built in the OAuth2LoginAuthenticationFilter.attemptAuthentication() which also calls
UriComponentsBuilder.fromHttpUrl(UrlUtils.buildFullRequestUrl(request))
and then
OAuth2AuthorizationResponseUtils.convert(params, redirectUri)
I will double check, but I don't remember UriComponentsBuilder.adaptFromForwardedHeaders(HttpHeaders headers) being called when building these URLs.
And even if that works, that still leaves the nonce issue :(
We stumbled upon the same problem , the problem was mainly because our server was behind a reverse proxy, and it seems the proxy changed the url somehow causing this check to fail
!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())
this line was removed in later versions of spring security , at commit
24500fa3ca23aa23ede86dfcfe02113671d5b8bc
commit at github
which was introduced on Dec 6, 2019 and was in spring security release 5.1.13
so the solution was to upgrade spring boot to at least 2.1.17 for spring boot 2.1.X line of versions.
while the OP said he can't upgrade his libraries, I hope this can help those who can.
We also did the solution mentioned above by Kavithakaran Kanapathippilla and configured our reverse proxy to add X-forwarded-proto http headers , also i believed we configured spring boot application.properties to check for them
spring boot documentation for working behind proxies

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.

Setting default fallback for Zuul routing failures

We are trying to override the default error page you get when there is a routing failure within the Zuul Edge Server and aren't having any luck. We have routes set up like so:
zuul:
routes:
ui: /**
api: /api/**
The default SendErrorFilter attempts to send the request to /error by default and that works when the ui service is up and running as it will serve up /error. But the problem is when the ui server is down, it tries to route to /error and fails. You then get the big nasty exception on your screen saying there was a forwarding error and no fallback was available.
com.netflix.zuul.exception.ZuulException: Forwarding error
org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.forward(RibbonRoutingFilter.java:140)
org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.run(RibbonRoutingFilter.java:105)
com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112)
com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:197)
com.netflix.zuul.FilterProcessor.runFilters(FilterProcessor.java:161)
com.netflix.zuul.FilterProcessor.route(FilterProcessor.java:120)
com.netflix.zuul.ZuulRunner.route(ZuulRunner.java:84)
com.netflix.zuul.http.ZuulServlet.route(ZuulServlet.java:111)
Root Cause:
com.netflix.hystrix.exception.HystrixRuntimeException: uiRibbonCommand failed and no fallback available.
com.netflix.hystrix.AbstractCommand$16.call(AbstractCommand.java:807)
com.netflix.hystrix.AbstractCommand$16.call(AbstractCommand.java:794)
rx.internal.operators.OperatorOnErrorResumeNextViaFunction$1.onError(OperatorOnErrorResumeNextViaFunction.java:77)
rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70)
rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70)
rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70)
com.netflix.hystrix.AbstractCommand$DeprecatedOnFallbackHookApplication$1.onError(AbstractCommand.java:1516)
com.netflix.hystrix.AbstractCommand$FallbackHookApplication$1.onError(AbstractCommand.java:1406)
com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:314)
com.netflix.hystrix.HystrixCommand$2.call(HystrixCommand.java:306)
How do you set a default Fallback in Zuul to handle these errors so the user doesn't see the nasty exception? I have seen this open issue on spring-cloud-netflix (#250), but I would deal with a default fallback for all routes, not just specific routes. What is the correct way to do this?
Fallbacks are now supported in the latest release of Spring cloud. Please review the post - Fallback methods at Zuul server in Spring cloud
for additional details

Resources