/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.systemservices.impl.resource; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeMap; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import com.emc.storageos.security.ipsec.IPsecConfig; import com.emc.storageos.security.password.InvalidLoginManager; import com.emc.storageos.model.auth.LoginFailedIPList; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.emc.storageos.coordinator.client.model.PropertyInfoExt; import com.emc.storageos.coordinator.client.model.RepositoryInfo; import com.emc.storageos.model.property.PropertiesMetadata; import com.emc.storageos.model.property.PropertyInfoRestRep; import com.emc.storageos.model.property.PropertyInfoUpdate; import com.emc.storageos.model.property.PropertyList; import com.emc.storageos.model.property.PropertyMetadata; import com.emc.storageos.security.audit.AuditLogManager; import com.emc.storageos.security.authentication.StorageOSUser; import com.emc.storageos.security.authorization.CheckPermission; import com.emc.storageos.security.authorization.Role; import com.emc.storageos.services.OperationTypeEnum; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.systemservices.exceptions.CoordinatorClientException; import com.emc.storageos.systemservices.impl.iso.CreateISO; import com.emc.storageos.systemservices.impl.property.PropertyManager; import com.emc.storageos.systemservices.impl.propertyhandler.PropertyHandlers; import com.emc.storageos.systemservices.impl.upgrade.ClusterAddressPoller; import com.emc.storageos.systemservices.impl.upgrade.CoordinatorClientExt; import com.emc.storageos.model.property.PropertyInfo.PropCategory; import com.emc.storageos.systemservices.impl.validate.PropertiesConfigurationValidator; import com.emc.vipr.model.sys.ClusterInfo; import com.emc.vipr.model.sys.eventhandler.ConnectEmcEmail; import com.emc.vipr.model.sys.eventhandler.ConnectEmcFtps; import static com.emc.storageos.coordinator.client.model.Constants.HIDDEN_TEXT_MASK; import static com.emc.storageos.systemservices.mapper.ClusterInfoMapper.toClusterResponse; @Path("/config/") public class ConfigService { // keys used in returning properties public static final String VERSION = "-clusterversion"; public static final String IPSEC_KEY = "-ipsec_key"; public static final Map<String, String> propertyToParameters = new HashMap() { { put("node_count", "-nodecount"); put("network_vip", "-vip"); put("network_1_ipaddr", "-ipaddr_1"); put("network_2_ipaddr", "-ipaddr_2"); put("network_3_ipaddr", "-ipaddr_3"); put("network_4_ipaddr", "-ipaddr_4"); put("network_5_ipaddr", "-ipaddr_5"); put("network_gateway", "-gateway"); put("network_netmask", "-netmask"); put("network_vip6", "-vip6"); put("network_1_ipaddr6", "-ipaddr6_1"); put("network_2_ipaddr6", "-ipaddr6_2"); put("network_3_ipaddr6", "-ipaddr6_3"); put("network_4_ipaddr6", "-ipaddr6_4"); put("network_5_ipaddr6", "-ipaddr6_5"); put("network_gateway6", "-gateway6"); put("network_prefix_length", "-ipv6prefixlength"); } }; public static final String MODE = "mode"; public static final String NODE_ID = "node_id"; @Autowired private AuditLogManager _auditMgr; @Autowired private ClusterAddressPoller clusterPoller; @Autowired private PropertyManager propertyManager; @Autowired protected InvalidLoginManager _invLoginManager; private IPsecConfig ipsecConfig; public static final String CERTIFICATE_VERSION = "certificate_version"; private static final Logger _log = LoggerFactory.getLogger(ConfigService.class); private static final String EVENT_SERVICE_TYPE = "config"; private CoordinatorClientExt _coordinator = null; private PropertiesMetadata _propsMetadata = null; private PropertiesConfigurationValidator _propertiesConfigurationValidator; private Properties defaultProperties; private Properties ovfProperties; private PropertyHandlers _propertyHandlers; @Context protected SecurityContext sc; /** * Get StorageOSUser from the security context * * @return */ protected StorageOSUser getUserFromContext() { if (!hasValidUserInContext()) { throw APIException.forbidden.invalidSecurityContext(); } return (StorageOSUser) sc.getUserPrincipal(); } /** * Determine if the security context has a valid StorageOSUser object * * @return true if the StorageOSUser is present */ protected boolean hasValidUserInContext() { if ((sc != null) && (sc.getUserPrincipal() instanceof StorageOSUser)) { return true; } else { return false; } } public void setProxy(CoordinatorClientExt proxy) { _coordinator = proxy; } public void setPropsMetadata(PropertiesMetadata propsMetadata) { _propsMetadata = propsMetadata; } public void setPropertiesConfigurationValidator(PropertiesConfigurationValidator propertiesConfigurationValidator) { _propertiesConfigurationValidator = propertiesConfigurationValidator; } public void setDefaultProperties(Properties defaults) { defaultProperties = defaults; } public void setPropertyHandlers(PropertyHandlers propertyHandlers) { _propertyHandlers = propertyHandlers; } public void setIpsecConfig(IPsecConfig ipsecConfig) { this.ipsecConfig = ipsecConfig; } /** * Get properties defaults * * @return map containing key, value pair */ @SuppressWarnings({ "unchecked", "rawtypes" }) public Map<String, String> getPropertiesDefaults() { return (Map) defaultProperties; } public void setOvfProperties(Properties ovfProps) { ovfProperties = ovfProps; } /** * Get ovf properties * * @return map containing key, value pair */ @SuppressWarnings({ "unchecked", "rawtypes" }) // this can't be named after the default getter, since the return type is different with // the argument type of the setter public Map<String, String> getPropertiesOvf() { return (Map) ovfProperties; } /** * Get config properties * * @return map containing key, value pair */ public Map<String, String> getConfigProperties() { Map<String, String> mergedProps = mergeProps(getPropertiesDefaults(), getMutatedProps()); return mergedProps; } /** * Get obsolete properties * * @return map containing key, value pair */ public Map<String, String> getObsoleteProperties() { Map<String, String> obsoletes = new HashMap<String, String>(); Map<String, String> overrides = new HashMap<String, String>(); overrides = getMutatedProps(); Set<String> obsoleteKeys = overrides.keySet(); obsoleteKeys.removeAll(defaultProperties.keySet()); for (String obsoleteKey : obsoleteKeys) { obsoletes.put(obsoleteKey, overrides.get(obsoleteKey)); } return obsoletes; } /** * Get system configuration properties * * @brief Get system properties * @prereq none * @param category - type of properties to return: all, config, ovf, mutated, secrets (require SecurityAdmin role) * or obsolete * @return Properties Information if success. Error response, if error./** */ @GET @Path("properties/") @CheckPermission(roles = { Role.SECURITY_ADMIN, Role.SYSTEM_MONITOR }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public PropertyInfoRestRep getProperties(@DefaultValue("all") @QueryParam("category") String category) throws Exception { switch (PropCategory.valueOf(category.toUpperCase())) { case ALL: return getTargetPropsCommon(); case CONFIG: return new PropertyInfoRestRep(getConfigProperties()); case OVF: return new PropertyInfoRestRep(getPropertiesOvf()); case REDEPLOY: Map<String, String> props = getPropertiesOvf(); props.remove(MODE); props.remove(NODE_ID); Map<String, String> clusterInfo = new HashMap(); Set<Map.Entry<String, String>> ovfProps = props.entrySet(); for (Map.Entry<String, String> ovfProp : ovfProps) { String parameter = propertyToParameters.get(ovfProp.getKey()); if (parameter == null) { continue; } clusterInfo.put(parameter, ovfProp.getValue()); } // Add ipsec key clusterInfo.put(IPSEC_KEY, ipsecConfig.getPreSharedKey()); // Add version info RepositoryInfo info = _coordinator.getTargetInfo(RepositoryInfo.class); clusterInfo.put(VERSION, info.getCurrentVersion().toString()); _log.info("clusterInfo={}", clusterInfo); return new PropertyInfoRestRep(clusterInfo); case MUTATED: return new PropertyInfoRestRep(getMutatedProps()); case SECRETS: StorageOSUser user = getUserFromContext(); if (!user.getRoles().contains(Role.SECURITY_ADMIN.toString())) { throw APIException.forbidden.onlySecurityAdminsCanGetSecrets(); } return getTargetPropsCommon(false); case OBSOLETE: return new PropertyInfoRestRep(getObsoleteProperties()); default: throw APIException.badRequests.invalidParameter("category", category); } } /** * Update system configuration properties * * @brief Update system properties * @param setProperty Property's key value pair. * @prereq Cluster state should be STABLE * @return Cluster information */ @PUT @Path("properties/") @CheckPermission(roles = { Role.SECURITY_ADMIN, Role.RESTRICTED_SECURITY_ADMIN }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response setProperties(PropertyInfoUpdate setProperty) throws Exception { PropertyInfoRestRep targetPropInfo = getTargetPropsCommon(); _log.info("setProperties(): {}", setProperty); PropertyInfoRestRep updateProps = getUpdateProps(setProperty, targetPropInfo.getAllProperties()); return updatePropertiesCommon(updateProps, null); } /** * Update system configuration properties * * @brief Update system properties * @prereq Cluster state should be STABLE * @return Cluster information */ @PUT @Path("internal/certificate-version") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response incrementCertificateVersion() throws Exception { PropertyInfoRestRep targetPropInfo = getTargetPropsCommon(); String versionStr = targetPropInfo.getProperty(CERTIFICATE_VERSION); Integer version = new Integer(versionStr); PropertyInfoUpdate setProperty = new PropertyInfoUpdate(); setProperty.addProperty(CERTIFICATE_VERSION, (++version).toString()); _log.info("setProperties(): {}", setProperty); PropertyInfoRestRep updateProps = getUpdateProps(setProperty, targetPropInfo.getAllProperties()); return updatePropertiesCommon(updateProps, null); } /** * Internal api to get system configuration properties. The api could be by data node. * * @brief Get system properties * @prereq none * @param category - type properties to return: config, ovf, or obsolete * @return Properties Information if success. Error response, if error./** */ @POST @Path("internal/properties/") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public PropertyInfoRestRep getInternalProperties(String category) throws Exception { return getProperties(category); } /** * Show metadata of system configuration properties * * @brief Show properties metadata * @prereq none * @return Properties Metadata if success. Error response, if error. */ @GET @Path("properties/metadata/") @CheckPermission(roles = { Role.SECURITY_ADMIN, Role.SYSTEM_MONITOR }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public PropertiesMetadata getPropMetadata() throws Exception { if (_propsMetadata == null) { throw APIException.internalServerErrors.targetIsNullOrEmpty("Property metadata"); } return _propsMetadata; } /** * Configure ConnectEMC FTPS transport related properties * * @brief Configure ConnectEMC FTPS properties * @prereq Cluster state should be STABLE * @return ConnectEMC FTPS related properties */ @POST @Path("connectemc/ftps/") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response configureConnectEmcFtpsParams(ConnectEmcFtps ftpsParams) throws Exception { PropertyInfoUpdate ext = ConfigService.ConfigureConnectEmc.configureFtps(ftpsParams); PropertyInfoRestRep targetPropInfo = getTargetPropsCommon(); PropertyInfoRestRep updateProps = getUpdateProps(ext, targetPropInfo.getAllProperties()); return updatePropertiesCommon(updateProps, null); } /** * Configure ConnectEMC SMTP/Email transport related properties * * @brief Configure ConnectEMC SMTP/Email properties * @prereq Cluster state should be STABLE * @return Properties related to ConnectEMC Email */ @POST @Path("connectemc/email/") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response configureConnectEmcEmailParams(ConnectEmcEmail emailParams) throws Exception { PropertyInfoRestRep targetPropInfo = getTargetPropsCommon(); PropertyInfoUpdate ext = ConfigService.ConfigureConnectEmc.configureEmail(emailParams); PropertyInfoRestRep updateProps = getUpdateProps(ext, targetPropInfo.getAllProperties()); return updatePropertiesCommon(updateProps, null); } /** * Reset configuration properties to their default values. Properties with * no default values will remain unchanged * * @brief Reset system properties * @param propertyList property list * @prereq Cluster state should be STABLE * @return Cluster information */ @POST @Path("properties/reset/") @CheckPermission(roles = { Role.SECURITY_ADMIN, Role.RESTRICTED_SECURITY_ADMIN }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response resetProps(PropertyList propertyList, @QueryParam("removeObsolete") String forceRemove) throws Exception { // get metadata Map<String, PropertyMetadata> metadata = PropertiesMetadata.getGlobalMetadata(); // get target property set PropertyInfoRestRep targetPropInfo = getTargetPropsCommon(); // get reset property set PropertyInfoRestRep resetProps = getResetProps(propertyList, targetPropInfo.getAllProperties(), metadata); // get obsolete property set List<String> obsoleteProps = isSet(forceRemove) ? getObsoleteProps(targetPropInfo.getAllProperties(), metadata) : null; // update properties with default value return updatePropertiesCommon(resetProps, obsoleteProps); } // Keep this library for now. private Response getVisiblePropertiesISOCommon() throws Exception { _log.info("getVisiblePropertiesISO(): going to fetch ISO information"); PropertyInfoRestRep propertyInfo = new PropertyInfoRestRep(getTargetPropsCommon().getProperties()); if (propertyInfo.getAllProperties() == null || propertyInfo.getAllProperties().size() == 0) { _log.error("getVisiblePropertiesISO(): No properties found"); throw APIException.internalServerErrors.targetIsNullOrEmpty("Properties"); } InputStream isoStream = new ByteArrayInputStream(CreateISO.getBytes (getPropertiesOvf(), getMutatedProps())); return Response.ok(isoStream).header("content-disposition", "attachment; filename = config.iso").build(); } /** * Get target properties * * @return target properties */ private PropertyInfoRestRep getTargetPropsCommon() { return getTargetPropsCommon(true); } /** * Get target properties * * @param maskSecretsProperties whether secrets properties should be masked out * @return target properties */ private PropertyInfoRestRep getTargetPropsCommon(boolean maskSecretsProperties) { PropertyInfoExt targetPropInfo = new PropertyInfoExt(); try { targetPropInfo.setProperties(mergeProps(getPropertiesDefaults(), getMutatedProps(maskSecretsProperties))); targetPropInfo.getProperties().putAll(getPropertiesOvf()); } catch (Exception e) { throw APIException.internalServerErrors.getObjectFromError("target property", "coordinator", e); } return new PropertyInfoRestRep(targetPropInfo.getAllProperties()); } /* * Get mutated props * * @return mutated properties from coordinator */ private Map<String, String> getMutatedProps() { return getMutatedProps(true); } /* * Get mutated props * * @param maskSecretsProperties whether secrets properties should be masked out * * @return mutated properties from coordinator */ private Map<String, String> getMutatedProps(boolean maskSecretsProperties) { Map<String, String> overrides; try { overrides = _coordinator.getTargetProperties().getProperties(); } catch (Exception e) { _log.info("Fail to get the cluster information ", e); return new TreeMap<>(); } if (!maskSecretsProperties) { return overrides; } // Mask out the secrets properties Map<String, String> ret = new TreeMap<>(); for (Map.Entry<String, String> entry : overrides.entrySet()) { if (PropertyInfoExt.isSecretProperty(entry.getKey())) { ret.put(entry.getKey(), HIDDEN_TEXT_MASK); } else { ret.put(entry.getKey(), entry.getValue()); } } return ret; } /** * Merge properties * * @param defaultProps * @param overrideProps * @return map containing key, value pair */ public static Map<String, String> mergeProps(Map<String, String> defaultProps, Map<String, String> overrideProps) { Map<String, String> mergedProps = new HashMap<String, String>(defaultProps); for (Map.Entry<String, String> entry : overrideProps.entrySet()) { mergedProps.put(entry.getKey(), entry.getValue()); } return mergedProps; } /** * Common method called by setProps and resetProps * Callers should prepare valid updateProps and deleteProps, * by verifying against validateAndUpdateProperties * before call this method * * @param updateProps update properties' keys and values * @param deleteKeys delete properties' keys * @throws Exception * @throws CoordinatorClientException */ private Response updatePropertiesCommon(PropertyInfoRestRep updateProps, List<String> deleteKeys) throws Exception { // validate if (!_coordinator.isClusterUpgradable()) { throw APIException.serviceUnavailable.clusterStateNotStable(); } StringBuilder propChanges = new StringBuilder(); // get current property set PropertyInfoRestRep oldProps = new PropertyInfoRestRep(); oldProps.addProperties(getTargetPropsCommon().getAllProperties()); boolean doSetTarget = false; PropertyInfoRestRep currentProps = _coordinator.getTargetProperties(); // remove properties if (deleteKeys != null && !deleteKeys.isEmpty()) { doSetTarget = true; for (String key : deleteKeys) { currentProps.removeProperty(key); propChanges.append(key); propChanges.append(" deleted"); } currentProps.removeProperties(deleteKeys); } // update properties, increment config_version if (updateProps != null && !updateProps.isEmpty()) { doSetTarget = true; currentProps.addProperties(updateProps.getAllProperties()); String configVersion = System.currentTimeMillis() + ""; currentProps.addProperty(PropertyInfoRestRep.CONFIG_VERSION, configVersion); if (propChanges.length() > 0) { propChanges.append(","); } propChanges.append(PropertyInfoRestRep.CONFIG_VERSION); propChanges.append("="); propChanges.append(configVersion); } if (doSetTarget) { // perform before handlers _propertyHandlers.before(oldProps, currentProps); _coordinator.setTargetProperties(currentProps.getAllProperties()); for (Map.Entry<String, String> entry : updateProps.getAllProperties().entrySet()) { if (propChanges.length() > 0) { propChanges.append(","); } propChanges.append(entry.getKey()); propChanges.append("="); // Hide encrypted string in audit log if (PropertyInfoExt.isEncryptedProperty(entry.getKey())) { propChanges.append(HIDDEN_TEXT_MASK); } else { propChanges.append(entry.getValue()); } } auditConfig(OperationTypeEnum.UPDATE_SYSTEM_PROPERTY, AuditLogManager.AUDITLOG_SUCCESS, null, propChanges.toString()); // perform after handlers _propertyHandlers.after(oldProps, currentProps); } ClusterInfo clusterInfo = _coordinator.getClusterInfo(); if (clusterInfo == null) { throw APIException.internalServerErrors.targetIsNullOrEmpty("Cluster information"); } return toClusterResponse(clusterInfo); } /** * Validate the properties being submitted. * * @param propsMap properties to be validated * @param bReset indicate the property change request is called from resetting path or updating path. * the value validation difference between resetting path and updating path is: * resetting path takes null and empty string as valid. */ private void validateAndUpdateProperties(Map<String, String> propsMap, boolean bReset) { for (Map.Entry<String, String> prop : propsMap.entrySet()) { if (prop.getKey() == null || prop.getKey().isEmpty()) { throw APIException.badRequests.propertyIsNullOrEmpty(); } // Get and update valid property value String validPropVal = _propertiesConfigurationValidator .getValidPropValue(prop.getKey(), prop.getValue(), true, bReset); propsMap.put(prop.getKey(), validPropVal); } } private boolean isSet(final String force) { return "1".equals(force); } /** * Get update property set, which values are different from target * * @param propsToUpdate property set to update in request * @param targetProps target properties * @return update property set */ private PropertyInfoRestRep getUpdateProps(final PropertyInfoUpdate propsToUpdate, final Map<String, String> targetProps) { // validate the changed property against it's metadata to ensure property // integrity. validateAndUpdateProperties(propsToUpdate.getAllProperties(), false); PropertyInfoRestRep updateProps = new PropertyInfoRestRep(); for (Map.Entry<String, String> entry : propsToUpdate.getAllProperties().entrySet()) { final String key = entry.getKey(); final String value = entry.getValue(); if (targetProps.containsKey(key) && !targetProps.get(key).equals(value)) { updateProps.addProperty(key, value); } else if (!targetProps.containsKey(key)) { updateProps.addProperty(key, value); } } return updateProps; } /** * Get reset properties based on properties specified in request, * current target property and metadata * This method iterates the target property set. * If a property is also in metadata * either it is contained keysToReset if not null or keysToReset is null (meaning, * reset all) * compare its value with default, if different, put it in resetProps * * @param keysToReset property set to delete in request * @param targetProps target properties * @param metadata metadata * @return reset property set with value set as defaults */ private PropertyInfoRestRep getResetProps(final PropertyList keysToReset, final Map<String, String> targetProps, final Map<String, PropertyMetadata> metadata) { // validate if properties exist in metadata if (keysToReset != null && keysToReset.getPropertyList() != null) { for (String key : keysToReset.getPropertyList()) { if (!targetProps.containsKey(key) || !metadata.containsKey(key)) { throw APIException.badRequests.propertyIsNotValid(key); } } } PropertyInfoRestRep resetProps = new PropertyInfoRestRep(); for (Map.Entry<String, String> entry : targetProps.entrySet()) { final String key = entry.getKey(); final String value = entry.getValue(); if (metadata.containsKey(key)) { // property exist both in target and metadata if (keysToReset == null || keysToReset.getPropertyList() == null || keysToReset.getPropertyList().contains(key)) { // property also shows in request list and current value is not equal to default final String defaultValue = metadata.get(key).getDefaultValue(); if (defaultValue != null && !value.equals(defaultValue)) { // property has a default value and current value is not equal to default, // reset it to default resetProps.addProperty(key, defaultValue); } } } } // validate the changed property against it's metadata to ensure property // integrity. validateAndUpdateProperties(resetProps.getAllProperties(), true); return resetProps; } /** * Get obsolete property list * This method compares each property in target with metadata, if not found, * add into obsolete property list. * * @param targetProps current target property * @param metadata metadata * @return obsolete property list */ private List<String> getObsoleteProps(final Map<String, String> targetProps, final Map<String, PropertyMetadata> metadata) { List<String> obsoleteProps = new ArrayList<String>(); for (Map.Entry<String, String> entry : targetProps.entrySet()) { final String key = entry.getKey(); if (!metadata.containsKey(key)) { // metadata doesn't contain the property in target, must be an obsolete property obsoleteProps.add(key); } } return obsoleteProps; } /** * Private static class for the purpose of grouping/validating Connect EMC * transport configuration properties * for Email and FTPS. */ public static class ConfigureConnectEmc { static final String FTPS_TRANSPORT = "FTPS"; static final String SMTP_TRANSPORT = "SMTP"; static final String YES_VALUE = "Yes"; /** * Build the FTPS Transport Configuration section * * @param ftps * @return */ public static PropertyInfoUpdate configureFtps(ConnectEmcFtps ftps) { PropertyInfoUpdate propInfo = new PropertyInfoUpdate(); // This property will cause genconfig to generate the ftps // ConnectEMC_config.xml file. propInfo.addProperty("system_connectemc_transport", FTPS_TRANSPORT); // Do not set any properties to NULL value as this causes exceptions // in property update processing. if (ftps.getSafeEncryption() != null) { propInfo.addProperty("system_connectemc_encrypt", (ftps.getSafeEncryption())); } if (ftps.getHostName() != null) { propInfo.addProperty("system_connectemc_ftps_hostname", ftps.getHostName()); } if (ftps.getEmailServer() != null) { propInfo.addProperty("system_connectemc_smtp_server", ftps.getEmailServer()); } if (ftps.getNotifyEmailAddress() != null) { propInfo.addProperty("system_connectemc_smtp_to", ftps.getNotifyEmailAddress()); } if (ftps.getEmailSender() != null) { propInfo.addProperty("system_connectemc_smtp_from", ftps.getEmailSender()); } return propInfo; } /** * Build the Primary Email Transport Configuration section * * @param email * @throws APIException Username and Password required when Auth Type is set * @return */ public static PropertyInfoUpdate configureEmail(ConnectEmcEmail email) { PropertyInfoUpdate propInfo = new PropertyInfoUpdate(); // This property will cause genconfig to generate the email ConnectEMC_config.xml file. propInfo.addProperty("system_connectemc_transport", SMTP_TRANSPORT); // Do not set any properties to NULL value as this causes exceptions in property update processing. if (email.getSafeEncryption() != null) { propInfo.addProperty("system_connectemc_encrypt", (email.getSafeEncryption())); } if (email.getEmailServer() != null) { propInfo.addProperty("system_connectemc_smtp_server", email.getEmailServer()); } if (email.getPort() != null) { propInfo.addProperty("system_connectemc_smtp_port", email.getPort()); } if (email.getPrimaryEmailAddress() != null) { propInfo.addProperty("system_connectemc_smtp_emcto", email.getPrimaryEmailAddress()); } if (email.getNotifyEmailAddress() != null) { propInfo.addProperty("system_connectemc_smtp_to", email.getNotifyEmailAddress()); } if (email.getEmailSender() != null) { propInfo.addProperty("system_connectemc_smtp_from", email.getEmailSender()); } if (email.getStartTls() != null) { propInfo.addProperty("system_connectemc_smtp_enabletls", (email.getStartTls())); } if (email.getSmtpAuthType() != null) { propInfo.addProperty("system_connectemc_smtp_authtype", email.getSmtpAuthType()); } // If auth type set, we need username and password. if (!isEmpty(email.getSmtpAuthType())) { if (!isEmpty(email.getUserName()) && !isEmpty(email.getPassword())) { // required fields for auth type. propInfo.addProperty("system_connectemc_smtp_username", email.getUserName()); propInfo.addProperty("system_connectemc_smtp_password", email.getPassword()); propInfo.addProperty("system_connectemc_smtp_enabletlscert", email.getEnableTlsCert()); } else { throw APIException.badRequests.configEmailError(); } } return propInfo; } /** * Convenience method for determining that a field has no data (i.e. null or * spaces)) * * @param field * @return */ private static boolean isEmpty(String field) { if (field == null || field.isEmpty()) { return true; } return false; } } /** * Record audit log for config service * * @param auditType Type of AuditLog * @param operationalStatus Status of operation * @param description Description for the AuditLog * @param descparams Description paramters */ public void auditConfig(OperationTypeEnum auditType, String operationalStatus, String description, Object... descparams) { _auditMgr.recordAuditLog(null, null, EVENT_SERVICE_TYPE, auditType, System.currentTimeMillis(), operationalStatus, description, descparams); } /** * remove specified IP from login-failed-ip list. * * @param ip * @return */ @DELETE @Path("/login-failed-ips/{ip}") @CheckPermission( roles = {Role.SECURITY_ADMIN, Role.RESTRICTED_SECURITY_ADMIN}) public Response removeLoginFailedIP(@PathParam("ip") String ip) { if (StringUtils.isEmpty(ip)) { throw APIException.badRequests.propertyIsNullOrEmpty(); } if (!_invLoginManager.isClientIPExist(ip)) { throw APIException.badRequests.clientIpNotExist(); } _invLoginManager.removeInvalidRecord(ip); return Response.ok().build(); } /** * list client IPs which have failed login attempts recently. * * @return */ @GET @Path("/login-failed-ips") @CheckPermission( roles = {Role.SECURITY_ADMIN, Role.RESTRICTED_SECURITY_ADMIN}) public LoginFailedIPList getLoginFailedIPs() { LoginFailedIPList response = new LoginFailedIPList(); response.setLockoutTimeInMinutes(_invLoginManager.getMaxAuthnLoginAttemtsLifeTimeInMins()); response.setMaxLoginAttempts(_invLoginManager.getMaxAuthnLoginAttemtsCount()); response.setInvalidLoginsList(_invLoginManager.listBlockedIPs()); return response; } }