I have a multi-tenant REST app. When a new user first tries to access my application ( and assuming their admin has already granted the app permission for their directory ) I create a user row in my User table and store their name/email and other fields. I perform this in the TokenValidated event of JwtBearerEvents.
Unfortunately, I'm ending up with multiple users rows attempting to be inserted because of simultaneous (parallel request) hitting my web API. I do a simple SQL query for the User by ObjectId, and then create if necessary. This isn't threadsafe. I tried wrapping it in a SQL transaction, but the select isn't blocking and I'm not sure EF Core lets me perform the kind of locking I'd need to block other selects from completing.
I'm basing my code off the TailSpin PnP and they perform the same logic here as well. My guess is their site logic is forcing a single call the the WEB API first as part of the sign-in/login process, where the new user is created if they don't exist. In my flow, the REST API is hit right off the bat with multiple HTTP GET's and I just have to validate the bearer token in the headers and let ADAL cache it.
Aside from changing my client logic, and forcing the first call to API to be a single HTTP GET, how else can I make this work in a REST world? I can't use SESSION logic to block other calls in the same session. I'm not sure how I can perform a lock across the whole server ( Which works only if there's one server ). I could use the DB layer to hold a write lock, but that seems dirty. Maybe there's a better place to put the Create new user logic? Is there some other way for me to safely perform a one time atomic operation?
Based on the description, it seems you were create the user record(sign-up) when the users call the REST API and after the token is validated.
To fix the duplicates records issue, one possible way is that separate the sign-up progress from token validation as same the code sample TailSpin PnP. For example, we can custom the token handler to verify whether the users is sign-up and provide the UI for the users sign-up.
Another way is that, you can insert the users sequentially by using the lock. For example, here is the code for your reference:
private Task tokenValidated(TokenValidatedContext context)
{
lock (obj)
{
//query db and insert users here
}
return Task.Delay(0);
}
Related
With IdentityServer4 I need to allow a single user session per time. If the user authenticates with device A and then with B, session and access token must be invalidated for A and, even better, client A could receive a notification that user has logged out in a second step.The main thing is making the server force invalidate session and token. There are similar questions, one of them redirects us to the following link:
https://github.com/IdentityServer/IdentityServer4/issues/736
where it is explained to use backchannel logout and in the login method of the identity server to obtain the previous IdentityServer sessionID that should have been persisted somewhere. Then I should send logout tokens to all clients.
Another solution is given here
How to Logout user from a particular session Identity Server 4, .Net Core?
telling us to use an ITicketStore implementation to be able to invalidate the session.
The configuration used is IdentityServer4 with authorizaton code flow with PKCE. Which approach is best for my case? Is there another approach where I could simply delete the access token in the id server database?
I think in your case probably a combination of both. In our real-world implementation we combine server-side storage of sessions via ITicketStore (stored in a custom database with sessions linked to user accounts and also storing the list of client IDs for each session) with the ability to trigger back-channel logout of any session at any time (i.e. not just via the default user-triggered mechanism).
In our case we do this to be able to invalidate sessions for other reasons (e.g. password or other security setting changes, a "log me out of everything" feature, impersonation rights being revoked etc) but this approach could form the foundation of a "single session per user" feature should you wish.
What I'd like to do is end all sessions for a user when a user changes/resets their password (using ASP.NET Core Identity). I'm using the oidc-client-js library inside of a SPA. I've figured out how to end the current session for a user and cause any tabs that're in that same session (say, other tabs in the same browser windows) to recognize the session is over via the check session iFrame, but any other sessions (say in an incognito window) still seem to have the session functioning, even if their refresh tokens/all persisted grants for that subject ID have been revoked.
Is there some way to make that iFrame return to the client that the session is over for all sessions, like maybe have the iFrame page be checking the persisted grants for that session or something? I'm okay if a currently issued access_token continues working (they're short-lived), but just want the refresh tokens to be invalidated and the session to end.
Option 1
There is an OpenID Connect Session draft specification which would do what you want - it allows front end clients to check the current session state via an iframe. This is a draft and may not be implemented by ASP.NET Core Identity though.
https://openid.net/specs/openid-connect-session-1_0.html
Option 2
An alternative mechanism for resolving your problem programatically is by putting a check in your token exchange code. Your access tokens will presumably be relatively short lived, and so the front end has to regularly acquire new access tokens (either via refresh token, or by id token on the implicit flow for instance.
In your token exchange you could check for timestamp when the password was last updated.
If it is more recent than the timestamp when the token was issued, then instead of issuing the fresh access token you could return a 401 and manage a redirect to your authentication endpoint by a mechanism of your choice.
This doesn't instantly log the user out of alternative browser windows, because it depends upon the expiry window of your access tokens. If does have the advantage of working cross browser though, because it doesn't depend upon browser specific session information. It can also check for customers who are blacklisted, or who have changed their email address and other checks which might be relevant to a desire to force re-authentication.
For belt and braces you can use both these techniques.
I am looking to implement SSO in all my future php/angular applications. I see there are services (Auth0, oauth.io, etc) that are sort of the middle man of an SSO app and there are protocols such as OAuth 1.0/2.0 but in regards to creating a custom SSO solution (using aforementioned OAuth protocols, I assume), I am a little foggy on the complete flow of the process.
What I do get:
App gets Access Token
(optional) App validates Access Token
App (with Access Token) gets access to a particular API and returns result. For
example, Facebook profile information.
What I don't get:
What to do with that information once I have it. Do I retain the access token and request information from the API source each time they login? How do I relate my own application data to the API data? Would I create a different kind of user record that just contains the access token and application's userid?
Do I retain the access token and request information from the API source each time they login?
If the token does not expire, you can hold on to it in a data store and use it with each request. Many times, though, the token will expire, and you need to request a new one each time you start a session. In this case you'd probably store the token in memory instead of a permanent storage location.
How do I relate my own application data to the API data?
I think we'd need to know a little more about your application to answer this question.
Would I create a different kind of user record that just contains the access token and application's userid?
Again, we'd probably need a little more information about your application. If you were persisting the token (in the case that it doesn't expire), then you need to make some considerations about how you want to store it. If not, you can probably just put it into a local variable or session.
We are trying to develop a SCIM enabled Provisioning system for provisioning data from an Enterprise Cloud Subscriber(ECS) to Salesforce(Cloud Service Provider-CSP). We are following SCIM 1.1 standard.
What are we able to do:
We are able to perform CRUD operations on User object using Salesforce auto-generated userId field
Exact Problem:
We are not able to update/delete User object using externalId provided by ECS.
Tried something as below... But it is not working, Unknown_Exception is thrown...
XXX/my.salesforce.com/services/scim/v1/Users/701984?fields=externalId
Please note that it is not possible to store Salesforce userId in ECS's database due to some compliance reasons. So we have to completely depend upon externalId only.
Possible Workaround:
Step1: Read the userId based on externalId from Salesforce
Step2: Update the User object using the salesforce UserId obtained in Step1.
But this two step process would definitely degrade the performance.
Is there any way to update/delete the User by externalId
Could you please guide us on this..
Thanks so much....
I realize this is old thread but wanted to note that you CAN update Users from REST using an external ID. The endpoint in above question is incorrect. Following is how it should be set, send as a PATCH request:
[instance]/services/data/v37.0/sobjects/user/[external_id__c]/[external id value]
Instance = your instance i.e. https://test.salesforce.com/
external_id__c = API name of your custom external Id field on User
external id value = whatever the value of the user's external Id
NOTES:
Salesforce responds with an HTTP 204 status code with No Content in the body, this isn't usual for patch requests, but it is 'success' response
The external id on user has to be a custom field, make sure it is set
as UNIQUE
Ensure the profile/permission set of the user that is making the call
has the Manage Users permission & has access to the external id field
It is pretty common pattern for other applications, too, to search first and then perform on update on the returned object. Your workaround seems fine to me. What performance problem are you concerned about? Are you concerned about Salesforce not being able to process more requests or are you concerned about the higher response time in your application because you need to make multiple requests? Have you actually measured how much an extra call costs?
I have a Servlet when a request comes it checks for the user id and then if id is not there it creates a new user id in the database. But if I get multiple requests with a very short delay then all those request tend to see that there is not user at the moment and create multiple users with the same name. I just don't want to make the user id field unique to solve this problem. Other than the user id I store some related data as well.
I need to know how to keep a DB locked until one Servlet request is finished processing.
You need to make your servlet code synchronized.
Easy way is to make your servlet implement SingleThreadModel.
http://www.javatpoint.com/SingleThreadModel-interface
But this is not a good approach as your servlet will handle only one thread/request at a time. Good solution is to synchronize the part where you check and generate the uid.