Adding Custom Password Complexity Policies
About this task
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
Procedure
-
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); } } - Deploy the application to My webMethods Server.
-
Configure My webMethods Server to use your custom class on the
Properties page for the
systemdirectory service, as described in Using Password Complexity Policies. - Debug and test the Java class.
- If required, make further changes to the Java class and repeat steps 2 and 3 until the class works as expected.