/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security.validation; import java.lang.reflect.Method; import java.util.HashSet; import java.util.Set; import org.geoserver.platform.GeoServerExtensions; import org.geoserver.security.GeoServerSecurityManager; import org.geoserver.security.config.PasswordPolicyConfig; import org.geoserver.security.password.GeoServerPasswordEncoder; import org.geoserver.security.password.PasswordValidator; import static org.geoserver.security.validation.PasswordPolicyException.*; /** * Implementation of the password {@link PasswordValidator} interface * * @author christian * */ public class PasswordValidatorImpl extends AbstractSecurityValidator implements PasswordValidator { protected PasswordPolicyConfig config; protected static Set<String> notAllowedPrefixes; protected static Object lock = new Object(); /** * Calculates not allowed prefixes */ public PasswordValidatorImpl(GeoServerSecurityManager securityManager) { super(securityManager); } public static Set<String> getNotAllowedPrefixes() { if (notAllowedPrefixes!=null) return notAllowedPrefixes; synchronized (lock) { if (notAllowedPrefixes!=null) return notAllowedPrefixes; notAllowedPrefixes = new HashSet<String>(); for (GeoServerPasswordEncoder enc : GeoServerExtensions.extensions( GeoServerPasswordEncoder.class)) { notAllowedPrefixes.add(enc.getPrefix()+GeoServerPasswordEncoder.PREFIX_DELIMTER); } return notAllowedPrefixes; } } /** * Checks if the password starts with an encoder prefix, if true * return the prefix, if false return <code>null</code> * * @param password * */ public static String passwordStartsWithEncoderPrefix (char[] password) { if (password==null) return null; O: for (String prefix: getNotAllowedPrefixes()) { if (prefix.length() > password.length) continue; for (int i = 0; i < prefix.length(); i++) { if (prefix.charAt(i) != password[i]) continue O; } return prefix; } return null; } @Override public void setConfig(PasswordPolicyConfig config) { this.config=config; } @Override public PasswordPolicyConfig getConfig() { return config; } @Override public void validatePassword(char[] password) throws PasswordPolicyException { //if (password==null) // throw createSecurityException(PW_IS_NULL); if (password == null) { //treat as "empty" password = new char[]{}; } if (password.length < config.getMinLength()) throw createSecurityException(MIN_LENGTH_$1, config.getMinLength()); if (config.getMaxLength() >=0 && password.length >config.getMaxLength()) throw createSecurityException(MAX_LENGTH_$1,config.getMaxLength()); if (config.isDigitRequired()) { if (checkUsingMethod("isDigit", password)==false) throw createSecurityException(NO_DIGIT); } if (config.isUppercaseRequired()) { if (checkUsingMethod("isUpperCase", password)==false) throw createSecurityException(NO_UPPERCASE); } if (config.isLowercaseRequired()) { if (checkUsingMethod("isLowerCase", password)==false) throw createSecurityException(NO_LOWERCASE); } String prefix = passwordStartsWithEncoderPrefix(password); if (prefix!=null) throw createSecurityException(RESERVED_PREFIX_$1,prefix); } /** * Executes statis check methods from the character class * * @param methodname * @param charArray * */ protected boolean checkUsingMethod(String methodname, char[] charArray) { try { Method m = getClass().getMethod(methodname, Character.class); for (char c : charArray) { Boolean result = (Boolean) m.invoke(this, c); if (result) return true; } return false; } catch (Exception ex) { throw new RuntimeException("never should reach this point",ex); } } public boolean isDigit(Character c) { return Character.isDigit(c); } public boolean isUpperCase(Character c) { return Character.isUpperCase(c); } public boolean isLowerCase(Character c) { return Character.isLowerCase(c); } /** * Helper method for creating a proper {@link PasswordPolicyException} object */ protected PasswordPolicyException createSecurityException (String errorid, Object ...args) { PasswordPolicyException ex = new PasswordPolicyException(errorid,args); return ex; } }