For a few reasons I cannot use refresh tokens on client, is it possible to implement RemoteTokenServices on ResourceServer so that it checks the token is not revoked on auth server, but get auth information like user details from JWT-token itself, not from authentication server, like default implementation does using uuid tokens?
upd: this question is not duplicate, it's about JS and general
approach, I'm fine with approach I explained, I wonder if and how I can implement it using spring boot and spring security.
JWT consists of three sections:
Header #info about used algorithm
Payload #contains data, this one is important in your case
Signature #basically a hash of the first two items on this list
You should read about Payload (and JWT itself) here https://jwt.io/introduction
Long story short, you can include public data in the payload. If it comes to the mentioned RemoteTokenServices - sure, you can do that but I'm not sure if it's a good idea. You could just add public expiration-date (or expires) property to the payload.
Also, take a look at this: https://jwt.io/
Related
I want to secure a REST API via JWTs provided as Authorization Header in the requests. I am have a quarkus application and would like to use their official guide - https://quarkus.io/guides/security-jwt
The guide specifies:
mp.jwt.verify.publickey.location=publicKey.pem
mp.jwt.verify.issuer=https://example.com/issuer
So far so good, now we can check if JWTs are signed by a private key that corresponds to this public key. The problem I have is that I have different APIs and different OAuth integrations, let's say 3. So different API Endpoints expect different JWTs and hence also have different public keys. Is this even supported in mp?
Spring Security allows multiple WebSecurity with different #Order and integrating multiple oAuth Servers works there. How can this be done in Quarkus/MP JAX-RS?
Yes. But using a JSON Jwt Key Set:
mp.jwt.verify.publickey.location=my-pubkeys.json
The Jwt Ket Set allows to provide several public keys in row. You can also provide an URL instead.
Also, forget about mp.jwt.verify.issuer: the property expects a string representing a single issuer. This property is not mandatory, so if you really want to control the issuer you will have to control it by yourself in your request filter.
If you only have PEM files for your pubkeys, you can turn them into Jwt Key Set using PEM to JWT convertor like this one (online). Then you just have to serve the .json file.
I am trying out an example to add user attributes to the claim. I am following the example here. I am trying to access the claim in a filter and am unsuccessful.
I would want to understand how the protocol mappers work behind the scenes, namely how and in which order are those claims from that protocol added into the token.
In Keycloak, the function of the protocol mappers is to add additional claims to a JWT besides those that are added by default by Keyloack.
Different Protocol Mapper will have different options, but for most of them you can chose to add the claims that those mappers will produce into the:
ID Token;
Access Token;
UserInfo;
I would want to understand how the protocol mappers work behind the
scenes.
Roughly, what will happen is the following the JWT is basically an encoded JSON Object based on a specific standard, Keycloak creates that object with the Registered claims (e.g., Issuer, Subject and so on), and then it will apply the custom claims (i.e., protocol Mappers) into that temporary object by the Priority Order that you have defined for that given protocol Mapper.
The end result (i.e., the token) will be a JWT with the default claims, and with the claims added with the protocol mappers.
I'm talking about the case when these two are separate apps. I'm not interested in merging them in one app.
So, in a authorization server we extend AuthorizationServerConfigurerAdapter class and in resource server ResourceServerConfigurerAdapter and in both we create exactly the same beans like JwtAccessTokenConverter, DefaultTokenServices etc. but mostly I don't get why do we need TokenStore in both.
Does this mean that we store for example in memory the same token in different applications?
What's the best approach to remove this code duplication? Create a library for common classes? Make request to auth server to validate the token? But how are we going to extract more info from JWT token if we don't have the decoding logic in resource server?
Does this mean that we store for example in memory the same token in different applications?
https://auth0.com/learn/json-web-tokens/
This is a stateless authentication mechanism as the user state is never saved in the server memory. The server’s protected routes will check for a valid JWT in the Authorization header, and if there is, the user will be allowed. As JWTs are self-contained, all the necessary information is there, reducing the need of going back and forward to the database.
What's the best approach to remove this code duplication? Create a library for common classes?
If you use a symmetric key:
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
JwtAccessTokenConverter, DefaultTokenServices etc will be identical beans in both resource server and authentication server, so you could have a common project for both with the declarations of these beans, and add them as a dependency in both projects.
But, if you use an asymmetric KeyPair, the beans declaration changes completely and they couldn't be the same.
You can see more information about this difference here:
https://www.baeldung.com/spring-security-oauth-jwt
Make request to auth server to validate the token?
JWT's main advantage is not having to do that.
But how are we going to extract more info from JWT token if we don't have the decoding logic in resource server?
If you use a symmetric key, you can decoding logic in resource server.
The best way to resolve this case in the microservice system - is to create some entities: API composer, authorization service and business services.
Base mechanism of this scheme is:
Firstly, you separate your requests with unauthorized and authorized with a token header. Usually, it's named something like "X-AUTHORIZATION-HEADER" or anything like this. In this header, you put your JWT-token and send it on the server's gateway, which role is performing 'API Composer' - It's some kind of router, which accept requests, and delivery them to the appropriate recipients.
In particular, API composer accepting a response, parsing headers, finding the appropriate header with a token, and sending it to Auth Service and receiving a response with user or error. And in this scheme, you need entities like JwtAccessTokenConverter and else only in Auth Service
Then, aggregated response payload will be complete, your API will send the response to the client.
I use this scheme when I developing my microservice systems, for me it's working fine.
Hope, I correctly understood your question and my answer is will help you) Best Regards.
I have an application where single user can work in contexts of multiple companies. We call such a connection (user<->company) a permit. Every one of this permits can have different sets of permissions/roles. We want user to login just once and then he can simply change permits within application without need to enter password again.
Till now we had only one application and kept this whole permission model in our own DB. Unfortunately now we have to support second application which should inherit those permits. I was wondering wether is possible to move that model to keycloak so we don't have to replicate it to every single db and keep it in sync manually.
I have searched keycloak documentation regarding this topic but have found no information att all, which seems quite odd, because I don't think we are the first one working with multiple context application.
So now I'm asking is it possible to configure our model in keycloak and if so, how to do it? Eventually are there different options? I guess that I can provided that model as a claim with json structure but that doesn't feel right to me. I was thinking about custom IDP which could provide such claims based on DB so there no spelling errors and less repetition but I feel there should be a better way.
You could try to write your own Keycloak provider (SPI). There is a built in mechanism that allows you to expose REST endpoint on the Keycloak: https://github.com/keycloak/keycloak/tree/master/examples/providers/domain-extension
That REST could be called with authorized context only for example by passing Access-Token (Authorization header with Bearer value). On the provider level (through implementation of: org.keycloak.services.resource.RealmResourceProviderFactory and org.keycloak.services.resource.RealmResourceProvider) you have access to user's Keycloak session and object UserModel like in the following code:
AuthenticationManager.AuthResult authResult = new AppAuthManager().authenticateBearerToken(keycloakSession, keycloakSession.getContext().getRealm());
UserModel userModel = authResult.getUser();
UserModel class has methods for getting and setting attributes, so some information that indicates the current permit/company ID can be stored there. You can use REST methods exposed on the Keycloak to modify the model within the 'session' (represented by Access-Token).
The Github example shows also how to use another Keycloak provider (ex. built-in JPA provider) from you custom provider's level, so using that approach you could try to connect to the database with your permits/company informations. Of course the datasource representing you database should also be registered as Keycloak datasource.
We use the Spring SAML Security Extension to implement SAML in our application. We now have the following problem:
One of our customers is providing a URL for their identity provider that contains a parameter. The metadata looks like this (heavily abbreviated for brevity):
<EntityDescriptor>
<IDPSSODescriptor>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="https://idp.example.com/login?parameter=value"/>
</IDPSSODescriptor>
</EntityDescriptor>
As can be seen, there is a parameter named "parameter" with a value "value". This parameter is not present in the generated redirect URL. I debugged a bit and found out that SAMLProcessorImpl gets the MessageEncoder from the binding (which is HTTPRedirectDeflateEncoder for HTTP redirect) and delegates encoding the message. The encoder in turn does the following in its buildRedirectURL method:
// endpointURL is https://idp.example.com/login?parameter=value here
URLBuilder urlBuilder = new URLBuilder(endpointURL);
List<Pair<String, String>> queryParams = urlBuilder.getQueryParams();
queryParams.clear(); // whoops
So for some reason, the parameters are stripped intentionally and unconditionally.
Why is this the case and how can I fix this in the most efficient way?
SAML Authentication Request should be only sent by trusted entities and with parameters which cannot be tampered with. Adding a parameter in addition to SAMLAuthnRequest encoded according to HTTP-Redirect binding will mean that a potential attacker can change the value as he/she pleases and IDP will not be able to detect such change - as the parameter will not be covered by digital signature.
SAML provides a mechanism for delivery of secured content in addition to request itself called relayState - and you can set it using WebSSOProfileOptions of Spring SAML.
The above is reason the parameters are cleared (at least I believe so, this logic comes from OpenSAML library which is not written by me), but of course in case you don't mind the security implications, the approach you found is just fine.
For now I solved the problem by extending HTTPRedirectDeflateEncoder, copying the code for buildRedirectURL and remove the queryParams.clear(). Because the URL is created by simple concatenation I explicitly removing all reserved SAML parameters (like SigAlg and the like) in order to avoid potential security issues. After that, it's a simple Spring configuration change to wire everything together.
I still don't know why the list is cleared in the first place, though.