/* * 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.util; import com.novell.ldapchai.ChaiConstant; import password.pwm.config.ActionConfiguration; import password.pwm.config.Configuration; import password.pwm.config.FormConfiguration; import password.pwm.config.LDAPPermissionInfo; import password.pwm.config.PwmSetting; import password.pwm.config.PwmSettingCategory; import password.pwm.config.PwmSettingTemplate; import password.pwm.config.PwmSettingTemplateSet; import password.pwm.config.UserPermission; import password.pwm.config.option.DataStorageMethod; import password.pwm.config.profile.LdapProfile; import password.pwm.config.stored.StoredConfigurationImpl; import password.pwm.config.stored.StoredConfigurationUtil; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.error.PwmUnrecoverableException; import password.pwm.i18n.Config; import password.pwm.util.logging.PwmLogger; import password.pwm.util.queue.SmsQueueManager; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class LDAPPermissionCalculator implements Serializable { private static final PwmLogger LOGGER = PwmLogger.forClass(LDAPPermissionCalculator.class); private final StoredConfigurationImpl storedConfiguration; private final Configuration configuration; private final Collection<PermissionRecord> permissionRecords; public LDAPPermissionCalculator(final StoredConfigurationImpl storedConfiguration) throws PwmUnrecoverableException { this.storedConfiguration = storedConfiguration; this.configuration = new Configuration(storedConfiguration); permissionRecords = figureRecords(storedConfiguration); } public Collection<PermissionRecord> getPermissionRecords() { return permissionRecords; } public Map<String,Map<LDAPPermissionInfo.Access,List<PermissionRecord>>> getPermissionsByActor(final LDAPPermissionInfo.Actor actor) { final Map<String,Map<LDAPPermissionInfo.Access,List<PermissionRecord>>> returnObj = new TreeMap<>(); for (final PermissionRecord permissionRecord : getPermissionRecords()) { if (permissionRecord.getActor() == actor) { if (!returnObj.containsKey(permissionRecord.getAttribute())) { returnObj.put(permissionRecord.getAttribute(), new TreeMap<LDAPPermissionInfo.Access,List<PermissionRecord>>()); } if (!returnObj.get(permissionRecord.getAttribute()).containsKey(permissionRecord.getAccess())) { returnObj.get(permissionRecord.getAttribute()).put(permissionRecord.getAccess(), new ArrayList<PermissionRecord>()); } returnObj.get(permissionRecord.getAttribute()).get(permissionRecord.getAccess()).add(permissionRecord); } } return Collections.unmodifiableMap(returnObj); } private Collection<PermissionRecord> figureRecords(final StoredConfigurationImpl storedConfiguration) throws PwmUnrecoverableException { final List<PermissionRecord> permissionRecords = new ArrayList<>(); for (final PwmSetting pwmSetting : PwmSetting.values()) { if (pwmSetting.getCategory().hasProfiles()) { final List<String> profiles = StoredConfigurationUtil.profilesForSetting(pwmSetting, storedConfiguration); for (final String profile : profiles) { permissionRecords.addAll(figureRecord(pwmSetting, profile)); } } else { permissionRecords.addAll(figureRecord(pwmSetting, null)); } } permissionRecords.addAll(permissionsForUserPassword()); permissionRecords.addAll(figureStaticRecords()); return permissionRecords; } private Collection<PermissionRecord> figureRecord(final PwmSetting pwmSetting, final String profile) throws PwmUnrecoverableException { final List<PermissionRecord> permissionRecords = new ArrayList<>(); final Collection<LDAPPermissionInfo> permissionInfos = figurePermissionInfos(pwmSetting, profile); if (permissionInfos == null) { return Collections.emptyList(); } for (final LDAPPermissionInfo permissionInfo : permissionInfos) { switch (pwmSetting.getSyntax()) { case STRING: { final String attrName = (String)storedConfiguration.readSetting(pwmSetting, profile).toNativeObject(); if (attrName != null && !attrName.trim().isEmpty()) { permissionRecords.add(new PermissionRecord(attrName, pwmSetting, profile, permissionInfo.getAccess(), permissionInfo.getActor())); } } break; case FORM: { final List<FormConfiguration> formItems = (List<FormConfiguration>)storedConfiguration.readSetting(pwmSetting, profile).toNativeObject(); if (formItems != null) { for (final FormConfiguration formConfiguration : formItems) { final String attrName = formConfiguration.getName(); if (attrName != null && !attrName.trim().isEmpty()) { permissionRecords.add(new PermissionRecord(attrName, pwmSetting, profile, permissionInfo.getAccess(), permissionInfo.getActor())); } } } } break; case ACTION: { final List<ActionConfiguration> actionItems = (List<ActionConfiguration>)storedConfiguration.readSetting(pwmSetting, profile).toNativeObject(); if (actionItems != null) { for (final ActionConfiguration actionConfiguration : actionItems) { if (actionConfiguration.getType() == ActionConfiguration.Type.ldap) { final String attrName = actionConfiguration.getAttributeName(); if (attrName != null && !attrName.trim().isEmpty()) { permissionRecords.add(new PermissionRecord(attrName, pwmSetting, profile, permissionInfo.getAccess(), permissionInfo.getActor())); } } } } } break; case STRING_ARRAY: { final List<String> strings = (List<String>) storedConfiguration.readSetting(pwmSetting, profile).toNativeObject(); for (final String attrName : strings) { if (attrName != null && !attrName.trim().isEmpty()) { permissionRecords.add(new PermissionRecord(attrName, pwmSetting, profile, permissionInfo.getAccess(), permissionInfo.getActor())); } } } break; case USER_PERMISSION: { final List<UserPermission> userPermissions = (List<UserPermission>) storedConfiguration.readSetting(pwmSetting, profile).toNativeObject(); if (configuration.getLdapProfiles() != null && !configuration.getLdapProfiles().isEmpty()) { for (final LdapProfile ldapProfile : configuration.getLdapProfiles().values()) { final String groupAttribute = ldapProfile.readSettingAsString(PwmSetting.LDAP_USER_GROUP_ATTRIBUTE); if (groupAttribute != null && !groupAttribute.trim().isEmpty()) { for (final UserPermission userPermission : userPermissions) { if (userPermission.getType() == UserPermission.Type.ldapGroup) { permissionRecords.add(new PermissionRecord(groupAttribute, pwmSetting, profile, permissionInfo.getAccess(), permissionInfo.getActor())); } } } } } } break; default: throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_UNKNOWN,"no ldap permission record reader handler for setting " + pwmSetting.getKey())); } } return permissionRecords; } private Collection<LDAPPermissionInfo> figurePermissionInfos(final PwmSetting pwmSetting, final String profile) { PwmSettingCategory category = pwmSetting.getCategory(); while (category.hasProfiles() && !category.isTopLevelProfile()) { category = category.getParent(); } switch (category) { case PEOPLE_SEARCH: { if (!(Boolean)storedConfiguration.readSetting(PwmSetting.PEOPLE_SEARCH_ENABLE).toNativeObject()) { return Collections.emptyList(); } final boolean proxyOverride = (Boolean)storedConfiguration.readSetting(PwmSetting.PEOPLE_SEARCH_USE_PROXY, profile).toNativeObject(); final boolean publicOverride = (Boolean)storedConfiguration.readSetting(PwmSetting.PEOPLE_SEARCH_ENABLE_PUBLIC, profile).toNativeObject(); if (proxyOverride || publicOverride) { final Collection<LDAPPermissionInfo> configuredRecords = pwmSetting.getLDAPPermissionInfo(); final Collection<LDAPPermissionInfo> returnRecords = new ArrayList<>(); for (final LDAPPermissionInfo ldapPermissionInfo : configuredRecords) { if (!(proxyOverride && publicOverride)) { returnRecords.add(ldapPermissionInfo); // include regular self-other permission } returnRecords.add(new LDAPPermissionInfo(ldapPermissionInfo.getAccess(), LDAPPermissionInfo.Actor.proxy)); } return returnRecords; } } break; case GUEST: { if (!(Boolean)storedConfiguration.readSetting(PwmSetting.GUEST_ENABLE).toNativeObject()) { return Collections.emptyList(); } } break; case UPDATE: case UPDATE_PROFILE: case UPDATE_SETTINGS: { if (!(Boolean)storedConfiguration.readSetting(PwmSetting.UPDATE_PROFILE_ENABLE).toNativeObject()) { return Collections.emptyList(); } } break; case FORGOTTEN_USERNAME: { if (!(Boolean)storedConfiguration.readSetting(PwmSetting.FORGOTTEN_USERNAME_ENABLE).toNativeObject()) { return Collections.emptyList(); } } break; case NEWUSER: case NEWUSER_PROFILE: case NEWUSER_SETTINGS: { if (!(Boolean)storedConfiguration.readSetting(PwmSetting.NEWUSER_ENABLE).toNativeObject()) { return Collections.emptyList(); } } break; case ACTIVATION: { if (!(Boolean)storedConfiguration.readSetting(PwmSetting.ACTIVATE_USER_ENABLE).toNativeObject()) { return Collections.emptyList(); } } break; case HELPDESK_PROFILE: { if (!(Boolean)storedConfiguration.readSetting(PwmSetting.HELPDESK_ENABLE).toNativeObject()) { return Collections.emptyList(); } if ((Boolean)storedConfiguration.readSetting(PwmSetting.HELPDESK_USE_PROXY, profile).toNativeObject()) { final Collection<LDAPPermissionInfo> configuredRecords = pwmSetting.getLDAPPermissionInfo(); final Collection<LDAPPermissionInfo> returnRecords = new ArrayList<>(); for (final LDAPPermissionInfo ldapPermissionInfo : configuredRecords) { returnRecords.add(new LDAPPermissionInfo(ldapPermissionInfo.getAccess(), LDAPPermissionInfo.Actor.proxy)); } return returnRecords; } } break; default: //continue processing break; } switch (pwmSetting) { case CHALLENGE_USER_ATTRIBUTE: { final Set<DataStorageMethod> storageMethods = new HashSet<>(); storageMethods.addAll(configuration.getResponseStorageLocations(PwmSetting.FORGOTTEN_PASSWORD_WRITE_PREFERENCE)); storageMethods.addAll(configuration.getResponseStorageLocations(PwmSetting.FORGOTTEN_PASSWORD_READ_PREFERENCE)); if (!storageMethods.contains(DataStorageMethod.LDAP)) { return Collections.emptyList(); } } break; case OTP_SECRET_LDAP_ATTRIBUTE: { if (!configuration.readSettingAsBoolean(PwmSetting.OTP_ENABLED)) { return Collections.emptyList(); } } break; case SMS_USER_PHONE_ATTRIBUTE: { if (!SmsQueueManager.smsIsConfigured(configuration)) { return Collections.emptyList(); } } break; default: //continue processing break; } return pwmSetting.getLDAPPermissionInfo(); } private Collection<PermissionRecord> permissionsForUserPassword() { final String userPasswordAttributeName = LocaleHelper.getLocalizedMessage(Config.Label_UserPasswordAttribute,null); final Collection<PermissionRecord> records = new ArrayList<>(); // user set password records.add(new PermissionRecord(userPasswordAttributeName, null, null, LDAPPermissionInfo.Access.write, LDAPPermissionInfo.Actor.self)); // proxy user set password if (configuration.readSettingAsBoolean(PwmSetting.FORGOTTEN_PASSWORD_ENABLE)) { final Collection<PwmSettingTemplate> templates = configuration.getTemplate().getTemplates(); if (templates.contains(PwmSettingTemplate.NOVL) || templates.contains(PwmSettingTemplate.NOVL_IDM)) { records.add(new PermissionRecord(userPasswordAttributeName, PwmSetting.FORGOTTEN_PASSWORD_ENABLE, null, LDAPPermissionInfo.Access.read, LDAPPermissionInfo.Actor.proxy)); } else { records.add(new PermissionRecord(userPasswordAttributeName, PwmSetting.FORGOTTEN_PASSWORD_ENABLE, null, LDAPPermissionInfo.Access.write, LDAPPermissionInfo.Actor.proxy)); } } if (configuration.readSettingAsBoolean(PwmSetting.HELPDESK_ENABLE)) { records.add(new PermissionRecord(userPasswordAttributeName, PwmSetting.HELPDESK_ENABLE, null, LDAPPermissionInfo.Access.write, LDAPPermissionInfo.Actor.helpdesk)); } if (configuration.readSettingAsBoolean(PwmSetting.GUEST_ENABLE)) { records.add(new PermissionRecord(userPasswordAttributeName, PwmSetting.GUEST_ENABLE, null, LDAPPermissionInfo.Access.write, LDAPPermissionInfo.Actor.guestManager)); } if (configuration.readSettingAsBoolean(PwmSetting.NEWUSER_ENABLE)) { records.add(new PermissionRecord(userPasswordAttributeName, PwmSetting.NEWUSER_ENABLE, null, LDAPPermissionInfo.Access.write, LDAPPermissionInfo.Actor.proxy)); } return records; } private static final Set<PwmSettingTemplate> EDIR_INTERESTED_TEMPLATES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( new PwmSettingTemplate[]{ PwmSettingTemplate.NOVL, PwmSettingTemplate.NOVL_IDM} ))); private Collection<PermissionRecord> figureStaticRecords() { final List<PermissionRecord> permissionRecords = new ArrayList<>(); final PwmSettingTemplateSet templateSet = storedConfiguration.getTemplateSet(); { // edir specific attributes if (!Collections.disjoint(templateSet.getTemplates(), EDIR_INTERESTED_TEMPLATES)) { final Map<String, LDAPPermissionInfo.Access> ldapAttributes = new LinkedHashMap<>(); ldapAttributes.put(ChaiConstant.ATTR_LDAP_LOCKED_BY_INTRUDER,LDAPPermissionInfo.Access.write); ldapAttributes.put(ChaiConstant.ATTR_LDAP_LOGIN_INTRUDER_ATTEMPTS,LDAPPermissionInfo.Access.write); ldapAttributes.put(ChaiConstant.ATTR_LDAP_LOGIN_INTRUDER_RESET_TIME,LDAPPermissionInfo.Access.write); ldapAttributes.put(ChaiConstant.ATTR_LDAP_LOGIN_GRACE_LIMIT,LDAPPermissionInfo.Access.write); ldapAttributes.put(ChaiConstant.ATTR_LDAP_LOGIN_GRACE_REMAINING,LDAPPermissionInfo.Access.write); ldapAttributes.put(ChaiConstant.ATTR_LDAP_PASSWORD_EXPIRE_TIME,LDAPPermissionInfo.Access.read); for (final String ldapAttribute : ldapAttributes.keySet()) { permissionRecords.add(new PermissionRecord( ldapAttribute, null, null, ldapAttributes.get(ldapAttribute), LDAPPermissionInfo.Actor.proxy )); } } } return permissionRecords; } public static class PermissionRecord implements Serializable { private final String attribute; private final PwmSetting pwmSetting; private final String profile; private final LDAPPermissionInfo.Access access; private final LDAPPermissionInfo.Actor actor; public PermissionRecord(final String attribute, final PwmSetting pwmSetting, final String profile, final LDAPPermissionInfo.Access access, final LDAPPermissionInfo.Actor actor) { this.attribute = attribute; this.pwmSetting = pwmSetting; this.profile = profile; this.access = access; this.actor = actor; } public String getAttribute() { return attribute; } public PwmSetting getPwmSetting() { return pwmSetting; } public String getProfile() { return profile; } public LDAPPermissionInfo.Access getAccess() { return access; } public LDAPPermissionInfo.Actor getActor() { return actor; } } }