This site contains the documentation that is relevant to older WSO2 product versions and offerings.
For the latest WSO2 documentation, visit https://wso2.com/documentation/.

User Store Listeners

WSO2 Carbon User Stores provide the ability to customize user store operations by registering an event listener for these operations. The listeners are executed at a fixed point in the user store operation, and the users are free to create a listener which implements their desired logic to be executed at these fixed points. Listener is an extension to extend the user core functions. Any number of listeners can be plugged with the user core and they would be called one by one. By using a listener, you are not overriding the user store implementation, which is good since you are not customizing the existing implementations.

The following diagram demonstrates a typical flow of execution of the user store operation, along with the listener's methods. The 'operation' method (here, representative of any user store operation) first calls the listener.doPreOperation which is implemented in the listener, then calls the doOperation, which is implemented in the subclass extending the org.wso2.carbon.user.core.common.AbstractUserStoreManager (the abstract class which implements the UserStoreManager interface). After this, the listener.doPostOperation method is called. However, this flow will change depending on the implementation (for instance in the carbon authorization flow, there is only one listener method that is being called). 

How listeners work

Every time when the user core method is called, all the listeners that are registered with that method are called. Listeners can be registered before or after the actual method is called. Consider this example; in the user core there is a method called addUser(). When a user is created in WSO2 Identity Server, the addUser() method is called. You can register a listener before the actual execution of addUser() method and also, you can register a listener after the actual execution of addUser() method.

The addUser() method can be seen as follows.

addUser() {
	preAddUser(); // you can implement this using listener
	actualAddUser();
	postAddUser(); // you can implement this using listener
}

Both preAddUser() and postAddUser() method can be customized as you want. This means you can do some customizations before the user is added or after the user is added.  All the methods in the user core have been implemented as above. You can customize them both before and after.

Consider the following simple scenario: When a user is authenticated with an LDAP, there is a requirement to add the authenticated time as an attribute of the user. For this requirement, you need to write some custom code after successful user authentication happened. The following is the custom listener implementation for this. The doPostAuthenticate() method would be called after actual user authentication is done.

package org.soasecurity.user.mgt.custom.extension;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.user.core.UserStoreException;
import org.wso2.carbon.user.core.UserStoreManager;
import org.wso2.carbon.user.core.common.AbstractUserOperationEventListener;
 
/**
*
*/
public class MyUserMgtCustomExtension extends AbstractUserOperationEventListener {
 
private static Log log = LogFactory.getLog(MyUserMgtCustomExtension.class);
 
@Override
public int getExecutionOrderId() {
return 9883;
}
@Override
public boolean doPreAuthenticate(String userName, Object credential,
UserStoreManager userStoreManager) throws UserStoreException {
 
// just log
log.info("doPreAuthenticate method is called before authenticating with user store");
 
return true;
}
 
@Override
public boolean doPostAuthenticate(String userName, boolean authenticated, UserStoreManager userStoreManager) throws UserStoreException {
// just log
log.info("doPreAuthenticate method is called after authenticating with user store");
 
// custom logic
 
// check whether user is authenticated
if(authenticated){
 
// persist user attribute in to user store
// "http://wso2.org/claims/lastlogontime" is the claim uri which represent the LDAP attribute
// more detail about claim management from here http://soasecurity.org/2012/05/02/claim-management-with-wso2-identity-server/
 
userStoreManager.setUserClaimValue(userName, "http://wso2.org/claims/lastlogontime",
Long.toString(System.currentTimeMillis()), null);
 
}
 
return true;
 
}
 
}

Likewise, you can add custom extensions to any method of the user core.

Tip: Make note of the following.

  1. The getExecutionOrderId() method can return any random value. This is important when there is more than one listener in the Identity Server and you need to consider the execution order of them
  2. All the methods return a boolean value. This value is mentioned regardless of whether you want to execute the next listener or not.

The following are the steps to configure the custom implementation.

  1. Listeners are registered as OSGI components. Therefore you need to register this class in an OSGI framework. You can go through this, which is the complete sample project.
  2. Copy the OSGI bundle file in to the <IS_HOME>/repository/components/dropins directory.
  3. Restart the server.

Interfaces

In WSO2 Carbon products that use the standard user manager kernel, there are multiple interfaces with which you can implement User Store Listeners. 

Listener InterfaceOperation TypeCaller ClassRemarks
org.wso2.carbon.user.core.listener.AuthorizationManagerListenerdoPreOperationorg.wso2.carbon.user.core.authorization.JDBCAuthorizationManagerOnly one listener method which gets called before each implemented operation logic
org.wso2.carbon.user.core.listener.ClaimManagerListenerdoPreOperationorg.wso2.carbon.user.core.claim.DefaultClaimManagerOnly one listener method which gets called before each implemented operation logic
org.wso2.carbon.user.core.listener.UserOperationEventListenerdoPreOperation and doPostOperationorg.wso2.carbon.user.core.common.AbstractUserStoreManagerpre and post operations that get called before and after (respectively) implemented operation logic
org.wso2.carbon.user.core.listener.UserStoreManagerConfigurationListenerdoPreOperationorg.wso2.carbon.user.core.common.AbstractUserStoreManagerOne listener method which is executed before the implemented logic
org.wso2.carbon.user.core.listener.UserStoreManagerListenerdoPreOperationorg.wso2.carbon.user.core.common.AbstractUserStoreManagerOne listener method which is executed before the implemented logic

It is recommended to extend the existing abstract implementation of these interfaces rather than implementing from scratch. For example, org.wso2.carbon.user.core.listener.UserOperationEventListener is implemented in the org.wso2.carbon.user.core.common.AbstractUserOperationEventListener abstract class.