Java tutorial
package org.apache.archiva.redback.policy; /* * 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. */ import org.apache.archiva.redback.configuration.UserConfiguration; import org.apache.archiva.redback.configuration.UserConfigurationKeys; import org.apache.archiva.redback.users.User; import org.apache.archiva.redback.policy.rules.MustHavePasswordRule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Named; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /** * User Security Policy. * * @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a> */ @Service("userSecurityPolicy") public class DefaultUserSecurityPolicy implements UserSecurityPolicy { private static final String ENABLEMENT_KEY = "UserSecurityPolicy" + ":ENABLED"; private Logger log = LoggerFactory.getLogger(getClass()); private PasswordRule defaultPasswordRule = new MustHavePasswordRule(); @Inject @Named(value = "userConfiguration#default") private UserConfiguration config; @Inject @Named(value = "passwordEncoder#sha256") private PasswordEncoder passwordEncoder; @Inject @Named(value = "userValidationSettings") private UserValidationSettings userValidationSettings; @Inject @Named(value = "cookieSettings#rememberMe") private CookieSettings rememberMeCookieSettings; @Inject @Named(value = "cookieSettings#signon") private CookieSettings signonCookieSettings; // TODO use something more generic to be able to do change about container @Inject private ApplicationContext applicationContext; /** * The List of {@link PasswordRule} objects. */ @Inject private List<PasswordRule> rules = new ArrayList<PasswordRule>(0); private int previousPasswordsCount; private int loginAttemptCount; private int passwordExpirationDays; private boolean passwordExpirationEnabled; private List<String> unlockableAccounts; // --------------------------------------- // Component lifecycle // --------------------------------------- // TODO move this to constructor @SuppressWarnings("unchecked") @PostConstruct public void initialize() { configurePolicy(); configureEncoder(); // In some configurations, rules can be unset. if (rules == null) { // Set rules to prevent downstream NPE. rules = new ArrayList<PasswordRule>(1); } if (rules.isEmpty()) { // there should be at least one rule addPasswordRule(defaultPasswordRule); } } private void configureEncoder() { String encoder = config.getString(UserConfigurationKeys.PASSWORD_ENCODER); if (encoder != null) { this.passwordEncoder = applicationContext.getBean("passwordEncoder#" + encoder, PasswordEncoder.class); } } private void configurePolicy() { this.previousPasswordsCount = config.getInt(UserConfigurationKeys.PASSWORD_RETENTION_COUNT); this.loginAttemptCount = config.getInt(UserConfigurationKeys.LOGIN_ATTEMPT_COUNT); this.passwordExpirationEnabled = config.getBoolean(UserConfigurationKeys.PASSWORD_EXPIRATION_ENABLED); this.passwordExpirationDays = config.getInt(UserConfigurationKeys.PASSWORD_EXPIRATION); this.unlockableAccounts = config.getList(UserConfigurationKeys.UNLOCKABLE_ACCOUNTS); } public String getId() { return "Default User Security Policy"; } public int getPreviousPasswordsCount() { return previousPasswordsCount; } public List<String> getUnlockableAccounts() { if (unlockableAccounts == null) { unlockableAccounts = new ArrayList<String>(0); } return unlockableAccounts; } /** * Sets a list of accounts which should never be locked by security policy * * @param unlockableAccounts */ public void setUnlockableAccounts(List<String> unlockableAccounts) { this.unlockableAccounts = unlockableAccounts; } /** * Sets the count of previous passwords that should be tracked. * * @param count the count of previous passwords to track. */ public void setPreviousPasswordsCount(int count) { this.previousPasswordsCount = count; } public int getLoginAttemptCount() { return loginAttemptCount; } public void setLoginAttemptCount(int count) { this.loginAttemptCount = count; } /** * Get the password encoder to be used for password operations * * @return the encoder */ public PasswordEncoder getPasswordEncoder() { return passwordEncoder; } public boolean isEnabled() { Boolean bool = (Boolean) PolicyContext.getContext().get(ENABLEMENT_KEY); return bool == null || bool.booleanValue(); } public void setEnabled(boolean enabled) { PolicyContext.getContext().put(ENABLEMENT_KEY, Boolean.valueOf(enabled)); } /** * Add a Specific Rule to the Password Rules List. * * @param rule the rule to add. */ public void addPasswordRule(PasswordRule rule) { // TODO: check for duplicates? if so, check should only be based on Rule class name. rule.setUserSecurityPolicy(this); this.rules.add(rule); } /** * Get the Password Rules List. * * @return the list of {@link PasswordRule} objects. */ public List<PasswordRule> getPasswordRules() { return this.rules; } /** * Set the Password Rules List. * * @param rules the list of {@link PasswordRule} objects. */ public void setPasswordRules(List<PasswordRule> rules) { this.rules.clear(); if (rules == null) { return; } // Intentionally iterating to ensure policy settings in provided rules. for (PasswordRule rule : rules) { addPasswordRule(rule); } } public void extensionPasswordExpiration(User user) throws MustChangePasswordException { if (passwordExpirationEnabled && !getUnlockableAccounts().contains(user.getUsername())) { Calendar expirationDate = Calendar.getInstance(); expirationDate.setTime(user.getLastPasswordChange()); expirationDate.add(Calendar.DAY_OF_MONTH, passwordExpirationDays); Calendar now = Calendar.getInstance(); if (now.after(expirationDate)) { log.info("User '{}' flagged for password expiry (expired on: {})", user.getUsername(), expirationDate); user.setPasswordChangeRequired(true); throw new MustChangePasswordException("Password Expired, You must change your password.", user); } } } public void extensionExcessiveLoginAttempts(User user) throws AccountLockedException { if (!getUnlockableAccounts().contains(user.getUsername())) { int attempt = user.getCountFailedLoginAttempts(); attempt++; user.setCountFailedLoginAttempts(attempt); if (attempt >= loginAttemptCount) { log.info("User '{}' locked due to excessive login attempts: {}", user.getUsername(), attempt); user.setLocked(true); throw new AccountLockedException("Account " + user.getUsername() + " is locked.", user); } } } public void extensionChangePassword(User user) throws PasswordRuleViolationException { extensionChangePassword(user, false); } public void extensionChangePassword(User user, boolean passwordChangeRequired) throws PasswordRuleViolationException { validatePassword(user); // set the current encoded password. user.setEncodedPassword(passwordEncoder.encodePassword(user.getPassword())); user.setPassword(null); // push new password onto list of previous password. List<String> previousPasswords = new ArrayList<String>(1); previousPasswords.add(user.getEncodedPassword()); if (!user.getPreviousEncodedPasswords().isEmpty()) { int oldCount = Math.min(previousPasswordsCount - 1, user.getPreviousEncodedPasswords().size()); //modified sublist start index as the previous value results to nothing being added to the list. List<String> sublist = user.getPreviousEncodedPasswords().subList(0, oldCount); previousPasswords.addAll(sublist); } user.setPreviousEncodedPasswords(previousPasswords); user.setPasswordChangeRequired(passwordChangeRequired); // Update timestamp for password change. user.setLastPasswordChange(new Date()); } public void validatePassword(User user) throws PasswordRuleViolationException { if (isEnabled()) { PasswordRuleViolations violations = new PasswordRuleViolations(); for (PasswordRule rule : this.rules) { if (rule.isEnabled()) { if (rule.requiresSecurityPolicy()) { rule.setUserSecurityPolicy(this); } rule.testPassword(violations, user); } } if (violations.hasViolations()) { PasswordRuleViolationException exception = new PasswordRuleViolationException(); exception.setViolations(violations); throw exception; } } // If you got this far, then ensure that the password is never null. if (user.getPassword() == null) { user.setPassword(""); } } public int getPasswordExpirationDays() { return passwordExpirationDays; } public void setPasswordExpirationDays(int passwordExpiry) { this.passwordExpirationDays = passwordExpiry; } public UserValidationSettings getUserValidationSettings() { return userValidationSettings; } public void setUserValidationSettings(UserValidationSettings settings) { this.userValidationSettings = settings; } public CookieSettings getRememberMeCookieSettings() { return rememberMeCookieSettings; } public CookieSettings getSignonCookieSettings() { return signonCookieSettings; } public UserConfiguration getConfig() { return config; } public void setConfig(UserConfiguration config) { this.config = config; } public void setPasswordEncoder(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } public void setRememberMeCookieSettings(CookieSettings rememberMeCookieSettings) { this.rememberMeCookieSettings = rememberMeCookieSettings; } public void setSignonCookieSettings(CookieSettings signonCookieSettings) { this.signonCookieSettings = signonCookieSettings; } public void setRules(List<PasswordRule> rules) { this.rules = rules; } public void setDefaultPasswordRule(PasswordRule defaultPasswordRule) { this.defaultPasswordRule = defaultPasswordRule; } }