com.evolveum.midpoint.common.policy.PasswordPolicyUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.evolveum.midpoint.common.policy.PasswordPolicyUtils.java

Source

/*
 * Copyright (c) 2010-2013 Evolveum
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.evolveum.midpoint.common.policy;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.xml.XsdTypeMapper;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.LimitationsType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordLifeTimeType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.StringLimitType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.StringPolicyType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ValuePolicyType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;

/**
 * 
 * @author mamut
 * 
 */
public class PasswordPolicyUtils {
    private static final transient Trace LOGGER = TraceManager.getTrace(PasswordPolicyUtils.class);

    private static final String DOT_CLASS = PasswordPolicyUtils.class.getName() + ".";
    private static final String OPERATION_PASSWORD_VALIDATION = DOT_CLASS + "passwordValidation";

    /**
     * add defined default values
     * 
     * @param pp
     * @return
     */
    public static void normalize(ValuePolicyType pp) {
        if (null == pp) {
            throw new IllegalArgumentException("Password policy cannot be null");
        }

        if (null == pp.getStringPolicy()) {
            StringPolicyType sp = new StringPolicyType();
            pp.setStringPolicy(StringPolicyUtils.normalize(sp));
        } else {
            pp.setStringPolicy(StringPolicyUtils.normalize(pp.getStringPolicy()));
        }

        if (null == pp.getLifetime()) {
            PasswordLifeTimeType lt = new PasswordLifeTimeType();
            lt.setExpiration(-1);
            lt.setWarnBeforeExpiration(0);
            lt.setLockAfterExpiration(0);
            lt.setMinPasswordAge(0);
            lt.setPasswordHistoryLength(0);
        }
        return;
    }

    /**
     * Check provided password against provided policy
     * 
     * @param password
     *            - password to check
     * @param policies
     *            - Password List of policies used to check
     * @param result
     *            - Operation result of password validator.
     * @return true if password meet all criteria , false if any criteria is not
     *         met
     */

    public static boolean validatePassword(String password, List<ValuePolicyType> policies,
            OperationResult result) {
        boolean ret = true;
        //iterate through policies 
        for (ValuePolicyType pp : policies) {
            OperationResult op = validatePassword(password, pp);
            result.addSubresult(op);
            //if one fail then result is failure
            if (ret == true && !op.isSuccess()) {
                ret = false;
            }
        }
        return ret;
    }

    public static boolean validatePassword(String password, List<PrismObject<ValuePolicyType>> policies) {
        boolean ret = true;
        //iterate through policies 
        for (PrismObject<ValuePolicyType> pp : policies) {
            OperationResult op = validatePassword(password, pp.asObjectable());
            //         result.addSubresult(op);
            //if one fail then result is failure
            if (ret == true && !op.isSuccess()) {
                ret = false;
            }
        }
        return ret;
    }

    public static boolean validatePassword(ProtectedStringType password,
            List<PrismObject<ValuePolicyType>> policies) {
        boolean ret = true;
        //iterate through policies 
        for (PrismObject<ValuePolicyType> pp : policies) {
            OperationResult op = validatePassword(password.getClearValue(), pp.asObjectable());
            //         result.addSubresult(op);
            //if one fail then result is failure
            if (ret == true && !op.isSuccess()) {
                ret = false;
            }
        }
        return ret;
    }

    /**
     * Check provided password against provided policy
     * 
     * @param password
     *            - password to check
     * @param pp
     *            - Password policy used to check
     * @param result
     *            - Operation result of password validator.
     * @return true if password meet all criteria , false if any criteria is not
     *         met
     */

    public static boolean validatePassword(String password, ValuePolicyType pp, OperationResult result) {
        OperationResult op = validatePassword(password, pp);
        result.addSubresult(op);
        return op.isSuccess();
    }

    /**
     * Check provided password against provided policy
     * 
     * @param password
     *            - password to check
     * @param pp
     *            - Password policy used
     * @return - Operation result of this validation
     */
    public static OperationResult validatePassword(String password, ValuePolicyType pp) {

        Validate.notNull(pp, "Password policy must not be null.");

        OperationResult ret = new OperationResult(OPERATION_PASSWORD_VALIDATION);
        ret.addParam("policyName", pp.getName());
        normalize(pp);

        if (password == null && pp.getMinOccurs() != null
                && XsdTypeMapper.multiplicityToInteger(pp.getMinOccurs()) == 0) {
            // No password is allowed
            ret.recordSuccess();
            return ret;
        }

        if (password == null) {
            password = "";
        }

        LimitationsType lims = pp.getStringPolicy().getLimitations();

        StringBuilder message = new StringBuilder();

        // Test minimal length
        if (lims.getMinLength() == null) {
            lims.setMinLength(0);
        }
        if (lims.getMinLength() > password.length()) {
            String msg = "Required minimal size (" + lims.getMinLength()
                    + ") of password is not met (password length: " + password.length() + ")";
            ret.addSubresult(
                    new OperationResult("Check global minimal length", OperationResultStatus.FATAL_ERROR, msg));
            message.append(msg);
            message.append("\n");
        }
        //      else {
        //         ret.addSubresult(new OperationResult("Check global minimal length. Minimal length of password OK.",
        //               OperationResultStatus.SUCCESS, "PASSED"));
        //      }

        // Test maximal length
        if (lims.getMaxLength() != null) {
            if (lims.getMaxLength() < password.length()) {
                String msg = "Required maximal size (" + lims.getMaxLength()
                        + ") of password was exceeded (password length: " + password.length() + ").";
                ret.addSubresult(
                        new OperationResult("Check global maximal length", OperationResultStatus.FATAL_ERROR, msg));
                message.append(msg);
                message.append("\n");
            }
            //         else {
            //            ret.addSubresult(new OperationResult("Check global maximal length. Maximal length of password OK.",
            //                  OperationResultStatus.SUCCESS, "PASSED"));
            //         }
        }
        // Test uniqueness criteria
        HashSet<String> tmp = new HashSet<String>(StringPolicyUtils.stringTokenizer(password));
        if (lims.getMinUniqueChars() != null) {
            if (lims.getMinUniqueChars() > tmp.size()) {
                String msg = "Required minimal count of unique characters (" + lims.getMinUniqueChars()
                        + ") in password are not met (unique characters in password " + tmp.size() + ")";
                ret.addSubresult(new OperationResult("Check minimal count of unique chars",
                        OperationResultStatus.FATAL_ERROR, msg));
                message.append(msg);
                message.append("\n");
            }
            //         else {
            //            ret.addSubresult(new OperationResult(
            //                  "Check minimal count of unique chars. Password satisfies minimal required unique characters.",
            //                  OperationResultStatus.SUCCESS, "PASSED"));
            //         }
        }

        // check limitation
        HashSet<String> allValidChars = new HashSet<String>(128);
        ArrayList<String> validChars = null;
        ArrayList<String> passwd = StringPolicyUtils.stringTokenizer(password);

        if (lims.getLimit() == null || lims.getLimit().isEmpty()) {
            if (message.toString() == null || message.toString().isEmpty()) {
                ret.computeStatus();
            } else {
                ret.computeStatus(message.toString());

            }

            return ret;
        }
        for (StringLimitType l : lims.getLimit()) {
            OperationResult limitResult = new OperationResult("Tested limitation: " + l.getDescription());
            if (null != l.getCharacterClass().getValue()) {
                validChars = StringPolicyUtils.stringTokenizer(l.getCharacterClass().getValue());
            } else {
                validChars = StringPolicyUtils.stringTokenizer(StringPolicyUtils.collectCharacterClass(
                        pp.getStringPolicy().getCharacterClass(), l.getCharacterClass().getRef()));
            }
            // memorize validChars
            allValidChars.addAll(validChars);

            // Count how many character for this limitation are there
            int count = 0;
            for (String s : passwd) {
                if (validChars.contains(s)) {
                    count++;
                }
            }

            // Test minimal occurrence
            if (l.getMinOccurs() == null) {
                l.setMinOccurs(0);
            }
            if (l.getMinOccurs() > count) {
                String msg = "Required minimal occurrence (" + l.getMinOccurs() + ") of characters ("
                        + l.getDescription() + ") in password is not met (occurrence of characters in password "
                        + count + ").";
                limitResult.addSubresult(new OperationResult("Check minimal occurrence of characters",
                        OperationResultStatus.FATAL_ERROR, msg));
                message.append(msg);
                message.append("\n");
            }
            //         else {
            //            limitResult.addSubresult(new OperationResult("Check minimal occurrence of characters in password OK.",
            //                  OperationResultStatus.SUCCESS, "PASSED"));
            //         }

            // Test maximal occurrence
            if (l.getMaxOccurs() != null) {

                if (l.getMaxOccurs() < count) {
                    String msg = "Required maximal occurrence (" + l.getMaxOccurs() + ") of characters ("
                            + l.getDescription()
                            + ") in password was exceeded (occurrence of characters in password " + count + ").";
                    limitResult.addSubresult(new OperationResult("Check maximal occurrence of characters",
                            OperationResultStatus.FATAL_ERROR, msg));
                    message.append(msg);
                    message.append("\n");
                }
                //            else {
                //               limitResult.addSubresult(new OperationResult(
                //                     "Check maximal occurrence of characters in password OK.", OperationResultStatus.SUCCESS,
                //                     "PASSED"));
                //            }
            }
            // test if first character is valid
            if (l.isMustBeFirst() == null) {
                l.setMustBeFirst(false);
            }
            // we check mustBeFirst only for non-empty passwords
            if (StringUtils.isNotEmpty(password) && l.isMustBeFirst()
                    && !validChars.contains(password.substring(0, 1))) {
                String msg = "First character is not from allowed set. Allowed set: " + validChars.toString();
                limitResult.addSubresult(
                        new OperationResult("Check valid first char", OperationResultStatus.FATAL_ERROR, msg));
                message.append(msg);
                message.append("\n");
            }
            //         else {
            //            limitResult.addSubresult(new OperationResult("Check valid first char in password OK.",
            //                  OperationResultStatus.SUCCESS, "PASSED"));
            //         }
            limitResult.computeStatus();
            ret.addSubresult(limitResult);
        }

        // Check if there is no invalid character
        StringBuilder sb = new StringBuilder();
        for (String s : passwd) {
            if (!allValidChars.contains(s)) {
                // memorize all invalid characters
                sb.append(s);
            }
        }
        if (sb.length() > 0) {
            String msg = "Characters [ " + sb + " ] are not allowed in password";
            ret.addSubresult(new OperationResult("Check if password does not contain invalid characters",
                    OperationResultStatus.FATAL_ERROR, msg));
            message.append(msg);
            message.append("\n");
        }
        //      else {
        //         ret.addSubresult(new OperationResult("Check if password does not contain invalid characters OK.",
        //               OperationResultStatus.SUCCESS, "PASSED"));
        //      }

        if (message.toString() == null || message.toString().isEmpty()) {
            ret.computeStatus();
        } else {
            ret.computeStatus(message.toString());

        }

        return ret;
    }

}