Spring boot+ Spring SAML not working for NGINX proxy_pass - spring-boot

I have structure where my rest service (SP) are build using spring boot + Spring SAML for authentication and UI using Nginx as reverse proxy.
If calling service by return/rewrite with direct URL everything is working fine : Calling IDP getting authenticated and return response.
But if I call same service using proxy_pass it fails with InResponseToField of the Response doesn't correspond to sent message
I have structure where UI using NGINX as web server and through NGINX calling SP.
SP having multiple instances under LB. Used SAMLContextProviderLB as context provider.
How can I do this calling using Nginx.

I suspect that your Nginx isn't configured to use sticky sessions. This causes that response from IDP can land on a server which isn't aware of the request which was originally sent from the other server, and therefore fail validating it. The Spring SAML manual says:
Make sure that your reverse-proxy or load-balancer is configured to
use sticky sessions.
There are multiple possible solutions:
enable sticky sessions on the Nginx, so the response goes to the same server which sent it
disable validations of InResponseTo fields (see manual for details)
enable HTTP session replication, so the HttpSession which contains the sent request is distributed to all servers - for doing this see e.g. spring-session

Related

SAML message intended destination endpoint 'https://serverA/saml/SSO' did not match the recipient endpoint 'https://serverB/saml/SSO'

I have the below structure for my spring boot 2.5.5 application where the client request reaches Server A which is then forwarded to Server B and then Server C.
I have implemented Spring Security and AD SAML Authentication using (spring-security-saml2-core)
Nginx (Server A) -> nginx.conf as been configured for proxy pass to Server B
Nginx (Server B) -> nginx.conf as been configured for proxy pass to Server C
Tomcat (Server C) -> Actual Spring Boot App deployed here
Now in Azure AD we create the App and get the Entity Id, Metadata URL and Reply URL [https://serverA/appName] the same are configured in my Spring Boot Application.
After all this configuration when we access the app from the client I am able to get the SSO Login page and I can enter the credentials. Once I try to log in I get the below exception listed on the Server C logs
SAML message intended destination endpoint 'https://serverA/appName/saml/SSO' did not match the recipient endpoint 'https://serverB/appName/saml/SSO'
SAML is very restrictive.
When you send a SAML request to AD you also specify where you want to answer to go back to.
You also configure on the AD side to where to send the response to.
These MUST match. If the response end point does not match, then you will get this error.
I guess your problem is that your request comes from SERVER A and AD is configured to return it to SERVER B.
Check your metadata return endpoint match what is configured in AZURE, your problem is probably there.

Spring boot Oauth2 SSO with Zuul proxy and multiple clients (native, mobile, web)

I'm currently working on a project that uses Zuul to proxy requests to both API endpoints as well as client resources. There is an angular app that is being served from the same endpoint as the Zuul proxy as outlined in this guide. I have the need for additional clients, specifically a desktop application.
I'm not sure I understand how Zuul proxy handles requests and I think there are several paths to get to where I want to go, I'm just not sure what the correct one is.
Here is what I have surmised thus far:
Option 1: Extract the Zuul proxy and SSO capabilities to it's own server. Then create a new UI server which is behind the gateway server. Follow this up with creating a new client application server which handles the authentication of the desktop client.
Option 2: Extract the Zuul proxy and SSO capabilities to it's own server. Serve the current angular app from its own server NOT behind the proxy and change the authorization flow to something different (implicit). Alter Zuul proxy and SSO configuration to ignore requests that already have a bearer token in the header.
If I go with option 2 then I don't understand how to register with the Zuul gateway client that I already am providing the authorization header with my requests so all it should be doing then is proxying my requests to the correct microservices.
Final Questions:
Which option is the most optimal one?
If an access token is already acquired (directly from the auth server using implicit flow) then how does Zuul need to be configured to not try and acquire the access token using the jsessionid?

spring session sharing between zuul and resource servers

I was trying to search, but did not find an answer suited to our situation.
Basically, we have zuul server as API gateway which does following responsibilites
+ Autheticate user, and create and maintain session with users
+ Sessions will be stored in redis (we are using spring session with redis)
I want to have all of resource servers having access to session information created by zuul server. But I could not get session information from resource servers. its alway return null, I have checked redis server and seen session is created by zuul server already
Note that we are using Netflix service discovery to forward request from Zuul respective service.
highly appreciate for any advice
actually I was missing the following code.
context.addZuulRequestHeader("Cookie", "SESSION=" + httpSession.getId());
After adding above code to pass session_id in the cookie from zuul filter to respective micro-services, it is able to pickup the session_id from zuul filter.
I had the same problem. But after I have configured the application.yml to set "sensitiveHeaders" to empty. My problem is solved! :)
zuul:
routes:
users:
path: /myusers/**
sensitiveHeaders:
url: https://downstream
you can see more details at this link
Even though you're storing session in Redis, session id is stored in cookie and must be delivered to your resource servers. But the default configuration of zuul is filtering out all cookie related headers.
The below is default configuration of zuul for senstive-headers those are not passed to downstream servers.
zuul.sensitiveHeaders=Cookie,Set-Cookie,Authorization
To pass cookie related headers from zuul to your resources servers, You need to redefine it without cookie related headers like belows.
zuul.sensitiveHeaders=Authorization
The above example is using global configuration. You can define it for each route. Please refer to the section "Cookies and Sensitive Headers" in the the linked doc : http://cloud.spring.io/spring-cloud-netflix/spring-cloud-netflix.html
If you also need to authorization header in your resources servers, you can define above configuration with blank list.
make sure your are using filter more than 5
#Override
public int filterOrder() {
return 10;
}
for more detail find the below example
https://stackoverflow.com/a/54833734/11103297
When using Spring Session and Spring Security to protect APIs in a Microservice application, it is easy to set up to use the request header to resolve the session, the usage is very similar to the OAuth2 opaque token.
Declare a bean HttpSessionIdResolver.
HeaderHttpSessionIdResolver.xAuthToken()
Note: this is for Spring MVC. It will resolve the HTTP header x-auth-token.
When a request is sent from client, in the gateway, pass the header x-auth-token to the downstream services/components.
An working example: hantsy/spring-microservice-sample (But I did not use Zuul like Gateway in this sample application, and simply I used Nginx as reserve proxy)

Getting HTTP 401 with Spring Boot custom authorization server when accessing spring client

Hi everyone i am not able to proceed with following settings. your small pointers are appreciated.
problem statement
i am trying to use custom authorization server provided by spring cloud security and OAuth2 with my web application so that it can propagate access token to micro services in back end.
i can able to see my authorization server can able to provide access token and when try to ingest access token for invoking endpoints for for back end micro service it work as per expectation
problem faced
when i provide following configuration in spring boot web client(which will call my back end micro service)
in application.properties
security.oauth2.client.clientId=myclient
security.oauth2.client.clientSecret=abcsecret
security.oauth2.client.access-token-uri=http://localhost:9000/services/oauth/token
security.oauth2.client.user-authorization-uri=http://localhost:9000/services/oauth/authorize
security.oauth2.client.clientAuthenticationScheme=form
security.oauth2.resource.user-info-uri=http://localhost:9000/services/user
security.oauth2.resource.prefer-token-info=true
and i provide
http://localhost:8080
in my browser. it asks for credentials. i provide credentials as present with authorization server.
once valid credentials provided authorization server asks for valid scopes.
but one important thing i observe when my web client routed to authorization server it has redirect_uri
http://localhost:8080/login
(not ok since initially i entered http://localhost:8080)
i am also getting HTTP 401 error

How to integrate keycloak in Spring Boot with a different context root and reverse proxy

We are currently developing a microservice application using Spring Boot 1.4 and Keycloak 2.5.0 (configured as openid-connect service) using the Keycloak Spring Adapter (not the Spring Boot adapter).
All of our microservices are put behind a load balancer and an additional reverse proxy as the application will be hosted on an existing domain behind a context root (so the root of our application is http://foo.bar/foobar/ and the rest services are http://foo.bar/foobar/rest/).
We are facing a couple of problems with Keycloak in this given scenario:
Keycloak forward to /sso/login if a sign-in is needed. This is in our case unwanted behaviour because http://foo.bar/sso/login will not exist. I have found a way to change the forward but there is no way to make Keycloak listen to the same url; we end up with a 404 in this case.
After signing in, Keycloak redirects back to the /sso/login url with the correct tokens, but if this is not the same server, the request fails and it redirects us to http://foo.bar/. Since every microservice exposes /sso/login, this can be in fact a completely different server.
If keycloak is hosted on the same domain, we end up in a redirect loop. We would also like to have Keycloak hosted on the same domain and on the context root http://foo.bar/foobar/auth/ .
We've already tried using the "token-store": "cookie" but this did not resolve the problem.
Is there a way to resolve these problems or is Keycloak maybe not the correct solution for our use-case ?
Update 05/05/2017:
Move my answer from here to an answer
We are now up and running with Keycloak so I'll briefly explain what we did. The front-end of our application runs Angular2 and we created a custom login page in the Angular application itself (so it's not a theme for Keycloak) which will directly query the Keycloak API for an OAuth2 Bearer token. The front-end will send this token on each request in the Authorization header (as per the OAuth standards).
On the service side we have configured keycloak as a bearer-only solution (bearer-only: true in the keycloak.json), this way the application just returns a 401 or a 403 instead of forwarding to the login page.
Using this configuration the user will never see anything from the /sso/login page and there is also no redirect issue anymore.
TLDR; the use-case I described was also not realistic, calling a REST URL and then forwarding to a login page is kind of bad stuff :)

Resources