diff --git a/index.adoc b/index.adoc index 546d8df..3eddf78 100644 --- a/index.adoc +++ b/index.adoc @@ -3940,7 +3940,7 @@ endif::internal-generation[] | permissions | -| DirectoryInternalPermissions +| DirectoryPermissions | | @@ -4002,67 +4002,6 @@ endif::internal-generation[] |=== -[#DirectoryInternalPermissions] -=== _DirectoryInternalPermissions_ - - - -[.fields-DirectoryInternalPermissions] -[cols="2,1,2,4,1"] -|=== -| Field Name| Required| Type| Description| Format - -| addGroup -| -| Boolean -| -| - -| addUser -| -| Boolean -| -| - -| modifyGroup -| -| Boolean -| -| - -| modifyUser -| -| Boolean -| -| - -| modifyGroupAttributes -| -| Boolean -| -| - -| modifyUserAttributes -| -| Boolean -| -| - -| removeGroup -| -| Boolean -| -| - -| removeUser -| -| Boolean -| -| - -|=== - - [#DirectoryLdapBean] === _DirectoryLdapBean_ @@ -4235,6 +4174,67 @@ endif::internal-generation[] |=== +[#DirectoryPermissions] +=== _DirectoryPermissions_ + + + +[.fields-DirectoryPermissions] +[cols="2,1,2,4,1"] +|=== +| Field Name| Required| Type| Description| Format + +| addGroup +| +| Boolean +| +| + +| addUser +| +| Boolean +| +| + +| modifyGroup +| +| Boolean +| +| + +| modifyUser +| +| Boolean +| +| + +| modifyGroupAttributes +| +| Boolean +| +| + +| modifyUserAttributes +| +| Boolean +| +| + +| removeGroup +| +| Boolean +| +| + +| removeUser +| +| Boolean +| +| + +|=== + + [#ErrorCollection] === _ErrorCollection_ diff --git a/pom.xml b/pom.xml index 9d7f0ec..f208ab9 100644 --- a/pom.xml +++ b/pom.xml @@ -60,13 +60,13 @@ - 5.1.3 + 5.1.5 4.4.0 8409 8.0.2 ${project.groupId}.${project.artifactId} 2.1.5 - 0.0.34 + 0.1.0-SNAPSHOT 2.0.1 8 diff --git a/src/main/java/de/aservo/confapi/crowd/model/util/DirectoryBeanUtil.java b/src/main/java/de/aservo/confapi/crowd/model/util/DirectoryBeanUtil.java index 8620af6..537dbfc 100644 --- a/src/main/java/de/aservo/confapi/crowd/model/util/DirectoryBeanUtil.java +++ b/src/main/java/de/aservo/confapi/crowd/model/util/DirectoryBeanUtil.java @@ -1,22 +1,30 @@ package de.aservo.confapi.crowd.model.util; +import com.atlassian.crowd.directory.AbstractInternalDirectory; +import com.atlassian.crowd.directory.DelegatedAuthenticationDirectory; +import com.atlassian.crowd.directory.SynchronisableDirectoryProperties; +import com.atlassian.crowd.directory.ldap.LDAPPropertiesMapper; +import com.atlassian.crowd.directory.ldap.LdapSecureMode; import com.atlassian.crowd.embedded.api.Directory; import com.atlassian.crowd.embedded.api.DirectoryType; import com.atlassian.crowd.embedded.api.OperationType; import com.atlassian.crowd.model.directory.ImmutableDirectory; import de.aservo.confapi.commons.model.AbstractDirectoryBean; import de.aservo.confapi.commons.model.DirectoryCrowdBean; +import de.aservo.confapi.commons.model.DirectoryDelegatingBean; import de.aservo.confapi.commons.model.DirectoryGenericBean; import de.aservo.confapi.commons.model.DirectoryInternalBean; import de.aservo.confapi.commons.model.DirectoryLdapBean; +import de.aservo.confapi.commons.model.type.DirectoryPermissions; +import lombok.Getter; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import static com.atlassian.crowd.directory.AbstractInternalDirectory.*; import static de.aservo.confapi.crowd.util.AttributeUtil.*; import static java.lang.Boolean.TRUE; @@ -24,6 +32,10 @@ public class DirectoryBeanUtil { public static final String ATTRIBUTE_USE_NESTED_GROUPS = "useNestedGroups"; + /* + * Methods for converting directories to directory beans. + */ + /** * Build directory bean. * @@ -36,62 +48,103 @@ public static AbstractDirectoryBean toDirectoryBean( if (directory.getType().equals(DirectoryType.INTERNAL)) { return toDirectoryInternalBean(directory); + } else if (directory.getType().equals(DirectoryType.DELEGATING)) { + return toDirectoryDelegatingBean(directory); } return toDirectoryGenericBean(directory); } + @Nonnull public static DirectoryInternalBean toDirectoryInternalBean( - final Directory directory) { + @Nonnull final Directory directory) { final DirectoryInternalBean directoryBean = new DirectoryInternalBean(); - directoryBean.setId(directory.getId()); - directoryBean.setName(directory.getName()); - directoryBean.setDescription(directory.getDescription()); - directoryBean.setActive(directory.isActive()); - directoryBean.setCreatedDate(directory.getCreatedDate()); - directoryBean.setUpdatedDate(directory.getUpdatedDate()); + setDirectoryBeanDetails(directoryBean, directory); final Map attributes = new HashMap<>(directory.getAttributes()); - final Set allowedOperations = new HashSet<>(directory.getAllowedOperations()); directoryBean.setCredentialPolicy(new DirectoryInternalBean.DirectoryInternalCredentialPolicy()); - directoryBean.getCredentialPolicy().setPasswordRegex(attributes.get(ATTRIBUTE_PASSWORD_REGEX)); - directoryBean.getCredentialPolicy().setPasswordComplexityMessage(attributes.get(ATTRIBUTE_PASSWORD_COMPLEXITY_MESSAGE)); - directoryBean.getCredentialPolicy().setPasswordMaxAttempts(toLong(attributes.get(ATTRIBUTE_PASSWORD_MAX_ATTEMPTS))); - directoryBean.getCredentialPolicy().setPasswordHistoryCount(toLong(attributes.get(ATTRIBUTE_PASSWORD_HISTORY_COUNT))); - directoryBean.getCredentialPolicy().setPasswordMaxChangeTime(toLong(attributes.get(ATTRIBUTE_PASSWORD_MAX_CHANGE_TIME))); - directoryBean.getCredentialPolicy().setPasswordExpiryNotificationDays(toIntegerList(attributes.get(ATTRIBUTE_PASSWORD_EXPIRATION_NOTIFICATION_PERIODS))); - directoryBean.getCredentialPolicy().setPasswordEncryptionMethod(attributes.get(ATTRIBUTE_USER_ENCRYPTION_METHOD)); + directoryBean.getCredentialPolicy().setPasswordRegex(attributes.get(AbstractInternalDirectory.ATTRIBUTE_PASSWORD_REGEX)); + directoryBean.getCredentialPolicy().setPasswordComplexityMessage(attributes.get(AbstractInternalDirectory.ATTRIBUTE_PASSWORD_COMPLEXITY_MESSAGE)); + directoryBean.getCredentialPolicy().setPasswordMaxAttempts(toLong(attributes.get(AbstractInternalDirectory.ATTRIBUTE_PASSWORD_MAX_ATTEMPTS))); + directoryBean.getCredentialPolicy().setPasswordHistoryCount(toLong(attributes.get(AbstractInternalDirectory.ATTRIBUTE_PASSWORD_HISTORY_COUNT))); + directoryBean.getCredentialPolicy().setPasswordMaxChangeTime(toLong(attributes.get(AbstractInternalDirectory.ATTRIBUTE_PASSWORD_MAX_CHANGE_TIME))); + directoryBean.getCredentialPolicy().setPasswordExpiryNotificationDays(toIntegerList(attributes.get(AbstractInternalDirectory.ATTRIBUTE_PASSWORD_EXPIRATION_NOTIFICATION_PERIODS))); + directoryBean.getCredentialPolicy().setPasswordEncryptionMethod(attributes.get(AbstractInternalDirectory.ATTRIBUTE_USER_ENCRYPTION_METHOD)); directoryBean.setAdvanced(new DirectoryInternalBean.DirectoryInternalAdvanced()); directoryBean.getAdvanced().setEnableNestedGroups(toBoolean(attributes.getOrDefault(ATTRIBUTE_USE_NESTED_GROUPS, "false"))); - directoryBean.setPermissions(new DirectoryInternalBean.DirectoryInternalPermissions()); - directoryBean.getPermissions().setAddGroup(allowedOperations.contains(OperationType.CREATE_GROUP)); - directoryBean.getPermissions().setAddUser(allowedOperations.contains(OperationType.CREATE_USER)); - directoryBean.getPermissions().setModifyGroup(allowedOperations.contains(OperationType.UPDATE_GROUP)); - directoryBean.getPermissions().setModifyUser(allowedOperations.contains(OperationType.UPDATE_USER)); - directoryBean.getPermissions().setModifyGroupAttributes(allowedOperations.contains(OperationType.UPDATE_GROUP_ATTRIBUTE)); - directoryBean.getPermissions().setModifyUserAttributes(allowedOperations.contains(OperationType.UPDATE_USER_ATTRIBUTE)); - directoryBean.getPermissions().setRemoveGroup(allowedOperations.contains(OperationType.DELETE_GROUP)); - directoryBean.getPermissions().setRemoveUser(allowedOperations.contains(OperationType.DELETE_USER)); + setDirectoryBeanPermissions(directoryBean, directory); return directoryBean; } - private static DirectoryGenericBean toDirectoryGenericBean( + @Nonnull + public static DirectoryDelegatingBean toDirectoryDelegatingBean( + @Nonnull final Directory directory) { + + final DirectoryDelegatingBean directoryBean = new DirectoryDelegatingBean(); + setDirectoryBeanDetails(directoryBean, directory); + + directoryBean.setConnector(new DirectoryDelegatingBean.DirectoryDelegatingConnector()); + directoryBean.getConnector().setType(toDirectoryDelegatingConnectorType(directory)); + directoryBean.getConnector().setUrl(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_URL_KEY)); + directoryBean.getConnector().setSsl(toDirectoryDelegatingConnectorSslType(directory)); + directoryBean.getConnector().setUseNodeReferrals(toBoolean(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_REFERRAL_KEY))); + directoryBean.getConnector().setNestedGroupsDisabled(toBoolean(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_NESTED_GROUPS_DISABLED))); + directoryBean.getConnector().setSynchronizeUserDetails(toBoolean(directory.getAttributes().get(SynchronisableDirectoryProperties.INCREMENTAL_SYNC_ENABLED))); + directoryBean.getConnector().setSynchronizeGroupMemberships(toBoolean(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_USING_USER_MEMBERSHIP_ATTRIBUTE_FOR_GROUP_MEMBERSHIP))); + directoryBean.getConnector().setUsePagedResults(toBoolean(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_PAGEDRESULTS_KEY))); + directoryBean.getConnector().setPagedResultsSize(toInteger(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_PAGEDRESULTS_SIZE))); + directoryBean.getConnector().setReadTimeoutInMillis(toInteger(directory.getAttributes().get(SynchronisableDirectoryProperties.READ_TIMEOUT_IN_MILLISECONDS))); + directoryBean.getConnector().setSearchTimeoutInMillis(toInteger(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_SEARCH_TIMELIMIT))); + directoryBean.getConnector().setConnectionTimeoutInMillis(toInteger(directory.getAttributes().get(SynchronisableDirectoryProperties.CONNECTION_TIMEOUT_IN_MILLISECONDS))); + directoryBean.getConnector().setBaseDn(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_BASEDN_KEY)); + directoryBean.getConnector().setUsername(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_USERDN_KEY)); + + directoryBean.setConfiguration(new DirectoryDelegatingBean.DirectoryDelegatingConfiguration()); + directoryBean.getConfiguration().setUserDn(directory.getAttributes().get(LDAPPropertiesMapper.USER_DN_ADDITION)); + directoryBean.getConfiguration().setUserObjectClass(directory.getAttributes().get(LDAPPropertiesMapper.USER_OBJECTCLASS_KEY)); + directoryBean.getConfiguration().setUserObjectFilter(directory.getAttributes().get(LDAPPropertiesMapper.USER_OBJECTFILTER_KEY)); + directoryBean.getConfiguration().setUserNameAttribute(directory.getAttributes().get(LDAPPropertiesMapper.USER_USERNAME_KEY)); + directoryBean.getConfiguration().setUserNameRdnAttribute(directory.getAttributes().get(LDAPPropertiesMapper.USER_USERNAME_RDN_KEY)); + directoryBean.getConfiguration().setUserFirstNameAttribute(directory.getAttributes().get(LDAPPropertiesMapper.USER_FIRSTNAME_KEY)); + directoryBean.getConfiguration().setUserLastNameAttribute(directory.getAttributes().get(LDAPPropertiesMapper.USER_LASTNAME_KEY)); + directoryBean.getConfiguration().setUserDisplayNameAttribute(directory.getAttributes().get(LDAPPropertiesMapper.USER_DISPLAYNAME_KEY)); + directoryBean.getConfiguration().setUserEmailAttribute(directory.getAttributes().get(LDAPPropertiesMapper.USER_EMAIL_KEY)); + directoryBean.getConfiguration().setUserGroupAttribute(directory.getAttributes().get(LDAPPropertiesMapper.USER_GROUP_KEY)); + directoryBean.getConfiguration().setUserUniqueIdAttribute(directory.getAttributes().get(LDAPPropertiesMapper.LDAP_EXTERNAL_ID)); + + setDirectoryBeanPermissions(directoryBean, directory); + + return directoryBean; + } + + private static DirectoryDelegatingBean.DirectoryDelegatingConnector.SslType toDirectoryDelegatingConnectorSslType( final Directory directory) { + final String ldapSecure = directory.getAttributes().get(LDAPPropertiesMapper.LDAP_SECURE_KEY); + // LdapSecureMode.fromString evaluates to the default value NONE ("false") if ldapSecure is null + final LdapSecureMode ldapSecureMode = LdapSecureMode.fromString(ldapSecure); + return DirectoryDelegatingBean.DirectoryDelegatingConnector.SslType.valueOf(ldapSecureMode.name().toUpperCase()); + } + + @Nonnull + private static DirectoryGenericBean toDirectoryGenericBean( + @Nonnull final Directory directory) { + final DirectoryGenericBean directoryBean = new DirectoryGenericBean(); - directoryBean.setId(directory.getId()); - directoryBean.setName(directory.getName()); - directoryBean.setDescription(directory.getDescription()); - directoryBean.setActive(directory.isActive()); + setDirectoryBeanDetails(directoryBean, directory); return directoryBean; } + /* + * Methods for converting directory beans to directories. + */ + /** * Build directory. * @@ -134,34 +187,12 @@ public static Directory toDirectory( if (DirectoryInternalBean.class.equals(directoryBean.getClass())) { final DirectoryInternalBean directoryInternalBean = (DirectoryInternalBean) directoryBean; - - final DirectoryInternalBean.DirectoryInternalCredentialPolicy credentialPolicy = directoryInternalBean.getCredentialPolicy(); - if (credentialPolicy != null) { - setAttributeIfNotNull(attributes, ATTRIBUTE_PASSWORD_REGEX, credentialPolicy.getPasswordRegex()); - setAttributeIfNotNull(attributes, ATTRIBUTE_PASSWORD_COMPLEXITY_MESSAGE, credentialPolicy.getPasswordComplexityMessage()); - setAttributeIfNotNull(attributes, ATTRIBUTE_PASSWORD_MAX_ATTEMPTS, fromLong(credentialPolicy.getPasswordMaxAttempts())); - setAttributeIfNotNull(attributes, ATTRIBUTE_PASSWORD_HISTORY_COUNT, fromLong(credentialPolicy.getPasswordHistoryCount())); - setAttributeIfNotNull(attributes, ATTRIBUTE_PASSWORD_MAX_CHANGE_TIME, fromLong(credentialPolicy.getPasswordMaxChangeTime())); - setAttributeIfNotNull(attributes, ATTRIBUTE_PASSWORD_EXPIRATION_NOTIFICATION_PERIODS, fromIntegerList(credentialPolicy.getPasswordExpiryNotificationDays())); - setAttributeIfNotNull(attributes, ATTRIBUTE_USER_ENCRYPTION_METHOD, credentialPolicy.getPasswordEncryptionMethod()); - } - - final DirectoryInternalBean.DirectoryInternalAdvanced advanced = directoryInternalBean.getAdvanced(); - if (advanced != null) { - setAttributeIfNotNull(attributes, ATTRIBUTE_USE_NESTED_GROUPS, fromBoolean(advanced.getEnableNestedGroups())); - } - - final DirectoryInternalBean.DirectoryInternalPermissions permissions = directoryInternalBean.getPermissions(); - if (permissions != null) { - setAllowedOperationIfNotNull(allowedOperations, OperationType.CREATE_GROUP, permissions.getAddGroup()); - setAllowedOperationIfNotNull(allowedOperations, OperationType.CREATE_USER, permissions.getAddUser()); - setAllowedOperationIfNotNull(allowedOperations, OperationType.UPDATE_GROUP, permissions.getModifyGroup()); - setAllowedOperationIfNotNull(allowedOperations, OperationType.UPDATE_USER, permissions.getModifyUser()); - setAllowedOperationIfNotNull(allowedOperations, OperationType.UPDATE_GROUP_ATTRIBUTE, permissions.getModifyGroupAttributes()); - setAllowedOperationIfNotNull(allowedOperations, OperationType.UPDATE_USER_ATTRIBUTE, permissions.getModifyUserAttributes()); - setAllowedOperationIfNotNull(allowedOperations, OperationType.DELETE_GROUP, permissions.getRemoveGroup()); - setAllowedOperationIfNotNull(allowedOperations, OperationType.DELETE_USER, permissions.getRemoveUser()); - } + setDirectoryAttributes(attributes, directoryInternalBean); + setDirectoryAllowedOperations(allowedOperations, directoryInternalBean); + } else if (DirectoryDelegatingBean.class.equals(directoryBean.getClass())) { + final DirectoryDelegatingBean directoryDelegatingBean = (DirectoryDelegatingBean) directoryBean; + setDirectoryAttributes(attributes, directoryDelegatingBean); + setDirectoryAllowedOperations(allowedOperations, directoryDelegatingBean); } return directoryBuilder @@ -170,6 +201,77 @@ public static Directory toDirectory( .build(); } + /* + * Private helper methods for converting directories to directory beans. + */ + + private static void setDirectoryBeanDetails( + final AbstractDirectoryBean directoryBean, + final Directory directory) { + + directoryBean.setId(directory.getId()); + directoryBean.setName(directory.getName()); + directoryBean.setDescription(directory.getDescription()); + directoryBean.setActive(directory.isActive()); + directoryBean.setCreatedDate(directory.getCreatedDate()); + directoryBean.setUpdatedDate(directory.getUpdatedDate()); + } + + private static void setDirectoryBeanPermissions( + final AbstractDirectoryBean directoryBean, + final Directory directory) { + + final DirectoryPermissions permissions = toDirectoryPermissions(directory); + + if (DirectoryInternalBean.class.equals(directoryBean.getClass())) { + DirectoryInternalBean directoryInternalBean = (DirectoryInternalBean) directoryBean; + directoryInternalBean.setPermissions(permissions); + } else if (DirectoryDelegatingBean.class.equals(directoryBean.getClass())) { + DirectoryDelegatingBean directoryDelegatingBean = (DirectoryDelegatingBean) directoryBean; + directoryDelegatingBean.setPermissions(permissions); + } + } + + private static DirectoryPermissions toDirectoryPermissions( + final Directory directory) { + + final Set allowedOperations = directory.getAllowedOperations(); + + final DirectoryPermissions permissions = new DirectoryPermissions(); + permissions.setAddGroup(allowedOperations.contains(OperationType.CREATE_GROUP)); + permissions.setAddUser(allowedOperations.contains(OperationType.CREATE_USER)); + permissions.setModifyGroup(allowedOperations.contains(OperationType.UPDATE_GROUP)); + permissions.setModifyUser(allowedOperations.contains(OperationType.UPDATE_USER)); + permissions.setModifyGroupAttributes(allowedOperations.contains(OperationType.UPDATE_GROUP_ATTRIBUTE)); + permissions.setModifyUserAttributes(allowedOperations.contains(OperationType.UPDATE_USER_ATTRIBUTE)); + permissions.setRemoveGroup(allowedOperations.contains(OperationType.DELETE_GROUP)); + permissions.setRemoveUser(allowedOperations.contains(OperationType.DELETE_USER)); + + return permissions; + } + + // There is no API from Crowd to get the connector type of a directory, + // so we need to implement all of it ourselves... + private static DirectoryDelegatingBean.DirectoryDelegatingConnector.ConnectorType toDirectoryDelegatingConnectorType( + final Directory directory) { + + final String implementationClass = directory.getAttributes().get(DelegatedAuthenticationDirectory.ATTRIBUTE_LDAP_DIRECTORY_CLASS); + + if (implementationClass != null) { + final DirectoryDelegatingConnectorTypeImplClass implClass = DirectoryDelegatingConnectorTypeImplClass.fromImplClass(implementationClass); + + if (implClass != null) { + return DirectoryDelegatingBean.DirectoryDelegatingConnector.ConnectorType.valueOf(implClass.name().toUpperCase()); + } + } + + return null; + } + + /* + * Private helper methods for converting directory beans to directories. + */ + @Nonnull private static DirectoryType toDirectoryType( @Nonnull final AbstractDirectoryBean directoryBean) { @@ -180,21 +282,138 @@ private static DirectoryType toDirectoryType( return DirectoryType.CROWD; } else if (DirectoryLdapBean.class.equals(directoryBean.getClass())) { return DirectoryType.AZURE_AD; + } else if (DirectoryDelegatingBean.class.equals(directoryBean.getClass())) { + return DirectoryType.DELEGATING; } return DirectoryType.UNKNOWN; } + @Nullable private static String toDirectoryImplClass( @Nonnull final AbstractDirectoryBean directoryBean) { - if (DirectoryInternalBean.class.equals(directoryBean.getClass())) { + if (DirectoryDelegatingBean.class.equals(directoryBean.getClass())) { + final DirectoryDelegatingBean directoryDelegatingBean = (DirectoryDelegatingBean) directoryBean; + return toDirectoryDelegatedConnectorTypeImplClass(directoryDelegatingBean.getConnector().getType()); + } else if (DirectoryInternalBean.class.equals(directoryBean.getClass())) { return "com.atlassian.crowd.directory.InternalDirectory"; } return null; } + private static void setDirectoryAttributes( + final Map attributes, + final DirectoryInternalBean directoryInternalBean) { + + final DirectoryInternalBean.DirectoryInternalCredentialPolicy credentialPolicy = directoryInternalBean.getCredentialPolicy(); + if (credentialPolicy != null) { + setAttributeIfNotNull(attributes, AbstractInternalDirectory.ATTRIBUTE_PASSWORD_REGEX, credentialPolicy.getPasswordRegex()); + setAttributeIfNotNull(attributes, AbstractInternalDirectory.ATTRIBUTE_PASSWORD_COMPLEXITY_MESSAGE, credentialPolicy.getPasswordComplexityMessage()); + setAttributeIfNotNull(attributes, AbstractInternalDirectory.ATTRIBUTE_PASSWORD_MAX_ATTEMPTS, fromLong(credentialPolicy.getPasswordMaxAttempts())); + setAttributeIfNotNull(attributes, AbstractInternalDirectory.ATTRIBUTE_PASSWORD_HISTORY_COUNT, fromLong(credentialPolicy.getPasswordHistoryCount())); + setAttributeIfNotNull(attributes, AbstractInternalDirectory.ATTRIBUTE_PASSWORD_MAX_CHANGE_TIME, fromLong(credentialPolicy.getPasswordMaxChangeTime())); + setAttributeIfNotNull(attributes, AbstractInternalDirectory.ATTRIBUTE_PASSWORD_EXPIRATION_NOTIFICATION_PERIODS, fromIntegerList(credentialPolicy.getPasswordExpiryNotificationDays())); + setAttributeIfNotNull(attributes, AbstractInternalDirectory.ATTRIBUTE_USER_ENCRYPTION_METHOD, credentialPolicy.getPasswordEncryptionMethod()); + } + + final DirectoryInternalBean.DirectoryInternalAdvanced advanced = directoryInternalBean.getAdvanced(); + if (advanced != null) { + setAttributeIfNotNull(attributes, ATTRIBUTE_USE_NESTED_GROUPS, fromBoolean(advanced.getEnableNestedGroups())); + } + } + + private static void setDirectoryAttributes( + final Map attributes, + final DirectoryDelegatingBean directoryDelegatingBean) { + + final DirectoryDelegatingBean.DirectoryDelegatingConnector connector = directoryDelegatingBean.getConnector(); + if (connector != null) { + setAttributeIfNotNull(attributes, DelegatedAuthenticationDirectory.ATTRIBUTE_LDAP_DIRECTORY_CLASS, toDirectoryDelegatedConnectorTypeImplClass(connector.getType())); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_URL_KEY, connector.getUrl()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_SECURE_KEY, toDirectoryDelegatingConnectorSecureModeName(connector.getSsl())); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_REFERRAL_KEY, fromBoolean(connector.getUseNodeReferrals())); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_NESTED_GROUPS_DISABLED, fromBoolean(connector.getNestedGroupsDisabled())); + setAttributeIfNotNull(attributes, SynchronisableDirectoryProperties.INCREMENTAL_SYNC_ENABLED, fromBoolean(connector.getSynchronizeUserDetails())); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_USING_USER_MEMBERSHIP_ATTRIBUTE_FOR_GROUP_MEMBERSHIP, fromBoolean(connector.getSynchronizeGroupMemberships())); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_PAGEDRESULTS_KEY, fromBoolean(connector.getUsePagedResults())); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_PAGEDRESULTS_SIZE, fromInteger(connector.getPagedResultsSize())); + setAttributeIfNotNull(attributes, SynchronisableDirectoryProperties.READ_TIMEOUT_IN_MILLISECONDS, fromInteger(connector.getReadTimeoutInMillis())); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_SEARCH_TIMELIMIT, fromInteger(connector.getSearchTimeoutInMillis())); + setAttributeIfNotNull(attributes, SynchronisableDirectoryProperties.CONNECTION_TIMEOUT_IN_MILLISECONDS, fromInteger(connector.getConnectionTimeoutInMillis())); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_BASEDN_KEY, connector.getBaseDn()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_USERDN_KEY, connector.getUsername()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_PASSWORD_KEY, connector.getPassword()); + } + + final DirectoryDelegatingBean.DirectoryDelegatingConfiguration configuration = directoryDelegatingBean.getConfiguration(); + if (configuration != null) { + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_DN_ADDITION, configuration.getUserDn()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_OBJECTCLASS_KEY, configuration.getUserObjectClass()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_OBJECTFILTER_KEY, configuration.getUserObjectFilter()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_USERNAME_KEY, configuration.getUserNameAttribute()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_USERNAME_RDN_KEY, configuration.getUserNameRdnAttribute()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_FIRSTNAME_KEY, configuration.getUserFirstNameAttribute()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_LASTNAME_KEY, configuration.getUserLastNameAttribute()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_DISPLAYNAME_KEY, configuration.getUserDisplayNameAttribute()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_EMAIL_KEY, configuration.getUserEmailAttribute()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.USER_GROUP_KEY, configuration.getUserGroupAttribute()); + setAttributeIfNotNull(attributes, LDAPPropertiesMapper.LDAP_EXTERNAL_ID, configuration.getUserUniqueIdAttribute()); + } + } + + private static String toDirectoryDelegatingConnectorSecureModeName( + final DirectoryDelegatingBean.DirectoryDelegatingConnector.SslType sslType) { + + if (sslType == null) { + return null; + } + + return LdapSecureMode.valueOf(sslType.name()).name(); + } + + private static void setDirectoryAllowedOperations( + final Set allowedOperations, + final AbstractDirectoryBean directoryBean) { + + final DirectoryPermissions permissions; + + if (DirectoryInternalBean.class.equals(directoryBean.getClass())) { + permissions = ((DirectoryInternalBean) directoryBean).getPermissions(); + } else if (DirectoryDelegatingBean.class.equals(directoryBean.getClass())) { + permissions = ((DirectoryDelegatingBean) directoryBean).getPermissions(); + } else { + permissions = null; + } + + if (permissions != null) { + setAllowedOperationIfNotNull(allowedOperations, OperationType.CREATE_GROUP, permissions.getAddGroup()); + setAllowedOperationIfNotNull(allowedOperations, OperationType.CREATE_USER, permissions.getAddUser()); + setAllowedOperationIfNotNull(allowedOperations, OperationType.UPDATE_GROUP, permissions.getModifyGroup()); + setAllowedOperationIfNotNull(allowedOperations, OperationType.UPDATE_USER, permissions.getModifyUser()); + setAllowedOperationIfNotNull(allowedOperations, OperationType.UPDATE_GROUP_ATTRIBUTE, permissions.getModifyGroupAttributes()); + setAllowedOperationIfNotNull(allowedOperations, OperationType.UPDATE_USER_ATTRIBUTE, permissions.getModifyUserAttributes()); + setAllowedOperationIfNotNull(allowedOperations, OperationType.DELETE_GROUP, permissions.getRemoveGroup()); + setAllowedOperationIfNotNull(allowedOperations, OperationType.DELETE_USER, permissions.getRemoveUser()); + } + } + + @Nullable + private static String toDirectoryDelegatedConnectorTypeImplClass( + final DirectoryDelegatingBean.DirectoryDelegatingConnector.ConnectorType connectorType) { + + if (connectorType == null) { + return null; + } + + return DirectoryDelegatingConnectorTypeImplClass.valueOf(connectorType.name()).getImplClass(); + } + + /* + * Other private helper methods. + */ + private static void setAttributeIfNotNull( final Map attributes, final String attribute, @@ -219,6 +438,26 @@ private static void setAllowedOperationIfNotNull( } } + @Getter + enum DirectoryDelegatingConnectorTypeImplClass { + MICROSOFT_ACTIVE_DIRECTORY("com.atlassian.crowd.directory.MicrosoftActiveDirectory"); + + private final String implClass; + + DirectoryDelegatingConnectorTypeImplClass(String implClass) { + this.implClass = implClass; + } + + public static DirectoryDelegatingConnectorTypeImplClass fromImplClass(String implClass) { + for (DirectoryDelegatingConnectorTypeImplClass directoryDelegatingConnectorTypeImplClass : DirectoryDelegatingConnectorTypeImplClass.values()) { + if (directoryDelegatingConnectorTypeImplClass.getImplClass().equals(implClass)) { + return directoryDelegatingConnectorTypeImplClass; + } + } + return null; + } + } + private DirectoryBeanUtil() { } diff --git a/src/main/java/de/aservo/confapi/crowd/util/AttributeUtil.java b/src/main/java/de/aservo/confapi/crowd/util/AttributeUtil.java index cc0def9..dbe733c 100644 --- a/src/main/java/de/aservo/confapi/crowd/util/AttributeUtil.java +++ b/src/main/java/de/aservo/confapi/crowd/util/AttributeUtil.java @@ -9,6 +9,17 @@ public class AttributeUtil { public static final String LIST_SEPARATOR = ","; + @Nullable + public static String fromInteger( + @Nullable final Integer value) { + + if (value == null) { + return null; + } + + return String.valueOf(value); + } + @Nullable public static String fromLong( @Nullable final Long value) { @@ -44,6 +55,17 @@ public static String fromIntegerList( .collect(Collectors.joining(LIST_SEPARATOR)); } + @Nullable + public static Integer toInteger( + @Nullable final String value) { + + if (value == null) { + return null; + } + + return Integer.valueOf(value); + } + @Nullable public static Long toLong( @Nullable final String value) { diff --git a/src/test/java/de/aservo/confapi/crowd/model/util/DirectoryBeanUtilTest.java b/src/test/java/de/aservo/confapi/crowd/model/util/DirectoryBeanUtilTest.java index 92452de..7dad58d 100644 --- a/src/test/java/de/aservo/confapi/crowd/model/util/DirectoryBeanUtilTest.java +++ b/src/test/java/de/aservo/confapi/crowd/model/util/DirectoryBeanUtilTest.java @@ -1,15 +1,23 @@ package de.aservo.confapi.crowd.model.util; +import com.atlassian.crowd.directory.DelegatedAuthenticationDirectory; +import com.atlassian.crowd.directory.SynchronisableDirectoryProperties; +import com.atlassian.crowd.directory.ldap.LDAPPropertiesMapper; +import com.atlassian.crowd.directory.ldap.LdapSecureMode; import com.atlassian.crowd.embedded.api.Directory; import com.atlassian.crowd.embedded.api.DirectoryType; import com.atlassian.crowd.embedded.api.MockDirectoryInternal; import com.atlassian.crowd.embedded.api.OperationType; +import com.atlassian.crowd.model.directory.ImmutableDirectory; import de.aservo.confapi.commons.model.AbstractDirectoryBean; +import de.aservo.confapi.commons.model.DirectoryDelegatingBean; import de.aservo.confapi.commons.model.DirectoryInternalBean; +import de.aservo.confapi.crowd.model.util.DirectoryBeanUtil.DirectoryDelegatingConnectorTypeImplClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.runners.MockitoJUnitRunner; +import java.util.Collections; import java.util.Map; import java.util.Set; @@ -24,8 +32,8 @@ public class DirectoryBeanUtilTest { @Test public void testToDirectoryInternalBean() { final Directory directory = new MockDirectoryInternal(); - final AbstractDirectoryBean directoryBean = DirectoryBeanUtil.toDirectoryBean(directory); + final AbstractDirectoryBean directoryBean = DirectoryBeanUtil.toDirectoryBean(directory); assertNotNull(directoryBean); assertEquals(directoryBean.getId(), directory.getId()); assertEquals(directoryBean.getName(), directory.getName()); @@ -44,12 +52,55 @@ public void testToDirectoryInternalBean() { assertEquals(attributes.get(ATTRIBUTE_USER_ENCRYPTION_METHOD), directoryInternalBean.getCredentialPolicy().getPasswordEncryptionMethod()); } + @Test + public void testToDirectoryDelegatingBean() { + final Directory directory = getDirectoryDelegating(); + + final DirectoryDelegatingBean directoryBean = (DirectoryDelegatingBean) DirectoryBeanUtil.toDirectoryBean(directory); + assertNotNull(directoryBean); + assertEquals(directoryBean.getId(), directory.getId()); + assertEquals(directoryBean.getName(), directory.getName()); + assertEquals(directoryBean.getDescription(), directory.getDescription()); + assertEquals(directoryBean.getActive(), directory.isActive()); + + final DirectoryDelegatingBean.DirectoryDelegatingConnector connector = directoryBean.getConnector(); + assertNotNull(connector); + assertEquals(DirectoryDelegatingConnectorTypeImplClass.MICROSOFT_ACTIVE_DIRECTORY.getImplClass(), directory.getValue(DelegatedAuthenticationDirectory.ATTRIBUTE_LDAP_DIRECTORY_CLASS)); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_URL_KEY), connector.getUrl()); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_SECURE_KEY), LdapSecureMode.valueOf(connector.getSsl().name()).getName()); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_REFERRAL_KEY), String.valueOf(connector.getUseNodeReferrals())); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_NESTED_GROUPS_DISABLED), String.valueOf(connector.getNestedGroupsDisabled())); + assertEquals(directory.getValue(SynchronisableDirectoryProperties.INCREMENTAL_SYNC_ENABLED), String.valueOf(connector.getSynchronizeUserDetails())); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_USING_USER_MEMBERSHIP_ATTRIBUTE_FOR_GROUP_MEMBERSHIP), String.valueOf(connector.getSynchronizeGroupMemberships())); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_PAGEDRESULTS_KEY), String.valueOf(connector.getUsePagedResults())); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_PAGEDRESULTS_SIZE), String.valueOf(connector.getPagedResultsSize())); + assertEquals(directory.getValue(SynchronisableDirectoryProperties.READ_TIMEOUT_IN_MILLISECONDS), String.valueOf(connector.getReadTimeoutInMillis())); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_SEARCH_TIMELIMIT), String.valueOf(connector.getSearchTimeoutInMillis())); + assertEquals(directory.getValue(SynchronisableDirectoryProperties.CONNECTION_TIMEOUT_IN_MILLISECONDS), String.valueOf(connector.getConnectionTimeoutInMillis())); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_BASEDN_KEY), connector.getBaseDn()); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_USERDN_KEY), connector.getUsername()); + + final DirectoryDelegatingBean.DirectoryDelegatingConfiguration configuration = directoryBean.getConfiguration(); + assertNotNull(configuration); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_DN_ADDITION), configuration.getUserDn()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_OBJECTCLASS_KEY), configuration.getUserObjectClass()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_OBJECTFILTER_KEY), configuration.getUserObjectFilter()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_USERNAME_KEY), configuration.getUserNameAttribute()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_USERNAME_RDN_KEY), configuration.getUserNameRdnAttribute()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_FIRSTNAME_KEY), configuration.getUserFirstNameAttribute()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_LASTNAME_KEY), configuration.getUserLastNameAttribute()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_DISPLAYNAME_KEY), configuration.getUserDisplayNameAttribute()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_EMAIL_KEY), configuration.getUserEmailAttribute()); + assertEquals(directory.getValue(LDAPPropertiesMapper.USER_GROUP_KEY), configuration.getUserGroupAttribute()); + assertEquals(directory.getValue(LDAPPropertiesMapper.LDAP_EXTERNAL_ID), configuration.getUserUniqueIdAttribute()); + } + @Test public void testToDirectoryGenericBean() { final Directory directory = spy(new MockDirectoryInternal()); doReturn(DirectoryType.CUSTOM).when(directory).getType(); - final AbstractDirectoryBean directoryBean = DirectoryBeanUtil.toDirectoryBean(directory); + final AbstractDirectoryBean directoryBean = DirectoryBeanUtil.toDirectoryBean(directory); assertNotNull(directoryBean); assertEquals(directoryBean.getId(), directory.getId()); assertEquals(directoryBean.getName(), directory.getName()); @@ -58,17 +109,8 @@ public void testToDirectoryGenericBean() { } @Test - public void testToDirectory() { + public void testDirectoryInternalBeanToDirectory() { final DirectoryInternalBean directoryBean = DirectoryInternalBean.EXAMPLE_1; - directoryBean.setPermissions(new DirectoryInternalBean.DirectoryInternalPermissions()); - directoryBean.getPermissions().setAddGroup(true); - directoryBean.getPermissions().setAddUser(true); - directoryBean.getPermissions().setModifyGroup(true); - directoryBean.getPermissions().setModifyUser(true); - directoryBean.getPermissions().setModifyGroupAttributes(true); - directoryBean.getPermissions().setModifyUserAttributes(true); - directoryBean.getPermissions().setRemoveGroup(true); - directoryBean.getPermissions().setRemoveUser(true); final Directory directory = DirectoryBeanUtil.toDirectory(directoryBean); assertNotNull(directory); @@ -96,4 +138,55 @@ public void testToDirectory() { assertEquals(directoryBean.getPermissions().getRemoveUser(), allowedOperations.contains(OperationType.DELETE_USER)); } + @Test + public void testDirectoryDelegatingBeanToDirectory() { + final DirectoryDelegatingBean directoryBean = DirectoryDelegatingBean.EXAMPLE_1; + + final Directory directory = DirectoryBeanUtil.toDirectory(directoryBean); + assertNotNull(directory); + assertEquals(directoryBean.getName(), directory.getName()); + assertEquals(directoryBean.getDescription(), directory.getDescription()); + assertEquals(directoryBean.getActive(), directory.isActive()); + assertEquals(DirectoryType.DELEGATING, directory.getType()); + } + + private Directory getDirectoryDelegating() { + final ImmutableDirectory.Builder directoryBuilder = ImmutableDirectory.builder("Delegating Directory", DirectoryType.DELEGATING, + DirectoryDelegatingConnectorTypeImplClass.MICROSOFT_ACTIVE_DIRECTORY.getImplClass()) + .setId(2L) + // Don't set any allowed operations, because we have all enabled in the DirectoryDelegatingBean example + .setAllowedOperations(Collections.emptySet()) + // Connector attributes + .setAttribute(DelegatedAuthenticationDirectory.ATTRIBUTE_LDAP_DIRECTORY_CLASS, DirectoryDelegatingConnectorTypeImplClass.MICROSOFT_ACTIVE_DIRECTORY.getImplClass()) + .setAttribute(LDAPPropertiesMapper.LDAP_URL_KEY, "ldap://example.com:389") + .setAttribute(LDAPPropertiesMapper.LDAP_SECURE_KEY, LdapSecureMode.START_TLS.getName()) + .setAttribute(LDAPPropertiesMapper.LDAP_REFERRAL_KEY, String.valueOf(true)) + .setAttribute(LDAPPropertiesMapper.LDAP_NESTED_GROUPS_DISABLED, String.valueOf(false)) + .setAttribute(SynchronisableDirectoryProperties.INCREMENTAL_SYNC_ENABLED, String.valueOf(true)) + .setAttribute(LDAPPropertiesMapper.LDAP_USING_USER_MEMBERSHIP_ATTRIBUTE_FOR_GROUP_MEMBERSHIP, String.valueOf(true)) + .setAttribute(LDAPPropertiesMapper.LDAP_PAGEDRESULTS_KEY, String.valueOf(true)) + .setAttribute(LDAPPropertiesMapper.LDAP_PAGEDRESULTS_SIZE, String.valueOf(999)) + .setAttribute(SynchronisableDirectoryProperties.READ_TIMEOUT_IN_MILLISECONDS, String.valueOf(123000)) + .setAttribute(LDAPPropertiesMapper.LDAP_SEARCH_TIMELIMIT, String.valueOf(456000)) + .setAttribute(SynchronisableDirectoryProperties.CONNECTION_TIMEOUT_IN_MILLISECONDS, String.valueOf(789000)) + .setAttribute(LDAPPropertiesMapper.LDAP_BASEDN_KEY, "baseDn") + .setAttribute(LDAPPropertiesMapper.LDAP_USERDN_KEY, "userDn") + .setAttribute(LDAPPropertiesMapper.LDAP_PASSWORD_KEY, "password") + // Configuration attributes + .setAttribute(LDAPPropertiesMapper.USER_DN_ADDITION, "userDnAddition") + .setAttribute(LDAPPropertiesMapper.USER_OBJECTCLASS_KEY, "userObjectClass") + .setAttribute(LDAPPropertiesMapper.USER_OBJECTFILTER_KEY, "userObjectFilter") + .setAttribute(LDAPPropertiesMapper.USER_USERNAME_KEY, "userName") + .setAttribute(LDAPPropertiesMapper.USER_USERNAME_RDN_KEY, "userNameRdn") + .setAttribute(LDAPPropertiesMapper.USER_FIRSTNAME_KEY, "userFirstName") + .setAttribute(LDAPPropertiesMapper.USER_LASTNAME_KEY, "userLastName") + .setAttribute(LDAPPropertiesMapper.USER_DISPLAYNAME_KEY, "userDisplayName") + .setAttribute(LDAPPropertiesMapper.USER_EMAIL_KEY, "userEmail") + .setAttribute(LDAPPropertiesMapper.USER_GROUP_KEY, "userGroup") + .setAttribute(LDAPPropertiesMapper.LDAP_EXTERNAL_ID, "userUniqueId") + ; + + return directoryBuilder.build(); + } + }