I'm implementing a Service Provider proof-of-concept for SAML/SSO authentication using Kentor.AuthServices. The use case is a kiosk style application on which numerous different users may be authenticating one after another as they sign up for our service.
The problem I'm having is as follows: after logging out the user is unauthenticated as expected (User.Identity.IsAuthenticated == false). But when the next user goes to log in, the previously logged out user is re-authenticated without having to enter credentials. Is that expected behavior? If so, is there a way to prevent the behavior (other than manually dumping cookies)?
What is most likely happening is that you are indeed terminating the local session on the SP. But when you try to log in again, the Idp still has an active session and automatically reauthenticates with that one.
To work around that you need to use Single Logout. AuthServices has support for that as of 0.17.0. To enable it, you need to have a service certificate configured (logout messages need to be signed). And of course your Idp must support it. Check for Logout endpoints in the Idp metadata.
Related
We have built a React web application that authenticates users with Microsoft via OAuth ( #azure/msal-browser package). Users are redirected to Microsoft auth page during signin, and then redirected back to our site once authentication has completed successfully. This is all working as expected.
However, we are in a position where we wish to add a custom PIN mechanism to protect some of our workflows. PINs will be encrypted/salted and stored in our own API, along with the existing mapping between Microsoft/Azure users and our own user state/records. In order for users to change/reset their PIN, we want to force them to reauthenticate with Microsoft before changing their PIN. I have not dealt with OAuth2 in a while, and am not entirely certain how this might be possible (since current auth workflow does not involve our server at all).
Ideally, users would navigate to the "Reset PIN" page and initiate the workflow. If possible, authentication would be handled through a pop-up (so as to not lose page state), which I think is possible as per documentation? If this is not possible, even a redirect to the same page with a specific query parameter (to indicate post-authentication) could work. The user would then be able to change/confirm their new PIN. At this point, a request would be sent to our API, including both the PIN and something from Microsoft that would allow our server to validate that the user did indeed just re-authenticate (proving they can change the PIN).
The primary sticking point is that our API must be able to verify that the user has just re-authenticated with Microsoft! One way to think about it would be that if a user gained temporary access to an unlocked authenticated workstation, they should not be able to perform restricted actions (as they do not know the PIN), nor be able to change the PIN (as they do not know the user's credentials). Yes, yes, I know physical access is effectively a compromise to any security, but this is a higher-level requirement...
I am guessing this workflow is possible, but am not certain how it might be possible. Would we use a different authentication workflow for this particular use case? Any pointers on a workflow we could investigate or use for this?
I can give you some info about how this should work. This type of flow can require a high level of extensibility in the authorization server though.
CLIENT REDIRECT
The client can send the OpenID Connect acr_values parameter, indicating the assurance levels it requires. In your case you would send two values.
CUSTOM AUTHENTICATION FACTOR
The user will perform standard authentication first, eg passwords. Then you would implement a custom second factor that uses the user identity and some custom logic to call your custom API.
ACCESS TOKENS
After authentication has completed, the authorization server will issue access tokens to the client. High privilege claims should only be included when strong authentication has been used. Some kind of scripting would be used here, that can read authentication result attributes.
API AUTHORIZATION
APIs should receive short lived access tokens. If it contains the high privilege claim, you know that your PIN requirements have been met.
CAN YOU SIMPLIFY?
It feels suspect to do your own PIN management. Can you outsource this, eg use a second factor of time based one time password (TOTP) instead? Mobile platforms such as the Google authenticator app provide tested solutions.
At the moment I'm still studing a solution for implementing the ADB2C logout for my desktop application (we implemented the Access tokens (used for implicit flows)). So far what I discovered is making me very confused about the purpose of the Logout feature in AD B2C (and probably in OpenId as well?). I realize the following things:
Log out process doesn't revoke the id tokens already issued
nothing stops a blocked user from using their refresh token (granted before the block) to get another access code, and continue to do so until they sign out themselves (from here)
From this link (actually the same..) they suggest to use the Azure Graph command "invalidateAllRefreshTokens", but from the Official Microsoft documentation seems is still in beta and is not supported in production.
So at the moment I'm wondering what is the real purpose of using the signout process. Seems I should take care of it all by my self (and that's fine), but should I still need to call the signout endpoint? Here they say:
If your app didn't go to the logout endpoint, the user will reauthenticate to your app without entering their credentials again. The reason is that they'll have a valid single sign-in session with the Microsoft identity platform. But at the moment I can't understand this sentence (probably bacause I'm still a little bit shocked from all these bad news). So my question is: how do you complete your logout process? Is there any considerations I shoud pay attention while I'm logging out from my desktop app? Thanks for your patience and time.
When you call the logout endpoint, a few things happen:
Access and Refresh tokens are destroyed by the client or confidential server
AAD B2C Session cookies are cleared
The point of the logout here is such that when the legitimate user requests to logout on a specific device, to login again, the user MUST provide credentials. Imagine a shared device in a family home, or in a library. Users must logout to protect THEMSELVES.
Everything you have stated concern over is in reference to a legitimate user who captures their tokens and replays them. That is not a concern when the user IS the one who authenticated in the first place, and IS the one who could reauthenticate anyway to obtain those tokens.
If your concern is around YOU as an ADMIN forcing the end user to lose complete access because YOU demand it, that is not achieved by the USER voluntarily logging out, it is determined by YOU as an ADMIN calling the /revoke endpoint on demand (albeit the AAD B2Cs session cookie will not be invalidated, only the refresh token/s).
In this case, the user will remain logged in until their Access Token expires. And if the account is marked as disabled at time of token revocation, they will not be able to authenticate again regardless. If this scenario is paramount to your service to operate securely, you want to reduce the Access Token lifetime (minimum: 5min).
Is there a addtional parameter & or workaround to get post_logout_redirect_uri to work if logout does not resolve internally in azure to a session. I am guessing no session & thus unkonwn client & thus no redirect? Just adding client_id=... does not seem to help.
I mean getting an uri to repeatable redirect back to app.
https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri=https%3A%2F%2Flocalhost%2Fmyapp%2Flogout%2F%3F&client_id=<...>
Want to do this for a specific tennant rather than common but I guess its the same.
You need an active session to be redirected to post_logout_redirect_uri, which usually is the case when calling the end_session_endpoint.
Microsoft response: https://learn.microsoft.com/en-us/answers/questions/60633/azure-ad-openid-connect-post-logout-redirect-uri-w.html#answer-64473
"Based on the internal discussions, I would say that, without session the logout redirect fails, since otherwise, it's an attack vector for open redirects."
They haven't specified how/why deeper thou.
I'm building an admin page for an application and have a state value 'authenticated' that flips from 'false' to 'true' after a successful login (which is authenticated on the server) which then shows the actual admin panel.
Are component state values safe from tampering by the client? Basically, if the client can modify my 'authenticated' state value to 'true', they can skip the login and go straight to the admin panel (which I obviously don't want).
I read that React Dev Tools allows the client to modify values yet everyone says "validate on the server" but I am validating on the server and updating my state accordingly, if the user is approved. If it is not wise to have a state value manage this, what is the right way to conditionally show the admin page after a successful, server-side authenticated login?
I think this is an important question since tampering with state values in a React app can have huge negative consequences on data integrity within an app/database.
TL;DR: Either require an authentication token with every request or require authentication through a session.
Never trust users always. One potentially big issue is if you "hide" admin actions behind the admins page without requiring authentication.
For example, assume the backend server uses a REST API to accept commands. In the admin panel you get links to administrative actions like a button 'Delete Everything' that sends a DELETE request to server.net:8080/api/admin/everything without requiring any authentication. If you're a user, you can find that in the code potentially and then send a DELETE request to that address from anywhere without any repercussions.
We'd never give administrative privileges to anyone who would want to delete everything... Because we'll never untrust someone. Right?
Worse, someone might find the server and fuzz some inputs to it, and oops! They manage to delete everything (or even worse, GET everything stored in the database). This wouldn't be hard to do, especially if the server you use to authenticate is the same server you use to issue commands. History has proven "security through obscurity" to be a very bad paradigm. Every action should be authenticated, even if it seems like the actions will be hard to find.
Generally, providing a JSON web token or some other form of authentication token and having the user send that with every request is a good start at least, especially if it has an expiration date. The token would be provided through a separate request with valid credentials.
Sending a token with every single request obviously isn't ideal. There are a couple of other things to try. For servers using PHP, you can probably trust sessions (though very many people who know more than me would probably disagree). In more modern cases, you could try to use Web Sockets, requiring the token after connection. Then only after authentication with the token do you allow the user to make administrative requests.
That way, even if a user knows the exact command they can send to perform any action, the server won't let them without a current session or token. Unfortunately, unless you're already using Web Sockets or depending on a session, it will likely require a lot of changes. I'd consider this to be critical though.
It is always possible to tamper values in the front-end, there is no way you can rely solely on the front end to ensure security.
Your best approach is to implement some form of authentication and authorization on your backend. In this way, even is some users pretend to be admin, they will be blocked when you do the next request to the server.
Perhaps if you can send more information regarding your problem, we can think of a more specific solution.
I have a Asp.net MVC application that uses Azure AD and OpenID Connect OWIN middlewares to handle authentication. Everything works fine except for one thing : if a user is already logged-in on another Microsoft Application lets say a Office 365 account or maybe a live mail account, when trying to login it recives a page saying that it is not allowed to log into my app, which is correct, but some how I need to catch that situation in my code to allow the user to sign in with a different account. Is there a way of doing that? This is by design? I mean : the user have to log in only with a live/azure account at the time ? I couldn't find any documentation about this.
As of today there is typically one user at a time, but we will soon support for you a way to select a specific user instead of automatically signing you in with the most recent one.
One way you can work around this today is by injecting the parameter "prompt=login" in your sign in requests. You can do that in the RedirectToIdentityProvider notifications, similarly to what is showin in http://www.cloudidentity.com/blog/2014/11/17/skipping-the-home-realm-discovery-page-in-azure-ad/ for domain_hint. This will cause the sign in experience to always start with a fresh prompt even if the user is already signed in. The draw back is that you'll never get SSO this way. Hopefully our account switiching feature will become available soon, keep an eye on http://blogs.technet.com/b/ad/ for announcements