Resteasy client : How to set Context Params - jax-rs

I'm using Resteasy client to run test cases for my Service. In application We set context Params in a session check filter,(which implements ContainerRequestFilter). I'm trying to set the same, in Resteasy client, using by adding a ClientRequestFilter implementation, but the property is not recognized, in the service call.
//Resteasy client calling logic
ResteasyClient resteasyClient = new ResteasyClientBuilder().build();
resteasyClient.register(new MyClientRequestFilter());
resteasyClient.target("http://localhost:" + port + "/myPath").request()
.post(Entity.json(authorization_reqParams)).readEntity(String.class));
//filter
public class MyClientRequestFilter implements ClientRequestFilter
{
#Override
public void filter(ClientRequestContext requestContext) throws IOException
{
requestContext.setProperty("CUSTOMER_ATTRIBUTE", "myCustomValue");
}
}
//Rest service method
#POST
#Path("/myPath")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response subpartner(Authorization_ReqParams authorizationReqParams, #Context HttpHeaders headers,
#Context HttpServletRequest request, #Context HttpServletResponse response)
{
String myAttribute= request.getAttribute("CUSTOMER_ATTRIBUTE");
//myAttribute is returned as null always
//additional logic
}
I'm able to set&get Header paramets with the same implementation, but Request param is always read as null.
How can I set the request context params ?

In MyClientRequestFilter you add a propery to the request object. What you really want is to send a header instead.
Try this instead:
#Override
public void filter(ClientRequestContext requestContext) {
MultivaluedMap<String, Object> headers = requestContext.getHeaders();
headers.add("CUSTOMER_ATTRIBUTE", "myCustomValue");
}
And read it like this:
#POST
#Path("/myPath")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response subpartner(Authorization_ReqParams authorizationReqParams, #Context HttpHeaders headers,
#Context HttpServletRequest request, #Context HttpServletResponse response)
{
String myAttribute= headers.getRequestHeader("CUSTOMER_ATTRIBUTE");
//additional logic
}

Related

After overriding the Application.getClasses() by a custom MessageBodyReader, methods on resource classes cannot be invoked

In a RESTEasy project running on Wildfly server, there is a resource class:
#Path("/company")
public class CompanyResource {
#Inject
CompanyService companyService;
#PUT
#Consumes(MediaType.APPLICATION_JSON)
public void update(Company company) {
companyService.update(company);
}
}
Initially the REST API configuration class just extends Application without any extra #override on the existing methods of Application class. An http request, http://localhost:8080/workcontext/company, with PUT as the http request method could work, meaning the CompanyResource.update() can be invoked successfully when receiving the aforementioned http request.
However, I then tried to add a custom MessageBodyReader<Company>:
public class CompanyReader implements MessageBodyReader<Company> {
#Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
return true;
}
#Override
public Company readFrom(Class<Company> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
try(JsonReader reader = Json.createReader(entityStream)) {
JsonObject companyJson = reader.readObject();
Company company = new Company();
company.setCompanyCode(companyJson.getString("companyCode"));
company.setName(companyJson.getString("name"));
company.setHeadquarter(Region.valueOf(companyJson.getString("headquarter")));
return company;
}
}
}
In order to make this custom MessageBodyReader<Company> work, I registered this class by overriding the Application.getClasses():
public class JaxRsConfiguration extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(CompanyReader.class);
return classes;
}
}
I expected that this MessageBodyReader<Company> could be invoked when sending the same http PUT request, but on the opposite the response is: RESTEASY003210: Could not find resource for full path: http://localhost:8080/workcontext/company
Question: How to make this custom MessageBodyReader work?
You should annotate you're CompanyReader with #Provider. In your application if you return any classes in Application.getClasses() or Application.getSingletons() then, per the spec, those are the only classes allowed to be used in your application.
If either getClasses or getSingletons returns a non-empty collection then only those classes or singletons returned MUST be included in the published JAX-RS application.

JAX-RS Client Filter to Modify Header Before Request is Dispatched to server

In JAX-RS (RestEasy), I want to implement a client filter that modifies the header before sending the request so I don't do this manually for every single call.
Currently I'm doing this in the receiving end to intercept requests before arriving to the resource.
#Provider
#Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// read header
}
Now I know this (Correct me if I'm wrong):
In the receiving end, ContainerRequestFilter can be used before the request arrives to the resource and get the request.
But I want to implement this in the client side, to modify the header before the request is ever sent to the server. Can the same server filter be used or there is something similar to for the client?
You must register a ClientRequestFilter into your Client
Client client = ClientBuilder.newClient().register(MyFilter.class);
#Provider
public class MyFilter implements ClientRequestFilter {
#Override
public void filter(ClientRequestContext ctx) throws IOException {
// modify header before send: ctx.getHeaders()
}
}

SpelEvaluationException interpreting "access" string in ResourceServerConfigurerAdapter

Any ideas on this?
From Tomcat:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1011E:(pos 8): Method call: Attempted to call method throwOnError(java.lang.Boolean) on null context object
Returned to Client:
java.lang.IllegalArgumentException: Failed to evaluate expression '#oauth2.throwOnError(#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN'))'
org.springframework.security.access.expression.ExpressionUtils.evaluateAsBoolean(ExpressionUtils.java:13)
org.springframework.security.web.access.expression.WebExpressionVoter.vote(WebExpressionVoter.java:34)
org.springframework.security.web.access.expression.WebExpressionVoter.vote(WebExpressionVoter.java:18)
org.springframework.security.access.vote.UnanimousBased.decide(UnanimousBased.java:77)
I do a POST to my authorization server /oauth/token and get a token.
If I take that token and add a Authorization: Bearer header to a GET request to the resource server, I get that error.
In my subclass of ResourceServerConfigurerAdapter, the line it blows up on is here:
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**")
.access("#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN')")
.accessDecisionManager(accessDecisionManager())
.anyRequest()
.fullyAuthenticated();
I know that the resource server recognizes the token because if i leave it out, I get the proper error. If I make up a fake one then I get the "invalid token" message, which is expected. If I use the actual token Spring is jumps in and blows up on the .access()
Thanks in advance for any help. I'm putting the code for my ResourceReserver below:
#Configuration
#EnableWebSecurity
#EnableResourceServer
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
#Autowired
private OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint;
#Autowired
private ResourceServerTokenServices tokenServices;
#Autowired
private TokenStore tokenStore;
#Autowired
#Qualifier("oauth2ResourceId")
private String oauth2ResourceId;
#Autowired
#Qualifier("oauth2Realm")
private String oauth2Realm;
#Bean
OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint() {
final OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
entryPoint.setRealmName(oauth2Realm);
entryPoint.setTypeName("Basic");
return entryPoint;
}
private AccessDecisionManager accessDecisionManager() {
return new UnanimousBased(Arrays.<AccessDecisionVoter>asList(new ScopeVoter(),
new AuthenticatedVoter(),
new WebExpressionVoter()));
}
private AuthenticationManager getAuthenticationManager() {
final OAuth2AuthenticationManager oAuth2AuthenticationManager = new OAuth2AuthenticationManager();
oAuth2AuthenticationManager.setTokenServices(tokenServices);
return oAuth2AuthenticationManager;
}
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**")
.access("#oauth2.hasScope('read') and #oauth2.hasScope('write') and #oauth2.hasAnyRole('ROLE_USER','ROLE_ADMIN')")
.accessDecisionManager(accessDecisionManager())
.anyRequest()
.fullyAuthenticated();
http
.anonymous()
.disable();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER);
http
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(logoutSuccessHandler())
.invalidateHttpSession(true);
/*
http
.requiresChannel()
.antMatchers("/oauth/api/**")
.requiresSecure();
http
.portMapper()
.http(8080)
.mapsTo(8443);
*/
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.authenticationManager(getAuthenticationManager())
.tokenServices(tokenServices)
.tokenStore(tokenStore)
.resourceId(oauth2ResourceId);
}
private LogoutSuccessHandler logoutSuccessHandler() {
return new OAuth2SuccessLogoutHandler(tokenStore);
}
static final class OAuth2SuccessLogoutHandler implements LogoutSuccessHandler {
private final TokenStore tokenStore;
public OAuth2SuccessLogoutHandler(final TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
request.toString();
}
}
}
The hasAnyRole() method is not OAuth2 related and therefore is not on the #oauth2 variable (it's on the root so you don't need to qualify it).

jaxrs queryparam not loaded for interceptor

I have a REST service of the form:
#GET
#NeedsInterception
public void getSomething(#QueryParam("xxx") #MyAnnotation String thing) {
//Stuff
}
I then have an interceptor for #NeedsInterception.
In it, I perform some logic on the element annotated with #MyAnnotation.
However, when the interceptor is called, the MethodInvocation object has not yet been resolved with the value of the QueryParam, instead it is always "";
Is there a way for me to make the interception happen after the QueryParam is resolved?
Don't know which kind of interceptor you are using but a jax-rs ReaderInterceptor is intended to wrap calls to MessageBodyReader.readFrom. As you don't send a request body with a #GET request this kind of interceptor won't be used.
A ContainerRequestFilter should help:
#Provider
public class SomeFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
MultivaluedMap<String,String> queryParameters = requestContext.getUriInfo().getQueryParameters();
}
}

How to Get the Authorization header from wcf request interceptor

I need to authenticate every request to wcf services
public class AuthenticationInterceptor : RequestInterceptor
{
public AuthenticationInterceptor() : base(false)
{
}
public override void ProcessRequest(ref System.ServiceModel.Channels.RequestContext requestContext)
{
//How to access Request Header (Authorization header) from here?
}
}
You can get the headers from the System.ServiceModel.Channels.Message, so try
var message = requestContext.RequestMessage;
var request = (HttpRequestMessageProperty)message.Properties[HttpRequestMessageProperty.Name];
string authorization = request.Headers[HttpRequestHeader.Authorization];