How to customise the response body when "401 Unauthorized" occurred? - helidon

Instead of an empty response body when "401 Unauthorized" occurs, I want to add the other information into the response (e.g timestamp, a message), how can I override it?
Expectation:
HTTP status: 401 Unauthorized
Response body:
{
"timestamp": 1234567890,
"message": "Your access token was expired"
}
I'm using the Helidon MP v2.5.5

To customize the response body when a "401 Unauthorized" error occurs in Helidon, you can handle the error in the error handling mechanism provided by Helidon. You can write your custom logic inside the error handling mechanism to return the desired response.
Here is an example code to demonstrate the same:
server.addErrorHandler(401, ex ->
ServerResponse
.status(401)
.header("Content-Type", "text/plain")
.send("Unauthorized Error Occurred!")
);
This code will return a response with a 401 status code and the response body "Unauthorized Error Occurred!" whenever a 401 error is encountered in the server.

Take a look at ExceptionMapper class in javax/jakarta. You can create a Provider that implements the ExceptionMapper using BadRequestException. Then override the toResponse method of ExceptionMapper. That way you can customize the response.
Some code doing this could look like this:
#Provider
#NoArgsConstructor
public class <YourExceptionHandler> implements ExceptionMapper<BadRequestException> {
#Override
public Response toResponse(BadRequestException exception){
<custom code>
return Response.status(<status>).entity(<custom code>).build()
}
}
In my case, for the custom code part I instance a class that handles the error's status, error message, etc...

Related

When does webflux validate the request body?

#Controller
public class IndexController {
#Resource
WebClient webClient;
#PostMapping
public Mono<User> index(#Valid #RequestBody Mono<User> user){
// I'm using webclient to call another service, just pass the mono object like this
return this.getResponse(user);
}
private Mono<User> getResponse(Mono<User> user) {
return webClient.post()
.body(user,User.class)
.retrieve().bodyToMono(User.class);
}
}
In above scenario, I don't need to operate the request body. request body will not be validated.
How can I make webflux to validate the request body?
In that scenario, SpringMVC(not sure which componment will do) connot vaildate the Mono, so I cannot get a webexchangebindexception. the validation will occur when the Mono is subscribed which is also when webclient actually send the message.
before webclient actually sending message, validation will be done,webexchangebindexception will be catch by webclient. webclient will wrap this exception into webclientrequestexception by default. we can add our own exception handler to webclient so that we can just throw webexchangebindexception to our global exception handler.

Retrofit 2.0 Header Interceptor vs Method Headers

There seems to be some discrepancy between using method headers and intercepting headers with OKHTTP and retrofit.
I'm looking to intercept each retrofit request going through my retrofit interface. I've written an Interceptor to go through OKHTTP like so:
OkHttpClient client = new OkHttpClient();
client.interceptors()
.add(ThisClass::onRequestIntercept);
...
private static Response onRequestIntercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", "auth")
.header("Accept", "json")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
But the server throws a 401 error unless I also add the following above each and every method in the retrofit interface:
#Headers({
"Authorization: auth",
"Accept: json"
})
The logs are identical for both headers with and without the second header annotation - only that the one with the second header directly above the method goes through with 200, and if only the intercepted code is used it returns a 401 error code.
What could be the discrepancy?

FOSRestBundle: Returning JSON/XML meta data for "Bad Credentials" Exception

I'm using FOSRestBundle for my REST API and so far it has been a great tool. I use HTTP Basic Auth and in most of the cases it works just fine. However, I have problems with the bundle's exception behaviour when bad credentials are submitted. When handling exceptions (via the integrated authentication handlers or the exception mapping configuration), the bundle always gives me a response with the correct HTTP status and JSON/XML content similar to this:
{
"code": 401,
"message": "You are not authenticated"
}
This is fine, it also works when no authentication information is submitted at all. However, when submitting bad credentials (e.g. unknown username or incorrect password) I get the HTTP code 401 Bad credentials (which is fine) with an empty message body. Instead, I would have expected something similar to the JSON above.
Is it a bug or a configuration issue on my side? I would also love to know how these kinds of authentication errors are exactly handled by the bundle, since overriding the BadCredentialsException's status code in the codes section of the bundle's exception configuration section seems to be ignored.
Thanks!
Alright, after digging into the bundle's code some more, I figured it out. The problem results from the way bad credentials are handled by Symfony's HTTP Basic Authentication impementation. The 401 Bad Credentials response is a custom response created by BasicAuthenticationEntryPoint, which is called by the BasicAuthenticationListener's handle function, immediately after an AuthenticationException has been thrown in the same function. So there is no way of catching this exception with a listener:
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if (false === $username = $request->headers->get('PHP_AUTH_USER', false)) {
return;
}
if (null !== $token = $this->securityContext->getToken()) {
if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $username) {
return;
}
}
if (null !== $this->logger) {
$this->logger->info(sprintf('Basic Authentication Authorization header found for user "%s"', $username));
}
try {
$token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->headers->get('PHP_AUTH_PW'), $this->providerKey));
$this->securityContext->setToken($token);
} catch (AuthenticationException $failed) {
$this->securityContext->setToken(null);
if (null !== $this->logger) {
$this->logger->info(sprintf('Authentication request failed for user "%s": %s', $username, $failed->getMessage()));
}
if ($this->ignoreFailure) {
return;
}
$event->setResponse($this->authenticationEntryPoint->start($request, $failed));
}
}
The entry point's start function creates the custom response, with no exceptions involved:
public function start(Request $request, AuthenticationException $authException = null)
{
$response = new Response();
$response->headers->set('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realmName));
$response->setStatusCode(401, $authException ? $authException->getMessage() : null);
return $response;
}
The fist if-clause in the handle function above also explains why it works in the case of "no user credentials at all", since in that case, the listener just stops trying to authenticate the user, and therefore an exception will be thrown by Symfony's firewall listeners (not quite sure where exactly), so FOSRestBundle's AccessDeniedListener is able to catch the AuthenticationException and do its thing.
You can extend AccessDeniedListener and tell FOSRestBundle to use your own listener with the parameter %fos_rest.access_denied_listener.class%. (service definition)
parameters:
fos_rest.access_denied_listener.class: Your\Namespace\For\AccessDeniedListener
Then add an additional check for BadCredentialsException and emmit an HttpException with the desired code/message similar to the check for AuthenticationException at Line 70.

In ASP.NET Web API, how can I make HTTP response syntax consistent if an exception is thrown?

I'm creating an HTTP API using ASP.NET Web API. I've noticed that if an exception occurs that I haven't handled, that behaviour is very different to if I deliberately throw an HttpResponseException. This will make it hard for clients to reliably handle an error and display the "reason" message.
Eg consider this code:
[HttpPost]
public void ThisWillThrowAnError()
{
try
{
var i = 0;
var b = 1 / i; // cause divide by zero exception for testing
}
catch (Exception ex)
{
HttpResponseMessage message = new HttpResponseMessage();
message.ReasonPhrase = "Error: " + ex.Message;
throw new HttpResponseException(message);
}
}
This creates a response which has the error in an HTTP header and the response code set to 500:
Error: This request could not be processed. Attempted to divide by zero.
The actual response body is empty.
However if I remove the try/catch block, or if an exception occurs for which I do not manually throw an HttpResponseException, I get totally different behaviour. Although the status code is still 500, the header message just says "Internal Server Error" and the message is encoded in a JSON format like this:
{
"Message": "An error has occurred.",
"ExceptionMessage": "Attempted to divide by zero.",
"ExceptionType": "System.DivideByZeroException",
"StackTrace": " at ProjectName.Controllers (etc....)"
}
I think I prefer the latter as it gives you more info for debugging but it removes the ability to customise the message or provide a user-readable message for the problem.
Why is WebAPI inconsistent with how it handles exceptions? Am I doing something myself to cause this inconsistency? It just seems rather messy and difficult to work with and may mean that the calling application will have to be coded to handle two different types of error response :(
When creating error responses, consider using HttpRequestMessage.CreateErrorResponse to create error responses that are consistent with the ones WebAPI sends.
This blog post should hopefully help:
http://blogs.msdn.com/b/youssefm/archive/2012/06/28/error-handling-in-asp-net-webapi.aspx
I would use message handlers. A message handler is a class that receives an HTTP request and returns an HTTP response. So you can basically change response structure in one place, and have same response for success and failure, and for all requests in your Web Api. You can read about it in my blog post: https://www.vladopandzic.com/asp-net-web-api/building-consistent-responses-asp-net-web-api/

WCF WebApi HttpResponseException Issue

I am trying to throw an HttpResponseException(HttpStatusCode.NotFound) and I am getting the following error
The response message returned by the Response property of this exception should be immediately returned to the client. No further handling of the request message is required.
I have removed all of the code in my method and I am just throwing the exception like this
[WebGet]
public MyData Get()
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
If I change my method to return a HttpResponseMessage I can get it to work correctly, however it does not solve the issue and I am unable to get my authentication operation handler to work without being able to throw a HttpResponseException.
Try using a WebFaultException for returning HTTP Status codes in WCF...
throw new WebFaultException(HttpStatusCode.NotFound);