001package org.apache.archiva.redback.policy.rules;
002
003/*
004 * Copyright 2001-2006 The Apache Software Foundation.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019import org.apache.archiva.redback.configuration.UserConfigurationKeys;
020import org.apache.archiva.redback.policy.PasswordRuleViolations;
021import org.apache.archiva.redback.policy.UserSecurityPolicy;
022import org.apache.archiva.redback.users.User;
023import org.apache.commons.lang3.StringUtils;
024import org.springframework.stereotype.Service;
025
026import javax.annotation.PostConstruct;
027import java.util.Iterator;
028
029/**
030 * Password Rule, Checks supplied password found at {@link User#getPassword()} against
031 * the {@link User#getPreviousEncodedPasswords()} to ensure that a password is not reused.
032 *
033 * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
034 */
035@Service("passwordRule#reuse")
036public class ReusePasswordRule
037    extends AbstractPasswordRule
038{
039    public static final String REUSE_VIOLATION = "user.password.violation.reuse";
040
041    private UserSecurityPolicy securityPolicy;
042
043    public void setUserSecurityPolicy( UserSecurityPolicy policy )
044    {
045        this.securityPolicy = policy;
046    }
047
048    /**
049     * true if the security policy is required for this rule
050     *
051     * @return boolean
052     */
053    public boolean requiresSecurityPolicy()
054    {
055        return true;
056    }
057
058    public int getPreviousPasswordCount()
059    {
060        if ( securityPolicy == null )
061        {
062            throw new IllegalStateException( "The security policy has not yet been set." );
063        }
064
065        return securityPolicy.getPreviousPasswordsCount();
066    }
067
068    private boolean hasReusedPassword( User user, String password )
069    {
070        if ( securityPolicy == null )
071        {
072            throw new IllegalStateException( "The security policy has not yet been set." );
073        }
074
075        if ( StringUtils.isEmpty( password ) )
076        {
077            return false;
078        }
079
080        String encodedPassword = securityPolicy.getPasswordEncoder().encodePassword( password );
081
082        int checkCount = getPreviousPasswordCount();
083
084        Iterator<String> it = user.getPreviousEncodedPasswords().iterator();
085
086        while ( it.hasNext() && checkCount >= 0 )
087        {
088            String prevEncodedPassword = it.next();
089            if ( encodedPassword.equals( prevEncodedPassword ) )
090            {
091                return true;
092            }
093            checkCount--;
094        }
095
096        return false;
097    }
098
099    public void setPreviousPasswordCount( int previousPasswordCount )
100    {
101        securityPolicy.setPreviousPasswordsCount( previousPasswordCount );
102    }
103
104    public void testPassword( PasswordRuleViolations violations, User user )
105    {
106        String password = user.getPassword();
107
108        if ( hasReusedPassword( user, password ) )
109        {
110            violations.addViolation( REUSE_VIOLATION,
111                                     new String[]{ String.valueOf( getPreviousPasswordCount() ) } ); //$NON-NLS-1$
112        }
113    }
114
115    @PostConstruct
116    public void initialize()
117    {
118        enabled = config.getBoolean( UserConfigurationKeys.POLICY_PASSWORD_RULE_REUSE_ENABLED );
119    }
120}