Spring Boot Admin: 401 on Jolokia endpoint causes authentication to fail - spring

I am using Spring-Boot-Admin in order to monitor a SpringBoot app whose actuator endpoints are secured using basic auth. The required credentials are transferred to Spring-Boot-Admin (SBA) like described in the documentation. SBA itself is also secured using spring-boot-admin-server-ui-login and the provided SecurityConfiguration (based on the documentation & sample apps, see Github Repo for code).
Both the app to be monitored and SBA are deployed via docker.
Logging in to SBA works fine and I can see the application state as well as the health results. For some content I see a nested login mask though. When I click on "Logging" or "JMX" I am redirected to the login mask:
In the browsers network tab I can see that a 401 is returned for the /jolokia endpoint. All requests after that seem to be forwarded to the login page.
I have the following questions:
Why am I logged out if one request to the application fails? Is that a bug?
What is the source of the 401? SBA or my app? I know that SBA proxies requests to the app. According to the access logs from my app no request to /jolokia is done when I login to SBA. Does this mean that the 401 is returned by SBA directly? Its logs contain nothing of relevance though.
Accessing the /jolokia endpoint directly works fine. It even works when I use the same (proxied) URL that SBA uses (e.g. http://XXX:8090/api/applications/XXX/jolokia/). What is different when this is executed from within SBA?
I've tried to find more error details in SBA but so far failed to find the proper logging options. They either contain nothing relevant or way too much information (e.g. Spring Security) that doesn't seem to be relevant. Logging the full response would probably help...
Edit: I just realized, that the request to the /jolokia endpoint actually contains a different cookie (Cookie:JSESSIONID=4E51B84AE15A6890500F967B23EB92AC) than the requests to the working endpoints (e.g. /metrics). Thats weird, but probably explains why the /jolokia endpoint returns a 401. Now the question is: Why does it send a different cookie`?

I tried various things, but in the end couldn't solve this.
I instead ended up with a different configuration: No security at all for the endpoints (management.security.enabled=false), but exposing them on a different port (management.port=8081). This management endpoint is blocked for external access to the system completely.
With that, SBA behaves nicely and the application is still secure. In the end, its a much simpler setup which is good, too.

I had a similar problem.
I could access all actuator endpoints, but everything with /jolokia would not be authorized. Although my security setup is a different to yours, i assume the problem is the same.
When i digged into this I found out that jolokia runs in its own servlet separately from the spring boot application. Maybe therefore you have different sessions!?
My Security Config tries to match this expression
.mvcMatchers("/actuator/**").access("hasAnyRole('ADMIN','SBA')"),
but the SBA user role was not able to access Jolokia. It always matched the last fallback-rule where only Admin was allowed.
In my case the context- and servlet-path of the jolokia servlet would be stripped away from the request path before trying to match it to my security config. Then it would only match "/list" against my MVC matchers instead of "/actuator/jolokia/list" which would then not fit as expected.
Unfortunately I do not have a fix for your problem. For my case i added a requestMatchers rule which is a little bit less opinionated and would still match:
.requestMatchers(request -> request.getRequestURI().contains("/actuator/jolokia/")).access("hasAnyRole('ADMIN','SBA')")
instead of
.mvcMatchers("/actuator/**").access("hasAnyRole('ADMIN','SBA')")

Related

SPRING Boot App Integration with IdP/PING Federate

I'm new here and posting the first question ever, and coming straight to the point.
I have a N Tier Application, Front UI on AngularJS, backend on Spring Boot and a NoSQL DB with some caching attached to it.
I'm struggling in getting the SSO configured using PING Identity for my Home grown application for following reason.
Lack of knowledge on PING SSO.
The knowledge that i have gained so far only gives me limited visibility on how i can achieve the solution for having a successful SSO configured.
Summarized Solution:
Front End UI -- Speaks to Middleware Service for Auth(current design) -- Middleware Service acts as a Interceptor for my backend services(also known as BFF) which handles all my tokens for necessary handshaking. --- Backend Services performs logics & functions
Problem: Trying to bring in PING for SSO is confusing:
as far as i know PING can be configured in 2 ways.
OAUTH2.0
SAML Based Auth.
in Oauth, User would access, Ping URL with context path which will internally speak to PING federate and AD and return a Token.. i might be wrong here. hence need clarification! as im not an expert on PING.
the confusion in case of OAUTH is, its totally confusing.. i have used oauth before, but via PING using it for the first time.
in SAML based Auth, again a PING URL with context path which will internally perform its work and then add some Assertion and then return the SAML token to a POST endpoint.
the confusion in case of SAML is as following:
if i configure my middleware to receive the SAML Token, how can i redirect the user to welcome page?
PS the middleware has some encryption logic that cannot be by passed!
any help in this matter would be highly appreciated. as im looking to see what options do i have on PING or even on my Springboot app.

Set up a proxy between multiple user machines and Okta for authentication

We are using Okta Customer Identity with our application. The challenge with our architecture is that each user gets their own server and subdomain, which is a little weird for Okta, because each redirect URL needs to be provided as part of the application configuration. As we add new users, the list of redirect URLs continues to grow, one per user machine. Their API is not really designed for this, so we have to write the complete list of redirect URLs with every change.
We would like to find a way to use a proxy for the Okta authentication, so that we can just have a single redirect URL for the Okta application configuration. But we're using https://github.com/okta/okta-spring-boot, and we're not really sure how to make it work with a proxy.
If we set up an HTTP proxy using -Dhttp.proxyHost=my.proxy.host -Dhttp.proxyPort=8080, that's going to affect all HTTP traffic, which is not acceptable.
Is there a way we can use an HTTP proxy purely for the Okta auth only, leaving all other HTTP traffic unproxied?
Is there something we can do with the Okta Spring Boot library that would make it possible for all user machines to share a common proxy machine?
The final alternative would be to write some "active" proxy code that runs on the proxy which handles the requests and forwards them on to Okta. It would have to introspect the Okta response and pass it back to the right user machine.
Is there a way to do #1?
Failing that, is there a way to do #2?
If neither of those are possible, are you aware of an existing implementation of #3?

Securing SpringBoot API for desktop application client

I have a SpringBoot Micro-Service based backend API that uses Zuul as a gateway proxy between a JavaFX Desktop Application. Right now there is no security in place, but I am looking to secure the backend with Spring Security, however, every tutorial I seem to run across seems to be based on web-apps and I haven't seen anything for my particular use case. I don't know much about spring security but would like to know if I can accomplish my goals with it, and if so, what modules or examples should I be looking for.
Goals:
Provide a way for my API to know that requests are coming from the desktop app itself, I think the technical term for this is assigning the desktop app a client id and then having the Zuul Server validate that the client id is that off the desktop app before accepting the request. This should be the case for all requests
Only allow API traffic through the Zuul Proxy, all of the downstream requests to the micro-services behind the Zuul gateway should only be accepted if they are coming from the Zuul Server itself.
Allow requests for logging in and registering as a new user without any type of security other than the desktop client id discussed in 1.
When a user provides a successful username/password on login, they are returned a JWT which is then stored in the JavaFX application and used for all of the other requests to the backend.
Configure the token to expire after a specific time frame, say like 90 minutes and provide a method for automatically refreshing an expired token as long as the users account is still valid. For this, I don't want the user to have to re-login, I just want it to check behind the scenes to make sure their account is still valid and then issue a new token if needed.
Have user based roles so certain features, methods, endpoints, etc. are only accessible to users with the valid role. Within the GUI these features will be hidden or disabled, but I would still like a layer of security on the server side to protect against unwanted access in case someone was able to modify the app.
I am just writing down answers to each of your goals :
Passing the client Id in every request from desktop application doesnt make sense, instead you client Id and secret can be passed during authenticaiton call, Like we have in Oauth 2.0 framework. Rest https calls should be made from client, So to avoid tampering of request, You can also go for mutual SSL between your client application and Zuul API gateway, It assures that call is coming from Desktop client only.
Yes, Zuul api gateway should be single entry point to your application, Your internal microservices should not be exposed to public.
For user registeration, Client authentication can be achieved using client Id and secret
Correct, You can also create http only cookie at backend, which will include your jwt token only.
Token refresh can be achieved at zuul api gateway, if session is active, make call to refresh token endpoint to get new access token.
On server side, At zuul proxy you can validate the incoming bearer token expiry along with signature validation, with generic claims too. Now at microservices level spring security can be used for role based access control for particular methods.

Spring Security Kerberos SSO for a REST API (Tomcat)

Here is my problem:
Context :
-Windows Server 2012 with ActiveDirectory
-Tomcat
-Rest API (Spring)
I'm currently trying to restrict REST request. I want that only specific groups of the AD could access to specific resources. I'm restricted to Kerberos authentication.
System configuration
Create a user in domain "Tomcat"
setspn -a HTTP/apirest.domain#DOMAIN
Generate a tomcat.keytab using ktpass
API rest configuration
I'm using the spring security sample on github that you can find here :
https://github.com/spring-projects/spring-security-kerberos/tree/master/spring-security-kerberos-samples/sec-server-win-auth
I know that there is an EntryPoint and this is not needed in my context (API Rest). I've chosen this sample because it seems to use the windows authentication context and use it to automatically authenticate me in the spring security context. Right after, an ldap request is send to extract all information about the user logged. In my case, I need to extract the group.
I'm also using :
https://github.com/GyllingSW/kerberos-demo
To extract the role of the user with the class "RoleStrippingLdapUserDetailsMapper.java" instead of the "ActiveDirectoryLdapAuthoritiesPopulator". This implementation also offers localhost authentication but the issue with the NTLM token seems to be fixed in last commit of spring security.
I'm not really sure if this is the right way to do what I want.
My authentication seems to fail and I only have one things going wrong in my logs..
"Property 'userDn' not set - anonymous context will be used for read-write operations"
Questions
Do I have to run my tomcat service using the tomcat account ? (Seems to be, yes)
Am I doing the right things with Kerberos security ?
How can I get rid of the anonymous context?
The anonymous context seems to be set just right after Tomcat start. I want to get a context just after that my user (For instance, user1) requests the rest API (EntryPoint or whatever)
If there is something unclear let me know, I will try to reformulate!
Thanks,
You do not need to query LDAP to get information about which groups does user belong to. Active Directory already adds this information to the Kerberos ticket which is sent from browser to Tomcat.
You just need to extract this information from the token for example using Kerb4J library. It comes with Spring integration inspired by spring-security-kerberos project so it should be pretty easy to switch to it.
If you still want to query LDAP you need to authenticate in LDAP before you can make any queries. Again there's no need to use end-user accounts for it - you can use the keytab file for Kerberos authentication in LDAP and query groups using "Tomcat" account
I found a way to fix my issue.
In a REST API context, you have no entry point. I tried to set my entry point to an unmapped URL, just to do the negociation. By doing this, you will receive an HTTP response with the error code 404 (Not found) but with the right header was added by spring security (WWW-Authenticate).
The web browser will not send the ticket service if the error code is not 401.
To solve this problem, you have to create a CustomEntryPoint class (implements AuthenticationEntryPoint) and you need to override the "commence" method to return a 401 HTTP code with the right header.
I hope that could help. If there is a better way, let me know !

Can't understand how to work with OpenID protocol using openidConnectClient-1.0 feature and Angular application which using REST API endpoints

So, I have a WAS Liberty server which configured to work with OpenID provider. Then I have an Angular application which heavily using REST Api endpoint.
When I first open an application or open it after token has been expired everything is ok, WAS redirects me to OpenID provider and then regular flow defined by OpenID and backed by openidConnectClient-1.0 implementation.
But how do I suppose to care about following use case: token has been expired while the application were open, and user issues GET or POST request without reloading the application? Right now WAS perform redirect too, so I can't actually distinguish between regular response and redirect (both return status 200).
The only solution which I think about is to say to Websphere not to perform redirect for some endpoints but to return 401/403 errors. So I'll be able to monitor response codes in my client side and perform accordingly. Is it possible to achieve? Perhaps there's another solution which I didn't know about?
Update: After I've written this I thought about using Authentication Filters, i.e. define something like:
<authFilter id="testFilter">
<webApp id="simple" matchType="contains" name="simple"/>
<requestUrl id="excludeUrl1" matchType="notContain" urlPattern="/basic"/>
<requestUrl id="excludeUrl1" matchType="notContain" urlPattern="/api"/>
</authFilter>
But I immediately see two drawbacks on this approach:
Maintain app's logic in two different places, server.xml and app itself. It'll make maintenance of the application very cumbersome.
Due to nature of Authentication Filters it will fallback to another registry to perform login. It potentially can be a security flaw.
Update 2: Solution from above doesn't work. When server returns 401 Error together with www-authenticate header, browser shows popup of basic authentication, see proposed solution below.
To resolve this issue I've used Angular's Interceptors, where I check if there're following headers within the response: no-cache, no-store, must-revalidate, private, max-age=0. If they persist within the response I know that session expired and perform reloading of my application.
While reloading, liberty itself redirect it to SSO provider. Another solution is to extract redirect URL from response and redirect to it manually.

Resources