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;
027
028/**
029 * Basic Password Rule, Checks for non-empty passwords that have at least {@link #setMinimumCount(int)} of
030 * alpha characters contained within.
031 *
032 * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
033 */
034@Service( "passwordRule#alpha-count" )
035public class AlphaPasswordRule
036    extends AbstractPasswordRule
037{
038
039    private int minimumCount;
040
041    private int countAlphaCharacters( String password )
042    {
043        int count = 0;
044
045        if ( StringUtils.isEmpty( password ) )
046        {
047            return count;
048        }
049
050        /* TODO: Eventually upgrade to the JDK 1.5 Technique
051         * 
052         * // Doing this via iteration of code points to take in account localized passwords.
053         * for ( int i = 0; i < password.length(); i++ )
054         * {
055         *     int codepoint = password.codePointAt( i );
056         *     if ( Character.isLetter( codepoint ) )
057         *     {
058         *        count++;
059         *     }
060         * }
061         */
062
063        // JDK 1.4 Technique - NOT LOCALIZED.
064        for ( int i = 0; i < password.length(); i++ )
065        {
066            char c = password.charAt( i );
067            if ( Character.isLetter( c ) )
068            {
069                count++;
070            }
071        }
072
073        return count;
074    }
075
076    public int getMinimumCount()
077    {
078        return minimumCount;
079    }
080
081    public void setMinimumCount( int minimumCount )
082    {
083        this.minimumCount = minimumCount;
084    }
085
086    public void setUserSecurityPolicy( UserSecurityPolicy policy )
087    {
088        // Ignore, policy not needed in this rule.
089    }
090
091    public void testPassword( PasswordRuleViolations violations, User user )
092    {
093        if ( countAlphaCharacters( user.getPassword() ) < this.minimumCount )
094        {
095            violations.addViolation( UserConfigurationKeys.ALPHA_COUNT_VIOLATION,
096                                     new String[]{ String.valueOf( minimumCount ) } ); //$NON-NLS-1$
097        }
098    }
099
100    @PostConstruct
101    public void initialize()
102    {
103        enabled = config.getBoolean( UserConfigurationKeys.POLICY_PASSWORD_RULE_ALPHACOUNT_ENABLED );
104        this.minimumCount = config.getInt( UserConfigurationKeys.ALPHA_COUNT_MIN );
105    }
106}