StackCheats

Custom Event Handlers for Password Validation

WSO2 Identity Server: Event Handlers + Java WatchService

June 15, 2019

wso2wso2-identity-serverevent-handlers

A Story Guide

Stackcheats is a cheat-blog platform where developers and technical writers can create & write tech-cheats by owning user accounts. More importantly, Stackcheats has been using the WSO2 Identity Server as its identity and access management tool to manage user registrations and management tasks.

A tech-developer named “Athiththan” have been requested to develop a custom component to validate the password against a list of defective passwords when users trying to update (renew).

Development

WSO2 Identity Server (5.3.0 ≤ onwards) now supports to handle published events using an integrated event framework by extending `AbstractEventHandler`

So, Athiththan chose to develop the custom component as an event-handler listening to different password-update events to trigger and to validate the given password. We can use the following custom maven archetype to generate boilerplate to extend and implement custom event-handlers for WSO2 Identity Server.

Handle Event

The AbstractEventHandler contains a method named handleEvent() which gets triggered whenever a pre-registered event is made upon the Identity Server. So, for this custom implementation, he will be using the following two publish events …

  • PRE_UPDATE_CREDENTIAL
  • PRE_UPDATE_CREDENTIAL_BY_ADMIN

@Override
public void handleEvent(Event event) throws IdentityEventException {
if (log.isDebugEnabled()) {
log.debug("handleEvent() invoked");
}
if (IdentityEventConstants.Event.PRE_UPDATE_CREDENTIAL.equals(event.getEventName())
|| IdentityEventConstants.Event.PRE_UPDATE_CREDENTIAL_BY_ADMIN.equals(event.getEventName())) {
Object credential = event.getEventProperties().get(IdentityEventConstants.EventProperty.CREDENTIAL);
if (!DefaultDefectivePasswordValidator.getInstance().validate(credential)) {
if (log.isDebugEnabled()) {
log.debug("given password is defective");
}
throw Utils.handleEventException(
DefectivePasswordValidatorConstants.ErrorMessages.ERROR_CODE_CRACKED_PASSWORD_VALIDATION, null);
}
}
}

Password Validator

Given below is the implementation to validate the given password against a list of defective passwords. The given implementation reads all the defective passwords from a text file named passwords.txt which is placed inside the /<IS_HOME>/deployments/server/defective folder.

For testing purposes, the given implementation can be modified to work with pre-defined list of defective passwords using ArrayList.

public class DefaultDefectivePasswordValidator implements DefectivePasswordValidator {
private static List<String> crackedPasswords = new ArrayList<>();
private static DefaultDefectivePasswordValidator dPasswordValidator = new DefaultDefectivePasswordValidator();
private static final Logger log = LoggerFactory.getLogger(DefaultDefectivePasswordValidator.class);
private DefaultDefectivePasswordValidator() {
}
public static DefaultDefectivePasswordValidator getInstance() {
return dPasswordValidator;
}
/**
* initialize defective password values from the given text file
*/
@Override
public void initValues() {
crackedPasswords = new ArrayList<>();
try {
crackedPasswords = Files.readAllLines(Paths.get(DefectivePasswordValidatorConstants.PASSWORD_FILE_PATH),
StandardCharsets.UTF_8);
} catch (IOException e) {
log.error("Exception occured while reading and initializing values from "
+ DefectivePasswordValidatorConstants.PASSWORD_FILE_NAME, e);
}
}
/**
* validate method
*/
@Override
public boolean validate(Object credential) {
return !crackedPasswords.contains((String) credential);
}
}

OSGi Component

The custom event-handler has to be registered as a service component (OSGi) with the Identity Server components to work flawlessly. In order to register the custom implementation as a service component, he wrote a ServiceComponent class containing both activate and deactivate methods to register it with the Bundle Context.

@Activate
protected void activate(ComponentContext context) {
try {
context.getBundleContext().registerService(AbstractEventHandler.class.getName(),
new DefectivePasswordValidatorEventHandler(), null);
// initialize all defective passwords from the text file
DefaultDefectivePasswordValidator.getInstance().initValues();
// initialize watchservice on /defective directory
initializeWatchService();
} catch (Throwable e) {
log.error("Error occured while initializing service component", e);
}
}
@Deactivate
protected void deactivate(ComponentContext context) { }

Prepare

Defective Passwords Text File

Create a file called passwords.txt and add all defective-passwords (cracked passwords) at each line. These defined cracked passwords are the values, will be used to validate the entered password.

Create a folder named defective inside the <IS_HOME>/repository/deployment/server directory and place the above created passwords.txt file in it.

WSO2 Identity Server

Navigate to <IS_HOME>/repository/conf/identity directory and open the identity-event.properties file and add the following lines at the bottom to subscribe to the published events.

Please update the digit value according to your identity-event.properties file (last used value + 1)

The given module.name value is the same value which configured in the getName() method in DefectivePasswordValidatorEventHandler class

module.name.13=defectivePasswordValidator
defectivePasswordValidator.subscription.1=PRE_UPDATE_CREDENTIAL
defectivePasswordValidator.subscription.2=PRE_UPDATE_CREDENTIAL_BY_ADMIN

Build, Run & Test

Build

You can clone or download the custom event-handler implementation project done by Athiththan from GitHub and build it using the following command …

mvn clean package

Run

After a successful build, copy the defective-password-validator-1.0.0.jar artifact and place it inside the <IS_HOME>/repository/components/dropins folder.

Start your WSO2 Identity Server by navigating to the <IS_HOME>/bin folder and executing the following command …

sh wso2server.sh

Test

After server startup, navigate to https://<ipaddress>:9443/dashboard and log in using admin as both username and password. Click on the “View Details” button on the “Change Password” section and type your current password and enter the new password as one of the defective passwords and try on.

GitHub

Defective Password Validator

Defective password validation using WSO2 Event Handlers extension


Athiththan Kathirgamasegaran