Custom error message on failed authentication in IdentityServer4 - asp.net-core

I would like to display custom error message when authentication fails in IdentityServer4. Namely I want to show what went wrong, e.g. "invalid redirect url" or "invalid authentication flow". When authentication fails I see only that exception occured but for what happened I need to go into logs. In this case I would like to know that e.g. redirect url is wrong directly. How can I achieve that?
I'm thinking about some exception filter or custom middleware on ASP.NET Core. However it seems to me that exception filter won't work since that is MVC stuff and exception occurs in the IdentityServer middleware. And I am not sure how to create the middleware so it shows the error and also manages to use the same layout and ui parts as in MVC views. Is there another way? Maybe some extension points I did not see?

Related

GetAccessTokenForUserAsync throws an exception

I'm trying to call a Web API from a Web App, passing a token for identifying the user.
I'm following the docs here:
https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-web-app-call-api-acquire-token?tabs=aspnetcore
However, when I call the GetAccessTokenForUserAsync method, I always get an error AADSTS65001, stating that The user or administrator has not consented to use the application with ID '....' named '...'.
I really don't understand this error. What kind of consent are we looking for here? The application ID mentioned in the error message is the client app, and I double checked that the scopes accessed from the client app in the API are already consented.
What am I missing? I thought it should be quite straightforward - take the token received by the web app, send it to the web API, and let it authenticate it.
Is there any simple way of doing that?
Thanks!
So for future reference, the problem was that the scopes specified in the GetAccessTokenForUserAsync method were not prefixed with the API URL prefix (usually in the form of api://346363-35262ffe-23cwf3-ve523632t), and therefore Azure AD assumed I was trying to access my own app, which did not have such scopes.
After I changed the code to include the prefix in the scope, ie. _tokenAcquisition.GetAccessTokenForUserAsync(new[] { $"api://346363-35262ffe-23cwf3-ve523632t/Employees.Read" }) it worked like a charm.

Jakarta and Glassfish - Basic authentication works, Form authentication do not

I am pretty new into web development. Currently I am trying to do an Form Based Authentication on my Jakarta app. I managed to create a realm on Glassfish 6.0.0 and to integrate it on the web.xml descriptor. I managed to make the Basic Authentication work, but when I try it to change to Form Authentication I get an 403 status code ever time I want to login. I got the following error every time I send a POST request to j_security_check with good credentials, along with 403 status code:
***WEB9102: Web Login Failed:
com.sun.enterprise.security.auth.login.common.LoginException
: Login failed: Security Exception*** which doesn't say to much for me.
I wanted to create an Form Authentication in order to use j_security_check to login using form-data format from Postman. If I can not do this, is there a way to create a custom endpoint to send a request in order to authenticate?
I found out a method to do what I needed for the moment. I just sent parameters in URL. For now it is perfect, even though the security suffer with this method.

Blazor Wasm with AAD B2C: SignUpSignIn userflow - reset password, how to catch AADB2C90118

I am working on a Blazor Wasm app which uses AAD B2C.
The AAD B2C is set up correctly, with different user flows.
The SignUpSignIn has the "Forgot your password" link which is not working out of the box. As I read the app needs to catch the error and trigger the PasswordReset userflow manually.
I try to catch it in the Authorization component, like reading the triggered uri.
It looks like this:
https://localhost:44319/authentication/login-callback#error=access_denied&error_description=AADB2C90118%3a+The+user+has+forgotten+their+password.%0d%0aCorrelation+ID%3a+ .... ids and token..
So it contains everything what I need, but the app completely ignores it. I am not able to debug at all.
After some redirects it ends up at: https://localhost:44319/authentication/login-failed page.
I can catch the "login-failed" case, but it is not what I am looking for.
What do you suggest to make it work?
Currently this feature is not supported. Please raise user voice feedback. This will help the product team evaluates such feature.

Equivalent of HttpContext.IsCustomErrorEnabled is ASP.NET CORE

I have a lot of filters, which are using HttpContext.IsCustomErrorEnabled in MVC 5. One of such filter is JsonExceptionFilter, to simply return status without full error when exception is fired on Production environment. The details of exception are returned based on CustomeErrors enabled. So in rare cases I can see production/staging error just by chanign this option in web.config. However in ASP.NET Core there is no such option because redirection is done by ExceptionHandler middleware.
Is there any way to check if redirection (custom error) is enabled?

How do I get Basic Authentication, GlassFish, REST, and a single page application to all work together with my own login form?

I'm using Glassfish 4 as a server with an AngularJS app as a client. Glassfish is exposing a REST API via JAX-RS (Jersey). I'm using Basic Authentication over an HTTPS connection. I have my own login form and am setting the Authorization header in my REST requests via JavaScript. My issue is that if I use normal web.xml based permissions (<auth-constraint> inside <security-constraint>), the responses come back with 401 with a WWW-Authenticate header (if the credentials are bad). This forces the browser to do the Basic Authentication dialog instead of my own and it appears there is no viable cross browser work around available on the browser side to stop it. So I need to somehow suppress the 401/WWW-Authenticate response.
I stopped using the web.xml based permissions, because it seems it is the Servlet level that is doing the 401 stuff. I was able to get Jersey authentication working with a filter and turning on the "RolesAllowedDynamicFeature" feature (in a matter similar to Glassfish #RolesAllowed with custom SecurityContext). That seems to work great and returns 403 for bad credentials (and thus no browser dialog). However, when I call my EJB's, they do not see the custom security context and the user I have set, so I get permission exceptions. If it matters: the EJB's are in a jar, the Jersey stuff is in a war, and both of them and bundled together in an ear. From what I can gather the only way to have the EJB's properly process credentials is to use the web.xml stuff.
I seemed to have painted myself into a corner and do not see how to make this work. Perhaps I can back out and return to using web.xml based permissions and somehow filter the servlet responses to not return 401/WWW-Authenticate? If so I could not find out how to do that. Or is there some way I can set EJB's security context? Or something else entirely? I wouldn't think using AngularJS with GlassFish and a REST API and Basic Authentication would be very unique, how does anyone do this?
Since posting this question I have found info on implementing a Servlet filter and using that to try to change the 401 response to a different status code. However, the filter never gains control if you have <auth-constraint> in your web.xml and the request is not authorized, so that did not help me. I still could not prevent the 401 responses.
But now I think I finally found the answer. I removed the <auth-constraint> tag from web.xml. I changed the Servlet filter to now extract the AUTHENTICATION_HEADER on its own and decode it (via javax.xml.bind.DatatypeConverter). Next I call HttpServletRequest.login (on the request object) with the decoded username and password. I catch the ServletException if the username/password combination is bad and use HttpServletResponse.sendError to send SC_FORBIDDEN. If I have a good login I call doFilter to continue on with processing of the request, and call HttpServletRequest.logout when it returns.
If I do this in combination with RolesAllowedDynamicFeature and annotations on the Jersey routines everything seems to work including calls to EJB's with their own security annotations.
Side note: before settling on HttpServletRequest.login I had tried to use HttpServletRequest.authenticate followed by checking the returned boolean, but when you gain control in that case the response has already been committed to be 401 and you cannot change it. I even tried passing a HttpServletResponseWrapper to authenticate to stop the commit from happening, but authenticate seems to get the response object through some other means, it seems to ignore the one you pass it (I even tried passed null and it didn't even notice).