From ff0c36d2099b8a1fc5f961e544b37eaa58ce2f95 Mon Sep 17 00:00:00 2001 From: jdotcms Date: Fri, 5 Jun 2020 17:29:06 -0600 Subject: [PATCH] Adding some enhacements in order to fetch the user by id or email on the assertion nameID, also adding a new variable on the configuration to avoid sync of the user assersion with the dotcms database --- build.gradle | 13 ++ .../DotsamlDefaultPropertiesService.java | 5 + .../saml/v3/parameters/DotsamlProperties.java | 11 +- .../v3/parameters/DotsamlPropertyName.java | 10 +- .../OpenSamlAuthenticationServiceImpl.java | 118 ++++++++++-------- 5 files changed, 100 insertions(+), 57 deletions(-) create mode 100644 build.gradle diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..aeb970d --- /dev/null +++ b/build.gradle @@ -0,0 +1,13 @@ +apply plugin: 'java' + +repositories { + maven { url "http://repo.dotcms.com/artifactory/libs-release" } +} + +dependencies { + compile('com.dotcms:dotcms:5.3.1') { transitive = true } + compile fileTree(dir: 'ROOT/dotserver/tomcat-8.5.32/webapps/ROOT/WEB-INF/lib', include: ['*.jar']) +} + +sourceSets.main.java.srcDirs += ['src'] + diff --git a/src/com/dotcms/plugin/saml/v3/parameters/DotsamlDefaultPropertiesService.java b/src/com/dotcms/plugin/saml/v3/parameters/DotsamlDefaultPropertiesService.java index 3960fa9..73bfe94 100644 --- a/src/com/dotcms/plugin/saml/v3/parameters/DotsamlDefaultPropertiesService.java +++ b/src/com/dotcms/plugin/saml/v3/parameters/DotsamlDefaultPropertiesService.java @@ -215,6 +215,9 @@ public static void updateDefaultParameter(DotsamlPropertyName property, String v case DOTCMS_SAML_LOGIN_UPDATE_EMAIL: defaultParams.setDotcmsSamlLoginEmailUpdate(Boolean.parseBoolean(value)); break; + case DOT_SAML_ALLOW_USER_SYNCHRONIZATION: + defaultParams.setAllowUserSynchronization(Boolean.parseBoolean(value)); + break; default: Logger.warn(DotsamlDefaultPropertiesService.class, NOT_FOUND_ERROR + property.getPropertyName() + ":" + value); @@ -317,6 +320,8 @@ public static boolean getDefaultBooleanParameter(DotsamlPropertyName property) t return defaultParams.isDotcmsSamlClearLocationQueryParams(); case DOTCMS_SAML_LOGIN_UPDATE_EMAIL: return defaultParams.isDotcmsSamlLoginEmailUpdate(); + case DOT_SAML_ALLOW_USER_SYNCHRONIZATION: + return defaultParams.isAllowUserSynchronization(); default: break; } diff --git a/src/com/dotcms/plugin/saml/v3/parameters/DotsamlProperties.java b/src/com/dotcms/plugin/saml/v3/parameters/DotsamlProperties.java index fc5655f..31f5eff 100644 --- a/src/com/dotcms/plugin/saml/v3/parameters/DotsamlProperties.java +++ b/src/com/dotcms/plugin/saml/v3/parameters/DotsamlProperties.java @@ -48,6 +48,7 @@ public class DotsamlProperties { private Boolean dotSamlVerifySignatureProfile = true; private Boolean dotcmsSamlClearLocationQueryParams = true; private Boolean dotcmsSamlLoginEmailUpdate = true; + private boolean allowUserSynchronization = true; public String getDotSamlAccessFilterValues() { return dotSamlAccessFilterValues; @@ -354,4 +355,12 @@ public Boolean isDotcmsSamlLoginEmailUpdate() { public void setDotcmsSamlLoginEmailUpdate(Boolean dotcmsSamlLoginEmailUpdate) { this.dotcmsSamlLoginEmailUpdate = dotcmsSamlLoginEmailUpdate; } -} \ No newline at end of file + + public boolean isAllowUserSynchronization() { + return allowUserSynchronization; + } + + public void setAllowUserSynchronization(final Boolean allowUserSynchronization) { + this.allowUserSynchronization = allowUserSynchronization; + } +} diff --git a/src/com/dotcms/plugin/saml/v3/parameters/DotsamlPropertyName.java b/src/com/dotcms/plugin/saml/v3/parameters/DotsamlPropertyName.java index 50627ef..3b245ac 100644 --- a/src/com/dotcms/plugin/saml/v3/parameters/DotsamlPropertyName.java +++ b/src/com/dotcms/plugin/saml/v3/parameters/DotsamlPropertyName.java @@ -219,7 +219,15 @@ public enum DotsamlPropertyName { * SAML User */ DOTCMS_SAML_OPTIONAL_USER_ROLE("role.extra"), - + + /** + * By default dotcms will allows the user synchronization, this means if the user does not exists on their database the user will be added to their storage, roles, etc. + * In case you do not want any synchronization set this to false. + * + */ + DOT_SAML_ALLOW_USER_SYNCHRONIZATION("allow.user.synchronization"), + + /** * If you want to allow to create an user that does not exists on the IdP, * set this to true, otherwise false. By default it is false, so won't allow diff --git a/src/com/dotcms/plugin/saml/v3/service/OpenSamlAuthenticationServiceImpl.java b/src/com/dotcms/plugin/saml/v3/service/OpenSamlAuthenticationServiceImpl.java index 016789a..45f9652 100644 --- a/src/com/dotcms/plugin/saml/v3/service/OpenSamlAuthenticationServiceImpl.java +++ b/src/com/dotcms/plugin/saml/v3/service/OpenSamlAuthenticationServiceImpl.java @@ -1,44 +1,5 @@ package com.dotcms.plugin.saml.v3.service; -import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.DOTCMS_SAML_BUILD_ROLES_ALL_VALUE; -import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.DOTCMS_SAML_BUILD_ROLES_IDP_VALUE; -import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.DOTCMS_SAML_BUILD_ROLES_NONE_VALUE; -import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.DOTCMS_SAML_BUILD_ROLES_STATIC_ADD_VALUE; -import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.SAML_USER_ID; -import static com.dotcms.plugin.saml.v3.util.SamlUtils.buildAuthnRequest; -import static com.dotcms.plugin.saml.v3.util.SamlUtils.buildLogoutRequest; -import static com.dotcms.plugin.saml.v3.util.SamlUtils.getCredential; -import static com.dotcms.plugin.saml.v3.util.SamlUtils.getIdentityProviderDestinationEndpoint; -import static com.dotcms.plugin.saml.v3.util.SamlUtils.getIdentityProviderSLODestinationEndpoint; -import static com.dotcms.plugin.saml.v3.util.SamlUtils.toXMLObjectString; -import static com.dotmarketing.util.UtilMethods.isSet; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.Arrays; -import java.util.Date; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.opensaml.core.xml.XMLObject; -import org.opensaml.messaging.context.MessageContext; -import org.opensaml.messaging.encoder.MessageEncodingException; -import org.opensaml.saml.common.messaging.context.SAMLEndpointContext; -import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext; -import org.opensaml.saml.saml2.binding.encoding.impl.HTTPRedirectDeflateEncoder; -import org.opensaml.saml.saml2.core.Assertion; -import org.opensaml.saml.saml2.core.Attribute; -import org.opensaml.saml.saml2.core.AttributeStatement; -import org.opensaml.saml.saml2.core.AuthnRequest; -import org.opensaml.saml.saml2.core.LogoutRequest; -import org.opensaml.saml.saml2.core.NameID; -import org.opensaml.xmlsec.SignatureSigningParameters; -import org.opensaml.xmlsec.context.SecurityParametersContext; -import org.opensaml.xmlsec.signature.support.SignatureConstants; - import com.dotcms.plugin.saml.v3.beans.AttributesBean; import com.dotcms.plugin.saml.v3.config.IdpConfig; import com.dotcms.plugin.saml.v3.config.SamlSiteValidator; @@ -53,11 +14,10 @@ import com.dotcms.plugin.saml.v3.parameters.DotsamlPropertyName; import com.dotcms.plugin.saml.v3.util.SiteIdpConfigResolver; import com.dotcms.repackage.com.google.common.annotations.VisibleForTesting; -import org.apache.commons.lang.StringUtils; import com.dotmarketing.business.APILocator; import com.dotmarketing.business.DotStateException; -import com.dotmarketing.business.NoSuchUserException; import com.dotmarketing.business.DuplicateUserException; +import com.dotmarketing.business.NoSuchUserException; import com.dotmarketing.business.Role; import com.dotmarketing.business.RoleAPI; import com.dotmarketing.business.UserAPI; @@ -71,9 +31,47 @@ import com.dotmarketing.util.UUIDGenerator; import com.dotmarketing.util.UtilMethods; import com.dotmarketing.util.json.JSONException; +import com.liferay.portal.model.Company; import com.liferay.portal.model.User; - import net.shibboleth.utilities.java.support.component.ComponentInitializationException; +import org.apache.commons.lang.StringUtils; +import org.opensaml.core.xml.XMLObject; +import org.opensaml.messaging.context.MessageContext; +import org.opensaml.messaging.encoder.MessageEncodingException; +import org.opensaml.saml.common.messaging.context.SAMLEndpointContext; +import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext; +import org.opensaml.saml.saml2.binding.encoding.impl.HTTPRedirectDeflateEncoder; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.Attribute; +import org.opensaml.saml.saml2.core.AttributeStatement; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.LogoutRequest; +import org.opensaml.saml.saml2.core.NameID; +import org.opensaml.xmlsec.SignatureSigningParameters; +import org.opensaml.xmlsec.context.SecurityParametersContext; +import org.opensaml.xmlsec.signature.support.SignatureConstants; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.Date; + +import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.DOTCMS_SAML_BUILD_ROLES_ALL_VALUE; +import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.DOTCMS_SAML_BUILD_ROLES_IDP_VALUE; +import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.DOTCMS_SAML_BUILD_ROLES_NONE_VALUE; +import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.DOTCMS_SAML_BUILD_ROLES_STATIC_ADD_VALUE; +import static com.dotcms.plugin.saml.v3.key.DotSamlConstants.SAML_USER_ID; +import static com.dotcms.plugin.saml.v3.util.SamlUtils.buildAuthnRequest; +import static com.dotcms.plugin.saml.v3.util.SamlUtils.buildLogoutRequest; +import static com.dotcms.plugin.saml.v3.util.SamlUtils.getCredential; +import static com.dotcms.plugin.saml.v3.util.SamlUtils.getIdentityProviderDestinationEndpoint; +import static com.dotcms.plugin.saml.v3.util.SamlUtils.getIdentityProviderSLODestinationEndpoint; +import static com.dotcms.plugin.saml.v3.util.SamlUtils.toXMLObjectString; +import static com.dotmarketing.util.UtilMethods.isSet; /** * Authentication with Open SAML @@ -759,7 +757,11 @@ public User resolveUser(final Assertion assertion, final IdpConfig idpConfig) { systemUser = this.userAPI.getSystemUser(); - user = this.userAPI.loadUserById(attributesBean.getNameID().getValue(), systemUser, false); + final Company company = APILocator.getCompanyAPI().getDefaultCompany(); + final String authType = company.getAuthType(); + user = Company.AUTH_TYPE_ID.equals(authType )? + this.userAPI.loadUserById(attributesBean.getNameID().getValue(), systemUser, false): + this.userAPI.loadByUserByEmail(attributesBean.getNameID().getValue(), systemUser, false); } catch (AttributesNotFoundException e) { Logger.error(this, e.getMessage()); return null; @@ -772,19 +774,25 @@ public User resolveUser(final Assertion assertion, final IdpConfig idpConfig) { user = null; } - if (null == user) { - // if user does not exists, create a new one. - user = this.createNewUser(systemUser, attributesBean, idpConfig); - } else { - // update it, since exists - user = this.updateUser(user, systemUser, attributesBean, idpConfig); - } + // check if the client wants synchronization + final boolean createUserWhenDoesNotExists = DotsamlPropertiesService.getOptionBoolean(idpConfig, + DotsamlPropertyName.DOT_SAML_ALLOW_USER_SYNCHRONIZATION); + if (createUserWhenDoesNotExists) { + if (null == user) { + // if user does not exists, create a new one. + user = this.createNewUser(systemUser, attributesBean, idpConfig); + } else { + // update it, since exists + user = this.updateUser(user, systemUser, attributesBean, idpConfig); + } - if (user.isActive()) { - this.addRoles(user, attributesBean, idpConfig); - } else { - Logger.info(this, "User with ID '" + attributesBean.getNameID().getValue() + "' is not active. No roles " + - "were added."); + if (user.isActive()) { + + this.addRoles(user, attributesBean, idpConfig); + } else { + Logger.info(this, "User with ID '" + attributesBean.getNameID().getValue() + "' is not active. No roles " + + "were added."); + } } return user;