/* * ==================== * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the Common Development * and Distribution License("CDDL") (the "License"). You may not use this file * except in compliance with the License. * * You can obtain a copy of the License at * http://opensource.org/licenses/cddl1.php * See the License for the specific language governing permissions and limitations * under the License. * * When distributing the Covered Code, include this CDDL Header Notice in each file * and include the License file at http://opensource.org/licenses/cddl1.php. * If applicable, add the following below this CDDL Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== */ package org.identityconnectors.vms; import static org.identityconnectors.vms.VmsConstants.*; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.identityconnectors.common.CollectionUtil; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.framework.common.objects.OperationalAttributes; import org.identityconnectors.framework.common.objects.PredefinedAttributes; public final class VmsAttributeValidator { private VmsAttributeValidator() { } private static class ValidatorInfo { enum ValidatorType { NUMERIC, PATTERN, METHOD }; private ValidatorType validatorType; private Object value; private int multiplicity; public ValidatorInfo(int multiplicity) { validatorType = ValidatorType.NUMERIC; this.multiplicity = multiplicity; } public ValidatorInfo(Pattern pattern, int multiplicity) { validatorType = ValidatorType.PATTERN; value = pattern; this.multiplicity = multiplicity; } public ValidatorInfo(Validity clazz) { validatorType = ValidatorType.METHOD; value = clazz; // Multiplicity will be checked by the Method, // so we set it to be unchecked. // multiplicity = -1; } public ValidatorType getValidatorType() { return validatorType; } public Pattern getPattern() { return (Pattern) value; } public Validity getValidity() { return (Validity) value; } public int getMultiplicity() { return multiplicity; } } // Pattern to validate values // private static final Pattern ACCOUNT_PATTERN = Pattern.compile(".{1,8}"); private static final Pattern ALGORITHM_PATTERN = Pattern.compile("(\\w+)=(\\w+)(=\\d+)?"); private static final Pattern CLI_PATTERN = Pattern.compile("[a-zA-Z0-9$_:]{1,31}"); private static final Pattern CLI_TABLES_PATTERN = Pattern.compile("[a-zA-Z0-9$_:]{1,31}"); private static final Pattern DEVICE_PATTERN = Pattern.compile(".{1,31}"); private static final Pattern DIRECTORY_PATTERN = Pattern .compile("(^\\[[a-zA-Z$0-9:_][a-zA-Z$0-9_-]{0,38}\\])|^[a-zA-Z$0-9:_][a-zA-Z$0-9_-]{0,38}"); private static final Pattern FILE_SPEC_PATTERN = Pattern.compile("[a-zA-Z0-9$_:]+"); private static final Pattern PASSWORD_PATTERN = Pattern.compile("[a-zA-Z0-9$_]{1,31}"); private static final Pattern UIC_PATTERN = Pattern.compile("\\[[0-7]+,([0-7]+|\\*)\\]"); private static final Map<String, ValidatorInfo> VALIDATOR_INFO = new HashMap<String, ValidatorInfo>(); public interface Validity { public boolean isValid(List<Object> dateList); }; public static class ValidBoolean implements Validity { /** * Determine if the string represents a valid Boolean. * * @param booleanList * @return */ public boolean isValid(List<Object> booleanList) { if (booleanList.size() != 1) { return false; } return (booleanList.get(0) instanceof Boolean); } } public static class ValidOwner implements Validity { /** * Determine if the string represents a valid VMS owner. * * @param ownerList * @return */ public boolean isValid(List<Object> ownerList) { if (ownerList.size() != 1) { return false; } String owner = ownerList.get(0).toString(); return (owner == null || owner.length() < 32); } } public static class ValidDate implements Validity { /** * Determine if the string represents a valid VMS date stamp. * * @param dateList * @return */ public boolean isValid(List<Object> dateList) { if (dateList.size() != 1) { return false; } String date = dateList.get(0).toString(); DateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy", Locale.US); try { dateFormat.parse(date.trim()); return true; } catch (ParseException e) { return false; } } } public static class ValidDateOrNone extends ValidDate { /** * Determine if the string represents a valid VMS date stamp, or "none". * * @param dateList * @return */ public boolean isValid(List<Object> dateList) { if (dateList.size() != 1) { return false; } String date = dateList.get(0).toString().trim().toUpperCase(); return "NONE".equals(date) || super.isValid(dateList); } } public static class ValidNumberOrNone implements Validity { /** * Determine if the string represents a number, or "none". * * @param numberList * @return */ public boolean isValid(List<Object> numberList) { if (numberList.size() != 1) { return false; } Object object = numberList.get(0); if (object instanceof Number) { return true; } try { Integer.parseInt(object.toString()); return true; } catch (NumberFormatException nfe) { return "NONE".equals(object.toString().trim().toUpperCase()); } } } /** * Determine if the value for ACCESS is valid. * * Only a pair of Strings representing hours is valid The hour list is a * comma-separated list of hours, and ranges. Hours are 0-origin, for * example 0-8, 9 */ public static class ValidAccessList implements Validity { public boolean isValid(List<Object> accessList) { try { if (accessList == null || accessList.size() != 2) { return false; } for (Object access : accessList) { if (!(access instanceof String)) { return false; } if (((String) access).length() == 0) { return true; } for (String pair : ((String) access).split(",")) { String[] split = pair.split("-"); if (split.length == 1) { int lower = Integer.parseInt(split[0]); if (lower > 23 || lower < 0) { return false; } } else { int lower = Integer.parseInt(split[0]); int upper = Integer.parseInt(split[1]); if (lower > 23 || lower < 0) { return false; } if (upper > 23 || upper < 0) { return false; } if (lower > upper) { return false; } } } } } catch (NumberFormatException nfe) { return false; } return true; } } public static class ValidAlgorithm implements Validity { /** * Determine if the value for ALGORITHM is valid. * * <pre> * /ALGORITHM=keyword=type [=value] * * Sets the password encryption algorithm for a user. The keyword * VMS refers to the algorithm used in the operating system version * that is running on your system, whereas a customer algorithm is * one that is added through the $HASH_PASSWORD system service by * a customer site, by a layered product, or by a third party. The * customer algorithm is identified in $HASH_PASSWORD by an integer * in the range of 128 to 255. It must correspond with the number * used in the AUTHORIZE command MODIFY/ALGORITHM. By default, * passwords are encrypted with the VMS algorithm for the current * version of the operating system. * * Keyword Function * * BOTH Set the algorithm for primary and secondary * passwords. * * CURRENT Set the algorithm for the primary, secondary, both, * or no passwords, depending on account status. CURRENT * is the default value. * * PRIMARY Set the algorithm for the primary password only. * * SECONDARY Set the algorithm for the secondary password only. * * The following table lists password encryption algorithms: * * Type Definition * * VMS The algorithm used in the version of the operating * system that is running on your system. * * CUSTOMER A numeric value in the range of 128 to 255 that * identifies a customer algorithm. * * The following example selects the VMS algorithm for Sontag's * primary password: * * UAF> MODIFY SONTAG/ALGORITHM=PRIMARY=VMS * * If you select a site-specific algorithm, you must give a value to * identify the algorithm, as follows: * * UAF> MODIFY SONTAG/ALGORITHM=CURRENT=CUSTOMER=128 * </pre> * * @param algorithmList * @return */ public boolean isValid(List<Object> algorithmList) { if (algorithmList.size() != 1) { return false; } String algorithm = algorithmList.get(0).toString().trim(); Matcher matcher = ALGORITHM_PATTERN.matcher(algorithm); if (matcher.matches()) { String keyword = matcher.group(1).trim().toUpperCase(); String type = matcher.group(2).trim().toUpperCase(); String userval = null; if (matcher.group(3) != null) { userval = matcher.group(3).trim(); } else { userval = ""; } if (ALGO_KEYS_LIST.contains(keyword)) { if (ALGO_TYPE_VMS.equals(type)) { if (userval.length() == 0) { return true; } } else if (ALGO_TYPE_CUSTOMER.equals(type) && userval.length() > 0) { int value = Integer.parseInt(userval.substring(1)); if (value >= 128 && value <= 255) { return true; } } } } return false; } } private static final Collection<String> ALGO_KEYS_LIST = makeList(new String[] { ALGO_KEY_BOTH, ALGO_KEY_CURRENT, ALGO_KEY_PRIMARY, ALGO_KEY_SECONDARY }); public static class ValidFlagList implements Validity { /** * Determine if the value for FLAG(s) is valid. * * <pre> * /FLAGS=([NO]option[,...]) * * Specifies login flags for the user. The prefix NO clears the * flag. The options are as follows: * * AUDIT Enables or disables mandatory security auditing for * a specific user. By default, the system does not * audit the activities of specific users (NOAUDIT). * * AUTOLOGIN Restricts the user to the automatic login mechanism * when logging in to an account. When set, the flag * disables login by any terminal that requires entry * of a user name and password. The default is to * require a user name and password (NOAUTOLOGIN). * * CAPTIVE Prevents the user from changing any defaults at * login, for example, /CLI or /LGICMD. It prevents * the user from escaping the captive login command * procedure specified by the /LGICMD qualifier and * gaining access to the DCL command level. Refer to * "Guidelines for Captive Command Procedures" in the * HP OpenVMS Guide to System Security. * * The CAPTIVE flag also establishes an environment * where Ctrl/Y interrupts are initially turned off; * however, command procedures can still turn on Ctrl/Y * interrupts with the DCL command SET CONTROL=Y. By * default, an account is not captive (NOCAPTIVE). * * DEFCLI Restricts the user to the default command * interpreter by prohibiting the use of the /CLI * qualifier at login. By default, a user can choose * a CLI (NODEFCLI). * * DISCTLY Establishes an environment where Ctrl/Y interrupts * are initially turned off and are invalid until a * SET CONTROL=Y is encountered. This could happen in * SYLOGIN.COM or in a procedure called by SYLOGIN.COM. * Once a SET CONTROL=Y is executed (which requires * no privilege), a user can enter a Ctrl/Y and reach * the DCL prompt ($). If the intent of DISCTLY is * to force execution of the login command files, * then SYLOGIN.COM should issue the DCL command * SET CONTROL=Y to turn on Ctrl/Y interrupts before * exiting. By default, Ctrl/Y is enabled (NODISCTLY). * * DISFORCE_ Removes the requirement that a user must change an * PWD_CHANGE expired password at login. By default, a person can * use an expired password only once (NODISFORCE_PWD_ * CHANGE) and then is forced to change the password * after logging in. If the user does not select a new * password, the user is locked out of the system. * * To use this feature, set a password expiration date * with the /PWDLIFETIME qualifier. * * DISIMAGE Prevents the user from executing RUN and foreign * commands. By default, a user can execute RUN and * foreign commands (NODISIMAGE). * * DISMAIL Disables mail delivery to the user. By default, mail * delivery is enabled (NODISMAIL). * * DISNEWMAIL Suppresses announcements of new mail at login. * By default, the system announces new mail * (NODISNEWMAIL). * * DISPWDDIC Disables automatic screening of new passwords * against a system dictionary. By default, passwords * are automatically screened (NODISPWDDIC). * * DISPWDHIS Disables automatic checking of new passwords against * a list of the user's old passwords. By default, the * system screens new passwords (NODISPWDHIS). * * DISPWDSYNCH Suppresses synchronization of the external password * for this account. See bit 9 in the SECURITY_ * POLICY system parameter for systemwide password * synchronization control. * * DISRECONNECT Disables automatic reconnection to an existing * process when a terminal connection has been * interrupted. By default, automatic reconnection * is enabled (NODISRECONNECT). * * DISREPORT Suppresses reports of the last login time, login * failures, and other security reports. By default, * login information is displayed (NODISREPORT). * * DISUSER Disables the account so the user cannot log in. * For example, the DEFAULT account is disabled. By * default, an account is enabled (NODISUSER). * * DISWELCOME Suppresses the welcome message (an informational * message displayed during a local login). This * message usually indicates the version number of * the operating system that is running and the name of * the node on which the user is logged in. By default, * a system login message appears (NODISWELCOME). * * EXTAUTH Considers user to be authenticated by an external * user name and password, not by the SYSUAF user name * and password. (The system still uses the SYSUAF * record to check a user's login restrictions and * quotas and to create the user's process profile.) * * GENPWD Restricts the user to generated passwords. * By default, users choose their own passwords * (NOGENPWD). * * LOCKPWD Prevents the user from changing the password for * the account. By default, users can change their * passwords (NOLOCKPWD). * * PWD_EXPIRED Marks a password as expired. The user cannot log in * if this flag is set. The LOGINOUT.EXE image sets the * flag when both of the following conditions exist: a * user logs in with the DISFORCE_PWD_CHANGE flag set, * and the user's password expires. A system manager * can clear this flag. By default, passwords are not * expired after login (NOPWD_EXPIRED). * * PWD2_ Marks a secondary password as expired. Users cannot * EXPIRED log in if this flag is set. The LOGINOUT.EXE image * sets the flag when both of the following conditions * exist: a user logs in with the DISFORCE_PWD_CHANGE * flag set, and the user's password expires. A system * manager can clear this flag. By default, passwords * are not set to expire after login (NOPWD2_EXPIRED). * * PWDMIX Enables case-sensitive and extended-character * passwords. * * After PWDMIX is specified, you can then use mixed- * case and extended characters in passwords. Be aware * that before the PWDMIX flag is enabled, the system * stores passwords in all upper-case. Therefore, until * you change passwords, you must enter your pre-PWDMIX * passwords in upper-case. * * To change the password after PWDMIX is enabled: * * o You (the user) can use the DCL command SET * PASSWORD, specifying the new mixed-case password * (omitting quotation marks). * * o You (the system manager) can use the AUTHORIZE * command MODIFY/PASSWORD, and enclose the user's * new mixed-case password in quotation marks " ". * * RESTRICTED Prevents the user from changing any defaults at * login (for example, by specifying /LGICMD) and * prohibits user specification of a CLI with the * /CLI qualifier. The RESTRICTED flag establishes * an environment where Ctrl/Y interrupts are initially * turned off; however, command procedures can still * turn on Ctrl/Y interrupts with the DCL command SET * CONTROL=Y. Typically, this flag is used to prevent * an applications user from having unrestricted access * to the CLI. By default, a user can change defaults * (NORESTRICTED). * * VMSAUTH Allows account to use standard (SYSUAF) * authentication when the EXTAUTH flag would otherwise * require external authentication. This depends on the * application. An application specifies the VMS domain * of interpretation when calling SYS$ACM to request * standard VMS authentication for a user account that * normally uses external authentication. * </pre> * * @param flagList * @return */ public boolean isValid(List<Object> flagList) { return isValidList(flagList, FLAGS_LIST); } } // TODO: FLAG_PWDMIX, not available in older VMS systems private static final String[] FLAGS_ARRAY = { FLAG_AUDIT, FLAG_AUTOLOGIN, FLAG_CAPTIVE, FLAG_DEFCLI, FLAG_DISCTLY, FLAG_DISFORCE_PWD_CHANGE, FLAG_DISIMAGE, FLAG_DISMAIL, FLAG_DISNEWMAIL, FLAG_DISPWDDIC, FLAG_DISPWDHIS, FLAG_DISPWDSYNCH, FLAG_DISRECONNECT, FLAG_DISREPORT, FLAG_DISWELCOME, FLAG_EXTAUTH, FLAG_GENPWD, FLAG_LOCKPWD, FLAG_PWD2_EXPIRED, FLAG_PWD_EXPIRED, FLAG_RESTRICTED, FLAG_VMSAUTH, FLAG_DISUSER, }; public static final Collection<String> FLAGS_LIST = makeList(FLAGS_ARRAY); public static class ValidGeneratePassword implements Validity { /** * <pre> * /GENERATE_PASSWORD[=keyword] * /NOGENERATE_PASSWORD (default) * * Invokes the password generator to create user passwords. * Generated passwords can consist of 1 to 10 characters. Specify * one of the following keywords: * * BOTH Generate primary and secondary passwords. * * CURRENT Do whatever the DEFAULT account does (for example, * generate primary, secondary, both, or no passwords). * This is the default keyword. * * PRIMARY Generate primary password only. * * SECONDARY Generate secondary password only. * * When you modify a password, the new password expires * automatically; it is valid only once (unless you specify * /NOPWDEXPIRED). On login, users are forced to change their * passwords (unless you specify /FLAGS=DISFORCE_PWD_CHANGE). * * Note that the /GENERATE_PASSWORD and /PASSWORD qualifiers are * mutually exclusive. * </pre> * * @param passwordTypeList * @return */ public boolean isValid(List<Object> passwordTypeList) { if (passwordTypeList.size() != 1) { return false; } String passwordType = passwordTypeList.get(0).toString().trim().toUpperCase(); return PWD_TYPE_LIST.contains(passwordType); } } private static final String[] PWD_TYPE_ARRAY = { PWD_TYPE_BOTH, PWD_TYPE_CURRENT, PWD_TYPE_PRIMARY, PWD_TYPE_SECONDARY, }; private static final Collection<String> PWD_TYPE_LIST = makeList(PWD_TYPE_ARRAY); public static class ValidPrivList implements Validity { /** * * @param privList * @return */ public boolean isValid(List<Object> privList) { return isValidList(privList, PRIVS_LIST); } } /* @formatter:off */ private static final String[] PRIVS_ARRAY = { PRIV_ACNT, PRIV_ALLSPOOL, PRIV_ALTPRI, PRIV_AUDIT, PRIV_BUGCHK, PRIV_BYPASS, PRIV_CMEXEC, PRIV_CMKRNL, PRIV_DIAGNOSE, PRIV_DOWNGRADE, PRIV_EXQUOTA, PRIV_GROUP, PRIV_GRPNAM, PRIV_GRPPRV, PRIV_IMPERSONATE, PRIV_IMPORT, PRIV_LOG_IO, PRIV_MOUNT, PRIV_NETMBX, PRIV_OPER, PRIV_PFNMAP, PRIV_PHY_IO, PRIV_PRMCEB, PRIV_PRMGBL, PRIV_PRMMBX, PRIV_PSWAPM, PRIV_READALL, PRIV_SECURITY, PRIV_SETPRV, PRIV_SHARE, PRIV_SHMEM, PRIV_SYSGBL, PRIV_SYSLCK, PRIV_SYSNAM, PRIV_SYSPRV, PRIV_TMPMBX, PRIV_UPGRADE, PRIV_VOLPRO, PRIV_WORLD, PRIV_WORLD }; /* @formatter:on */ public static final Collection<String> PRIVS_LIST = makeList(PRIVS_ARRAY); public static class ValidIntegerRange implements Validity { private int minValue; private int maxValue; public ValidIntegerRange(int min, int max) { minValue = min; maxValue = max; } public boolean isValid(List<Object> integers) { if (integers.size() != 1) { return false; } if (!(integers.get(0) instanceof Integer)) { return false; } int value = ((Integer) integers.get(0)).intValue(); if (value < minValue) { return false; } if (value > maxValue) { return false; } return true; } } public static class ValidPrimeDaysList implements Validity { /** * * @param primeDaysList * @return */ public boolean isValid(List<Object> primeDaysList) { return isValidList(primeDaysList, PRIMEDAYS_LIST); } } private static final String[] PRIMEDAYS_ARRAY = { DAYS_SUN, DAYS_MON, DAYS_TUE, DAYS_WED, DAYS_THU, DAYS_FRI, DAYS_SAT }; public static final Collection<String> PRIMEDAYS_LIST = makeList(PRIMEDAYS_ARRAY); public static boolean isValidList(List<Object> valueList, Collection<String> validList) { for (Object value : valueList) { String valueString = value.toString().trim(); if (!validList.contains(valueString) && (!valueString.startsWith("NO") || !validList.contains(valueString .substring(2)))) { return false; } } return true; } private static Collection<String> makeList(String[] strings) { Collection<String> list = CollectionUtil.newCaseInsensitiveSet(); for (String string : strings) { list.add(string); } return list; } static { VALIDATOR_INFO.put(ATTR_ALGORITHM, new ValidatorInfo(new ValidAlgorithm())); VALIDATOR_INFO.put(ATTR_ACCOUNT, new ValidatorInfo(ACCOUNT_PATTERN, 1)); VALIDATOR_INFO.put(ATTR_ASTLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_BATCH, new ValidatorInfo(new ValidAccessList())); VALIDATOR_INFO.put(ATTR_BIOLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_BYTLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_CLI, new ValidatorInfo(CLI_PATTERN, 1)); VALIDATOR_INFO.put(ATTR_CLITABLES, new ValidatorInfo(CLI_TABLES_PATTERN, 1)); VALIDATOR_INFO.put(ATTR_CPUTIME, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_DEFPRIVILEGES, new ValidatorInfo(new ValidPrivList())); VALIDATOR_INFO.put(ATTR_DEVICE, new ValidatorInfo(DEVICE_PATTERN, 1)); VALIDATOR_INFO.put(ATTR_DIALUP, new ValidatorInfo(new ValidAccessList())); VALIDATOR_INFO.put(ATTR_DIOLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_DIRECTORY, new ValidatorInfo(DIRECTORY_PATTERN, 1)); VALIDATOR_INFO.put(ATTR_EXPIRATION, new ValidatorInfo(new ValidDateOrNone())); VALIDATOR_INFO.put(ATTR_ENQLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_FILLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_FLAGS, new ValidatorInfo(new ValidFlagList())); VALIDATOR_INFO.put(ATTR_GENERATE_PASSWORD, new ValidatorInfo(new ValidGeneratePassword())); VALIDATOR_INFO.put(ATTR_INTERACTIVE, new ValidatorInfo(new ValidAccessList())); VALIDATOR_INFO.put(ATTR_JTQUOTA, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_LGICMD, new ValidatorInfo(FILE_SPEC_PATTERN, 1)); VALIDATOR_INFO.put(ATTR_LOCAL, new ValidatorInfo(new ValidAccessList())); VALIDATOR_INFO.put(ATTR_MAXACCTJOBS, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_MAXDETACH, new ValidatorInfo(new ValidNumberOrNone())); VALIDATOR_INFO.put(ATTR_MAXJOBS, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_NETWORK, new ValidatorInfo(new ValidAccessList())); VALIDATOR_INFO.put(ATTR_OWNER, new ValidatorInfo(new ValidOwner())); VALIDATOR_INFO.put(ATTR_PBYTLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_PGFLQUOTA, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_PRCLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_PRIMEDAYS, new ValidatorInfo(new ValidPrimeDaysList())); VALIDATOR_INFO.put(ATTR_PRIORITY, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_PRIVILEGES, new ValidatorInfo(new ValidPrivList())); VALIDATOR_INFO.put(ATTR_PWDEXPIRED, new ValidatorInfo(0)); VALIDATOR_INFO.put(ATTR_PWDMINIMUM, new ValidatorInfo(new ValidIntegerRange(1, 32))); VALIDATOR_INFO.put(ATTR_QUEPRIO, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_REMOTE, new ValidatorInfo(new ValidAccessList())); VALIDATOR_INFO.put(ATTR_SHRFILLM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_TQELM, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_UIC, new ValidatorInfo(UIC_PATTERN, 1)); VALIDATOR_INFO.put(ATTR_WSDEFAULT, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_WSEXTENT, new ValidatorInfo(1)); VALIDATOR_INFO.put(ATTR_WSQUOTA, new ValidatorInfo(1)); VALIDATOR_INFO .put(PredefinedAttributes.PASSWORD_CHANGE_INTERVAL_NAME, new ValidatorInfo(1)); VALIDATOR_INFO.put(OperationalAttributes.DISABLE_DATE_NAME, new ValidatorInfo(1)); VALIDATOR_INFO.put(OperationalAttributes.PASSWORD_EXPIRED_NAME, new ValidatorInfo( new ValidBoolean())); VALIDATOR_INFO.put(OperationalAttributes.PASSWORD_NAME, new ValidatorInfo(PASSWORD_PATTERN, 1)); } /** * Determine whether the Attribute has a valid value. * * @param name * @param values * @param vmsConfiguration */ public static void validate(String name, List<Object> values, VmsConfiguration vmsConfiguration) { name = name.trim().toUpperCase(); ValidatorInfo validatorInfo = VALIDATOR_INFO.get(name); // If the attribute is negated, it does not need a value // if (validatorInfo == null && name.startsWith("NO")) { name = name.substring(2); validatorInfo = VALIDATOR_INFO.get(name); if (validatorInfo != null && values.size() == 0) { return; } } // Ensure we have an attribute of this name // if (validatorInfo == null) { throw new IllegalArgumentException(vmsConfiguration.getMessage( VmsMessages.UNKNOWN_ATTR_NAME, name)); } // Ensure the multiplicity is correct // int multiplicity = validatorInfo.getMultiplicity(); if ((multiplicity >= 0) && (values.size() != multiplicity)) { throw new IllegalArgumentException(vmsConfiguration.getMessage( VmsMessages.INVALID_ATTR_MULTIPLICITY, name)); } // Ensure the values are valid // switch (validatorInfo.getValidatorType()) { case NUMERIC: for (Object value : values) { if (!(value instanceof Number)) { throw new IllegalArgumentException(vmsConfiguration.getMessage( VmsMessages.INVALID_ATTR_VALUE, value, name)); } } break; case PATTERN: for (Object value : values) { if (validatorInfo.getPattern() != null) { if (value instanceof String) { Matcher matcher = validatorInfo.getPattern().matcher((String) value); if (!matcher.matches()) { throw new IllegalArgumentException(vmsConfiguration.getMessage( VmsMessages.INVALID_ATTR_VALUE, value, name)); } } else if (value instanceof GuardedString) { GuardedStringAccessor accessor = new GuardedStringAccessor(); ((GuardedString) value).access(accessor); Matcher matcher = validatorInfo.getPattern().matcher(new String(accessor.getArray())); if (!matcher.matches()) { throw new IllegalArgumentException(vmsConfiguration.getMessage( VmsMessages.INVALID_ATTR_VALUE, "****", name)); } } else { throw new IllegalArgumentException(vmsConfiguration.getMessage( VmsMessages.INVALID_ATTR_VALUE, value, name)); } } } break; case METHOD: try { Validity validity = validatorInfo.getValidity(); if (!validity.isValid(values)) { throw new IllegalArgumentException(vmsConfiguration.getMessage( VmsMessages.INVALID_ATTR_VALUE, values, name)); } } catch (IllegalArgumentException e) { throw e; } catch (Exception e) { throw new IllegalArgumentException(vmsConfiguration.getMessage( VmsMessages.EXCEPTION_IN_ATTR, name), e); } break; } } }