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

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).

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!

Custom Auth request in ServiceStack for multi-tenancy

I am already using a custom authentication provider in my ServiceStack based web services application.
I'm overriding the Authenticate method, and validating my user against one of multiple backend tenant databases. I currently determine the tenant database by matching an API key to a database string.
public override object Authenticate(
IServiceBase authService,
IAuthSession session,
Auth request) // <- custom object here, MyCustomAuth request
{
// ...
}
This works when each application is for a single tenant (a tenant/customer can build their own application and use that API key). Moving forward I want to build a multi-tenant mobile application. Thus the API key method cannot be used because I can't expect each user to type it in, hence I can't determine which tenant is using the application.
I wanted to alter the Auth object so that I could include the TenantId (provided by the user on login). However, I can't see how I can customize that object.
Is there anyway to customize that Auth object, or do I have to find an alternative solution?
You can't modify the built-in Authenticate Request DTO used, but you can use its Dictionary<string, string> Meta property to send additional metadata with the Authenticate request, e.g:
client.Post(new Authenticate {
...
Meta = new Dictionary<string,string> {
{"TenantId", tenantId},
}
}
Alternatively you can send additional info in the QueryString or HTTP Headers and access the IRequest with:
var tenantId = authService.Request.QueryString["TenantId"];

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

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.

How to store custom information in SecurityContext of spring-security?

In my application I'm using LDAP authentication. But i'm also have 2 remote services which requires authentication via method login(username, password). The method returns security token which makes me able to invoke another methods, i.e. I should pass security token to service methods as first argument.
So I'd like to get these security tokens immediately after successful login using LDAP and store them in SecurityContext. I tried to use authentication-success-handler-ref of form-login element. Using the handler I replace Authentication object in the SecurityContext with custom AuthenticationToken that holds not only password but also security tokens. But in this case I have an exception that no authentication provider supports this class of token.
I know it's also possible to store tokens in the HTTP session but in this case I have to pass session to service object, so I'd like to store the tokens in SecurityContext.
What is the best approach to handle service security token?
I often use the Authentication.getDetails() object to store additional info that may not be directly linked to the user per say. So you can store any object you want in that field (a HashMap for instance) and it shares the Authentication object life cycle.
HashMap<String, Object> info = new HashMap<String, Object>();
info.put("extraInfo", "info");
auth.setDetails(info);
...
Map<String, Object> i = (Map<String, Object>)SecurityContextHolder.getContext().getAuthentication.getDetails();
Your implementation of 'UserDetails' may hold any additional data. This is what gets stored in the SecurityContext which is later accessible after successful login.
You can later access it as (Assumes MyUserDetails implements UserDetails)
Object principal = SecurityContextHolder.getContext().getAuthentication();
if (principal instanceof MyUserDetails) {
MyUserDetails mud = (MyUserDetails) principal;
mud.getMyData(); //Extract your additional data here
}

Set username credential for a new channel without creating a new factory

I have a backend service and front-end services. They communicate via the trusted subsystem pattern. I want to transfer a username from the frontend to the backend and do this via username credentials as found here:
http://msdn.microsoft.com/en-us/library/ms730288.aspx
This does not work in our scenerio where the front-end builds a backend service channel factory via:
channelFactory = new ChannelFactory<IBackEndService>(.....);
Creating a new channel is done via die channel factory. I can only set the credentials one time after that I get an exception that the username object is read-only.
channelFactory.Credentials.Username.Username = "myCoolFrontendUser";
var channel = channelFactory.CreateChannel();
Is there a way to create the channel factory only one time as this is expensive to create and then specify username credential when creating a channel?
I found out that this is not possible. I know add a custom header value to each call that identifies the user. You need to do this as you do not want to create a factory for each user that could hit your front-end. Besides that, creating factories is expensive.