/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.core.security.userstore; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.util.Assert; import com.google.common.base.Preconditions; import com.enonic.cms.core.security.group.DeleteGroupCommand; import com.enonic.cms.core.security.group.GroupEntity; import com.enonic.cms.core.security.group.GroupKey; import com.enonic.cms.core.security.group.GroupSpecification; import com.enonic.cms.core.security.group.GroupType; import com.enonic.cms.core.security.group.StoreNewGroupCommand; import com.enonic.cms.core.security.group.UpdateGroupCommand; import com.enonic.cms.core.security.user.UserEntity; import com.enonic.cms.core.security.userstore.connector.GroupAlreadyExistsException; import com.enonic.cms.core.security.userstore.connector.UserAlreadyExistsException; import com.enonic.cms.core.time.TimeService; import com.enonic.cms.store.dao.CategoryAccessDao; import com.enonic.cms.store.dao.ContentAccessDao; import com.enonic.cms.store.dao.DefaultSiteAccessDao; import com.enonic.cms.store.dao.GroupDao; import com.enonic.cms.store.dao.MenuItemAccessDao; import com.enonic.cms.store.dao.UserDao; public class GroupStorer { private GroupDao groupDao; private UserDao userDao; private MenuItemAccessDao menuItemAccessDao; private CategoryAccessDao categoryAccessDao; private ContentAccessDao contentAccessDao; private DefaultSiteAccessDao defaultSiteAccessDao; private TimeService timeService; private boolean resurrectDeletedGroups; private boolean groupsStoredLocally; private UserStoreEntity userStore; public GroupKey storeNewGroup( StoreNewGroupCommand command ) { if ( userStore != null ) { Preconditions.checkArgument( command.getUserStoreKey().equals( userStore.getKey() ), "This UserStorer only supports creating groups for user store " + userStore.getKey() + ", was: " + command.getUserStoreKey() ); } else { Preconditions.checkArgument( command.getUserStoreKey() == null, "This UserStorer only supports creating groups for global user stores" ); } checkIfGroupAlreadyExistsUndeleted( command ); if ( groupAlreadyExistsDeleted( command ) ) { if ( userStore != null && resurrectDeletedGroups ) { return resurrectDeletedGroup( command ); } else if ( !groupsStoredLocally ) { makeExistingDeletedGroupsHaveNonRepeatableSyncValues( command ); } } UserEntity user = null; if ( command.getUserKey() != null ) { user = userDao.findByKey( command.getUserKey().toString() ); } final GroupEntity newGroup = new GroupEntity(); newGroup.setRestricted( command.isRestriced() ); newGroup.setDeleted( false ); newGroup.setDescription( command.getDescription() ); newGroup.setName( command.getName() ); final String syncValue = command.getSyncValue(); newGroup.setSyncValue( syncValue == null ? "NA" : syncValue ); if ( user != null ) { newGroup.setUser( user ); } newGroup.setUserStore( userStore ); newGroup.setType( command.getType() ); if ( command.getMembers() != null ) { for ( GroupKey memberKey : command.getMembers() ) { GroupEntity member = groupDao.find( memberKey.toString() ); if ( newGroup.isInUserStore() && !newGroup.getUserStore().equals( member.getUserStore() ) ) { throw new IllegalArgumentException( member.getQualifiedName() + " cannot be member of group " + newGroup.getQualifiedName() + ". Group and member must be located in same user store." ); } member.addMembership( newGroup ); } } groupDao.storeNew( newGroup ); return newGroup.getGroupKey(); } public void addMembershipToGroup( GroupEntity groupToAdd, GroupEntity groupToAddTo ) { groupToAdd.addMembership( groupToAddTo ); } public void removeMembershipFromGroup( GroupEntity groupToRemove, GroupEntity groupToRemoveFrom ) { if ( groupToRemove.hasMembership( groupToRemoveFrom ) ) { groupToRemove.removeMembership( groupToRemoveFrom ); } } public void updateGroup( UpdateGroupCommand command ) { GroupEntity group = groupDao.findByKey( command.getGroupKey() ); Preconditions.checkNotNull( group, "group does not exist: " + command.getGroupKey() ); group.setName( command.getName() ); group.setDescription( command.getDescription() ); if ( group.isBuiltIn() ) { // Force restricted enrollment for built-in groups - always! group.setRestricted( true ); } else { if ( command.isRestricted() != null ) { group.setRestricted( command.isRestricted() ? 1 : 0 ); } } if ( command.getMembersAsKeys() != null ) { syncMembers( group, command.getMembersAsKeys() ); } } private void syncMembers( final GroupEntity group, final Collection<GroupKey> expectedMembers ) { Preconditions.checkNotNull( group ); Preconditions.checkNotNull( expectedMembers ); removeMembershipsNotExistingInCollection( group, expectedMembers ); addMembershipsToGroup( group, expectedMembers ); } private void removeMembershipsNotExistingInCollection( final GroupEntity group, final Collection<GroupKey> expectedMembers ) { final List<GroupEntity> membersToRemove = new ArrayList<GroupEntity>(); for ( GroupEntity existingMember : group.getMembers( false ) ) { if ( !expectedMembers.contains( existingMember.getGroupKey() ) ) { membersToRemove.add( existingMember ); } } for ( GroupEntity memberToRemove : membersToRemove ) { memberToRemove.removeMembership( group ); } } private void addMembershipsToGroup( final GroupEntity group, final Collection<GroupKey> expectedMembers ) { for ( GroupKey expectedMemberGroupKey : expectedMembers ) { final GroupEntity expectedMember = groupDao.findByKey( expectedMemberGroupKey ); if ( expectedMember != null && !expectedMember.hasMembership( group ) ) { if ( group.isInUserStore() && !group.getUserStore().equals( expectedMember.getUserStore() ) ) { throw new IllegalArgumentException( expectedMember.getQualifiedName() + " cannot be member of group " + group.getQualifiedName() + ". Group and member must be located in same user store." ); } expectedMember.addMembership( group ); } } } public void deleteGroup( final DeleteGroupCommand command ) { final GroupEntity groupToDelete = groupDao.findSingleBySpecification( command.getSpecification() ); Assert.notNull( groupToDelete, "No group matching specification: " + command.getSpecification() ); groupToDelete.setDeleted( true ); final GroupKey groupKey = groupToDelete.getGroupKey(); defaultSiteAccessDao.deleteByGroupKey( groupKey ); menuItemAccessDao.deleteByGroupKey( groupKey ); contentAccessDao.deleteByGroupKey( groupKey ); categoryAccessDao.deleteByGroupKey( groupKey ); } private boolean groupAlreadyExistsDeleted( final StoreNewGroupCommand command ) { final GroupSpecification spec = new GroupSpecification(); spec.setDeletedState( GroupSpecification.DeletedState.DELETED ); if ( userStore != null ) { spec.setUserStoreKey( userStore.getKey() ); if ( groupsStoredLocally ) { spec.setName( command.getName() ); } else { spec.setSyncValue( command.getSyncValue() ); } } else { spec.setName( command.getName() ); spec.setType( GroupType.GLOBAL_GROUP ); } final List<GroupEntity> groups = groupDao.findBySpecification( spec ); return !groups.isEmpty(); } private GroupKey resurrectDeletedGroup( final StoreNewGroupCommand command ) { Preconditions.checkArgument( !groupsStoredLocally, "Only resurrection of groups in remote userStores is expected" ); final GroupSpecification existingGroupToResurrectSpec = new GroupSpecification(); existingGroupToResurrectSpec.setUserStoreKey( userStore.getKey() ); existingGroupToResurrectSpec.setDeletedState( GroupSpecification.DeletedState.DELETED ); existingGroupToResurrectSpec.setSyncValue( command.getSyncValue() ); final List<GroupEntity> groups = groupDao.findBySpecification( existingGroupToResurrectSpec ); final GroupEntity groupToResurrect = groups.get( 0 ); groupToResurrect.setDeleted( false ); groupToResurrect.setName( command.getName() ); if ( command.getMembers() != null ) { syncMembers( groupToResurrect, command.getMembers() ); } return groupToResurrect.getGroupKey(); } private void makeExistingDeletedGroupsHaveNonRepeatableSyncValues( final StoreNewGroupCommand command ) { Preconditions.checkArgument( !groupsStoredLocally, "No use in making sync values for groups stored in local userStores non-repeatable." ); final GroupSpecification specification = new GroupSpecification(); specification.setUserStoreKey( userStore.getKey() ); specification.setSyncValue( command.getSyncValue() ); specification.setDeletedState( GroupSpecification.DeletedState.DELETED ); final List<GroupEntity> groups = groupDao.findBySpecification( specification ); final NonRepeatableSyncValueResolver nonRepeatableSyncValueResolver = new NonRepeatableSyncValueResolver( timeService ); for ( GroupEntity group : groups ) { group.setSyncValue( nonRepeatableSyncValueResolver.resolve( group.getSyncValue() ) ); } } private void checkIfGroupAlreadyExistsUndeleted( final StoreNewGroupCommand command ) throws UserAlreadyExistsException { final GroupSpecification groupSpec = new GroupSpecification(); groupSpec.setDeletedState( GroupSpecification.DeletedState.NOT_DELETED ); if ( userStore == null ) { groupSpec.setType( GroupType.GLOBAL_GROUP ); groupSpec.setName( command.getName() ); } else { groupSpec.setUserStoreKey( command.getUserStoreKey() ); if ( groupsStoredLocally ) { groupSpec.setName( command.getName() ); } else if ( command.getSyncValue() != null ) { groupSpec.setSyncValue( command.getSyncValue() ); } if ( command.getType() != null ) { groupSpec.setType( command.getType() ); } } final List<GroupEntity> groups = groupDao.findBySpecification( groupSpec ); if ( !groups.isEmpty() ) { if ( userStore == null ) { throw new GroupAlreadyExistsException( command.getName() ); } else { throw new GroupAlreadyExistsException( userStore.getName(), command.getName() ); } } } public void setGroupDao( GroupDao groupDao ) { this.groupDao = groupDao; } public void setUserDao( UserDao userDao ) { this.userDao = userDao; } public void setMenuItemAccessDao( MenuItemAccessDao menuItemAccessDao ) { this.menuItemAccessDao = menuItemAccessDao; } public void setCategoryAccessDao( CategoryAccessDao categoryAccessDao ) { this.categoryAccessDao = categoryAccessDao; } public void setContentAccessDao( ContentAccessDao contentAccessDao ) { this.contentAccessDao = contentAccessDao; } public void setDefaultSiteAccessDao( DefaultSiteAccessDao defaultSiteAccessDao ) { this.defaultSiteAccessDao = defaultSiteAccessDao; } public void setTimeService( TimeService timeService ) { this.timeService = timeService; } public void setUserStore( UserStoreEntity userStore ) { this.userStore = userStore; } public void setResurrectDeletedGroups( boolean resurrectDeletedGroups ) { this.resurrectDeletedGroups = resurrectDeletedGroups; } public void setGroupsStoredLocally( boolean groupsStoredLocally ) { this.groupsStoredLocally = groupsStoredLocally; } }