How to customize Unauthorized response in Quarkus?

208 Views Asked by At

Because we use a custom format of error we want to customize all error responses ... in particular Forbidden (we succeed) and Unauthorized (we failed).

I read many docs, posts and I tried different solutions you can find in my sample project

First: ServerExceptionMapper

@ServerExceptionMapper
@Priority(1)
fun unauthorized(e: UnauthorizedException) =
   mapExceptionIntoError(Response.Status.UNAUTHORIZED, "UNAUTHORIZED", e.message)

Second: ExceptionMapper

@Provider
@Priority(Priorities.AUTHORIZATION)
class UnauthorizedErrorMapper : ExceptionMapper<UnauthorizedException> {

    private val logger: Logger = Logger.getLogger(this.javaClass.simpleName)

    @Override
    override fun toResponse(exception: UnauthorizedException): Response {
        logger.severe(exception.message)

        val message = exception.message
        val code = STATUS.statusCode
        val error =  ErrorInfo(STATUS.statusCode, STATUS.name, message)

        return Response
            .status(code)
            .entity(error)
            .build()
    }

    companion object {
        private val STATUS = Response.Status.UNAUTHORIZED
    }
}

Third: failureHandler

@ApplicationScoped
class UnauthorizedExceptionHandler {
    fun init(@Observes router: Router) {
        router.route().failureHandler { event ->
            if (event.failure() is UnauthorizedException) {
                event.response().end("CUSTOMIZED_RESPONSE")
            } else {
                event.next()
            }
        }
    }
}

With no success. What did I miss or do wrong?

Thanks in advance Patrice

2

There are 2 best solutions below

0
Patrice Conil On BEST ANSWER

ServerExceptionMapper works only for /hello using RolesAllowed annotation like in

    @GET
    @Path("/hello")
    @RolesAllowed("role1")
    fun hello(): RestResponse<Reply> = RestResponse.ok(Reply("Hello from RESTEasy Reactive"))


    @GET
    @Path("/helloNotAnnotated")
    @Produces(MediaType.APPLICATION_JSON)
    fun helloNotAnnotated() = RestResponse.ok(Reply("Hello from helloNotAnnotated"))

and not for role2 defined in application.properties using elytron

quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.user=password
quarkus.security.users.embedded.roles.role1=user
quarkus.security.users.embedded.roles.role2=user
quarkus.http.auth.permission.role-role2.paths=/helloNotAnnotated
quarkus.http.auth.permission.role-role2.policy=role2-policy
quarkus.http.auth.policy.role2-policy.roles-allowed=role2

See differences in action in my sample project

4
geoand On

This use case does work as we have a test in the repo that does this.

public static final class CustomExceptionMappers {

    @ServerExceptionMapper(UnauthorizedException.class)
    public Response forbidden() {
        return Response.status(999).build();
    }
}