My webMethods Server 10.15 | My webMethods Server Webhelp | Administering My webMethods Server | System Administrator Functions | Managing Security | Using Password Complexity Policies | Adding Custom Password Complexity Policies
 
Adding Custom Password Complexity Policies
To implement a custom password complexity policy, you include a password complexity Java class in a Composite Application Framework (CAF) application. When you deploy the application to My webMethods Server, the server registers the Java class. The password complexity policy component is then available for use during subsequent requests to the server. Implementing the password complexity policy does not require restarting My webMethods Server.
Before creating the Java class, you must create a CAF application in Designer. For more information about creating, working with, and deploying CAF applications, see webMethods CAF and OpenUI Development Help.
*To implement a custom password complexity as a Java class
1. In an existing CAF application in Designer, create a Java class that implements the ISystemPasswordComplexityPolicy interface. The component is registered as an OSGi service via the @Component annotation.
The following example shows how to implement the custom password complexity policy.
package caf.war.cafapp1.dir;

import java.util.Map;
import java.util.regex.Pattern;

import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.webmethods.portal.resources.Ui;
import com.webmethods.portal.service.dir.IDirPrincipal;
import com.webmethods.portal.service.dir.ISystemPasswordComplexityPolicy;
import com.webmethods.portal.service.global.IGlobalProvider;
import com.webmethods.portal.service.global.IMessageInfo;
import com.webmethods.portal.system.init.InitializationException;

/**
* Custom implementation of password complexity policy
*/
@Component (
service = {
ISystemPasswordComplexityPolicy.class
},
property = {
"name:String=CustomSystemPasswordComplexityPolicy1"
},
immediate = true
)
public class CustomSystemPasswordComplexityPolicy1 implements
ISystemPasswordComplexityPolicy {
private Logger logger = LoggerFactory.getLogger(getClass());

//references to other services
private IGlobalProvider gp = null;

/**
* Reference injection of the other OSGi service
*/
@Reference
protected void bindGlobalProvider(IGlobalProvider globalProvider) {
if (logger.isTraceEnabled()) {
logger.trace("Bound IGlobalProvider");
}

this.gp = globalProvider;
}

/**
* Activation of OSGi declaritive service
* @param config the configuration properties of the OSGi service
* @throws InitializationException if activation fails
*/
@Activate
protected void activate(Map<String,Object> config) throws
InitializationException {
if (logger.isInfoEnabled()) {
logger.info("Activating service");
}
}

/**
* Deactivation of OSGi declaritive service
*/
@Deactivate
protected void deactivate() {
if (logger.isInfoEnabled()) {
logger.info("Deactivating service");
}
}

/**
* Check the candidate password to make sure the value satisfies the
complexity
* requirements. If the password is not complex enough, this method
should throw
* an {@link InvalidPasswordException} with the reason. If no exception
is thrown
* the password is valid.
*
* @param candidatePassword the password to check
* @throws InvalidPasswordException if the password is not valid
*/
@Override
public void checkPasswordForNewUser(String candidatePassword)
throws InvalidPasswordException {
if (candidatePassword == null || candidatePassword.length() < 6) {
IMessageInfo messageInfo = gp.getMessageInfo(Ui.class,
"password.too.short", null);
String msg = messageInfo.getLocalizedMessage(false);
throw new InvalidPasswordException(msg);
}

boolean hasUpper = !candidatePassword.toLowerCase().equals(candidatePassword);
boolean hasLower = !candidatePassword.toUpperCase().equals(candidatePassword);
if (!(hasUpper && hasLower)) {
IMessageInfo messageInfo = gp.getMessageInfo(Ui.class,
"password.mix.case", null);
String msg = messageInfo.getLocalizedMessage(false);
throw new InvalidPasswordException(msg);
}

boolean hasNumberOrSpecialChar = Pattern.matches(".*[\\W\\d]+.*$",
candidatePassword);
if (!hasNumberOrSpecialChar) {
IMessageInfo messageInfo = gp.getMessageInfo(Ui.class,
"password.special.char", null);
String msg = messageInfo.getLocalizedMessage(false);
throw new InvalidPasswordException(msg);
}
}

/**
* Check the candidate password to make sure the value satisfies the
complexity
* requirements. If the password is not complex enough, this method
should throw
* an {@link InvalidPasswordException} with the reason. If no exception
is thrown
* the password is valid.
*
* @param user the user whose password is being checked.
* @param candidatePassword the password to check
* @throws InvalidPasswordException if the password is not valid
*/
@Override
public void checkPasswordForExistingUser(IDirPrincipal user,
String candidatePassword) throws InvalidPasswordException {
checkPasswordForNewUser(candidatePassword);
}

/**
* Return how long a password is valid (in milliseconds) before it
expires. The user
* will not be able to login after this time duration has expired
and the user must be
* reset by an administrator or a custom reset password page.
*
* @param user the user to get the expiration value for.
* @return return -1 for no password expiration, or the duration (in ms)
*/
@Override
public long getPasswordExpirationDuration(IDirPrincipal user) {
try {
if ("sysadmin".equals(user.getName())) {
return -1; //don't expire the sysadmin password.
}
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
return 1 * 60 * 60 * 1000; //1 hour
}

/**
* Returns a description of the expected pattern a password must have.
This text
* is displayed on the create user and update user pages of the UI.
*
* @return password descriptive text.
*/
@Override
public String getPasswordPatternText() {
IMessageInfo messageInfo = gp.getMessageInfo(Ui.class,
"password.complexity.description", null);
return messageInfo.getLocalizedMessage(false);
}
}
2. Deploy the application to My webMethods Server.
3. Configure My webMethods Server to use your custom class on the Properties page for the system directory service, as described in Using Password Complexity Policies.
4. Debug and test the Java class.
5. If required, make further changes to the Java class and repeat steps 2 and 3 until the class works as expected.