IdentityServer IsActiveAsync method not being called on the profile service - asp.net

I'm using IdentityServer v4 to handle authorisation for my ASP.NET application, using Resource Owner flow.
I've implemented the IdentityServer4.Core.Services.IProfileService interface which has two methods, GetProfileDataAsync and IsActiveAsync.
When making a request to the token endpoint, the GetProfileDataAsync gets called as expected. We use this method to issue our claims.
However the IsActiveAsync method does not get called. I'd like to implement this method to determine whether the user is active in our database. At what point is this method supposed to get called?
The comment in the IdentityServer source (see below) suggests it should get called during token issuance, but the method isn't called when requesting a token. I suspect I'm missing something. Any help would be appreciated.
// Summary:
// This method gets called whenever identity server needs to determine
// if the user is valid or active (e.g. if the user's account has been
// deactivated since they logged in). (e.g. during token issuance or
// validation).
Task IsActiveAsync(IsActiveContext context);

Right now IsActiveAsync does not get called for resource owner password requests. I guess the assumption was that you wouldn't successfully authenticate a user if the user is inactive.
These details are not yet decided on - if you have a strong opinion on how this should work - please open an issue on github. We will lock down the API in late August.

Related

Synchronize users created with Firebase Auth to my custom backend

I want to use Firebase Auth for my user login/registration process. Everything else should be handled by my own backend (spring boot app + postgres db).
Now I'm asking myself how I can synchronize a new created user to my user table in postgres. I thought about the following:
REST call through client - Everytime I get a success event from the firebase sdk I call an additional request to my backend which sends uid, username etc.
Problem: What if my backend call fails but the register process was successful ? That would lead to an inconsistent state since (at least thats what I understanded) I can't easily rollback. That would lead to situations where a user can login into my app without my backend knowing the user. This would crash/ invalidate all my following queries (e.g. search after user xyz would lead to no result even though he/she exists)
Check the existence of the user in the postgres database
Here I would query the uid from the database (which I got from the jwt) and create a new user if it doesn't exists in every incoming request.
Problem: The user query is a unnessecary overhead for every incoming request.
Trigger with cloud functions - When I understood it right firebase auth is firing events when a new user is created in cloud functions. This could be used to make the external api call.
Problem: I dont know what happens when my external rest call fails at this point. Can I rollback the registration ? Will I be ever catch this event again ? I also proably would have an eventual consistency situation, since I dont know when the cloud function triggers. Furthermore I would prefer not to include cloud functions to my stack
Is there any way how I could do this in a transactional manner ? Did anyone else tried is using sth simular ?
Thanks for every help!
The easiest way is actually to not synchronize auth data, but instead decode and verify the ID token of the user in your backend code.
This operation is (by design) stateless, although Firebase's own backend services often implement a cache of recently decoded tokens to speed up future calls with the same ID token.
Apparently, I finally came up with a different solution:
Register user per Firebase SDK (e.g. with email + pw method)
Make a post-call to my own registration api including the resulting uid from the previous step and some metadata
API creates a new user including a column with the UID + Fetches the firebase token of the user and adds an internal claim that references to the internal Postgres UUID via Admin SDK.
Frontend gets the created user and hard refreshes (very important, since the previously fetched token won't contain the newly added claim !) the firebase token and verifies that it contains the token. If it does -> everything is cool, if not some oopsie happened :) That will require a request retry.
Later when you start your app you can just check if the passed token contains the custom claim, if not open the sign up/sign in page.
Every endpoint except the one for registration should check if the claim is set. If not just forbid the request.
How to set custom claims:
https://firebase.google.com/docs/auth/admin/custom-claims#set_and_validate_custom_user_claims_via_the_admin_sdk
You can use the Firebase Admin SDK to create the user account from your back-end instead of from the client.
So first you create the user in your database, then grab the ID and use it to create a user with the same ID in Firebase.
If all goes well, send a confirmation to the client and sign it in using the same credentials they entered.
Why not creating an endpoint in your backend service and call this endpoint when a client side authentication succeeds?
This method should do 2 things:
decode token to get access to Firebase user object (Firebase Admin)
Compare Firebase user with your internal user table. if it doesn't exist you can create it using firebase user object, otherwise do nothing.
This solution allows you to do other nice things as well (Syncing user info between Firebase and your internal db, providing a way to let a frontend know if this user is new or not, ...) at a relative small cost (1 get call per sign in)

How to get the state of a Token?

I'm trying to implement a way to restrict the usage of a token only once. After its first use, you must not be able to use it alright by tagging the token on its state with UsedAlready tag and Unused if its not yet used. How do I do that in apigee?. Currently I have the following condition to determine whether if the Token is used already or not.
<Step>
<Condition>(request.queryparam.state NotEquals accesstoken.state)</Condition>
<Name>RF-TokenAlreadyUsed</Name>
</Step>
Looking on my Tracetool though, apigee is throwing out that my accesstoken.state doesn't contain anything, why is that though?. My API proxy and policy for saving a default state on token creation seems to work fine anyway.
PS: Also I did the almost the same thing but using a non existing variable instead using the attribute to associate a token to a particular account. But doing the same thing with state with what I did with an attribute doesnt work. What am I doing wrong though?, am I using the state parameter of apigee right? , cuz state parameter is an optional parameter like scope and I want to make use of the state for token accesibility.
Turns out I was using the state wrong. A state should function like this as stated in this thread.
So in order for me to be able to do what I want to do is that I should add another attribute to the token so that I would know if the token is already used or not. It's not that I havent done a similar thing before using an attribute, rather I thought the use of state is for token accessibility.
Can you explain me why are you more worried about the token state? Until unless you store the token in cache, you will get a new token for your every request.
And you have a built-in policy in APIGEE that validates your token.
Even if you are storing the token in cache, you can set the expiry time for your token.
More over, the cache is used to reduce the traffic and reuse the token.
So I couldn't understand your objective, can you explain more.
#user2462133
To answer your question.
We want the token1 to be valid only only once and after that be invalid for next payment alright . But this token1 will be used for generating a new token2 to access the payment API again as the previously made token is for binding the account on first use. This new token2 will then have another state which will only be valid only once and after successful transaction, it will not be valid for another transaction again even if the token is not yet expired. For another payment, token1 will be called again and check if its still a valid token, and if so, create another token2 for another payment. But if this token1 is already expired. Then the user would have to bind his account again to our service by loggin in to his account (i.e facebook), do the OTP, etc. To be able to gain another token1 that will then only be used once for payment but multiple times for validating whether if the account is binded to our service or not.

Logging Out With AspNet.Security.OpenIdConnect.Server (ASP.NET vNext)

I am using Visual Studio 2015 Enterprise and ASP.NET vNext Beta8 to issue and consume JWT tokens as described here.
In our implementation we're storing some client details in Redis at token issuing time and we would like the flush this information when the user logs out.
My question is what is the best practices for logging out with OIDC?
While I could roll my own contoller for this purpose I couldn't help but notice Open ID Connect (OIDC) seems somewhat primed to handle this case. For example OIDC has an OnLogoutEndpoint handler and LogoutEndpointPath settings. But when I call the OIDC logout URI that handler appears to accept any random x-www-form-urlencoded form I throw at it and doesn't in any particular way seem to be demanding the presence of a token.
Any advice on proper OIDC logout practices would be very much appreciated.
In AspNet.Security.OpenIdConnect.Server, the logic used for the logout endpoint is left as an exercise.
In this sample, it is implemented using an MVC 6 controller, where you're - of course - free to add custom logic to remove cached details from your Redis server.
[HttpPost("~/connect/logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout() {
// When invoked, the logout endpoint might receive an unauthenticated request if the server cookie has expired.
// When the client application sends an id_token_hint parameter, the corresponding identity can be retrieved using AuthenticateAsync.
var identity = await HttpContext.Authentication.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);
// Remove the cached details here. If you need to determine
// who's the authenticated user, you can use the identity variable.
// Remove the authentication cookie and return the user to the client application.
return SignOut("ServerCookie", OpenIdConnectServerDefaults.AuthenticationScheme);
}
You can also do something similar directly from the LogoutEndpoint event. Don't forget to call context.HandleResponse() to make sure the request is not intercepted by another middleware.

Customizing CQ / AEM Authentication

What exactly do you have to do to authenticate users against an external source while accessing pages on a CQ publish instance?
From what I have read, a custom AuthenticationHandler can be used for this. The AuthenticationHandler can be configured to be called against the paths requiring authentication and inside the extractCredentials() method, the users will be authenticated against the external source and an AuthenticationInfo object will be returned.
If the supplied credentials are invalid, null would be returned from this method to indicate the same. The SlingAuthenticator will then call requestCredentials() where the user can be redirected to the login page.
Is this understanding correct? If so, what does SlingAuthenticator do with the AuthenticationInfo object returned from extractCredentials()?
In some places, having a custom LoginModule (by overriding AbstractLoginModule) is also suggested for the same purpose. Are these 2 different approaches (custom AuthenticationHandler and Loginmodule) for having custom authentication or are they used together somehow? If so, how do they interact?
And also, the concept of CUG (Closed User Group) can be used to redirect users to the login page if they don't have access to a page. Can CUG still be used with a custom auth mechanism or it only works if the users are present in CQ repository?
Any light shed on this would be much appreciated :)
Your understanding is correct. The AuthenticationInfo object ultimately contains a JCR user id -- but rather than having to use the JCR password for the user, a 3rd party service basically says "this user has authenticated successfully and can access the repository as X".
Example: you're using OpenID or SAML to verify a user is X. user X is then mapped to a user Y in the repository.
I haven't used LoginModule but from what I'm reading, that's just extending login processing for the JackRabbit repo. So, rather than using AuthenticationHandler to redirect a user to some other place and processing the response, you're plugging further down into the chain where there's already AuthenticationInfo (or something like that) being given to JackRabbit to verify and return a session for a user.
So, let's say you did successfully authenticate with OpenID but the user you're mapped to doesn't exist. You could write a login module to create the user in this case (and assign user to a default group). For instance, if user came in with a gmail id, the JCR user could be gmail_$id. And the login module, seeing the name starts with gmail, will know it's ok to create that user automatically.
As far as CUG, yes, all the above can be used in conjunction with it. Basically, if a request doesn't have access to a resource and the request hasn't been authenticated, the authentication handling system kicks in. If a user has authenticated but still doesn't have access to the resource (e.g. not part of a group that can read it), a 403 will be generated.

impersonation via token stored in a cookie

I want to know more about win32 LogonUser api function. The last parameter is a token which can be used to impersonate a windows identity to execute code on a person's behalf. Say I have a login page where I enter my username, password and domain. When the user submits the page I validate the user by making a call to LogonUser() and get a token reference.
I am thinking why not store the token in a cookie and use it at a later stage (perhaps in another page). I just don't know what issues I might have to face upfront...
Can the token expire even if we don't close it properly using the CloseHandle() win32 call? Is there any article related with this particular requirement?

Resources