| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF 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.apache.jackrabbit.oak.spi.security.user.action; |
| |
| import java.util.regex.Pattern; |
| import java.util.regex.PatternSyntaxException; |
| import javax.jcr.RepositoryException; |
| import javax.jcr.nodetype.ConstraintViolationException; |
| |
| import org.apache.jackrabbit.api.security.user.User; |
| import org.apache.jackrabbit.oak.api.Root; |
| import org.apache.jackrabbit.oak.namepath.NamePathMapper; |
| import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; |
| import org.apache.jackrabbit.oak.spi.security.SecurityProvider; |
| import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * {@code PasswordValidationAction} provides a simple password validation |
| * mechanism with the following configurable option: |
| * |
| * <ul> |
| * <li><strong>constraint</strong>: a regular expression that can be compiled |
| * to a {@link java.util.regex.Pattern} defining validation rules for a password.</li> |
| * </ul> |
| * |
| * <p>The password validation is executed on user creation and upon password |
| * change. It throws a {@code ConstraintViolationException} if the password |
| * validation fails.</p> |
| * |
| * @see org.apache.jackrabbit.api.security.user.UserManager#createUser(String, String) |
| * @see org.apache.jackrabbit.api.security.user.User#changePassword(String) |
| * @see org.apache.jackrabbit.api.security.user.User#changePassword(String, String) |
| */ |
| public class PasswordValidationAction extends AbstractAuthorizableAction { |
| |
| private static final Logger log = LoggerFactory.getLogger(PasswordValidationAction.class); |
| |
| public static final String CONSTRAINT = "constraint"; |
| |
| private Pattern pattern; |
| |
| //-------------------------------------------------< AuthorizableAction >--- |
| @Override |
| public void init(SecurityProvider securityProvider, ConfigurationParameters config) { |
| String constraint = config.getConfigValue(CONSTRAINT, null, String.class); |
| if (constraint != null) { |
| setConstraint(constraint); |
| } |
| } |
| |
| @Override |
| public void onCreate(@NotNull User user, @Nullable String password, @NotNull Root root, @NotNull NamePathMapper namePathMapper) throws RepositoryException { |
| validatePassword(password, false); |
| } |
| |
| @Override |
| public void onPasswordChange(@NotNull User user, @Nullable String newPassword, @NotNull Root root, @NotNull NamePathMapper namePathMapper) throws RepositoryException { |
| validatePassword(newPassword, true); |
| } |
| |
| //------------------------------------------------------------< private >--- |
| /** |
| * Set the password constraint. |
| * |
| * @param constraint A regular expression that can be used to validate a new password. |
| */ |
| private void setConstraint(@NotNull String constraint) { |
| try { |
| pattern = Pattern.compile(constraint); |
| } catch (PatternSyntaxException e) { |
| log.warn("Invalid password constraint: {}", e.getMessage()); |
| } |
| } |
| |
| /** |
| * Validate the specified password. |
| * |
| * @param password The password to be validated |
| * @param forceMatch If true the specified password is always validated; |
| * otherwise only if it is a plain text password. |
| * @throws RepositoryException If the specified password is too short or |
| * doesn't match the specified password pattern. |
| */ |
| private void validatePassword(@Nullable String password, boolean forceMatch) throws RepositoryException { |
| if (password != null && (forceMatch || PasswordUtil.isPlainTextPassword(password))) { |
| if (pattern != null && !pattern.matcher(password).matches()) { |
| throw new ConstraintViolationException("Password violates password constraint (" + pattern.pattern() + ")."); |
| } |
| } |
| } |
| } |