/* * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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 org.wso2.carbon.identity.base; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; /** * This class defines utility methods to be used with input validation */ public class IdentityValidationUtil { private static final IdentityValidatorConfig validatorConfig = new IdentityValidatorConfig(); private static final String msgSection1 = "The provided input "; private static final String msgSection2 = "does not match any of the white list patterns [ %s ]"; private static final String msgSection3 = "contains illegal characters matching one of the black list patterns [ %s ]"; private static final String msgSection4 = " or "; /** * Defines a predefined set of pattern list */ public static enum ValidatorPattern { DIGITS_ONLY("^[0-9]+"), ALPHABETIC_ONLY("^[a-zA-Z]+"), ALPHANUMERICS_ONLY("^[a-zA-Z0-9]+"), URL("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"), EMAIL("^\\s*?(.+)@(.+?)\\s*$"), WHITESPACE_EXISTS(".*\\s+.*"), URI_RESERVED_EXISTS(".*[:/\\?#\\[\\]@!\\$&'\\(\\)\\*\\+,;=]+.*"), URI_UNSAFE_EXISTS(".*[<>%\\{\\}\\|\\^~\\[\\]`]+.*"), HTML_META_EXISTS(".*[&<>\"'/]+.*"), XML_META_EXISTS(".*[&<>\"']+.*"), REGEX_META_EXISTS(".*[\\\\\\^\\$\\.\\|\\?\\*\\+\\(\\)\\[\\{]+.*"), HTTP_URL("^(http:)([^/?#])?(:)?(([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"), HTTPS_URL("^(https:)([^/?#])?(:)?(([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"), FTP_URL("^(ftp:)([^/?#])?(:)?(([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); private String regex; ValidatorPattern(String regex) { this.regex = regex; } public String getRegex() { return regex; } } static { for (ValidatorPattern pattern : ValidatorPattern.values()) { validatorConfig.addPattern(pattern.name(), pattern.getRegex()); } } /** * Validates the provided input against the given white list patterns * * @param input input * @param whiteListPatterns a String array of white list pattern keys * @return true if matches with any of the white list patterns */ public static boolean isValidOverWhiteListPatterns(String input, String... whiteListPatterns) { if (ArrayUtils.isEmpty(whiteListPatterns)) { throw new IllegalArgumentException("Should provide at least one white list pattern"); } if (StringUtils.isEmpty(input)) { return true; } boolean isValid = false; for (String key : whiteListPatterns) { if (validatorConfig.getPattern(key) != null) { isValid = validatorConfig.getPattern(key).matcher(input).matches(); if (isValid) { break; } } } return isValid; } /** * Validates the provided input against the given black list patterns * * @param input input * @param blackListPatterns a String array of black list pattern keys * @return true if does not match with any of the black list patterns */ public static boolean isValidOverBlackListPatterns(String input, String... blackListPatterns) { if (ArrayUtils.isEmpty(blackListPatterns)) { throw new IllegalArgumentException("Should provide at least one black list pattern"); } if (StringUtils.isEmpty(input)) { return true; } boolean isValid = false; for (String key : blackListPatterns) { if (validatorConfig.getPattern(key) != null) { isValid = !validatorConfig.getPattern(key).matcher(input).matches(); if (!isValid) { break; } } } return isValid; } /** * Validates the provided input against the given white list and black list patterns. * Precedence was give to the white list patterns. Thus, if the input is both white listed and blacklisted it * will be considered as valid. * * @param input input * @param whiteListPatterns a String array of white list pattern keys * @param blackListPatterns a String array of black list pattern keys * @return isWhiteListed || isNotBlackListed */ public static boolean isValid(String input, String[] whiteListPatterns, String[] blackListPatterns) { if (ArrayUtils.isEmpty(whiteListPatterns) || ArrayUtils.isEmpty(blackListPatterns)) { throw new IllegalArgumentException("Should provide at least one white list pattern and black list pattern"); } return isValidOverWhiteListPatterns(input, whiteListPatterns) || isValidOverBlackListPatterns(input, blackListPatterns); } /** * Returns the input if valid over the given white list patterns else throws an IdentityValidationException * * @param input input * @param whiteListPatterns a String array of white list pattern keys * @return input if valid over the given white list patterns else throws an IdentityValidationException */ public static String getValidInputOverWhiteListPatterns(String input, String... whiteListPatterns) throws IdentityValidationException { if (StringUtils.isEmpty(input) || isValidOverWhiteListPatterns(input, whiteListPatterns)) { return input; } throw new IdentityValidationException( msgSection1 + String.format(msgSection2, getPatternString(whiteListPatterns))); } /** * Returns the input if valid over the given black list patterns else throws an IdentityValidationException * * @param input input * @param blackListPatterns a String array of black list pattern keys * @return input if valid over the given black list patterns else throws an IdentityValidationException */ public static String getValidInputOverBlackListPatterns(String input, String... blackListPatterns) throws IdentityValidationException { if (StringUtils.isEmpty(input) || isValidOverBlackListPatterns(input, blackListPatterns)) { return input; } throw new IdentityValidationException( msgSection1 + String.format(msgSection3, getPatternString(blackListPatterns))); } /** * Returns the input if valid over the given white list and black list patterns else throws an * IdentityValidationException * * @param input input * @param whiteListPatterns a String array of white list pattern keys * @param blackListPatterns a String array of black list pattern keys * @return input if valid over the given white list and black list patterns else throws an * IdentityValidationException */ public static String getValidInput(String input, String[] whiteListPatterns, String[] blackListPatterns) throws IdentityValidationException { if (StringUtils.isEmpty(input) || isValid(input, whiteListPatterns, blackListPatterns)) { return input; } StringBuilder message = new StringBuilder(); message.append(msgSection1); message.append(String.format(msgSection2, getPatternString(whiteListPatterns))); message.append(msgSection4); message.append(String.format(msgSection3, getPatternString(blackListPatterns))); throw new IdentityValidationException(message.toString()); } /** * Adds a validation pattern and stores it against the provided key. * Throws an IllegalArgumentException if pattern key or pattern is empty, or if a pattern exists for the given key * * @param key pattern key * @param regex pattern regex */ public static void addPattern(String key, String regex) { validatorConfig.addPattern(key, regex); } /** * Removes a validation pattern * * @param key pattern key */ public static void removePattern(String key) { validatorConfig.removePattern(key); } /** * Checks if a pattern exists for the provided key * * @param key pattern key * @return true if pattern exists or false if pattern does not exist */ public static boolean patternExists(String key) { return validatorConfig.patternExists(key); } private static String getPatternString(String[] patterns) { StringBuilder patternString = new StringBuilder(); for (int i = 0; i < patterns.length; i++) { patternString.append(validatorConfig.getPattern(patterns[i]).pattern()); if ((patterns.length - 1) != i) { patternString.append(", "); } } return patternString.toString(); } }