I'm trying to customise the response for authentication failures in Quarkus. I need to set a custom header, a custom response code and a custom response body. I developed my custom (Kotlin) HttpAuthenticationMechanism because I need a custom authentication logic. In it, I tried returning a failure Uni.
return Uni.createFrom().failure(AuthenticationFailedException())
And then implement my own ExceptionMapper
#Provider
#Priority(Priorities.AUTHENTICATION)
class AuthenticationFailedExceptionMapper : ExceptionMapper<AuthenticationFailedException> {
override fun toResponse(exception: AuthenticationFailedException): Response {
logger.info("====== custom auth error")
It doesn't get triggered. I have proactive authentication disabled:
quarkus.http.auth.proactive=false
Instead, I noticed that the getChallenge method in my custom HttpAuthenticationMechanism gets triggered, which can be used to overwrite the response, but it doesn't allow to set the body, just the result code and one header.
I also tried returning and mapping a different, custom exception, but then I only see some errors in the log and the client gets a 500 response code - the exception mapper is still not triggered. Why?
Related
I'm using react-admin and I have a page that makes api calls via the dataProvider to /posts, but there is also a custom UserMenu that fetches /user, and the authProvider also runs an AUTH_CHECK that fetches /session.
On the first page load, all three requests are issued and all three correctly return 401 unauthorized, but then I also get three pop-up notifications with the same message: "Request failed with status code 401".
Is there a way to either
show this message only once
not show any of these messages at all
Also, is there a way to customize the text of this message to something more user friendly?
So what is happening is that I have a condition within my override of the HandleUnauthorizedRequest method in my custom authorize attribute. Up to this point, I've been throwing a 403 which gets picked up and redirects to a custom error page. Well now, that's not really what I want. What I actually want is to show the same login page but add a message to the validation summary "You do not have access to this resource.", that way it's a bit more user friendly. It'll indicate that your creds were good, but you don't belong here.
I thought something like this would work:
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// passed authentication, failed authorization
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Controller.ViewData.ModelState.AddModelError("", "Not Authorized");
return;
}
base.HandleUnauthorizedRequest(filterContext);
}
But this isn't working. What's happening is that the login page simply reloads. So this makes me feel like I'm close, but I need that model error to show up.
Any ideas?
UPDATE:
It would seem that the Controller that I'm adding an error to here is actually controller of whichever action had the attribute that led to here. I need to somehow add the error to the login controller. Not sure if that's even possible.
You are calling the base method here:
base.HandleUnauthorizedRequest(filterContext);
If you are using Forms Authentication this base method simply redirects you to the login page. And a redirect means a new HTTP request from the client. The current context and whatever you stored in it is lost. Well, to be more precise, the base method is returning a 401 HTTP status code which is then intercepted by the FormsAuthenticationModule which redirects to the login page defined in your web.config. But this implementation details is not important.
What you could do is perform the redirect yourself to the login page instead of leaving it to the base method. You could do this by setting the filterContext.Result property to a RedirectToRouteResult instance. In this case you could pass the error message as a query string parameter.
UPDATE:
According to your updated question it seems that you are calling return; after setting the ModelState value and not calling the base method and thus no redirect will happen to the login url. You could in this case return some error view by setting the filterContext.Result to an instance of a ViewResult in which view you could use the value you stored in the ModelState.
when symfony2 authenticates user by login form, an event security.authentication.success is fired and is handled by DefaultAuthenticationSuccessHandler. Constructor of this object takes two arguments HttpUtils $httpUtils and array $options. Variable $options is not empty and contains configuration options from security.yml like:
login_path => pkr_blog_admin_login
user_referer => false
...
I created a service AuthenticationSuccessHandler that extends DefaultAuthenticationSuccessHandler but can't find a way to pass values from security.yml as $options to constructor of my object. How can I do this?
I had tried using xdebug step by step debugging to see how those options are passed to DefaultAuthenticationSuccessHandler but couldn't find exact place in code :/
//EDIT
I found out that this configuration is set in src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php and only for default handler.
Here are some comments about not getting configuration from security.yml in custom handler:
https://github.com/symfony/symfony/issues/5432
https://github.com/symfony/symfony/issues/5488
Anyone know a way to get configuration parsed and ready to use by default handler from within my handler?
I suppose that it might be done by passing service container to my handler. I'll try this when I'll be back from work.
It seems that only way to make it work is to use compiler pass and change default handler class. See my similar question:
Better way of doing this is to use service as event handler:
Symfony2 extending DefaultAuthenticationSuccessHandler
I have a unique problem with passing an action message in a JSON result.
Right now, if I add an action message within my action (in a JSON action), I will pick that up in JavaScript and capture the action message and alert the user via JGrowl. However, I don't want the logic of adding an action message in each action. I have an underlying service project with a request context that is shared among the request, and I am able to add warning messages there. What I'd like to do is to transform those warning messages to action messages for use on my front end, but the action will never have to be aware of them. This is useful because I can insert warnings when accessing databases, or if there are hairy business rules, etc.
As I mentioned before, it already works when adding them directly in the action so I know the JSON result works fine and passes along the action messages correctly. We have an interceptor that is hit every time for managing this request context already, so I'd like to append on the action messages in this interceptor to the action being called.
However, the problem I'm finding is that I need to call actionInvocation.invoke() first as any warning messages will be generated as a result of that. After that, I check for the messages and attempt to apply them as action messages. These action messages never show up in my JSON response, so I'm wondering if it's possible to add those messages into the response in the interceptor AFTER the invoke() call. Here's the bulk of my intercept method:
try {
// Invoke the action.
String result = actionInvocation.invoke();
//add all warning messages as an action message to be displayed on that front end
if (CollectionUtils.isNotEmpty(context.getWarningMessages())) {
ActionSupport action = (ActionSupport) actionInvocation.getAction();
for (String s : context.getWarningMessages()) {
action.addActionError(s);
}
}
return result;
I tried adding the logic to add the action messages in the finally block instead of after the call to invoke() to no avail.
Thanks,
Andy
The result has been rendered by the time invoke returns.
You need to implement a PreResultListener as discussed in the "Writing Interceptors" docs.
I notice that when I do AJAX submission using Rails UJS form, the Javascript response will only be evaluated when the server return HTTP success (2xx) and do nothing if the server return status code 4xx or 5xx.
I want to modify this behavior so that Javascript response will be evaluated even if the server return HTTP error. I'm thinking about binding my form with the event ajax:error, but then I have to do this for every AJAX form I have within my application. Anyone has an idea how to do this globally?
One more question: can I check if the content type returned by server is Javascript via JQuery?
Thanks!
Since all Rails UJS handlers need to have data-remote="true" defined, you could bind to the ajax:error event globally by doing
$('[data-remote="true"]').on('ajax:error', my_special_error_callback);
Then you need to ensure that you define your callback to check on the error codes:
function my_special_error_callback(event, data, status, xhr) {
if(status == 'error') {
alert('error');
responseText = JSON.parse(data.responseText)["errors"] // This is dependent on how you're returning your errors from Rails
}