diff --git a/index.adoc b/index.adoc index 8cf87ef..4136326 100644 --- a/index.adoc +++ b/index.adoc @@ -4401,12 +4401,97 @@ endif::internal-generation[] | | +| cachedDirectoriesAuthenticationOrderOptimisationEnabled +| +| Boolean +| +| + +| directoryMappings +| +| List of <> +| +| + +| accessBasedSynchronisation +| +| String +| +| _Enum:_ NO_FILTERING, USER_ONLY_FILTERING, USER_AND_GROUP_FILTERING, + +| membershipAggregationEnabled +| +| Boolean +| +| + | remoteAddresses | | List of <> | | +| aliasingEnabled +| +| Boolean +| +| + +| lowercaseOutputEnabled +| +| Boolean +| +| + +| authenticationWithoutPasswordEnabled +| +| Boolean +| +| + +|=== + + +[#ApplicationDirectoryMapping] +=== _ApplicationDirectoryMapping_ + + + +[.fields-ApplicationDirectoryMapping] +[cols="2,1,2,4,1"] +|=== +| Field Name| Required| Type| Description| Format + +| directoryName +| +| String +| +| + +| authenticationAllowAll +| +| Boolean +| +| + +| authenticationGroups +| +| List of <> +| +| + +| autoAssignmentGroups +| +| List of <> +| +| + +| allowedOperations +| +| List of <> +| +| _Enum:_ + |=== diff --git a/pom.xml b/pom.xml index b0814f3..219b9fb 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ confapi-crowd-plugin - 0.5.3-SNAPSHOT + 0.6.0-SNAPSHOT atlassian-plugin ConfAPI for Crowd diff --git a/src/main/java/de/aservo/confapi/crowd/model/ApplicationBean.java b/src/main/java/de/aservo/confapi/crowd/model/ApplicationBean.java index bb3be68..a0f78a3 100644 --- a/src/main/java/de/aservo/confapi/crowd/model/ApplicationBean.java +++ b/src/main/java/de/aservo/confapi/crowd/model/ApplicationBean.java @@ -1,13 +1,14 @@ package de.aservo.confapi.crowd.model; +import com.atlassian.crowd.embedded.api.OperationType; import de.aservo.confapi.commons.constants.ConfAPI; import lombok.Data; import lombok.NoArgsConstructor; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; - -import java.util.*; +import java.util.Collection; +import java.util.Collections; @Data @NoArgsConstructor @@ -27,6 +28,13 @@ public enum ApplicationType { ; } + public enum AccessBasedSynchronisation { + NO_FILTERING, + USER_ONLY_FILTERING, + USER_AND_GROUP_FILTERING, + ; + } + @XmlElement private Long id; @@ -45,31 +53,99 @@ public enum ApplicationType { @XmlElement private String password; + @XmlElement + private Boolean cachedDirectoriesAuthenticationOrderOptimisationEnabled; + + @XmlElement + private Collection directoryMappings; + + @XmlElement + private AccessBasedSynchronisation accessBasedSynchronisation; + + @XmlElement + private Boolean membershipAggregationEnabled; + @XmlElement private Collection remoteAddresses; + @XmlElement + private Boolean aliasingEnabled; + + @XmlElement + private Boolean lowercaseOutputEnabled; + + @XmlElement + private Boolean authenticationWithoutPasswordEnabled; + + @Data + @NoArgsConstructor + public static class ApplicationDirectoryMapping { + + @XmlElement + private String directoryName; + + @XmlElement + private Boolean authenticationAllowAll; + + @XmlElement + private Collection authenticationGroups; + + @XmlElement + private Collection autoAssignmentGroups; + + @XmlElement + private Collection allowedOperations; + + } + public static final ApplicationBean EXAMPLE_1; public static final ApplicationBean EXAMPLE_2; static { EXAMPLE_1 = new ApplicationBean(); + EXAMPLE_1.setId(1L); EXAMPLE_1.setName("app_name"); EXAMPLE_1.setDescription("app_description"); EXAMPLE_1.setActive(true); - EXAMPLE_1.setPassword("3x4mpl3"); EXAMPLE_1.setType(ApplicationType.GENERIC); - EXAMPLE_1.setId(1L); + EXAMPLE_1.setPassword("3x4mpl3"); + EXAMPLE_1.setCachedDirectoriesAuthenticationOrderOptimisationEnabled(false); + final ApplicationDirectoryMapping directoryMapping = new ApplicationDirectoryMapping(); + directoryMapping.setDirectoryName("directory"); + directoryMapping.setAuthenticationAllowAll(true); + directoryMapping.setAuthenticationGroups(Collections.singleton("app_access")); + directoryMapping.setAutoAssignmentGroups(Collections.singleton("app_users")); + directoryMapping.setAllowedOperations(Collections.singleton(OperationType.CREATE_USER)); + EXAMPLE_1.setDirectoryMappings(Collections.singleton(directoryMapping)); + EXAMPLE_1.setAccessBasedSynchronisation(AccessBasedSynchronisation.NO_FILTERING); + EXAMPLE_1.setMembershipAggregationEnabled(false); EXAMPLE_1.setRemoteAddresses(Collections.singletonList("127.0.0.1")); + EXAMPLE_1.setAliasingEnabled(true); + EXAMPLE_1.setLowercaseOutputEnabled(true); + EXAMPLE_1.setAuthenticationWithoutPasswordEnabled(true); } static { EXAMPLE_2 = new ApplicationBean(); + EXAMPLE_2.setId(2L); EXAMPLE_2.setName("app_name2"); EXAMPLE_2.setDescription("app_description2"); EXAMPLE_2.setActive(false); - EXAMPLE_2.setPassword("3x4mpl32"); EXAMPLE_2.setType(ApplicationType.BAMBOO); - EXAMPLE_2.setId(2L); + EXAMPLE_2.setPassword("3x4mpl32"); + EXAMPLE_2.setCachedDirectoriesAuthenticationOrderOptimisationEnabled(true); + final ApplicationDirectoryMapping directoryMapping = new ApplicationDirectoryMapping(); + directoryMapping.setDirectoryName("directory"); + directoryMapping.setAuthenticationAllowAll(false); + directoryMapping.setAuthenticationGroups(Collections.singleton("app_access2")); + directoryMapping.setAutoAssignmentGroups(Collections.singleton("app_users2")); + directoryMapping.setAllowedOperations(Collections.singleton(OperationType.CREATE_GROUP)); + EXAMPLE_2.setDirectoryMappings(Collections.singleton(directoryMapping)); + EXAMPLE_2.setAccessBasedSynchronisation(AccessBasedSynchronisation.USER_AND_GROUP_FILTERING); + EXAMPLE_2.setMembershipAggregationEnabled(true); EXAMPLE_2.setRemoteAddresses(Collections.singletonList("127.0.0.3")); + EXAMPLE_2.setAliasingEnabled(false); + EXAMPLE_2.setLowercaseOutputEnabled(false); + EXAMPLE_2.setAuthenticationWithoutPasswordEnabled(false); } } diff --git a/src/main/java/de/aservo/confapi/crowd/model/util/ApplicationBeanUtil.java b/src/main/java/de/aservo/confapi/crowd/model/util/ApplicationBeanUtil.java index bbb6c0c..76f5e8c 100644 --- a/src/main/java/de/aservo/confapi/crowd/model/util/ApplicationBeanUtil.java +++ b/src/main/java/de/aservo/confapi/crowd/model/util/ApplicationBeanUtil.java @@ -1,22 +1,23 @@ package de.aservo.confapi.crowd.model.util; import com.atlassian.crowd.embedded.api.PasswordCredential; -import com.atlassian.crowd.model.application.Application; -import com.atlassian.crowd.model.application.ApplicationType; -import com.atlassian.crowd.model.application.ImmutableApplication; -import com.atlassian.crowd.model.application.RemoteAddress; +import com.atlassian.crowd.exception.OperationFailedException; +import com.atlassian.crowd.manager.application.DefaultGroupMembershipService; +import com.atlassian.crowd.model.application.*; +import de.aservo.confapi.commons.exception.BadRequestException; +import de.aservo.confapi.commons.exception.InternalServerErrorException; import de.aservo.confapi.crowd.model.ApplicationBean; +import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.validation.constraints.NotNull; - import java.util.*; import java.util.stream.Collectors; public class ApplicationBeanUtil { public static ApplicationBean toApplicationBean( - final Application application) { + final Application application, + final DefaultGroupMembershipService defaultGroupMembershipService) { final ApplicationBean applicationBean = new ApplicationBean(); @@ -25,21 +26,104 @@ public static ApplicationBean toApplicationBean( applicationBean.setDescription(application.getDescription()); applicationBean.setActive(application.isActive()); applicationBean.setType(toApplicationBeanType(application.getType())); + applicationBean.setCachedDirectoriesAuthenticationOrderOptimisationEnabled(application.isCachedDirectoriesAuthenticationOrderOptimisationEnabled()); + applicationBean.setDirectoryMappings(toApplicationBeanDirectoryMappings(application, defaultGroupMembershipService)); + applicationBean.setAccessBasedSynchronisation(toApplicationBeanAccessBasedSynchronisation(application)); + applicationBean.setMembershipAggregationEnabled(application.isMembershipAggregationEnabled()); applicationBean.setRemoteAddresses(toStringCollection(application.getRemoteAddresses())); + applicationBean.setAliasingEnabled(application.isAliasingEnabled()); + applicationBean.setLowercaseOutputEnabled(application.isLowerCaseOutput()); + applicationBean.setAuthenticationWithoutPasswordEnabled(application.isAuthenticationWithoutPasswordEnabled()); return applicationBean; } + public static Application toApplication( + final ApplicationBean applicationBean, + final Application existingApplication) { + + final ImmutableApplication.Builder applicationBuilder = new ImmutableApplication.Builder(existingApplication); + return toApplicationInternal(applicationBean, applicationBuilder); + } + public static Application toApplication( final ApplicationBean applicationBean) { // don't set id from request data - return ImmutableApplication.builder(applicationBean.getName(), toApplicationType(applicationBean.getType())) - .setDescription(applicationBean.getDescription()) - .setActive(applicationBean.getActive()) - .setPasswordCredential(PasswordCredential.unencrypted(applicationBean.getPassword())) - .setRemoteAddresses(toAddressSet(applicationBean.getRemoteAddresses())) - .build(); + final ImmutableApplication.Builder applicationBuilder = ImmutableApplication.builder(applicationBean.getName(), toApplicationType(applicationBean.getType())); + return toApplicationInternal(applicationBean, applicationBuilder); + } + + private static Application toApplicationInternal( + final ApplicationBean applicationBean, + final ImmutableApplication.Builder applicationBuilder) { + + // we need to run null checks everywhere because the application builder doesn't really support setting null... + + if (applicationBean.getId() != null) { + applicationBuilder.setId(applicationBean.getId()); + } + + if (applicationBean.getName() != null) { + applicationBuilder.setName(applicationBean.getName()); + } + + if (applicationBean.getDescription() != null) { + applicationBuilder.setDescription(applicationBean.getDescription()); + } + + if (applicationBean.getActive() != null) { + applicationBuilder.setActive(applicationBean.getActive()); + } + + // updating the application type is not possible, and error handling is difficult here, + // because the application builder has no getters, so see end of method + + if (applicationBean.getPassword() != null) { + applicationBuilder.setPasswordCredential(PasswordCredential.unencrypted(applicationBean.getPassword())); + } + + if (applicationBean.getCachedDirectoriesAuthenticationOrderOptimisationEnabled() != null) { + applicationBuilder.setCachedDirectoriesAuthenticationOrderOptimisationEnabled(applicationBean.getCachedDirectoriesAuthenticationOrderOptimisationEnabled()); + } + + // setting directory mappings is pointless because they are not respected when adding / updating applications + + if (applicationBean.getAccessBasedSynchronisation() != null) { + applicationBuilder.setFilteringGroupsWithAccessEnabled( + applicationBean.getAccessBasedSynchronisation() == ApplicationBean.AccessBasedSynchronisation.USER_AND_GROUP_FILTERING); + applicationBuilder.setFilteringUsersWithAccessEnabled( + applicationBean.getAccessBasedSynchronisation() == ApplicationBean.AccessBasedSynchronisation.USER_AND_GROUP_FILTERING + || applicationBean.getAccessBasedSynchronisation() == ApplicationBean.AccessBasedSynchronisation.USER_ONLY_FILTERING); + } + + if (applicationBean.getMembershipAggregationEnabled() != null) { + applicationBuilder.setMembershipAggregationEnabled(applicationBean.getMembershipAggregationEnabled()); + } + + if (applicationBean.getRemoteAddresses() != null) { + applicationBuilder.setRemoteAddresses(toAddressSet(applicationBean.getRemoteAddresses())); + } + + if (applicationBean.getAliasingEnabled() != null) { + applicationBuilder.setAliasingEnabled(applicationBean.getAliasingEnabled()); + } + + if (applicationBean.getLowercaseOutputEnabled() != null) { + applicationBuilder.setLowercaseOutput(applicationBean.getLowercaseOutputEnabled()); + } + + if (applicationBean.getAuthenticationWithoutPasswordEnabled() != null) { + applicationBuilder.setAuthenticationWithoutPasswordEnabled(applicationBean.getAuthenticationWithoutPasswordEnabled()); + } + + final Application application = applicationBuilder.build(); + + if (applicationBean.getType() != null && application.getType() != toApplicationType(applicationBean.getType())) { + throw new BadRequestException("Changing the application type is not allowed"); + } + + return application; } @Nullable @@ -96,8 +180,61 @@ public static ApplicationType toApplicationType( return null; } - @NotNull - public static Set toAddressSet( + @Nonnull + static Collection toApplicationBeanDirectoryMappings( + @Nonnull final Application application, + @Nonnull final DefaultGroupMembershipService defaultGroupMembershipService) { + + final Collection applicationDirectoryMappings = application.getApplicationDirectoryMappings(); + final List applicationBeanDirectoryMappings = new ArrayList<>(); + + for (final ApplicationDirectoryMapping applicationDirectoryMapping : applicationDirectoryMappings) { + final ApplicationBean.ApplicationDirectoryMapping applicationBeanDirectoryMapping = new ApplicationBean.ApplicationDirectoryMapping(); + applicationBeanDirectoryMapping.setDirectoryName(applicationDirectoryMapping.getDirectory().getName()); + applicationBeanDirectoryMapping.setAuthenticationAllowAll(applicationDirectoryMapping.isAllowAllToAuthenticate()); + + // if all directory users are allowed to authenticate, we don't return the unused list of groups that are allowed to do so, + // but instead we just return an empty list + if (!applicationDirectoryMapping.isAllowAllToAuthenticate()) { + applicationBeanDirectoryMapping.setAuthenticationGroups(applicationDirectoryMapping.getAuthorisedGroupNames()); + } else { + applicationBeanDirectoryMapping.setAuthenticationGroups(Collections.emptyList()); + } + + try { + applicationBeanDirectoryMapping.setAutoAssignmentGroups(defaultGroupMembershipService.listAll(application, + applicationDirectoryMapping).stream().sorted().collect(Collectors.toList())); + } catch (OperationFailedException e) { + throw new InternalServerErrorException(e); + } + + applicationBeanDirectoryMapping.setAllowedOperations(applicationDirectoryMapping.getAllowedOperations().stream().sorted().collect(Collectors.toList())); + + applicationBeanDirectoryMappings.add(applicationBeanDirectoryMapping); + } + + return applicationBeanDirectoryMappings; + } + + static ApplicationBean.AccessBasedSynchronisation toApplicationBeanAccessBasedSynchronisation( + final Application application) { + + // the case that filtering groups with access is enabled without + // filtering users with access is enabled also should not exist + if (application.isFilteringGroupsWithAccessEnabled() && application.isFilteringUsersWithAccessEnabled()) { + return ApplicationBean.AccessBasedSynchronisation.USER_AND_GROUP_FILTERING; + } + + // so if filtering groups with access is not enabled, there are only two cases left + if (application.isFilteringUsersWithAccessEnabled()) { + return ApplicationBean.AccessBasedSynchronisation.USER_ONLY_FILTERING; + } + + return ApplicationBean.AccessBasedSynchronisation.NO_FILTERING; + } + + @Nonnull + static Set toAddressSet( @Nullable final Collection remoteAddresses) { if (remoteAddresses == null) { @@ -109,9 +246,9 @@ public static Set toAddressSet( .collect(Collectors.toSet()); } - @NotNull + @Nonnull public static Collection toStringCollection( - @NotNull final Set remoteAddresses) { + @Nonnull final Set remoteAddresses) { return remoteAddresses.stream() .map(RemoteAddress::getAddress) @@ -121,5 +258,4 @@ public static Collection toStringCollection( private ApplicationBeanUtil() { } - } diff --git a/src/main/java/de/aservo/confapi/crowd/service/ApplicationsServiceImpl.java b/src/main/java/de/aservo/confapi/crowd/service/ApplicationsServiceImpl.java index 8a3ed57..0fda00f 100644 --- a/src/main/java/de/aservo/confapi/crowd/service/ApplicationsServiceImpl.java +++ b/src/main/java/de/aservo/confapi/crowd/service/ApplicationsServiceImpl.java @@ -1,13 +1,15 @@ package de.aservo.confapi.crowd.service; -import com.atlassian.crowd.embedded.api.PasswordCredential; -import com.atlassian.crowd.exception.ApplicationAlreadyExistsException; -import com.atlassian.crowd.exception.ApplicationNotFoundException; -import com.atlassian.crowd.exception.InvalidCredentialException; +import com.atlassian.crowd.embedded.api.Directory; +import com.atlassian.crowd.embedded.api.OperationType; +import com.atlassian.crowd.exception.*; import com.atlassian.crowd.manager.application.ApplicationManager; import com.atlassian.crowd.manager.application.ApplicationManagerException; +import com.atlassian.crowd.manager.application.DefaultGroupMembershipService; +import com.atlassian.crowd.manager.directory.DirectoryManager; import com.atlassian.crowd.model.application.Application; -import com.atlassian.crowd.model.application.ImmutableApplication; +import com.atlassian.crowd.model.application.ApplicationDirectoryMapping; +import com.atlassian.crowd.model.application.ImmutableApplicationDirectoryMapping; import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService; import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport; import de.aservo.confapi.commons.exception.BadRequestException; @@ -19,9 +21,10 @@ import de.aservo.confapi.crowd.service.api.ApplicationsService; import org.springframework.stereotype.Component; +import javax.annotation.Nonnull; import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; @Component @@ -30,17 +33,25 @@ public class ApplicationsServiceImpl implements ApplicationsService { private final ApplicationManager applicationManager; + private final DefaultGroupMembershipService defaultGroupMembershipService; + + private final DirectoryManager directoryManager; + @Inject public ApplicationsServiceImpl( - @ComponentImport final ApplicationManager applicationManager) { + @ComponentImport final ApplicationManager applicationManager, + @ComponentImport final DefaultGroupMembershipService defaultGroupMembershipService, + @ComponentImport final DirectoryManager directoryManager) { this.applicationManager = applicationManager; + this.defaultGroupMembershipService = defaultGroupMembershipService; + this.directoryManager = directoryManager; } @Override public ApplicationsBean getApplications() { return new ApplicationsBean(applicationManager.findAll().stream() - .map(ApplicationBeanUtil::toApplicationBean) + .map(application -> ApplicationBeanUtil.toApplicationBean(application, defaultGroupMembershipService)) .collect(Collectors.toList())); } @@ -49,7 +60,7 @@ public ApplicationBean getApplication( final long id) { try { - return ApplicationBeanUtil.toApplicationBean(applicationManager.findById(id)); + return ApplicationBeanUtil.toApplicationBean(applicationManager.findById(id), defaultGroupMembershipService); } catch (ApplicationNotFoundException e) { throw new NotFoundException(e); } @@ -74,50 +85,37 @@ public ApplicationsBean setApplications( } @Override - public ApplicationBean setApplication( - final long id, + public ApplicationBean addApplication( final ApplicationBean applicationBean) { try { - Application existingApplication = applicationManager.findById(id); - final ImmutableApplication.Builder applicationBuilder = new ImmutableApplication.Builder(existingApplication); - - if (applicationBean.getName() != null) { - applicationBuilder.setName(applicationBean.getName()); - } - if (applicationBean.getType() != null) { - applicationBuilder.setType(ApplicationBeanUtil.toApplicationType(applicationBean.getType())); - } - if (applicationBean.getDescription() != null) { - applicationBuilder.setDescription(applicationBean.getDescription()); - } - if (applicationBean.getActive() != null) { - applicationBuilder.setActive(applicationBean.getActive()); - } - if (applicationBean.getPassword() != null) { - applicationManager.updateCredential(existingApplication, PasswordCredential.unencrypted(applicationBean.getPassword())); - } - if (applicationBean.getRemoteAddresses() != null) { - applicationBuilder.setRemoteAddresses(ApplicationBeanUtil.toAddressSet(applicationBean.getRemoteAddresses())); - } - - return ApplicationBeanUtil.toApplicationBean(applicationManager.update(applicationBuilder.build())); - } catch (ApplicationNotFoundException e) { - throw new NotFoundException(e); - } catch (ApplicationManagerException e) { - throw new InternalServerErrorException(e); + final Application createdApplication = applicationManager.add(ApplicationBeanUtil.toApplication(applicationBean)); + persistApplicationDirectoryMappings(createdApplication, applicationBean); + persistApplicationBeanAuthenticationGroups(createdApplication, applicationBean); + persistApplicationBeanAutoAssignmentGroups(createdApplication, applicationBean); + return getApplication(createdApplication.getId()); + } catch (InvalidCredentialException | ApplicationAlreadyExistsException e) { + throw new BadRequestException(e); } } @Override - public ApplicationBean addApplication( + public ApplicationBean setApplication( + final long id, final ApplicationBean applicationBean) { try { - final Application createdApplication = applicationManager.add(ApplicationBeanUtil.toApplication(applicationBean)); - return ApplicationBeanUtil.toApplicationBean(createdApplication); - } catch (InvalidCredentialException | ApplicationAlreadyExistsException e) { - throw new BadRequestException(e); + final Application existingApplication = applicationManager.findById(id); + final Application modifiedApplication = ApplicationBeanUtil.toApplication(applicationBean, existingApplication); + final Application updatedApplication = applicationManager.update(modifiedApplication); + persistApplicationDirectoryMappings(updatedApplication, applicationBean); + persistApplicationBeanAuthenticationGroups(updatedApplication, applicationBean); + persistApplicationBeanAutoAssignmentGroups(updatedApplication, applicationBean); + return getApplication(updatedApplication.getId()); + } catch (ApplicationNotFoundException e) { + throw new NotFoundException(e); + } catch (ApplicationManagerException e) { + throw new InternalServerErrorException(e); } } @@ -148,4 +146,256 @@ public void deleteApplication( } } + void persistApplicationDirectoryMappings( + final Application application, + final ApplicationBean applicationBean) { + + if (applicationBean.getDirectoryMappings() == null) { + return; + } + + final Map applicationDirectoryMappingsByDirectoryName = application.getApplicationDirectoryMappings().stream() + .collect(Collectors.toMap(adm -> adm.getDirectory().getName(), Function.identity())); + final Map applicationBeanDirectoryMappingsByDirectoryName = applicationBean.getDirectoryMappings().stream() + .collect(Collectors.toMap(ApplicationBean.ApplicationDirectoryMapping::getDirectoryName, Function.identity())); + + final List applicationDirectoryMappingsToCreate = new ArrayList<>(); + final List applicationDirectoryMappingsToUpdate = new ArrayList<>(); + + // before performing any actual changes using the application manager, we first collect all data + // and wait for any potential validation errors (performed in the `toApplicationDirectoryMapping` method) + for (ApplicationDirectoryMapping applicationDirectoryMapping : toApplicationDirectoryMappings(applicationBeanDirectoryMappingsByDirectoryName.values())) { + if (!applicationDirectoryMappingsByDirectoryName.containsKey(applicationDirectoryMapping.getDirectory().getName())) { + applicationDirectoryMappingsToCreate.add(applicationDirectoryMapping); + } else { + applicationDirectoryMappingsToUpdate.add(applicationDirectoryMapping); + } + } + + for (ApplicationDirectoryMapping applicationDirectoryMapping : applicationDirectoryMappingsToCreate) { + addApplicationDirectoryMapping(application, applicationDirectoryMapping); + } + + for (ApplicationDirectoryMapping applicationDirectoryMapping : applicationDirectoryMappingsToUpdate) { + updateApplicationDirectoryMapping(application, applicationDirectoryMapping); + } + + for (ApplicationDirectoryMapping applicationDirectoryMapping : applicationDirectoryMappingsByDirectoryName.values()) { + if (!applicationBeanDirectoryMappingsByDirectoryName.containsKey(applicationDirectoryMapping.getDirectory().getName())) { + removeApplicationDirectoryMapping(application, applicationDirectoryMapping); + } + } + } + + void persistApplicationBeanAuthenticationGroups( + final Application application, + final ApplicationBean applicationBean) { + + if (applicationBean.getDirectoryMappings() == null) { + return; + } + + final Map> authenticationGroupsByDirectoryName = applicationBean.getDirectoryMappings().stream() + .collect(Collectors.toMap(ApplicationBean.ApplicationDirectoryMapping::getDirectoryName, ApplicationBean.ApplicationDirectoryMapping::getAuthenticationGroups)); + + for (ApplicationDirectoryMapping applicationDirectoryMapping : application.getApplicationDirectoryMappings()) { + final Set authenticationGroups = new HashSet<>(authenticationGroupsByDirectoryName.getOrDefault( + applicationDirectoryMapping.getDirectory().getName(), Collections.emptySet())); + + final Set currentAuthenticationGroups = applicationDirectoryMapping.getAuthorisedGroupNames(); + + final Set authenticationGroupsToAdd = new HashSet<>(authenticationGroups); + authenticationGroupsToAdd.removeAll(currentAuthenticationGroups); + addAuthenticationGroups(application, applicationDirectoryMapping.getDirectory(), authenticationGroupsToAdd); + + final Set authenticationGroupsToRemove = new HashSet<>(currentAuthenticationGroups); + authenticationGroupsToRemove.removeAll(authenticationGroups); + removeAuthenticationGroups(application, applicationDirectoryMapping.getDirectory(), authenticationGroupsToRemove); + } + } + + void persistApplicationBeanAutoAssignmentGroups( + final Application application, + final ApplicationBean applicationBean) { + + if (applicationBean.getDirectoryMappings() == null) { + return; + } + + final Map> autoAssignmentGroupsByDirectoryName = applicationBean.getDirectoryMappings().stream() + .collect(Collectors.toMap(ApplicationBean.ApplicationDirectoryMapping::getDirectoryName, ApplicationBean.ApplicationDirectoryMapping::getAutoAssignmentGroups)); + + for (ApplicationDirectoryMapping applicationDirectoryMapping : application.getApplicationDirectoryMappings()) { + final Collection autoAssignmentGroups = autoAssignmentGroupsByDirectoryName.getOrDefault( + applicationDirectoryMapping.getDirectory().getName(), Collections.emptyList()); + + final Set currentAutoAssignmentGroups; + try { + currentAutoAssignmentGroups = new HashSet<>(defaultGroupMembershipService.listAll(application, applicationDirectoryMapping)); + } catch (OperationFailedException e) { + throw new InternalServerErrorException(e); + } + + final Set autoAssignmentGroupSet = new HashSet<>(autoAssignmentGroups); + + final Set autoAssignmentGroupsToAdd = new HashSet<>(autoAssignmentGroupSet); + autoAssignmentGroupsToAdd.removeAll(currentAutoAssignmentGroups); + addAutoAssignmentGroups(application, applicationDirectoryMapping, autoAssignmentGroupsToAdd, defaultGroupMembershipService); + + final Set autoAssignmentGroupsToRemove = new HashSet<>(currentAutoAssignmentGroups); + autoAssignmentGroupsToRemove.removeAll(autoAssignmentGroupSet); + removeAutoAssignmentGroups(application, applicationDirectoryMapping, autoAssignmentGroupsToRemove, defaultGroupMembershipService); + } + } + + @Nonnull + Collection toApplicationDirectoryMappings( + @Nonnull final Collection applicationBeanDirectoryMappings) { + + return applicationBeanDirectoryMappings.stream() + .map(this::toApplicationDirectoryMapping) + .collect(Collectors.toList()); + } + + @Nonnull + ApplicationDirectoryMapping toApplicationDirectoryMapping( + @Nonnull final ApplicationBean.ApplicationDirectoryMapping applicationBeanDirectoryMapping) { + + if (applicationBeanDirectoryMapping.getDirectoryName() == null || applicationBeanDirectoryMapping.getDirectoryName().isEmpty()) { + throw new BadRequestException("Application directory mapping must contain a directory name"); + } + + final ImmutableApplicationDirectoryMapping.Builder applicationDirectoryMappingBuilder = ImmutableApplicationDirectoryMapping.builder(); + applicationDirectoryMappingBuilder.setDirectory(findDirectory(applicationBeanDirectoryMapping.getDirectoryName(), directoryManager)); + + if (applicationBeanDirectoryMapping.getAuthenticationAllowAll() != null) { + applicationDirectoryMappingBuilder.setAllowAllToAuthenticate(applicationBeanDirectoryMapping.getAuthenticationAllowAll()); + } + + if (applicationBeanDirectoryMapping.getAuthenticationGroups() != null) { + applicationDirectoryMappingBuilder.setAuthorisedGroupNames(new HashSet<>(applicationBeanDirectoryMapping.getAuthenticationGroups())); + } + + // the auto assignment groups must be set after these mappings have been persisted... + + if (applicationBeanDirectoryMapping.getAllowedOperations() != null) { + applicationDirectoryMappingBuilder.setAllowedOperations(new HashSet<>(applicationBeanDirectoryMapping.getAllowedOperations())); + } + + return applicationDirectoryMappingBuilder.build(); + } + + void addApplicationDirectoryMapping( + final Application application, + final ApplicationDirectoryMapping applicationDirectoryMapping) { + + try { + applicationManager.addDirectoryMapping( + application, + applicationDirectoryMapping.getDirectory(), + applicationDirectoryMapping.isAllowAllToAuthenticate(), + applicationDirectoryMapping.getAllowedOperations().toArray(new OperationType[0])); + } catch (ApplicationNotFoundException | DirectoryNotFoundException e) { + // both exceptions should not happy anymore at this stage, so handle as internal server error + throw new InternalServerErrorException(e); + } + } + + void updateApplicationDirectoryMapping( + final Application application, + final ApplicationDirectoryMapping applicationDirectoryMapping) { + + try { + applicationManager.updateDirectoryMapping( + application, + applicationDirectoryMapping.getDirectory(), + applicationDirectoryMapping.isAllowAllToAuthenticate(), + applicationDirectoryMapping.getAllowedOperations()); + } catch (ApplicationNotFoundException | DirectoryNotFoundException e) { + // both exceptions should not happy anymore at this stage, so handle as internal server error + throw new InternalServerErrorException(e); + } + } + + void removeApplicationDirectoryMapping( + final Application application, + final ApplicationDirectoryMapping applicationDirectoryMapping) { + + try { + applicationManager.removeDirectoryFromApplication(applicationDirectoryMapping.getDirectory(), application); + } catch (ApplicationManagerException e) { + throw new InternalServerErrorException(e); + } + } + + void addAuthenticationGroups( + final Application application, + final Directory directory, + final Collection authenticationGroupsToAdd) { + + for (String authenticationGroupToAdd : authenticationGroupsToAdd) { + try { + applicationManager.addGroupMapping(application, directory, authenticationGroupToAdd); + } catch (ApplicationNotFoundException e) { + throw new InternalServerErrorException(e); + } + } + } + + void removeAuthenticationGroups( + final Application application, + final Directory directory, + final Collection authenticationGroupsToRemove) { + + for (String authenticationGroupToRemove : authenticationGroupsToRemove) { + try { + applicationManager.removeGroupMapping(application, directory, authenticationGroupToRemove); + } catch (ApplicationNotFoundException e) { + throw new InternalServerErrorException(e); + } + } + } + + void addAutoAssignmentGroups( + final Application application, + final ApplicationDirectoryMapping applicationDirectoryMapping, + final Collection autoAssignmentGroupsToAdd, + final DefaultGroupMembershipService defaultGroupMembershipService) { + + for (String autoAssignmentGroupToAdd : autoAssignmentGroupsToAdd) { + try { + defaultGroupMembershipService.add(application, applicationDirectoryMapping, autoAssignmentGroupToAdd); + } catch (OperationFailedException e) { + throw new InternalServerErrorException(e); + } + } + } + + void removeAutoAssignmentGroups( + final Application application, + final ApplicationDirectoryMapping applicationDirectoryMapping, + final Collection autoAssignmentGroupsToRemove, + final DefaultGroupMembershipService defaultGroupMembershipService) { + + for (String autoAssignmentGroupToRemove : autoAssignmentGroupsToRemove) { + try { + defaultGroupMembershipService.remove(application, applicationDirectoryMapping, autoAssignmentGroupToRemove); + } catch (OperationFailedException e) { + throw new InternalServerErrorException(e); + } + } + } + + @Nonnull + private static Directory findDirectory( + final String directoryName, + final DirectoryManager directoryManager) { + + try { + return directoryManager.findDirectoryByName(directoryName); + } catch (DirectoryNotFoundException e) { + throw new BadRequestException(e); + } + } + } diff --git a/src/test/java/de/aservo/confapi/crowd/model/util/ApplicationBeanTest.java b/src/test/java/de/aservo/confapi/crowd/model/util/ApplicationBeanTest.java deleted file mode 100644 index a7b3508..0000000 --- a/src/test/java/de/aservo/confapi/crowd/model/util/ApplicationBeanTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package de.aservo.confapi.crowd.model.util; - -import com.atlassian.crowd.model.application.Application; -import com.atlassian.crowd.model.application.ApplicationType; -import de.aservo.confapi.crowd.model.util.ApplicationBeanUtil; -import de.aservo.confapi.crowd.model.ApplicationBean; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.runners.MockitoJUnitRunner; - -import static de.aservo.confapi.crowd.model.ApplicationBean.EXAMPLE_1; -import static de.aservo.confapi.crowd.model.util.ApplicationBeanUtil.*; -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertNull; - -@RunWith(MockitoJUnitRunner.class) -public class ApplicationBeanTest { - - @Test - public void testMapTypesApplication() { - for (ApplicationType type : ApplicationType.values()) { - assertEquals(type, toApplicationType(toApplicationBeanType(type))); - } - assertNull(toApplicationType(toApplicationBeanType(null))); - } - - @Test - public void testMapTypesApplicationBean() { - for (ApplicationBean.ApplicationType type : ApplicationBean.ApplicationType.values()) { - assertEquals(type, toApplicationBeanType(toApplicationType(type))); - } - assertNull(toApplicationBeanType(toApplicationType(null))); - } - - @Test - public void testToApplication() { - Application application = toApplication(EXAMPLE_1); - - assertEquals(EXAMPLE_1.getName(), application.getName()); - assertEquals(EXAMPLE_1.getType(), toApplicationBeanType(application.getType())); - assertEquals(EXAMPLE_1.getDescription(), application.getDescription()); - assertEquals(EXAMPLE_1.getActive().booleanValue(), application.isActive()); - assertEquals(application.getCredential().getCredential(), EXAMPLE_1.getPassword()); - assertEquals(EXAMPLE_1.getRemoteAddresses(), toStringCollection(application.getRemoteAddresses())); - } - - @Test - public void testToApplicationBean() { - Application application = toApplication(EXAMPLE_1); - ApplicationBean applicationBean = toApplicationBean(application); - - assertEquals(application.getName(), applicationBean.getName()); - assertEquals(application.getDescription(), applicationBean.getDescription()); - assertEquals(application.isActive(), applicationBean.getActive().booleanValue()); - assertEquals(toApplicationBeanType(application.getType()), applicationBean.getType()); - assertEquals(application.getRemoteAddresses(), toAddressSet(applicationBean.getRemoteAddresses())); - } -} diff --git a/src/test/java/de/aservo/confapi/crowd/model/util/ApplicationBeanUtilTest.java b/src/test/java/de/aservo/confapi/crowd/model/util/ApplicationBeanUtilTest.java new file mode 100644 index 0000000..bdaa57c --- /dev/null +++ b/src/test/java/de/aservo/confapi/crowd/model/util/ApplicationBeanUtilTest.java @@ -0,0 +1,134 @@ +package de.aservo.confapi.crowd.model.util; + +import com.atlassian.crowd.embedded.api.Directory; +import com.atlassian.crowd.embedded.api.DirectoryType; +import com.atlassian.crowd.exception.DirectoryNotFoundException; +import com.atlassian.crowd.exception.OperationFailedException; +import com.atlassian.crowd.manager.application.DefaultGroupMembershipService; +import com.atlassian.crowd.manager.directory.DirectoryManager; +import com.atlassian.crowd.model.application.*; +import com.atlassian.crowd.model.directory.ImmutableDirectory; +import de.aservo.confapi.crowd.model.ApplicationBean; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; + +import static de.aservo.confapi.crowd.model.ApplicationBean.EXAMPLE_1; +import static de.aservo.confapi.crowd.model.util.ApplicationBeanUtil.*; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; + +@RunWith(MockitoJUnitRunner.class) +public class ApplicationBeanUtilTest { + + @Mock + private DefaultGroupMembershipService defaultGroupMembershipService; + + @Mock + private DirectoryManager directoryManager; + + @Before + public void setup() throws DirectoryNotFoundException { + } + + @Test + public void testMapTypesApplication() { + for (ApplicationType type : ApplicationType.values()) { + assertEquals(type, toApplicationType(toApplicationBeanType(type))); + } + assertNull(toApplicationType(toApplicationBeanType(null))); + } + + @Test + public void testMapTypesApplicationBean() { + for (ApplicationBean.ApplicationType type : ApplicationBean.ApplicationType.values()) { + assertEquals(type, toApplicationBeanType(toApplicationType(type))); + } + assertNull(toApplicationBeanType(toApplicationType(null))); + } + + @Test + public void testToApplication() { + Application application = toApplication(EXAMPLE_1); + + assertEquals(EXAMPLE_1.getName(), application.getName()); + assertEquals(EXAMPLE_1.getType(), toApplicationBeanType(application.getType())); + assertEquals(EXAMPLE_1.getDescription(), application.getDescription()); + assertEquals(EXAMPLE_1.getActive().booleanValue(), application.isActive()); + assertEquals(application.getCredential().getCredential(), EXAMPLE_1.getPassword()); + assertEquals(EXAMPLE_1.getRemoteAddresses(), toStringCollection(application.getRemoteAddresses())); + } + + @Test + public void testToApplicationBean() { + Application application = toApplication(EXAMPLE_1); + ApplicationBean applicationBean = toApplicationBean(application, defaultGroupMembershipService); + + assertEquals(application.getName(), applicationBean.getName()); + assertEquals(application.getDescription(), applicationBean.getDescription()); + assertEquals(application.isActive(), applicationBean.getActive().booleanValue()); + assertEquals(toApplicationBeanType(application.getType()), applicationBean.getType()); + assertEquals(application.getRemoteAddresses(), toAddressSet(applicationBean.getRemoteAddresses())); + } + + @Test + public void testToApplicationBeanDirectoryMappings() throws OperationFailedException, DirectoryNotFoundException { + final ApplicationBean applicationBean = EXAMPLE_1; + final Application application = toApplication(applicationBean); + // since we cannot persist directory mappings together with the application, the `toApplication` method has no mapper for them, + // and for this reason the collection is empty + assertTrue(application.getApplicationDirectoryMappings().isEmpty()); + + final ApplicationBean.ApplicationDirectoryMapping applicationBeanDirectoryMapping = applicationBean.getDirectoryMappings().iterator().next(); + final Directory directory = ImmutableDirectory + .builder(applicationBeanDirectoryMapping.getDirectoryName(), DirectoryType.INTERNAL, "internal") + .setId(1L) + .build(); + doReturn(directory).when(directoryManager).findDirectoryByName(directory.getName()); + + // since we cannot persist directory mappings together with the application, the `toApplication` method has no mapper for them, + // and for this reason we need to construct the directory mapping of the application manually... + final ApplicationDirectoryMapping applicationDirectoryMapping = ImmutableApplicationDirectoryMapping.builder() + .setDirectory(directory) + .setAllowAllToAuthenticate(applicationBeanDirectoryMapping.getAuthenticationAllowAll()) + .setAuthorisedGroupNames(new HashSet<>(applicationBeanDirectoryMapping.getAuthenticationGroups())) + .setAllowedOperations(new HashSet<>(applicationBeanDirectoryMapping.getAllowedOperations())) + .build(); + // and for the same reason we now also need to create a new application with it... + final Application applicationWithDirectoryMappings = ImmutableApplication.builder(application) + .setApplicationDirectoryMappings(Collections.singletonList(applicationDirectoryMapping)) + .build(); + doReturn(new ArrayList<>(applicationBeanDirectoryMapping.getAutoAssignmentGroups())) + .when(defaultGroupMembershipService).listAll(applicationWithDirectoryMappings, applicationDirectoryMapping); + + final Collection transformedApplicationBeanDirectoryMappings + = toApplicationBeanDirectoryMappings(applicationWithDirectoryMappings, defaultGroupMembershipService); + assertEquals(1, transformedApplicationBeanDirectoryMappings.size()); + + final ApplicationBean.ApplicationDirectoryMapping transformedApplicationBeanDirectoryMapping + = transformedApplicationBeanDirectoryMappings.iterator().next(); + assertEquals(applicationBeanDirectoryMapping.getDirectoryName(), transformedApplicationBeanDirectoryMapping.getDirectoryName()); + assertEquals(applicationBeanDirectoryMapping.getAuthenticationAllowAll(), transformedApplicationBeanDirectoryMapping.getAuthenticationAllowAll()); + // if all users are allowed to authenticate, then we also expect the groups that authenticate to be empty + assertEquals(applicationBeanDirectoryMapping.getAuthenticationAllowAll().booleanValue(), transformedApplicationBeanDirectoryMapping.getAuthenticationGroups().isEmpty()); + assertCollectionsEqual(applicationBeanDirectoryMapping.getAutoAssignmentGroups(), transformedApplicationBeanDirectoryMapping.getAutoAssignmentGroups()); + assertCollectionsEqual(applicationBeanDirectoryMapping.getAllowedOperations(), transformedApplicationBeanDirectoryMapping.getAllowedOperations()); + } + + private static void assertCollectionsEqual( + final Collection expected, + final Collection actual) { + + assertTrue(actual.containsAll(expected) && expected.containsAll(actual)); + } + +} diff --git a/src/test/java/de/aservo/confapi/crowd/service/ApplicationsServiceImplTest.java b/src/test/java/de/aservo/confapi/crowd/service/ApplicationsServiceTest.java similarity index 74% rename from src/test/java/de/aservo/confapi/crowd/service/ApplicationsServiceImplTest.java rename to src/test/java/de/aservo/confapi/crowd/service/ApplicationsServiceTest.java index bd1d05a..8486861 100644 --- a/src/test/java/de/aservo/confapi/crowd/service/ApplicationsServiceImplTest.java +++ b/src/test/java/de/aservo/confapi/crowd/service/ApplicationsServiceTest.java @@ -1,11 +1,18 @@ package de.aservo.confapi.crowd.service; + +import com.atlassian.crowd.embedded.api.Directory; +import com.atlassian.crowd.embedded.api.DirectoryType; import com.atlassian.crowd.exception.ApplicationAlreadyExistsException; import com.atlassian.crowd.exception.ApplicationNotFoundException; +import com.atlassian.crowd.exception.DirectoryNotFoundException; import com.atlassian.crowd.exception.InvalidCredentialException; import com.atlassian.crowd.manager.application.ApplicationManager; import com.atlassian.crowd.manager.application.ApplicationManagerException; +import com.atlassian.crowd.manager.application.DefaultGroupMembershipService; +import com.atlassian.crowd.manager.directory.DirectoryManager; import com.atlassian.crowd.model.application.Application; import com.atlassian.crowd.model.application.ImmutableApplication; +import com.atlassian.crowd.model.directory.ImmutableDirectory; import de.aservo.confapi.commons.exception.BadRequestException; import de.aservo.confapi.commons.exception.InternalServerErrorException; import de.aservo.confapi.commons.exception.NotFoundException; @@ -18,34 +25,84 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import static de.aservo.confapi.crowd.model.ApplicationBean.EXAMPLE_1; import static de.aservo.confapi.crowd.model.ApplicationBean.EXAMPLE_2; -import static de.aservo.confapi.crowd.model.util.ApplicationBeanUtil.*; -import static org.junit.Assert.*; +import static de.aservo.confapi.crowd.model.util.ApplicationBeanUtil.toApplication; +import static de.aservo.confapi.crowd.model.util.ApplicationBeanUtil.toStringCollection; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) -public class ApplicationsServiceImplTest { +public class ApplicationsServiceTest { @Mock private ApplicationManager applicationManager; + @Mock + private DefaultGroupMembershipService defaultGroupMembershipService; + + @Mock + private DirectoryManager directoryManager; + private ApplicationsServiceImpl applicationsService; @Before - public void setup() { - applicationsService = new ApplicationsServiceImpl(applicationManager); + public void setup() throws DirectoryNotFoundException { + for (Directory directory : getDirectories()) { + doReturn(directory).when(directoryManager).findDirectoryByName(directory.getName()); + } + + applicationsService = new ApplicationsServiceImpl(applicationManager, defaultGroupMembershipService, directoryManager); + } + + @Test + public void testGetApplication() throws ApplicationNotFoundException { + Application application = toApplication(EXAMPLE_1); + doReturn(application).when(applicationManager).findById(anyLong()); + + ApplicationBean resultingApplicationBean = applicationsService.getApplication(1L); + assertEquals(EXAMPLE_1.getName(), resultingApplicationBean.getName()); + assertEquals(EXAMPLE_1.getDescription(), resultingApplicationBean.getDescription()); + assertEquals(EXAMPLE_1.getActive(), resultingApplicationBean.getActive()); + assertEquals(EXAMPLE_1.getType(), resultingApplicationBean.getType()); + assertEquals(EXAMPLE_1.getRemoteAddresses(), resultingApplicationBean.getRemoteAddresses()); } @Test - public void testAddApplication() throws InvalidCredentialException, ApplicationAlreadyExistsException { + public void testGetApplications() { Application application = toApplication(EXAMPLE_1); + Collection applications = Collections.singletonList(application); + doReturn(applications).when(applicationManager).findAll(); + + ApplicationsBean applicationBeans = applicationsService.getApplications(); + assertNotNull(applicationBeans); + Collection applicationsCollection = applicationBeans.getApplications(); + assertNotNull(applicationsCollection); + assertEquals(1,applicationsCollection.size()); + + ApplicationBean resultApplicationBean = applicationsCollection.iterator().next(); + + assertEquals(EXAMPLE_1.getName(), resultApplicationBean.getName()); + assertEquals(EXAMPLE_1.getDescription(), resultApplicationBean.getDescription()); + assertEquals(EXAMPLE_1.getActive(), resultApplicationBean.getActive()); + assertEquals(EXAMPLE_1.getType(), resultApplicationBean.getType()); + assertEquals(EXAMPLE_1.getRemoteAddresses(), resultApplicationBean.getRemoteAddresses()); + } + + @Test + public void testAddApplication() throws InvalidCredentialException, ApplicationAlreadyExistsException, ApplicationNotFoundException { + Application application = toApplication(EXAMPLE_1); + doReturn(application).when(applicationManager).findById(application.getId()); doReturn(application).when(applicationManager).add(application); - ApplicationBean resultApplicationBean = applicationsService.addApplication(EXAMPLE_1); + ApplicationBean resultApplicationBean = applicationsService.addApplication(EXAMPLE_1); assertEquals(EXAMPLE_1.getActive(), resultApplicationBean.getActive()); assertEquals(EXAMPLE_1.getName(), resultApplicationBean.getName()); assertEquals(EXAMPLE_1.getDescription(), resultApplicationBean.getDescription()); @@ -53,14 +110,30 @@ public void testAddApplication() throws InvalidCredentialException, ApplicationA assertEquals(EXAMPLE_1.getRemoteAddresses(), resultApplicationBean.getRemoteAddresses()); } + @Test + public void testAddApplicationEnsurePersistenceCalls() throws InvalidCredentialException, ApplicationAlreadyExistsException, ApplicationNotFoundException { + final ApplicationBean applicationBean = EXAMPLE_1; + final Application applicationWithDirectoryMappings = ImmutableApplication.builder(toApplication(applicationBean)) + .setApplicationDirectoryMappings(applicationsService.toApplicationDirectoryMappings(applicationBean.getDirectoryMappings())) + .build(); + doReturn(applicationWithDirectoryMappings).when(applicationManager).add(any(Application.class)); + doReturn(applicationWithDirectoryMappings).when(applicationManager).findById(applicationWithDirectoryMappings.getId()); + + final ApplicationsServiceImpl spy = spy(applicationsService); + spy.addApplication(applicationBean); + verify(spy).persistApplicationDirectoryMappings(any(), any()); + verify(spy).persistApplicationBeanAuthenticationGroups(any(), any()); + verify(spy).persistApplicationBeanAutoAssignmentGroups(any(), any()); + } + @Test public void testSetApplicationAllAttributes() throws ApplicationNotFoundException, ApplicationManagerException { Application application1 = toApplication(EXAMPLE_1); ApplicationBean requestApplicationBean = new ApplicationBean(); + requestApplicationBean.setId(application1.getId()); requestApplicationBean.setName("Changed Name"); requestApplicationBean.setDescription("Changed Description"); requestApplicationBean.setActive(false); - requestApplicationBean.setType(ApplicationBean.ApplicationType.BAMBOO); requestApplicationBean.setRemoteAddresses(Collections.singletonList("127.0.0.5")); Application application2 = toApplication(requestApplicationBean); @@ -76,7 +149,7 @@ public void testSetApplicationAllAttributes() throws ApplicationNotFoundExceptio assertEquals(requestApplicationBean.getName(), updatedApplication.getName()); assertEquals(requestApplicationBean.getDescription(), updatedApplication.getDescription()); assertEquals(requestApplicationBean.getActive(), updatedApplication.isActive()); - assertEquals(requestApplicationBean.getType(), toApplicationBeanType(updatedApplication.getType())); + // it's not possible to change the application type assertEquals(requestApplicationBean.getRemoteAddresses() , toStringCollection(updatedApplication.getRemoteAddresses())); } @@ -101,7 +174,23 @@ public void testSetApplicationNoAttributes() throws ApplicationNotFoundException } @Test - public void testSetApplications() throws ApplicationNotFoundException, ApplicationManagerException { + public void testSetApplicationEnsurePersistenceCalls() throws ApplicationNotFoundException, ApplicationManagerException { + final ApplicationBean applicationBean = EXAMPLE_1; + final Application applicationWithDirectoryMappings = ImmutableApplication.builder(toApplication(applicationBean)) + .setApplicationDirectoryMappings(applicationsService.toApplicationDirectoryMappings(applicationBean.getDirectoryMappings())) + .build(); + doReturn(applicationWithDirectoryMappings).when(applicationManager).findById(applicationWithDirectoryMappings.getId()); + doReturn(applicationWithDirectoryMappings).when(applicationManager).update(any(Application.class)); + + final ApplicationsServiceImpl spy = spy(applicationsService); + spy.setApplication(applicationBean.getId(), applicationBean); + verify(spy).persistApplicationDirectoryMappings(any(), any()); + verify(spy).persistApplicationBeanAuthenticationGroups(any(), any()); + verify(spy).persistApplicationBeanAutoAssignmentGroups(any(), any()); + } + + @Test + public void testSetApplications() throws ApplicationNotFoundException { Application applicationExample1 = ImmutableApplication.builder(toApplication(EXAMPLE_1)) .setId(EXAMPLE_1.getId()) .build(); @@ -161,6 +250,8 @@ public void testDeleteApplications() throws ApplicationNotFoundException { verify(spy).deleteApplication(application2.getId()); } + // exception test cases to feed Sonarqube + @Test(expected = BadRequestException.class) public void testDeleteApplicationsForceFalse() { doReturn(Collections.emptyList()).when(applicationManager).findAll(); @@ -199,44 +290,19 @@ public void testAddApplicationCredentialsException() throws ApplicationAlreadyEx applicationsService.addApplication(EXAMPLE_1); } - @Test - public void testGetApplication() throws ApplicationNotFoundException { - Application application = toApplication(EXAMPLE_1); - doReturn(application).when(applicationManager).findById(anyLong()); - - ApplicationBean resultingApplicationBean = applicationsService.getApplication(1L); - assertEquals(EXAMPLE_1.getName(), resultingApplicationBean.getName()); - assertEquals(EXAMPLE_1.getDescription(), resultingApplicationBean.getDescription()); - assertEquals(EXAMPLE_1.getActive(), resultingApplicationBean.getActive()); - assertEquals(EXAMPLE_1.getType(), resultingApplicationBean.getType()); - assertEquals(EXAMPLE_1.getRemoteAddresses(), resultingApplicationBean.getRemoteAddresses()); - } - @Test(expected = NotFoundException.class) public void testGetApplicationException() throws ApplicationNotFoundException { doThrow(new ApplicationNotFoundException("")).when(applicationManager).findById(anyLong()); applicationsService.getApplication(1L); } - @Test - public void testGetApplications() { - Application application = toApplication(EXAMPLE_1); - Collection applications = Collections.singletonList(application); - - doReturn(applications).when(applicationManager).findAll(); - - ApplicationsBean applicationBeans = applicationsService.getApplications(); - assertNotNull(applicationBeans); - Collection applicationsCollection = applicationBeans.getApplications(); - assertNotNull(applicationsCollection); - assertEquals(1,applicationsCollection.size()); - - ApplicationBean resultApplicationBean = applicationsCollection.iterator().next(); + private static Collection getDirectories() { + final Directory directory = ImmutableDirectory + .builder("directory", DirectoryType.INTERNAL, "internal") + .setId(1L) + .build(); - assertEquals(EXAMPLE_1.getName(), resultApplicationBean.getName()); - assertEquals(EXAMPLE_1.getDescription(), resultApplicationBean.getDescription()); - assertEquals(EXAMPLE_1.getActive(), resultApplicationBean.getActive()); - assertEquals(EXAMPLE_1.getType(), resultApplicationBean.getType()); - assertEquals(EXAMPLE_1.getRemoteAddresses(), resultApplicationBean.getRemoteAddresses()); + return Collections.singletonList(directory); } + } diff --git a/src/test/java/de/aservo/confapi/crowd/service/LicensesServiceImplTest.java b/src/test/java/de/aservo/confapi/crowd/service/LicensesServiceTest.java similarity index 90% rename from src/test/java/de/aservo/confapi/crowd/service/LicensesServiceImplTest.java rename to src/test/java/de/aservo/confapi/crowd/service/LicensesServiceTest.java index 897ed16..7cef651 100644 --- a/src/test/java/de/aservo/confapi/crowd/service/LicensesServiceImplTest.java +++ b/src/test/java/de/aservo/confapi/crowd/service/LicensesServiceTest.java @@ -24,7 +24,7 @@ import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) -public class LicensesServiceImplTest { +public class LicensesServiceTest { @Mock private CrowdLicenseManager licenseManager; @@ -37,8 +37,8 @@ public void setup() { } @Test - public void testGetLicenses() throws CrowdLicenseManagerException { - CrowdLicense license = toMockCrowdLicense(EXAMPLE_2_DEVELOPER_LICENSE); + public void testGetLicenses() { + CrowdLicense license = toMockCrowdLicense(); doReturn(license).when(licenseManager).getLicense(); @@ -54,7 +54,7 @@ public void testGetLicenses() throws CrowdLicenseManagerException { @Test public void testAddLicense() throws CrowdLicenseManagerException { - CrowdLicense license = toMockCrowdLicense(EXAMPLE_2_DEVELOPER_LICENSE); + CrowdLicense license = toMockCrowdLicense(); doReturn(license).when(licenseManager).storeLicense(EXAMPLE_2_DEVELOPER_LICENSE.getKey()); @@ -74,7 +74,7 @@ public void testAddLicenseBadRequestException() throws CrowdLicenseManagerExcept licensesService.addLicense(EXAMPLE_2_DEVELOPER_LICENSE); } - private CrowdLicense toMockCrowdLicense(LicenseBean licenseBean) throws CrowdLicenseManagerException { + private CrowdLicense toMockCrowdLicense() { CrowdLicense license = mock(CrowdLicense.class); Organisation organisation = mock(Organisation.class);