Authenticate a GraphQL endpoint against Keycloak with custom response in Quarkus - java

I want to secure a GraphQL API using authentication against Keycloak. This works fine by using the "quarkus-oidc" extension as described in the corresponding guide. I simply added an "#Authenticated" annotation to the same method that has the "#Query" annotation. However, I also need to customize the 401 response in case of an authorization failure (because my client expects a JSON with some details). How can I do that?
I already tried adding an ExceptionMapper (as described here), but it is not invoked. (It works for a standard REST endpoint, though.)
I also tried doing the authentication manually: I removed the "#Authenticated" annotation and instead injected a "SecurityIdentity" object. I then used the "hasRole" method, which throws an "AuthenticationFailedException" if authentication fails. I can catch this exception, but the default 401 response is already sent to the client in the background, and when I try sending any other response, I get an IllegalStateException ("Response head already sent")

Related

ResponseEntity body lost between two webservice calls

I have a webservice which calls another WS and returns the response from the second WS. It looks like so:
// MyController
public ResponseEntity<Foo> requestFooController(#RequestBody #Valid Bar request) {
return this.myService.requestFooService(request);
}
//MyService
ResponseEntity<Foo> requestFooService(Bar request) {
Buzz improvedRequest = ...
return this.secondWS.secondRequestFoo(improvedRequest);
}
When I call the API through Postman, I receive a HTTP OK response with an empty body. Yet, when I'm in debug mode I can see that the service is returning a ResponseEntity with a body. The headers are not lost though.
I changed my code like so and it works fine:
// MyController
public ResponseEntity<Foo> requestFooController(#RequestBody #Valid Bar request) {
ResponseEntity<Foo> tmp = this.myService.requestFooService(request);
return ResponseEntity.status(tmp.getStatusCode()).body(tmp.getBody());
}
Now through Postman I do have the expected body. However, I don't understand the behaviour. I thought that maybe it's due to the fact that the body is some kind of stream that can be read once or something similar. But from reading the source code I don't see anything that could explain this behaviour.
I'm using the Netflix-stack (so HTTP calls between the two WS are made through a Feign client).
Any idea why I'm getting this result?
EDIT:
More details on my stask:
SpringBoot 1.5.3.RELEASE
Feign 2.0.5
There is a bug that causes the named body of an HTTP MultiPart POST to fail. The symptom of this is that you make a POST request with a body, and Spring-Boot can't match it up to an endoint. The exception I see is:
2019-01-23 15:22:45.046 DEBUG 1639 --- [io-8080-exec-10] .w.s.m.m.a.ServletInvocableHandlerMethod : Failed to resolve argument 3 of type 'org.springframework.web.multipart.MultipartFile'
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
Zuul is doing caching of the request in order to re-try multiple times. In this process, it fails to preserve the named field for the binary body. You may find it working if you preface the request with zuul. So instead of http://myserver.com/myservice/endpoint use zuul in the path: http://myserver.com/zuul/myservice/endpoint
That will effectively avoid the saving of the request and the retry mechanism.
More details are available on this issue in Zuul's GitHub Bug List.

Validating REST Request using RequestBodyAdvice

Im trying to use RequestBodyAdvice in Spring Boot application to validate my JWT token and Device info. It works for POST method as it has #RequestBody in Controller however it is not working for GET method because there is no request body/payload. How to validate GET Services using RequestBodyAdvice, is there any other option?
As far as I know, GET request do not have request body. You should use interceptor or filter.

Can I access request parameters in a custom Google Cloud Endpoints Authenticator?

Is there a way to get access to the request parameters in a custom com.google.api.server.spi.config.Autenticator?
I would like to authenticate my users using a token, sent as a request parameter according to https://<mydomain>/_ah/api/v1/myapi/endpoint?token=<mytoken>. Unfortunately, in this case, it is not possible to send it as a request header. Currently, I manage authentication in each endpoint (where I do have access to the request parameters, either through the HttpServletRequest object or through a named parameter) but it would be nice to decouple auth from implementation.
As I understand, Cloud Endpoints will wrap the original request in a new POST request to /_ah/spi/... but only the request headers will be accessible in the Authenticator.
It doesn't matter if the initial request to Cloud Endpoints is GET or POST.
Your understanding is correct--your request is translated such that all query parameters are injected as part of the JSON body as well. I believe the body does have the query parameter, but I'm not 100% sure on that. If you upgrade to the new Endpoints Frameworks beta, you can access it using getParameter or getParameterValues on the servlet request, as you would expect.

Modifying JSON Body in Interceptor

I want to have the following flow:
Request -> 1) Validate JSON Body -> 2) Validate JSON for Security Concerns -> ...etc
And Throw exceptions / give appropriate JSON Responses in 1) or 2).
I have tried to use Interceptors and Filters.
Filters: I can modify the body by having a Request Wrapper and then passing it along the chain to the JSON Validation, however when I throw exceptions they are not intercepted by the #ControllerAdvice Exception Handler, which works for everything else. From what I have read this is by design...? Also I have tried to set a response manually, example below, but it seems spring boot changes the status code to 405.
response.getWriter().write("{\"test\" : \"test\"");
response.sendError(400);
Interceptors: I get an error because I am reading the body more than once, I can not see how to set the Custom HttpServletRequestWrapper I have made before the interceptors run.
I am after a way of implementing this scenario.
Any help would be greatly appreciated. Thanks!
I realised that because Filters are run first I can modify the request by using a Request Wrapper. Then I use an interceptor to run the security and json checks.
I would still like to know how to modify responses in a Filter though, I do not like how spring boot will change it even though you already have a response code.

Apache CXF: how to return failure response from an interceptor

I have written a custom interceptor that does some parameter validation. I want to be able to return an error code and serialize a JAXB-annotated class as the response body.
If I throw a WebApplicationException, it doesn't have any special processing done to serialize the Response object inside (which makes sense; I assume that is done by another interceptor).
How should I go about stopping the interceptor chain but still have JAXB serialize the response entity?
Well, at least in the CXF JAX-RS interceptor flow, if you set:
message.getExchange().put(Response.class, response);
...then the actual service does not get invoked, while the other phases do get invoked. Haven't dug in to the CXF code to see where that logic kicks in.
So I built a response like this:
Response response = Response
.status(Response.Status.FORBIDDEN)
.entity(new ErrorEntity("This is a JAXB object with an error string"))
.build();
I also have some custom authentication running in a CXF JAX-RS filter and I only want to check the parameters when the authentication is alright, so I set my parameter interceptor class to run during the PRE_INVOKE phase.

Categories