Setting default fallback for Zuul routing failures - spring

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

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 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

Spring Security in Grails runnable jar redirects to HTTP

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.

Spring Security Oauth2 SSO with Zuul Proxy

I'm modifying the oauth2-vanilla sample from Springs excellent security tutorials. The oauth2-vanilla combines the Zuul Proxy and the UI into a single application. I would like to seperate the Zuul Proxy and the UI. (The Zuul Proxy should act as an API gateway and as a reverse proxy for several UIs).
When accessing the UI via the zuul proxy, it should be able to do SSO based on Oauth2 between the UI and the resource backend.
The oauth2-vanilla looks like this
Where I want to move to something like this :
I've removed the UI part from the gateway, and added a zuul route for the ui
zuul:
routes:
resource:
url: http://localhost:9000
user:
url: http://localhost:9999/uaa/user
ui:
url: http://localhost:8080
I created a new UI webapp containing the UI (Angular stuff) with an #EnableOAuth2Sso annotation.
So I'm accessing the UI via http://localhost:8888 (through the zuul proxy).
After authenticating and doing through the UI flow, I can access the /user endpoint that returns me the user. (During debugging, I see that when I access the /user endpoint that I have an HTTP Session with an OAuth2Authentication.
When I access the /resource endpoint however, the HttpSessionSecurityContextRepository cannot find a session and is unable to build a context with the OAuth2Authentication.
I've created a git repository with the modified sample.
I'm guessing there is something wrong with the gateway configuration.
I've tried changing cookie paths, changing HttpSecurity rules in the proxy but I cannot get it to work.
What I don't understand is why the UI, when accessed through the proxy is able to resolve the /user endpoint fine (with an HTTP session and a OAuth2Authentication), but it is unable to access the /resource endpoint.
Also, as the UI is now running in the /ui context, it seems that I need to have the following code in the gateway for it to load up the angular css / js files.
.antMatchers("/ui/index.html", "/ui/home.html", "ui/css/**", "/ui/js/**").permitAll().anyRequest().authenticated();
It also doesn't seem right that I need to prefix it with the zuul ui route.
Any help would be appreciated.
I was never able to get the #EnableOauthSso to work. Instead, I annotated as an #EnableResourceServer and created a security config for Zuul.
#Configuration
#EnableResourceServer
public class JwtSecurityConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/**").hasAuthority("ROLE_API")
.and()
.csrf().disable();
}
}

Resources