/* * Password Management Servlets (PWM) * http://www.pwm-project.org * * Copyright (c) 2006-2009 Novell, Inc. * Copyright (c) 2009-2017 The PWM Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package password.pwm.config.profile; import com.novell.ldapchai.cr.ChaiChallenge; import com.novell.ldapchai.cr.ChaiChallengeSet; import com.novell.ldapchai.cr.Challenge; import com.novell.ldapchai.cr.ChallengeSet; import com.novell.ldapchai.exception.ChaiValidationException; import password.pwm.PwmConstants; import password.pwm.config.ChallengeItemConfiguration; import password.pwm.config.Configuration; import password.pwm.config.PwmSetting; import password.pwm.config.StoredValue; import password.pwm.config.UserPermission; import password.pwm.config.stored.StoredConfiguration; import password.pwm.config.value.ChallengeValue; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.error.PwmOperationalException; import password.pwm.util.LocaleHelper; import password.pwm.util.logging.PwmLogger; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; public class ChallengeProfile implements Profile, Serializable { private static final PwmLogger LOGGER = PwmLogger.forClass(ChallengeProfile.class); private final String profileID; private final Locale locale; private final ChallengeSet challengeSet; private final ChallengeSet helpdeskChallengeSet; private final int minRandomSetup; private final int minHelpdeskRandomsSetup; private final List<UserPermission> userPermissions; private ChallengeProfile( final String profileID, final Locale locale, final ChallengeSet challengeSet, final ChallengeSet helpdeskChallengeSet, final int minRandomSetup, final int minHelpdeskRandomSetup, final List<UserPermission> userPermissions ) { this.profileID = profileID; this.locale = locale; this.challengeSet = challengeSet; this.helpdeskChallengeSet = helpdeskChallengeSet; this.minRandomSetup = minRandomSetup; this.minHelpdeskRandomsSetup = minHelpdeskRandomSetup; this.userPermissions = userPermissions != null ? Collections.unmodifiableList(userPermissions) : Collections.<UserPermission>emptyList(); } public static ChallengeProfile readChallengeProfileFromConfig( final String profileID, final Locale locale, final StoredConfiguration storedConfiguration ) { final int minRandomRequired = (int)Configuration.JavaTypeConverter.valueToLong(storedConfiguration.readSetting(PwmSetting.CHALLENGE_MIN_RANDOM_REQUIRED,profileID)); ChallengeSet readChallengeSet = null; try { readChallengeSet = readChallengeSet( profileID, locale, storedConfiguration, PwmSetting.CHALLENGE_REQUIRED_CHALLENGES, PwmSetting.CHALLENGE_RANDOM_CHALLENGES, minRandomRequired ); } catch (PwmOperationalException e) { LOGGER.trace("configured challengeSet for profile '" + profileID + "' is not valid: " + e.getMessage()); } ChallengeSet readHelpdeskChallengeSet = null; try { readHelpdeskChallengeSet = readChallengeSet( profileID, locale, storedConfiguration, PwmSetting.CHALLENGE_HELPDESK_REQUIRED_CHALLENGES, PwmSetting.CHALLENGE_HELPDESK_RANDOM_CHALLENGES, 1 ); } catch (PwmOperationalException e) { LOGGER.trace("discarding configured helpdesk challengeSet for profile '" + profileID + "' issue: " + e.getMessage()); } final int minRandomSetup = (int)Configuration.JavaTypeConverter.valueToLong(storedConfiguration.readSetting(PwmSetting.CHALLENGE_MIN_RANDOM_SETUP, profileID)); final int minHelpdeskRandomSetup = (int)Configuration.JavaTypeConverter.valueToLong(storedConfiguration.readSetting(PwmSetting.CHALLENGE_HELPDESK_MIN_RANDOM_SETUP, profileID)); final List<UserPermission> userPermissions = (List<UserPermission>)storedConfiguration.readSetting(PwmSetting.CHALLENGE_POLICY_QUERY_MATCH, profileID).toNativeObject(); return new ChallengeProfile(profileID, locale, readChallengeSet, readHelpdeskChallengeSet, minRandomSetup, minHelpdeskRandomSetup, userPermissions); } public static ChallengeProfile createChallengeProfile( final String profileID, final Locale locale, final ChallengeSet challengeSet, final ChallengeSet helpdeskChallengeSet, final int minRandomSetup, final int minHelpdeskRandomSetup ) { return new ChallengeProfile(profileID, locale, challengeSet, helpdeskChallengeSet, minRandomSetup, minHelpdeskRandomSetup, null); } public String getIdentifier() { return profileID; } public String getDisplayName(final Locale locale) { return getIdentifier(); } public Locale getLocale() { return locale; } public ChallengeSet getChallengeSet() { return challengeSet; } public ChallengeSet getHelpdeskChallengeSet() { return helpdeskChallengeSet; } public int getMinRandomSetup() { return minRandomSetup; } public int getMinHelpdeskRandomsSetup() { return minHelpdeskRandomsSetup; } public List<UserPermission> getUserPermissions() { return userPermissions; } private static ChallengeSet readChallengeSet( final String profileID, final Locale locale, final StoredConfiguration storedConfiguration, final PwmSetting requiredChallenges, final PwmSetting randomChallenges, final int minimumRands ) throws PwmOperationalException { final List<ChallengeItemConfiguration> requiredQuestions = valueToChallengeItemArray( storedConfiguration.readSetting(requiredChallenges, profileID), locale); final List<ChallengeItemConfiguration> randomQuestions = valueToChallengeItemArray( storedConfiguration.readSetting(randomChallenges, profileID), locale); final List<Challenge> challenges = new ArrayList<>(); int randoms = minimumRands; if (requiredQuestions != null) { for (final ChallengeItemConfiguration item : requiredQuestions) { if (item != null) { final Challenge chaiChallenge = new ChaiChallenge( true, item.getText(), item.getMinLength(), item.getMaxLength(), item.isAdminDefined(), item.getMaxQuestionCharsInAnswer(), item.isEnforceWordlist() ); challenges.add(chaiChallenge); } } } if (randomQuestions != null) { for (final ChallengeItemConfiguration item : randomQuestions) { if (item != null) { final Challenge chaiChallenge = new ChaiChallenge( false, item.getText(), item.getMinLength(), item.getMaxLength(), item.isAdminDefined(), item.getMaxQuestionCharsInAnswer(), item.isEnforceWordlist() ); challenges.add(chaiChallenge); } } if (randoms > randomQuestions.size()) { randoms = randomQuestions.size(); } } else { randoms = 0; } try { return new ChaiChallengeSet(challenges, randoms, locale, PwmConstants.PWM_APP_NAME + "-defined " + PwmConstants.SERVLET_VERSION); } catch (ChaiValidationException e) { throw new PwmOperationalException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR,"invalid challenge set configuration: " + e.getMessage())); } } static List<ChallengeItemConfiguration> valueToChallengeItemArray( final StoredValue value, final Locale locale ) { if (!(value instanceof ChallengeValue)) { throw new IllegalArgumentException("may not read ChallengeValue value"); } final Map<String, List<ChallengeItemConfiguration>> storedValues = (Map<String, List<ChallengeItemConfiguration>>)value.toNativeObject(); final Map<Locale, List<ChallengeItemConfiguration>> availableLocaleMap = new LinkedHashMap<>(); for (final String localeStr : storedValues.keySet()) { availableLocaleMap.put(LocaleHelper.parseLocaleString(localeStr), storedValues.get(localeStr)); } final Locale matchedLocale = LocaleHelper.localeResolver(locale, availableLocaleMap.keySet()); return availableLocaleMap.get(matchedLocale); } @Override public ProfileType profileType() { throw new UnsupportedOperationException(); } @Override public List<UserPermission> getPermissionMatches() { throw new UnsupportedOperationException(); } }