I am following the guide of the new quarkus-resteasy-reactive-jackson extension to use it in an existing Quarkus application deployed in production.
In the Custom headers support section it's introduced the ClientHeadersFactory interface to allow injecting headers in a request, but you are forced to return a sync response. One can not use Uni<MultivaluedMap<String, String>>, which is of what is desired in my case, because I need to add a token in the header, and this token is retrieved by a request to another rest endpoint that returns a Uni<Token>.
How can I achieve this in the new implementation? If not possible, is there a workaround?
It's not possible to use Uni<MultivaluedMap<...>> in ClientHeadersFactory in Quarkus 2.2.x (and older versions). We may add such a feature in the near future.
Currently, you can #HeaderParam directly. Your code could probably look as follows:
Uni<String> token = tokenService.getToken();
token.onItem().transformToUni(tokenValue -> client.doTheCall(tokenValue));
Where the client interface would be something like:
#Path("/")
public interface MyClient {
#GET
Uni<Foo> doTheCall(#HeaderParam("token") String tokenValue);
}
Related
I've recently upgraded a project from using spring-security 6.0.0-M6 to 6.0.0, gradle config if you want to see it.
This project does not use spring-boot.
Context
My securityFilterChain is configured via code and looks approximately like this:
http.
authenticationManager(authnManager).
securityContext().securityContextRepository(securityRepo).
and().
authorizeRequests(). // <-- DEPRECATED
requestMatchers(RAID_V2_API + "/**").fullyAuthenticated().
The full codebase, starting with the FilterChain config, is publicly available.
Note that usage of WebSecurityConfigurerAdapter is deprecated, and I have not been using it since the original usage of 6.0.0-M6. So calling stuff like WebSecurityConfigurerAdapter.authenticationManagerBean() won't work.
This code works fine, but the call to authorizeRequests() causes a deprecation warning that I want to get rid of.
Problem
The deprecation tag says that I should use authorizeHttpRequests() instead, but when I do that - requests that require authorization (via the fullyAuthenticated() specification above) will be denied with a 403 error.
Analysis
It seems this happens because my AuthenticationProvider instances aren't being called,
because the ProviderManager isn't being called. Since the AuthnProviders don't get called, the security context still contains the pre-auth token instead of a verified post-auth token, so the eventual call to AuthorizationStrategy.isGranted() ends up calling isAuthenticated() on the pre-auth token, which (correctly) returns false and the request is denied.
Question
How do I use the authorizeHttpRequests() method but still have the ProviderManager be called so that my security config works?
My workaround is just to ignore the deprecation warning.
First, your security configuration does not specify any kind of authentication, like httpBasic, formLogin, etc. The AuthenticationManager is invoked by the filters created by those authentication mechanisms in order to authenticate credentials.
Second, the application is probably unwittingly relying on FilterSecurityInterceptor (authorizeRequests) to authenticate the user, which is not supported with authorizeHttpRequests. You need to declare an auth mechanism that collects credentials from the request and authenticates the user.
Because you are using JWT, you might want to consider Spring Security's OAuth2 Resource Server support. You can also refer to our samples repository in order to help you with sample configurations.
Here's a rough outline of what I did to to implement the "just use the resource server" suggestion from the answer.
include the oauth2-resource-server libraries in the build.
create an AuthenticationManagerResolver that replaces what the SecuritycontextRepository and the FilterSecurityInterceptor used to do:
#Bean
public AuthenticationManagerResolver<HttpServletRequest>
tokenAuthenticationManagerResolver(
AuthenticationProvider authProvider
) {
return (request)-> {
return authProvider::authenticate;
};
}
change AuthenticationProvider implementations to use the BearerTokenAuthenticationToken class as the pre-auth token, it still works basically the same way it used to: verifying the pre-auth token and returning a post-auth token.
hook up the new resolver class in the securityFilterChain config by replacing the old securityContextRepository() config with the new authenticationManagerResolver() config, which passes in the resolver created in step 2:
http.oauth2ResourceServer(oauth2 ->
oauth2.authenticationManagerResolver(tokenAuthenticationManagerResolver) );
I like this new approach because it makes it more obvious how the security chain works.
It's nice to replace the custom pre-auth token implementation with the built-in class too.
Note that it's likely this config can be simplified, but I needed the custom resolver since the project uses different types of bearer token depending on the endpoint called. Pretty sure the auth providers don't need to be AuthenticationProvider any more; the lambda function returned from the resolver serves that purpose - they can probably just be random spring components and as long as the method is SAM-type compatible.
The spring-security multi-tenancy doco was helpful for this.
I use Quarkus 1.6.1.Final version with GraphQL implementation using SmallRye GraphQL. My aim is to define logic to check user permissions on every request (Query + Mutation) made to /graphql endpoint. So, I am trying to find something like jax-rs ContainerRequestFilter but for GraphQL. Do you have any ideas on how to do it? I've tried to define ContainerRequestFilter but it catches only RestEasy requests but not GraphQL ones.
I was looking into this myself. It seems like GraphQL directly registers a Vert.X routing call [1] rather than using Undertow(servlets) or RestEASY(jaxrs). This is so it can do stuff like partial results more easily from what I can tell.
You're going to want to look at intercepting Vert.X requests using the RouteFilter annotation. I've included the link below, but it works a lot like the ContainerRequestFilter from jax-rs. I've copied the sample code from the Quarkus help guide [2] to provide a quick example:
package org.acme.reactive.routes;
import io.vertx.ext.web.RoutingContext;
public class MyFilters {
#RouteFilter(100)
void myFilter(RoutingContext rc) {
// Put your logic here
// continue the filtering of the request
rc.next();
}
}
1: https://github.com/quarkusio/quarkus/blob/master/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLRecorder.java
2: https://quarkus.io/guides/reactive-routes#intercepting-http-requests
In a spring boot application using Netflix's Feign to make HTTP requests to a service, is there an easy way to cache and return these cached values automatically? The cache should be based on the parameters passed to the request (similar to memoizing a function for X minutes).
I'm looking for something like the #Cache annotation below:
#Component
#FeignClient(value = "facebook", url = "${auth.facebook.url}")
public interface FacebookClient {
#Cache(600) // Something like this.
#RequestMapping(method = RequestMethod.GET, value = "/debug_token?input_token={input_token}&access_token={access_token}")
Map debugToken(#PathVariable("input_token") String inputToken, #PathVariable("access_token") String appToken);
}
Of course I could cache it myself using a decorator around the FacebookClient, I was wondering if there was a quicker/less code way.
Springs #Cacheable does what you need.
Check: Caching Data with Spring
Feign does not support caching. I would prefer the JCache (JSR-107) and maybe use it via the spring-boot-starter-cache described in the spring guide
JCache is an abstraction for the proprietary implementation of EhCache, Hazelcast, ... so it is possible to change the implementation with very less impact on the application. At first I would prefer EhCache 3.
Feign client doesn't support caching.
Another better way would be to create a Service class which calls FeignClient and put up cache on methods of this new Service class.
I am currently developing an OData service using Web Api 2 and EF6 with a Code First Approach. My controllers inherit from the normal ApiController Base.
I have decorated my action methods with the Queryable attribute and have also enabled Query Support in the WebApiConfig file. Through my CORS policy, I have specified the DataServiceVersion and MaxDataServiceVersion as part of my Accept and Exposed Headers.
Strangely, my odata endpoint seems to not return the DataServiceVersion as part of the response header but, if my controllers inherit from the ODataController base I am able to see it in the response.
Is there a way to enable this header while using ApiController as the base.
This header is needed as datajs requires it on the client side.
First to answer your question:
Yes, you can expose the DataServiceVersion http header yourself. It's custom code though, not a setting on an existing component.
Add a "Filter" to your global http configuration. A filter is a class derived from "System.Web.Http.Filters.ActionFilterAttribute".
for example;
internal class DataServiceVersionHeaderFilterWebAPI : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Content.Headers.Add("DataServiceVersion", "3.0");
actionExecutedContext.Response.Content.Headers.Add("Access-Control-Expose-Headers", "DataServiceVersion");
}
}
Then configure this filter to be used (in application start of global.asax)
GlobalConfiguration.Configuration.Filters.Add( new DataServiceVersionHeaderFilterWebAPI() );
This will allow your cross domain OData query from a security perspective. There is however another issue with this;
OData is a specification larger than just the request URI's & HTTP headers. It also specifies how to exchange model information and the actual data exchange is a predefined object structure. Simple, but still a predefined structure.
object.d = service returned content
You will have to implement all those pieces of the specification ($filter,$metadata,$top, return formats, etc) yourself.
Some food for thought.
I have a JIRA plugin that I'm developing that has a REST service. That service should be able to accept POSTed requests, unmarshall some data and store it. The seemingly suggested way to do this in JIRA is to make use of the Bandana persistence framework. According to this page, I should be able to simply define a setter that Spring should call to give me my Bandana manager.
#Path("/path")
public class SCMService {
private BandanaManager bandanaManager;
// setter called by Spring
public void setBandanaManager(BandanaManager bandanaManager) {
this.bandanaManager = bandanaManager;
}
//...More methods...
}
However, when I test this, the setter is never being called and my manager is null. I'm guessing this should be as simple as registering this service with Spring for injection somehow but I can't seem to find anything like that.
How would I get my setter called? Is there a better way to do this?
Er, I'm not sure that JIRA uses Bandana in that way, though Confluence does. You can certainly post data to a JIRA rest resource and then store it using properties tables
Something like this:
#POST
#Consumes (MediaType.APPLICATION_XML)
public Response createComponentAndIssues(#Context HttpServletRequest request, ...