Why is Logout Controller anonymous in Micronaut? - logout

io.micronaut.security.endpoints.LogoutController is annotated by #Secured(SecurityRule.IS_ANONYMOUS)
In general one would expect a user to be authenticated before logout. What am I missing?

You're right that it doesn't make sense to logout without being logged in, but if there was a non-anonymous rule for the controller and you access it without being logged in, it would trigger a login. The best thing to do is to let it be a no-op for non-authenticated access.

Related

Best way to restrict login to adjustable set of roles

I have the requirement that only certain user roles should be allowed to log in. The set of roles may change at runtime.
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
subject.login(token);
Which implementation is the most appropriate / secure?
Lookup the user roles (outside of Shiro) before calling subject.login() and raise an AuthenticationException if no role is permitted.
Let the authenticationQuery of the JdbcRealm only return a password (via SQL JOIN), when a user has one of the permitted roles.
Log the user in, then check roles / permissions, and immediately logout and raise AuthenticationException if not permitted.
other options?
You may want to consider user behavior here. If your webapp makes it look like a user was unable to logout, (IMHO) the first thing the user will do is try again, the second thing is they will call the help desk and try to reset their password.
This depends on your actual application, (so take this with a grain of salt). I'd suggest letting the user login and then blocking access e.g. show a 403 page with a ("You shall not pass" warning), or show a 404 (this is what GitHub does as it does NOT leak information that a valid page exists).
This also simplifies the Shiro implementation, just require a role/permission for your routes.

Keycloak token doesn't include mapped user session note on first login

I have created a custom IDP and whenever I login I need to set a User Session Note which is mapped in Keycloak and then added to the access token. The problem I am facing is that this User Session Note is not saved the first time a user logs in. It works the second time, and third and so on, but on the first login the user does not simply get the key/value added to the token.
The login succeeds every time, however it is missing the user session note that I wanted to be mapped on the token.
I'm not sure what the problem is. The IDP is set up to have a custom "First Login Flow" which has Create User If Unique (alternative) and Automatically Set Existing User (alternative). Maybe there is something here that I need to change so that it also includes User Session Notes on token for the first login?
I found that you need to implement the importNewUser() method in your extension of AbstractIdentityProviderMapper and set your notes on the authenticationSessionModel there.
Inside of the authenticated method, where preprocessFederatedIdentity() is called, Keycloak checks if federatedUser == null. At this point, you are in the state of preprocessing the federated user; it does not yet exist. Keycloak then calls resetFlow() within this if block where it then clears auth notes from the authenticationSessionModel.
Hopefully someone finds a more delicate solution than I did, but I managed to solve this by a little hack.
I noticed that in the provider I could override the method "preprocessFederatedIdentity" and when listing the User Session Notes there I saw that they do in fact exist on the session. However, when reaching the method "authenticationFinished" (also overridden) they have been cleared from the session (the clearing seems to happen right before method "updateBrokeredUser" is reached). This odd behaviour only happens on the first login.
What I then noticed is that User Attributes stored on the context however are not cleared. They persist, and this was key to my solution. Then what I did was simply to loop through all of the User Session Notes in the method "preprocessFederatedIdentity" and store them as User Attributes (with the key prefixed with "UserSessionNote:"), and in the latter step "authenticationFinished" I add them to User Session Notes again. I also stored all of the keys of the User Session Notes in a User Attribute called "UserSessionNotesKeys" as a comma separated string so that I could simply split that string and loop through the attributes in the "authenticationFinished" method and then add them to User Session Notes.
This basically solved my issue in a generic way, and also made sure it would work if future User Session Notes were added.

How to ignore session in specific filters

We have a few filters that run and we are trying to implement the "hybrid" approach mentioned in the documentation.
Users can login through a web form and in most cases that is ok and using the created session works fine, but for /api/** calls we want to force the use of a tokens and ignore an authenticated user who may of come from a form login.
/api/content/** : jwt, api, user
/api/**: noSessionCreation, jwt, api, end
/**: jwt, api, user
We would like the /api/** to ignore any authenticated subjects that come from a session (created by a form login). Right now, if I login through the form page the session carries over to the /api calls and bypasses the need for the token being passed in on the url.
So, once I login from the form these calls will work:
/api/info
/api/info?token=123
/api/content/hello.png <-- This is the only one i want to work based off of the logged in user from the from
Our goal, basing of of the hybrid approach mentioned in the documentation is:
/api/** calls must be stateless and always use the token passed to the call.
/api/content/** can use a session, from a form login or the standard filter chain jwt and api calls
/** can pretty much take in anything - session or token.
Is there a way to recognize and forcibly (in a filter?) ignore authenticated users that come from the session?
Sounds like you would need to implement your own filter.
the noSessionCreation filter will not create a session but does not stop the use of an existing one.

IdentityServer3 - Contacting IdP after user is authenticated

We have SPA, IdSvr3, and a third party IdP(AAD B2C).
The user authenticates successfully. When the user clicks an edit profile link in the SPA, they are directed to IdSvr using the authorization_endpoint. I pass in an acr_value called "profile."
I believe this is the same problem as this gentleman- https://github.com/IdentityServer/IdentityServer3/issues/2816#issuecomment-217161898
I've tried a few things:
Implemented ICustomRequestValidator.ValidateAuthorizeRequestAsync.- In this method, I retrieve the acr_values. There doesn't appear to be a good way to direct the user from here. There is the RedirectUrl on the ValidatedAuthorizeRequest that does redirect the user, but all the information on that object is from the client request to IdSvr and is not relevant to the IdP.
Perhaps there is a setting on the ValidatedRequest that could be tweaked to force IdSvr to direct over to the identity provider(in this case the IdP is - Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthentication)
Implemented a UserService. If the user is logged in, the events trigger IsActiveAsync and GetProfileDataAsync. In IsActiveAsync I can get the acr value from the HTTP context, and set IsActive to false, forcing IdSvr to go back to the IdP. I can't access the context from OpenIdConnectAuthenticationNotifications.RedirectToIdentityProvider, so I haven't found a way to access the acr value there. Is there a way to pass something into here to check if this should be an edit profile?
Similar to the UserService I've implemented IsAuthenticationSessionValidAsync to invalidate the session and force the idsvr to direct to the Idp. This has the same issue of not being able to access the acr value.
PartialLogin doesn't appear to be the right strategy for this either because it appears to only be triggered from a user who isn't authenticated yet. Perhaps if we force the user to log-out, this could be used to direct them to the IdP? https://identityserver.github.io/Documentation/docsv2/advanced/userService.html
Logging the user out feels like the wrong approach to begin with, but it seems like it could be made to work.
Is there a standard way of intercepting a request and directing it over to the IdP based on something in the request?

Identityserver3 - User Impersonation

I have read the issues about impersonation, and from what i could find so far it can be achieved. I'm not sure tho if the following could be done using it.
A user doesn't have permission to do a certain operation, but it can be done if a supervisor grant him access.
The grant would be only for that operation/request.
is this something that can be done using impersonation, or there is a better approach for this?
Thanks in advance.
Quick brain dump of what you could do: You would have to implement this yourself in the user service in IdentityServer. One approach is to pass a custom param in the acr_values from the client with the ID of the user you want to impersonate (you will also have to pass prompt=login to force the request to go to the login workflow and thus the user service). In your user service implementation in PreAuthenticate you can check if the user is already authenticated, the custom acr_values is present, and the user is allowed to impersonate the user being requested. You'd then assign the AuthenticateResult on the context with the identity of the new user. This short circuits the login process and will return back to the authorization endpoint, and then back to your client app.