Authenticating with an API key in JAX-RS - java

We'd like to secure our rest api using an api key. Here are the requirements:
Public-facing services require an api key.
"Private" services can only accept a call from within the cluster,
not the outside world.
Each api identifies a user, and the User object must be available to
the rest service.
Is there some standard way to do this in a JAX-RS app? (We're using Resteasy.)
I've read all about filters, interceptors and basic auth, but it isn't clear to me what's the best approach.
In an earlier version of the app we had a roll-your-own solution in which public services ran on a public port and private ones on a private port. There was a custom api key lookup that set the User object as a variable into the rest service object.
I can't figure out how to do either of these things using standard JAX-RS.

Using a filter to intercept the request
This kind of authentication could be achieved with a ContainerRequestFilter, intercepting the requests to your resource methods.
The filter will be used to extract the API key from the request and validate it. If the API key is not valid, the request will be refused. Otherwise, the request will proceed to the resource methods.
Have a look at the following piece of code. The ContainerRequestContext API can be used to extract information from the HTTP request:
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Extract and validate the API key from the request
String apiKey = requestContext.getHeaderString("API-Key");
...
}
}
Also have a look at this answer I wrote a while ago about authentication with tokens in JAX-RS. There you will find plenty of details that can be useful to address the situation you described in your question.
Identifying the user
During the authentication process, you must be able to identify the user who is performing the request. To propagate this information to your resource classes/methods you could:
Override the SecurityContext and inject it into your resource classes/methods.
Use a CDI Event and a producer method to create an object that contains the user identifier that can be injected in your resource classes/methods.
For more details on the these approaches, refer to the answer I mentioned above.
Binding the filter to some resource classes/methods
By default, the filters are global (it means they are executed for all the resource methods of your application). To bind the filter to a subset of resource methods or classes, you could use name binding annotations.

Not giving a detailed answer, but just a suggestion. Check for CustomInvokers and register the invoker for the services. Validate the api-key and throw an error if it's not valid. If there is an error then your client gets an error. The Service code won't be called.
For the actual security framework, please check netflix zuul.

Related

Quarkus and Keycloak: evaluate scope based permission

I have a REST API, that should use Keycloak for authorizing incoming requests. I have problems with configuring desired scopes in my API.
In Keycloak I defined a client for my API, a client for the calling service and two users. Both users have some realm roles. The client for my API defines a resource, some scopes (eg read, delete), policies and permissions.
One permissions allows an user with the admin role to perform scopes read and delete on the resource. The other allows an user with the monitoring role to read the resource.
I understand that the path of my endpoint will be checked against the path defined in the Keycloak client resource.
My concrete problem here is that I don't know how to tell my endpoint, which scopes he needs.
In the end I want to have multiple endpoints with the same path but different scopes (for each HTTP method).
Here is my example config:
quarkus.http.port=8080
quarkus.resteasy.path=/api
quarkus.oidc.auth-server-url=https://myUrl:8443/auth/realms/enaq
quarkus.oidc.client-id=rest-api
quarkus.oidc.credentials.secret=secret-string
quarkus.oidc.enabled=true
quarkus.application.name=keycloak-test-api
quarkus.application.version=0.0.1
quarkus.keycloak.policy-enforcer.enable=true
Here is an example implementation:
#Path("/measurements")
public class MeasurementResource {
#Autowired
MeasurementService delegate;
#GET
#Path("/{id}/{from}/{to}/{resolution}")
#Produces(MediaType.APPLICATION_JSON)
public MeasurementHistory getMeasurementHistory(#PathParam("id") String deviceId, #PathParam("from") Long from,
#PathParam("to") Long to, #PathParam("resolution") Integer resolution) {
return delegate.getMeasurementHistory(from, to, resolution, deviceId);
}
}
In my example my permissions will be evaluated, but only the admin gets access. The monitoring user will be denied, although he should be able to read.
In order to define the exact scopes that should be protected and map them to the appropriate HTTP verb, you should configure the policy enforcer as documented here.
There is no documentation on Quarkus side yet that shows how to map that to properties (application.properties) but it should be quite trivial to do so. You can grab an example from here.
Another option is to set the quarkus.keycloak.policy-enforcer.http-method-as-scope=true. By doing that, your resources would be associated with scopes such as GET, POST, DELETE, etc. And the policy enforcer will enforce access accordingly without forcing you to map paths in your configuration file.

Why do we need exactly the same configuration in resource and Authorization server

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.

Proper way to enrich Keycloak token via external service

What is the proper way of extending Keycloak -- for example via Service Provider Interface (SPI) -- to enrich the issued JWT token with information fetched from another service but without delegating the user credential check to the other service?
You create - what Keycloak documentation refers to as - a Protocol Mapper. They are various types of them that you can find out by going to the Clients > your_client > Mappers menu and try to create one. Besides, you should see that you can choose which JWT token you want to enrich, ID token or Access token. In your case, you need to customise the mapper's logic enough to fetch info from another service. There are two types of mapper that allow that (at least as far as I know):
The Script mapper: allows you to code a custom mapper in JavaScript, so you can implement the service call and add the result to the token claims in javascript. See the example on Stackoverflow, and source code of the mapper for more info. This has some limitations, e.g. does not support multi-valued claims properly.
Implement the mapper directly in Java: full flexibiliy but more work (implement Java interface AbstractOIDCProtocolMapper). See this Custom Keycloak Protocol Mapper for group membership for instance.

Is a GWT app running on Google App Engine protected from CSRF

I'm developing a GWT app running on the Google App Engine and wondering if I need to worry about Cross-site request forgery or is that automatically taken care of for me?
For every RPC request that requires authentication, I have the following code:
public class BookServiceImpl extends RemoteServiceServlet implements
BookService {
public void deleteInventory(Key<Inventory> inventoryKey) throws NotLoggedInException, InvalidStateException, NotFoundException {
DAO dao = new DAO();
// This will throw NotLoggedInException if user is not logged in
User user = dao.getCurrentUser();
// Do deletion here
}
}
public final class DAO extends DAOBase {
public User getCurrentUser() throws NotLoggedInException {
currentUser = UserServiceFactory.getUserService().getCurrentUser();
if(currentUser == null) {
throw new NotLoggedInException();
}
return currentUser;
}
I couldn't find any documentation on how the UserService checks authentication. Is it enough to rely on the code above or do I need to to more? I'm a beginner at this, but from what I understand to avoid CSRF attacks some of the strategies are:
adding an authentication token in
the request payload instead of just
checking a cookie
checking the HTTP
Referer header
I can see that I have cookies set from Google with what look like SID values, but I can't tell from the serialized Java objects in the payloads if tokens are being passed or not. I also don't know if the Referer header is being used or not.
So, am I worrying about a non-issue? If not, what is the best strategy here? This is a common enough problem, that there must be standard solutions out there...
If you were to put the same code in a regular servlet, you'd surely be vulnerable to XSRF. But since you are using GWTs RemoteServiceServlet - the answer depends on the version of GWT you are using.
Starting with the yet-to-be-release GWT 2.1, the RPC mechanism adds request headers and validates the presence of these headers in RemoteServiceServlet. This has its limitations - in particular, older versions of flash allow you to send the request headers from a different domain, but it does make things more difficult for a potential attacker.
If you want to adequately protect yourself from XSRF, refer to Lombardi's Development blog. The blog discusses two techniques. The first is a simple change that ports 2.1 changes to older versions of GWT. The second approach requires duplicating the session identifier as a request parameter, and is the recommended way to protect against XSRF.
References
GWT RPC - Does it do enough to protect against CSRF?
Lombardi development blog on GWT RPC and XSRF
Security for GWT Applications

JAXWS and sessions

I'm fairly new to writing web services. I'm working on a SOAP service using JAXWS. I'd like to be able to have users log-in and in my service know which user is issuing a command. In other words, have some session handling.
One way I've seen to do this is to use cookies and access the HTTP layer from my web service. However, this puts a dependency on using HTTP as the transport layer (I'm aware HTTP is almost always the transport layer but I'm a purist).
Is there a better approach which keeps the service layer unaware of the transport layer? Is there some way I can accomplish this with servlet filters? I'd like the answer to be as framework agnostic as possible.
I'm working on a SOAP service using JAXWS. I'd like to be able to have users log-in and in my service know which user is issuing a command. In other words, have some session handling.
Conventional Web services are stateless in nature, there is no session handling in web services (which has by the say nothing to do with identifying the caller).
If you want to require your users to be authenticated to call a service, the traditional approach is to:
Expose an "authentication" web service (passing user credentials) that returns an authentication token.
Have the users call this authentication first.
Have the users pass the token in a custom header on subsequent calls of "business" web services.
On the server side:
Reject any call that doesn't contain a valid token.
Invalidate tokens after some time of inactivity
You can implement a custom solution for this approach (this is a highly interoperable solution). Or you can use WS-Security/UsernameTokens that provides something similar out of the box. WS-Security is a standard (Metro implements it), it isn't "framework" specific.
As you mention, servlet filters can provide the basis of solution. Use a filter to store the current session details (e.g. the session context Map) in a threadLocal storage. This is implemented as your application class, so is transport agnostic. Your service simply uses a static method to fetch the current context, unaware of where it came from.
E.g.
class ServiceSessionContext
{
static ThreadLocal<Map> local = new ThreadLocal<Map>();
// context set by the transport layer, e.g. servlet filter
static public void setContext(Map map)
{
local.put(map);
}
// called when request is complete
static public void clearContext()
{
local.put(null);
}
// context fetched by the service
static public Map getContext()
{
return local.get();
}
}

Categories