How do I configure static multi-tenant authentication in Quarkus - security

We are using a single Quarkus instance to serve multiple user groups (ADMIN and USER). Up to now we were using one single authentication service so secure our web endpoints (configured in application.properties).
Now requirements changed and we have to authenticate the USER endpoints with a different AS.
Does anybody have an hint how to do this in a simple way. My expectation would be to have some Quarkus config in application.properties like
# user authorisation (default, well documented at Quarkus)
quarkus.oidc.auth-server-url=https://url/to/user-auth
(...)
quarkus.http.auth.permission.app.paths=/admin/*
# admin authorisation (my guess)
quarkus.oidc.ADMIN.auth-server-url=https://url/to/admin-auth
(...)
quarkus.http.ADMIN.auth.permission.app.paths=/admin/*
I know best practice would be to create different service instances but we would like to safe the efforts duplicating the infrastructure and keep things in a single block.

Related

Grant access Keycloack roles to specific subdomains with traefik

My goal
overall goal
I want to serve various applications running on docker containers hosted on the same server, each on a subdomain of company.com. And I want only people from my organization (Microsoft AD azure) to access subdomains, in some cases even only people having specific AD groups.
goal specific to Keycloak
I simply want to have specific realm roles have access to specific subdomains, and nothing else. And this, using only a single realm client (see further for explanation).
what I have achieved to do
I have linked several applications on a server and serving each using traefik on a specific subdomain. For example app1.company.com and app2.company.com.
I have also made a middleware so that all routers using it will make sure users must login. I have used a thomseddon/traefik-forward-auth container that I called oauth. I am using Keycloak and I have successfully linked an Azure Active Directory as identity provider. For this, I enabled a single-tenant application and used its client id & key. I also mapped successfully some AD group to a Keycloak role.
Within oauth configuration, I have added the client id & secret from a single keycloak client rather than from the azure application. I believe this is mandatory if we want to use traefik to redirect trafic.
Now, only people from within my organization can access each app. Success!
Some documentations I used
Homelab Single Sign-On & TLS
How to Configure Microsoft Azure Active Directory as Keycloak Identity Provider to Enable Single Sign-On
what I want to do
Each application has its own subdomain. However I cannot figure out where to make it so that some subdomains are accessible only if a user has a specific realm role (linked automatically depending on a AD group thanks to the above-mentioned mapper).
I thought of adding resources within the Keycloak client, but I don't find how to do it using subdomains.
other alternative is to make one client per subdomain, but this means I need to run one oauth container per subdomain... This seems overkill & a waste of resources without counting maintenance.
The only relatively simple solution I found was to create one Keycloak client per type of permission rules (aka Roles in Keycloak) I wanted.
Then for each type, I had to make a traefik-forward-auth container and connect it to each Keycloak client. I am still using the same Identity provider, so once you've configured it to generate roles, you only need to tell which roles may use which client.
To give an example, you want to have 3 types of permission rules: one for admin, one for trusted users, and one for untrusted user. It could look like this:
admin.example.com
trustedusers.example.com/app1 and trustedusers.example.com/app2
untrustedusers.example.com/app3 and untrustedusers.example.com/app4
You would then have 3 forwardAuth middlewares within traefik.
It is a little bit more cumbersome, but your applications are still connected to your OIDC provider using a single key, then you manage the details using keycloak and these clients.
Of course there is still the solution to have one client per application as is originally planned. This may be unnecessary, and cumbursome if you have a large number of applications (one additional container per application + additional middleware).

How can I replicate user roles from an Authorization Server to downstream microservices?

I need to implement an application where I am going to use an Authorization Server generating a JWT token. These token will include the roles a user is granted to then authorize the user access to different resources. There will also be a gateway where this security will be added.
My question is regarding the user roles and the security between internal microservices.
When the user is created, he should be granted a set of roles and he may be granted different ones at a later point or maybe new roles will be added later. All this information should be stored in the Authorization Server. But how is this information replicated to other microservices? If I use a framework like Spring Security to secure my endpoints, where I add the roles needed for the different URLs, do I need to hardcode the user roles into my security configuration in the downstream microservices or is there any other way to find them from the Authorization Server?
The architecture is going to use an API gateway in a public network that then communicates with a service discovery in an internal one to find the different microservices. These also find each other through the service discovery. I use Zuul for routing. In this situation, do I need to also secure the communication within the internal network? I understand that to use Spring Security for authorization I would need to pass the JWT token anyway to get the user roles. But would it be necessary otherwise? Would it be enough to use HTTPS from the client to the gateway and unsafe HTTP within the private network?
There are many options here.
One of these is that you may use spring-security-oauth2 in combination with spring security. In this setup you will distinguish two kind of applications:
Authorization service (AS) - this service issues and verifies access tokens for authenticating clients (e.g. using password grants or authorization codes);
Resource service (RS) - it exposes a REST API for CRUD operations on resources, for example. The endpoints are protected. The RS communicates with the AS in order to grant access;
In a resource server you will use and configure the Spring Security as you would normally do in a stand alone application. Below is one very simple example.
Here is the code in a REST controller with protected endpoints:
#PreAuthorize("hasRole('READ_BOOK')")
#GetMapping(value = "/books/{id}")
public ResponseEntity<Book> getBook(#PathVariable("id") String id) {
...
//retrieves book details if you have role READ_BOOK
}
#PreAuthorize("hasRole('WRITE_BOOK')")
#PostMapping(value = "/books")
public Book createBook(#RequestParam("title") String title) {
...
//creates a book if you have role WRITE_BOOK
}
The security configuration will look just as if you are writing a monolithic application with the exception that:
you will add an #EnableResourceServer annotation on your configurations;
you will configure an instance of RemoteTokenServices - the task of this service is to verify the provided tokens against the authorization server and fetch user roles;
The AS will issue access tokens based on some OAuth2 workflow. These tokens will be used by the client to access the protected endpoints.
I've made a small PoC (proof of concept) setup in which I created two simple apps showing the whole thing in action. Please find it here and feel free to submit questions, proposals and PRs. The complete source code is included bundled with more explanations.
Please note though that this setup in certain cases may cause too much inter-service communication. I have seen a more complicated setup in which the API gateway acts as a resource server and if the user has enough credentials it enriches the request with the necessary details and passes the request to downstream services which basically trust the gateway.

Azure AD Login/logout implementation for Spring cloud microservices

I want to implement login and logout functionality and retrive user details like username and user role using Azure Active Directory.
We are using Docker to deploy Spring cloud microservices project on Azure cloud. Could you please suggest me steps to get user details?
Do we need to secure all microservices edge points using Spring cloud OAuth2 security using JWT or just we can secure one web microservice ? Do I need any permission ,specific user roles to implement this?
You can find Azure's documentation about OAuth 2.0 support for AAD here
https://learn.microsoft.com/en-us/azure/active-directory/active-directory-protocols-oauth-code
I've got an application that's using OAuth 2.0 with a different Authentication Server, and I'm about to see if I can use AAD as the Authentication Server. But, whatever ends up being your Auth Server, the rest of the application should be the same...
The Auth Server handles the log in (typically as a Single-Sign On pattern)
The Auth Server will return a Json Web Token (at some point, depending on the Grant Type being used to retrieve it)
The JWT should be included in each subsequent request to ensure the caller has authorization
From a Spring perspective, you'll need at least a SSO Client (denoted by the #EnableOAuthSSO annotation). If everything in hosted by that process, you'll need that JWT to call subsequent methods. If you have processes hosted in other processes, it's likely you'll want them secured as well. Using the #EnableResourceServer annotation will configure Spring Security to look for the JWT, just not attempt to retrieve one if the request does not have it.
Unless the endpoint is meant to be publicly accessible, you will want to secure it. Of course, I really don't know the context of your application, so this statement is purely an uninformed opinion based on zero knowledge of what you're trying to do with your application. Take it for what it's worth.
EDIT
This has become a little more complex than I originally thought. I have been able to write some code to dynamically retrieve the public key from Microsoft in order to validate the returned JWT.
But, the main issue is the fact the Azure AD supports Open Id Connect when acting as an Identity/Authentication Server. And, at the moment, spring-security-oauth2 doesn't support Open Id Connect.
I was able to make some small changes to the spring code, but I did ask the question to the Spring group and they are actively working on adding support for Open Id Connect. They hope to have a release two months (ish?).
For the short term, the oauth2 support doesn't support Open Id Connect. Given this is the protocol used by AAD, the current version of oauth2 won't work with AAD. That said, I will be happy to wait for the official support which shouldn't be too long.

Is it possible to supply custom authentication mechanism to javaee security from within the webapp?

I would like to use javaee security, but I need to authenticate users against an external proprietary authentication mechanism, which is different from LDAP and any other standard mechanisms coming with Wildfly. In particular, I would prefer if the authentication is taken care of by the application, not by the container. I only have come across PolicyConfiguration. But I think that it implies buiding an extension to be plugged into the underlying application server.
What I would like is to let application server obtain credentials in a standard javaee way, then execute a callback into the application in order to authorize them, and then establish current user together with his roles, so that I may use declarative security using annotations.
Is this possible in standard way? Or the only solution is to build an extension module for the application server?
An not so elegant solution would be to perform the login using HttpServlet.login. You still need to configure a realm that would acknowledge the username and password you provide in the method call.
Another, more complex, solution would be to create an JASPIC authentication provider. In short, you are in charge of the whole authentication process. Here is a collection of resources to get you started: Zeef

Websphere Application Login

I was trying to register an Application Login Module in Websphere but I don´t find any easy example in web.
There are a lot of IBM documents, but too much complex, and I can´t figure out how to register an Application Login Module.
I already have success with a System Login Module bounded to WEB_INBOUND, it works, but affects all my system. I want a Login Module to serve only my applications web, with JAAS authentication.
I´ve tried to bound a login module to existing WSLogin but it doesn´t seems to be working.
Any help ?
tks[]
You need to setup security domains to get the separation you are looking for wrt to the login configurations. The security framework uses the WEB_INBOUND login configuration to authenticate the user for all web applications irrespective of adminConsole or user applications. When you create a security domain and customize the WEB_INBOUND configuration at the server/cluster domain level, it will be used for all the user web applications deployed in those processes. You need to setup the multidomain in a cell topology and assign the domain to the server/cluster where you applications are deployed.
Once you setup the domains, the WEB_INBOUND configuration at the server/cluster domain will be used by the user applications hosted in that server/cluster while the WEB_INBOUND configuration at the admin/global domain will be used for the adminConsole application at the Deploymener Management process where it is deployed.
The application JAAS login configurations are meant to be used by the applications directly. One can create an application login configuration and programmatically use it in the application to perform direct login -
LoginContext lc = new LoginContext("myAppLoginCfg1", callBackHandler);
I asked around and this is the answer that comes from the owner of container security:
The WEB_INBOUND is a JAAS system login that is always configured by default. However, you can specify your own JAAS application login or customize the existing WEB_INBOUND system login. If you want only one application to use a different JAAS login from all your other applications, you can use a security domain that has those different security configurations. The only catch is that application server has to be in a separate server from the other apps. That way, you can map your security domain to that server.
Here's an info center article about security domains:
http://www-01.ibm.com/support/knowledgecenter/#!/SS7K4U_8.5.5/com.ibm.websphere.zseries.doc/ae/tsec_sec_domains_config.html?cp=SS7K4U_8.5.5%2F1-8-2-33-1
And one on application logins:
http://www-01.ibm.com/support/knowledgecenter/#!/SS7K4U_8.5.5/com.ibm.websphere.zseries.doc/ae/rsec_logmod.html?cp=SS7K4U_8.5.5
And system logins:
http://www-01.ibm.com/support/knowledgecenter/#!/SS7K4U_8.5.5/com.ibm.websphere.zseries.doc/ae/usec_sysjaas.html
And here is a much more practical answer that comes from the security dev lead:
So an additional question is - why would you want to do that? Do you want to do anything specific for just one app during login that you do not want for other app logins? (I would think so) You can get the app name in your custom login module and can use that to provide your own app based login requirement in your login module (or skip it) if needed.
Me: Ya, this is what I would do. You can also implement this based on what is in the request. I did one where it would request a SAML token from an STS and put it on the runas subject if I could tell that the request came from WebSeal (and not if it didn't).
If what you need to do for the 'app-specific' case requires skipping what is done in ltpaLoginModule and wsMapDefaultInboundLoginModule (that should run for the other apps), you can't really do that. However, you can modify their behavior.
Read through the task I've given a link to below. Yes, I understand it is a WS-Security task, but its about using APIs. You'll get what I'm talking about if you read closely, particularly the 3rd ("When a caller...") and 5th ("To use a..") paragraphs. The parts that you should be concerned about in the code is the WSCREDENTIAL* stuff.
http://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/twbs_config_wssec_caller_no_reg.html

Resources