Class DefaultAdminUserContextValidator<P extends AdminUser>

java.lang.Object
com.broadleafcommerce.adminuser.user.service.DefaultAdminUserContextValidator<P>
Type Parameters:
P -
All Implemented Interfaces:
AdminUserContextValidator<P>

public class DefaultAdminUserContextValidator<P extends AdminUser> extends Object implements AdminUserContextValidator<P>
Default validator for use on admin user modifications. Includes verification of the following:
  1. Addition/removal of applications. User must be in the correct context (tenant or global) to add/remove a user from an application.
  2. Username/email uniqueness per tenant. Usernames and emails must be unique for a particular tenant. This includes all applications that are members of a tenant.
  3. User context: User should be in the correct context to perform modifications (e.g. tenant/app admin cannot modify a user belonging to another application or tenant).
  4. Tenant modification: A tenant or application admin may not modify another user's tenant.
  5. all assigned AdminUser.permissions are accessible from the user's context
  6. all assigned AdminUser.roles are accessible from the user's context
  7. the existing state of the user being updated/deleted is not already less restrictive than the currently authenticated user. The comparison is based on restrictions and the state of AdminUser.isGrantAnyAuthorityAllowed() at the very least. If the authenticated user is not allowed to grant any authority, then all of the users' privileges will be taken into consideration as well (see validateUserPrivileges(AdminUser, Errors, boolean)). Note that AdminUserValidator is responsible for validating the restrictiveness of the end-state of the user
  • Field Details

    • ERROR_USERNAME_IN_USE

      public static final String ERROR_USERNAME_IN_USE
    • ERROR_EMAIL_IN_USE

      public static final String ERROR_EMAIL_IN_USE
    • ERROR_EMAIL_IN_USE_OTHER_APP

      public static final String ERROR_EMAIL_IN_USE_OTHER_APP
    • NO_APPLICATION_ACCESS_CANNOT_HAVE_APPLICATIONS

      public static final String NO_APPLICATION_ACCESS_CANNOT_HAVE_APPLICATIONS
    • USER_MUST_HAVE_APPLICATIONS

      public static final String USER_MUST_HAVE_APPLICATIONS
  • Constructor Details

    • DefaultAdminUserContextValidator

      public DefaultAdminUserContextValidator(com.broadleafcommerce.common.extension.TypeFactory typeFactory, @Nullable com.broadleafcommerce.data.tracking.core.policy.PolicyUtils policyUtils)
  • Method Details

    • setAdminUserService

      @Autowired @Lazy public void setAdminUserService(AdminUserService<P> adminUserService)
      Lazy injection since this validator is itself a service component. This avoids circular dependency exceptions
      Parameters:
      adminUserService - the user service
    • setAuthProvider

      @Autowired @Lazy public void setAuthProvider(AuthProvider authProvider)
    • setAdminPrivilegeService

      @Autowired @Lazy public void setAdminPrivilegeService(AdminPrivilegeService adminPrivilegeService)
      Lazy injection since this validator is itself a service component. This avoids circular dependency exceptions
      Parameters:
      adminPrivilegeService - the restriction service
    • validateCreate

      public org.springframework.validation.Errors validateCreate(@NonNull P user, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Description copied from interface: AdminUserContextValidator
      Validates a create operation is allowed in the current context.
      Specified by:
      validateCreate in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - The user to validate
      contextInfo - The current context
      Returns:
      An Errors object bound to a {code user}
      See Also:
    • validateUpdate

      public org.springframework.validation.Errors validateUpdate(@NonNull P user, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Description copied from interface: AdminUserContextValidator
      Validates an update operation is allowed in the current context.
      Specified by:
      validateUpdate in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - The user to validate
      contextInfo - The current context
      Returns:
      An Errors object bound to a {code user}
      See Also:
    • validateDelete

      public org.springframework.validation.Errors validateDelete(@NonNull P user, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Description copied from interface: AdminUserContextValidator
      Validates a delete operation is allowed in the current context.
      Specified by:
      validateDelete in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - The user to validate
      contextInfo - The current context
      Returns:
      An Errors object bound to a {code user}
      See Also:
    • validateCreate

      public void validateCreate(@NonNull P user, org.springframework.validation.Errors errors, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Description copied from interface: AdminUserContextValidator
      Validates a create operation is allowed in the current context.
      Specified by:
      validateCreate in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - The user to validate
      errors - An errors object bound to the user to be validated
      contextInfo - The current context
    • validateTenantContextForCreation

      protected void validateTenantContextForCreation(P user, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • validateApplicationContextForCreation

      protected void validateApplicationContextForCreation(P user, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • validateRestrictedPermissionsPermissionRefs

      protected void validateRestrictedPermissionsPermissionRefs(P user, org.springframework.validation.Errors errors)
    • validateDirectlyAssignedPermissions

      @Deprecated protected void validateDirectlyAssignedPermissions(P user, org.springframework.validation.Errors errors)
      Deprecated.
    • validatePermissions

      @Deprecated protected void validatePermissions(P user, String permissionsFieldNameOnParent, Set<AdminPermissionRef> permissions, org.springframework.validation.Errors errors)
      Deprecated.
      since 1.7.0.
    • prefixWithEntityValidationMessageKey

      protected static String prefixWithEntityValidationMessageKey(String errorCode)
    • validatePermissionsAccessibleFromUserContext

      @Deprecated protected void validatePermissionsAccessibleFromUserContext(P user, String permissionsFieldNameOnParent, Set<AdminPermissionRef> permissionRefs, org.springframework.validation.Errors errors)
      Deprecated.
      Validates that all of the user's assigned permission IDs belong to permissions that are accessible from the user's context.

      This is important, because the create/update/delete operation itself may be occurring in a context different from that of the user itself and thus its context cannot be used. For example, if a user is being created in a specific tenant from a global context, the permissions accessible from the global context (ex: permissions from other tenants) do not reflect the permissions accessible by the user itself.

      TODO when global users are supported, update this validation to disallow assigning tenant permissions to global users

      Parameters:
      user - the user whose permissions need to be checked for context accessibility. The AdminUser.getPermissions() should be pre-validated to not contain any null elements or empty IDs.
      permissionRefs -
      errors - the errors object bound to the given user on which errors can be registered
    • buildContextMatchingUserTenant

      protected com.broadleafcommerce.data.tracking.core.context.ContextRequest buildContextMatchingUserTenant(P user)
      Builds a ContextRequest that has a ContextRequest.tenantId matching the AdminUser.tenantId. Useful in situations where it is necessary to determine what entities are accessible by this user.
      Parameters:
      user - the user for which to build a context request
      Returns:
      a ContextRequest matching the given user's tenant ID
    • validateDirectlyAssignedRoles

      protected void validateDirectlyAssignedRoles(P user, org.springframework.validation.Errors errors)
    • validateRestrictedRoles

      protected void validateRestrictedRoles(P user, org.springframework.validation.Errors errors)
    • validateRoles

      protected void validateRoles(P user, String roleFieldNameOnParent, Set<AdminRoleRef> roles, org.springframework.validation.Errors errors)
    • validateExternalRoles

      protected void validateExternalRoles(P user, org.springframework.validation.Errors errors)
      Ensure that there are not internal and external roles with the same role id.
      Parameters:
      user - The User whose roles should be checked.
      errors - the errors object bound to the given user on which errors can be registered
    • validateRolesAccessibleFromUserContext

      protected void validateRolesAccessibleFromUserContext(P user, String rolesFieldNameOnParent, Set<AdminRoleRef> roleRefs, org.springframework.validation.Errors errors)
      Validates that all of the user's assigned role IDs belong to roles that are accessible from the user's context.

      This is important, because the create/update/delete operation itself may be occurring in a context different from that of the user itself and thus its context cannot be used. For example, if a user is being created in a specific tenant from a global context, the roles accessible from the global context (ex: roles from other tenants) do not reflect the roles accessible by the user itself.

      TODO when global users are supported, update this validation to disallow assigning tenant roles to global users

      Parameters:
      user - the user whose roles need to be checked for context accessibility. The AdminUser.getRoles() should be pre-validated to not contain any null elements or empty IDs.
      errors - the errors object bound to the given user on which errors can be registered
    • validateUpdate

      public void validateUpdate(@NonNull P user, org.springframework.validation.Errors errors, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Description copied from interface: AdminUserContextValidator
      Validates a create operation is allowed in the current context.
      Specified by:
      validateUpdate in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - The user to validate
      errors - An errors object bound to the user to be validated
      contextInfo - The current context
    • validateDelete

      public void validateDelete(@NonNull P user, org.springframework.validation.Errors errors, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Description copied from interface: AdminUserContextValidator
      Validates a create operation is allowed in the current context.
      Specified by:
      validateDelete in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - The user to validate
      errors - An errors object bound to the user to be validated
      contextInfo - The current context
    • validateContextForModification

      public void validateContextForModification(@NonNull P user, org.springframework.validation.Errors errors, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Description copied from interface: AdminUserContextValidator
      Validate that modification of a user is valid in the current context. The default implementation immediately aborts by throwing a runtime exception, though custom implementations may use the errors object if desired.
      Specified by:
      validateContextForModification in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - The user to validate against
      errors - An errors object bound to the user to be validated
      contextInfo - The current context
      Throws:
      com.broadleafcommerce.data.tracking.core.exception.EntityMissingException - If modification of the user in this context is not allowed.
      See Also:
    • checkContextMutabilityAndReturnIfError

      @Nullable protected String checkContextMutabilityAndReturnIfError(@NonNull P user, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Checks whether the given user is mutable in the given contextInfo.
      Parameters:
      user - the user whose mutability should be checked
      contextInfo - the context in which mutability should be evaluated
      Returns:
      an error message describing why the user is not mutable in the contextInfo, or null if the user is mutable in the context
    • isMutableFromContext

      public boolean isMutableFromContext(@NonNull P user, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Description copied from interface: AdminUserContextValidator
      Returns whether or not the given entity is mutable from the given context.
      Specified by:
      isMutableFromContext in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - the entity whose mutability should be checked
      contextInfo - the context in which mutability should be checked
      Returns:
      true if the entity is mutable from the given context, false otherwise
    • validateCurrentUserForModification

      public void validateCurrentUserForModification(P user, org.springframework.validation.Errors errors)
      Description copied from interface: AdminUserContextValidator
      Validate that modification of a user is permitted for the current authenticated user. The default implementation immediately aborts by throwing a runtime exception, though custom implementations may use the errors object if desired.
      Specified by:
      validateCurrentUserForModification in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - The user to validate against
      errors - An errors object bound to the user to be validated
      Throws:
      com.broadleafcommerce.data.tracking.core.exception.EntityMissingException - If modification of the user in this context is not allowed.
    • checkCurrentUserMutabilityAndReturnIfError

      @Nullable protected String checkCurrentUserMutabilityAndReturnIfError(P user)
    • isMutableByCurrentUser

      public boolean isMutableByCurrentUser(P user)
      Description copied from interface: AdminUserContextValidator
      Returns whether or not the given entity is mutable by the current authenticated user.
      Specified by:
      isMutableByCurrentUser in interface AdminUserContextValidator<P extends AdminUser>
      Parameters:
      user - the entity whose mutability should be checked
      Returns:
      true if the entity is mutable by the current user, false otherwise
    • validateTenant

      protected void validateTenant(P existingUser, P updatedUser, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Validates that the tenant ID has not changed on a user. Validation is skipped if in a global context.
      Parameters:
      existingUser - The existing user
      updatedUser - The proposed user modification
      contextInfo - The current context.
    • getTenantId

      @Nullable protected String getTenantId(P user, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Returns the tenant ID to be validated against. If there is no tenant ID on the contextInfo or the context is null this is either a global request or a request not performed in a context (e.g. service call, persistence handler), so we must fall back to the tenant ID on the user.
      Parameters:
      user - The user being validated.
      contextInfo - The current context.
      Returns:
      The tenant ID to validate against.
    • validateUserPrivileges

      protected void validateUserPrivileges(P existingUser, org.springframework.validation.Errors errors, boolean throwIfError)
      Validates that the user being updated/deleted is equally or more restrictive as the currently authenticated AdminUser based on their restrictions at the very least. However, if the authenticated user cannot grant any authority, which is set by the AdminUser.isGrantAnyAuthorityAllowed() flag, then it will validate the privileges based on flat permissions, roles, restrictions, restricted roles, and restricted permissions as well, making sure that the user being updated/deleted is not already less restrictive than the authenticated user. As a user can only be updated/deleted by another user that is already less restrictive overall prior the mutation.

      In addition, if the authenticated user's grantAnyAuthorityAllowed flag is false, it cannot modify another user whose grantAnyAuthorityAllowed flag is true.

      This protects against situations where, for example, a more restricted user can modify a more powerful user like "Global Master".

      Parameters:
      existingUser - the existing user prior the mutation from the update/delete operation
      throwIfError - flag to determine whether it should throw NotPermittedException if there's any error. Reason for this is to have field-level error if needed, such as when performing an update operation.
      Throws:
      com.broadleafcommerce.data.tracking.core.exception.NotPermittedException - if throwIfError is true and if the user being updated/deleted is already less restrictive than the currently authenticated user based on restrictions, grantAnyAuthorityAllowed flag, and/or all privileges
    • isEmailChange

      protected boolean isEmailChange(P updatedUser, P existingUser)
      Parameters:
      updatedUser - The requested update of an existing user
      existingUser - The existing user, as they currently exist in the database.
      Returns:
      true if this is an e-mail address change, else false.
    • isUsernameChange

      protected boolean isUsernameChange(P updatedUser, P existingUser)
      Parameters:
      updatedUser - The requested update of an existing user
      existingUser - The existing user, as they current exist in the database.
      Returns:
      true if this is a username change, else false.
    • validateApplications

      protected void validateApplications(P existingUser, P updatedUser, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Validate that any potential application modifications are allowed.
      Parameters:
      existingUser - The user as they exist in the data store prior to modification.
      updatedUser - The potential modifications of the existing user.
    • validateUserAssignedApplications

      protected void validateUserAssignedApplications(P user, org.springframework.validation.Errors errors)
      If a user doesn't have application access (see AdminUser.isApplicationAccess()) this validates that they do not have any applications assigned to them. If a user only has application access, this validates that they have applications assigned.
      Parameters:
      user - The user to validate
      errors - The errors object bound to user
    • getErrors

      protected org.springframework.validation.Errors getErrors(P user)
    • findByEmail

      @Nullable protected P findByEmail(String email, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • findByUsername

      @Nullable protected P findByUsername(String username, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • validateUsernameNotInUse

      protected void validateUsernameNotInUse(String username, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo, org.springframework.validation.Errors errors)
      Validates if a username is already in use for a particular context.
      Parameters:
      username - The username to check
      contextInfo - The current context
    • validateEmailNotInUse

      protected void validateEmailNotInUse(String email, org.springframework.validation.Errors errors, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Validates if a particular e-mail address is already in use for a particular tenant. If the e-mail is in use, but the user is a member of a different application, a more specific error is communicated.
      Parameters:
      email - The e-mail address to check.
      contextInfo - The current context
    • validateExternalAccessManagementForCreate

      protected void validateExternalAccessManagementForCreate(P user, org.springframework.validation.Errors errors)
      Validate that tenantAccess, applicationAccess and applicationIds are not set if these are intended to be managed by a third-party authentication provider.
      Parameters:
      user - The user to validate
      errors - The errors object bound to user
      See Also:
    • validateExternalAccessManagementForUpdate

      protected void validateExternalAccessManagementForUpdate(P user, P existingUser, org.springframework.validation.Errors errors)
      Validate that tenantAccess, applicationAccess and applicationIds are not set if these are intended to be managed by a third-party authentication provider.
      Parameters:
      user - The user object from the API being validated.
      existingUser - The user object that already exists in the database being updated.
      See Also:
    • findById

      protected P findById(String id, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • getCurrentUserPrincipal

      protected String getCurrentUserPrincipal()
    • currentUserHasTenantAccess

      protected boolean currentUserHasTenantAccess()
      Uses policyUtils to check if currently authenticated user has tenant access.

      If policyUtils is null or it's not an instance of TrackablePolicyUtils, that means policy validation is turned off or trackable considerations should be ignored. Therefore it will automatically report the currently authenticated user has tenant access, since we want to allow everything in those cases.

      Returns:
      true if currently authenticated user has tenant access, otherwise false
      See Also:
      • TrackablePolicyUtils.isUserTenantLevelAccess()
    • currentUserHasApplicationAccess

      protected boolean currentUserHasApplicationAccess()
      Uses policyUtils to check if currently authenticated user has application access.

      If policyUtils is null or it's not an instance of TrackablePolicyUtils, that means policy validation is turned off or trackable considerations should be ignored. Therefore it will automatically report the currently authenticated user has application access, since we want to allow everything in those cases.

      Returns:
      true if currently authenticated user has application access, otherwise false
      See Also:
      • TrackablePolicyUtils.isUserApplicationLevelAccess()
    • getCurrentUserApplicationIds

      @Nullable protected Collection<String> getCurrentUserApplicationIds()
    • getAuthenticationDetails

      @NonNull protected Map<String,Object> getAuthenticationDetails()
    • getAdminUserService

      protected AdminUserService<P> getAdminUserService()
    • getTypeFactory

      protected com.broadleafcommerce.common.extension.TypeFactory getTypeFactory()
    • getPolicyUtils

      @Nullable protected com.broadleafcommerce.data.tracking.core.policy.PolicyUtils getPolicyUtils()
    • getAuthProvider

      protected AuthProvider getAuthProvider()
    • getAdminPrivilegeService

      protected AdminPrivilegeService getAdminPrivilegeService()
    • getAdminUserAccessLevelProperties

      protected AdminUserAccessLevelProperties getAdminUserAccessLevelProperties()
    • setAdminUserAccessLevelProperties

      @Autowired(required=false) public void setAdminUserAccessLevelProperties(AdminUserAccessLevelProperties adminUserAccessLevelProperties)