How to get the userIdentity of the user being logged out when using Worklight adapter based authentication - ibm-mobilefirst

I am currently implementing an adapter based authentication for my Worklight application.
For the record, I am using Worklight version 5.0.6.1.
What I would like to do is, as it seems to be advised in the documentation, to perform some cleanup in the "logout" function of my authentication adapter.
Thus, inside the logout function being called automatically by the Worklight framework, I'd like to retrieve the userIdentity object holding the info about the user being logged out. I tried to achieve this by calling "WL.Server.getActiveUser()", but it does not seem to be possible to do this in the logout function.
I can see the following exception in the logs (WebSphere App Server 7):
[9/3/13 17:13:11:683 IST] 00000039 DataAccessSer 1 com.worklight.integration.services.impl.DataAccessServiceImpl invokeProcedureInternal Procedure 'onLogout' invocation failed. Runtime: Adapter 'onLogout' security test has no user realm.java.lang.RuntimeException: Adapter 'onLogout' security test has no user realm.
The idea behind this is that I want to call an external REST service that will perform some cleanup in a DB, and I need the mobile application userId to be passed as a parameter of this service.
Could someone please give some best practices in order to retrieve the identity of the user being logged out from inside the authentication adapter logout function?
Thanks.

User identity is destroyed by an underlying auth framework before Adapter.onLogout() is invoked. As a result when Adapter.onLogout() is called the user identity doesn't exist any more. Therefore WL.Server.getActiveUser() will return null or throw exception (in your case because it doesn't have any user realm defined, which is perfectly fine).
In case you still require data from userIdentity even AFTER underlying auth framework discards it (and this IS your case) you can save userIdentity in session state. However you need to remember that since you're manually storing it there - it is also your responsibility to wipe it once it is not required anymore.
So the adapter code would be something like:
/* global var, not inside of any function*/
var userIdentity = null;
function submitCredentials(user, pass){
if (/*validate credentials*/){
/* using previously created global var, not declaring it again */
userIdentity = {
userId:user,
displayName:user
};
WL.Server.setActiveUser("realm", userIdentity);
}
}
function onLogout(){
/* do your stuff with userIdentity object and then wipe it*/
userIdentity = null;
}
The main difference with regular adapter flow is that userIdentity object is not created in the scope of a submitCredentials() function but as a global variable, therefore it is a session scoped var.

Related

How to create and persist a custom user object before endpoint execution in webflux?

I am currently developing an OAuth 2.0 resource server (REST API) with Spring Webflux.
I have Spring Security set up and I can successfully authenticate users with Spring's built-in principal class.
The problem:
The application needs to store additional information about the user as per requirement.
Users that access the API for the first time are not stored in the REST API's internal user database. Right now I have to check if the provided principal name (I have access to the respective OAuth UUID - the one stored in the authorization server) already exists in the application database.
I would like to avoid code duplication, where I would have to call a method that does exactly that on every endpoint
Here is what already works:
#GetMapping("/secure")
fun secureEndpoint(principal: Principal): ResponseEntity<Void> {
println(principal.name)
// here I would have to check if the user has already been
// created in the database
return ResponseEntity.ok().build()
}
As I said, the principals correct UUID is already being displayed.
What I am looking for is some kind of webfilter, that runs before every (authenticated) endpoint, and automatically creates the user, so I do not have to do it in the controller layer.
This is my Security configuration:
#Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
val cookieServerCsrfTokenRepository = CookieServerCsrfTokenRepository()
cookieServerCsrfTokenRepository.setCookieHttpOnly(false)
http.authorizeExchange()
.pathMatchers("/**").permitAll()
.pathMatchers("/secure/**").authenticated()
.and()
.oauth2ResourceServer()
.jwt()
http.csrf()
.csrfTokenRepository(cookieServerCsrfTokenRepository)
return http.build()
}
I would greatly appreciate any help!

Update User Role Mapping in Keycloak using User Storage SPI

I have developed a Keycloak Provider and have registered it under User Federation. My users are stored in a MySQL Database. It is working fine, and whenever getUserById() is called, keycloak calls my implemented method, and user with proper roles are returned, and the user gets cached.
The problem occurs when I update user roles externally (in some other/external portal), now I want to tell Keycloak to invalidate the cache (may be via some REST API), so that it calls my getUserById() or getUserByUsername() method again.
What is the best possible way to do it?
Thanks!
Dealing with cache sometimes is undersirable for Authentication purposes, you can force your User Storage to load user from database every time isValid method is called.
In Example:
I put this code at top of isValid method.
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input)
{
CustomUserAdapter userDb;
if (user instanceof CachedUserModel)
{
userDb = (CustomUserAdapter)this.getUserByUsername(user.getUsername(), realm);
}
else if (user instanceof CustomUserAdapter)
{
userDb = (CustomUserAdapter)user;
}
[...]
Your custom code
[...]
}
Another way is change your User Federation Settings by setting Cache Policy to NO_CACHE.
Disable Cache Policy User Storage SPI

Detecting actual login in Spring Security filter chain

For a non-trivial setup involving session concurrency control, authentication is not equivalent to login. For example, a user can be authenticated successfully but still redirected to a logout or error page if this is a second login attempt and max-sessions="1". If I have post-login logic that needs to be invoked at the point of login (not authentication), what is an optimal way to incorporate this logic into a Spring Security-based webapp? The solution I came up with, based on my limited understanding of the framework, was to implement my own custom ConcurrentSessionControlAuthenticationStrategy adapter extending the framework's ConcurrentSessionControlAuthenticationStrategy and inject it into CompositeSessionAuthenticationStrategy in my Spring Security configuration XML. I created a 1-arg constructor and onAuthentication method. onAuthentication performs my post-login processing before calling super.onAuthentication. Is there a better way to do this?
My custom onAuthentication method looks something like
.
.
if (sessionCount < allowedSessions) {
// Record login timestamp in database
Date now = new Date();
userDao.setLastLogin(now);
userDao.save();
}
super.onAuthentication(...);
Because sessionRegistry member variable is declared private (as opposed to protected) in the parent, I had to declare my own sessionRegistry and initialize it inside the 1-arg constructor so that my onAuthentication method would have access to it.

IBM MobileFirst Platform Foundation 7 - Adapter authentication - Update the user identity attributes

I'm using the adapter based authentication for protecting resources as well as managing the entire authentication logic (credentials validation).
If the user/password validation passed successfully, the WL.Server.setActiveUser method is called to create an authenticated session for the Realm, with user data stored in a userIdentity object.
The user/password validation process returns OK/Fail and also a cookie if the validation passed. And this cookie should be sent on the following adapter calls, so I'm adding it into the userIdentity data object as well.
My idea was to store it within the userIdentity object, since it can be retrieved on the others adapters (var userIdentity = WL.Server.getActiveUser();) for adding the cookie value into the adapter's request header and it works properly!
What's the problem? The adapter response can contain a new value for this cookie, so I should update the userIdentity object for replacing the cookie's old value by the new value.
Nevertheless, the userIdentity object is immutable so it always contains the original cookie the login process got.
Is there a way for updating the userIdentity object? Otherwise, how can I manage a mutable table for saving and updating a cookie linked to each user session in order to send it on the adapter request to the Backend?
Is there a better way to manage this backend cookie required on each user adapter request?
Many thanks!
Sergi
PS: There is a question that tries to solve this but the possible answer is not valid to me (IBM MobileFirst Platform Foundation 6.3: Can we edit the custom attributes of User Identity Object [MobileFirst Session]):
I have tried the following code for updating the userIdentity:
var newUserIdentity = {
userId: userIdentity.userId,
attributes: {
cookies: newValue
}
};
WL.Server.setActiveUser(realm, null);
WL.Server.setActiveUser(realm, newUserIdentity);
But when it's retrieved from another adapter (var userIdentity = WL.Server.getActiveUser()), it contains the original value!
You could remove the userIdentity (WL.Server.setActiveUser("realm", null);), and then set a new active user object.
If you can depend on HTTP Sessions (single server or sticky sessions), you can access the session object and store whatever you want. (WL.Server.getClientRequest().getSession())
If you do not want to use HTTP sessions, you can use an external storage mechanism such as SQL or Cloudant to store that information. You can use the Client-ID as the identifier (see example https://ibm.biz/BdXUHt).

WCF service void method Will operation complete with Windows Impersonation

I have a WCF which is configured on Windows Authentication. This means that only authenticated Windows users will be able to access. I have a method which does not return anything but spins up a thread that does some long running task under the called windows user impersonation.
My code is below:
public void SampleTask();
{
Task.Factory.StartNew(this.Activity);
}
private void Activity()
{
WindowsIdentity identity = ServiceSecurityContext.Current.WindowsIdentity;
using (WindowsImpersonationContext ctx = identity.Impersonate())
{
// Log status in a log database as "In Progress"
// Do long running task (accessing database as current user)
// retreive the results and save in a file
// Update the log database as "Complete"
}
}
My question is will the task still complete of retrieving the results and saving it and put the status as it should. Or will the impersonation will not work as there will be no open session. Or am I mistaken
Regards,
Girija Shankar
The session should remain open as long as the method is executing. Even if the method is returning void, the request that started the execution of the method will be replied to.
If you don't need a reply from the service, you can use the IsOneWay = true attribute on the method, which will tell the service to not send a reply to the client. Since this is a long-running method that is not returning data to the client, that makes it a good candidate for being a one-way method. In this case I'm not sure if the session would remain open or not, but it doesn't matter because the impersonation context will be scoped to the service, and have no dependency on the client.
In your method, you can see this because of the declaration:
WindowsIdentity identity = ServiceSecurityContext.Current.WindowsIdentity;
The variable identity is scoped to the Activity method.
using (WindowsImpersonationContect ctx = identity.Impersonate())
The variable ctx is likewise scoped to the using block within the Activity method.
The only time you would run into a problem that I can think of is if the service throws an exception and crashes - then of course the method wouldn't finish.
To sum up, since the impersonation is based on the identity the service is running under, and you're not returning any data to the client, session should have no impact on both the method running to completion or the identity the service is running under.