Merge branch 'trunk' into branch-feature-AMBARI-20859
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/de4deaf0 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/de4deaf0 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/de4deaf0 Branch: refs/heads/branch-feature-AMBARI-20859 Commit: de4deaf0b04f69692c5226c31ad11deb228b367c Parents: b6cf432 c7cc560 Author: Robert Levas <[email protected]> Authored: Mon Dec 4 18:23:25 2017 -0500 Committer: Robert Levas <[email protected]> Committed: Mon Dec 4 18:23:25 2017 -0500 ---------------------------------------------------------------------- ...xternalServerAuthenticationProviderTest.java | 1 - .../controller/ResourceProviderFactory.java | 17 +- .../AbstractAuthorizedResourceProvider.java | 12 +- .../AbstractControllerResourceProvider.java | 81 +- .../internal/AbstractDRResourceProvider.java | 9 +- .../internal/ActionResourceProvider.java | 34 +- .../ActiveWidgetLayoutResourceProvider.java | 2 +- .../AlertDefinitionResourceProvider.java | 2 +- .../internal/AlertGroupResourceProvider.java | 2 +- .../internal/AlertHistoryResourceProvider.java | 2 +- .../internal/AlertNoticeResourceProvider.java | 2 +- .../internal/AlertResourceProvider.java | 2 +- .../internal/AlertTargetResourceProvider.java | 2 +- .../AmbariPrivilegeResourceProvider.java | 36 +- .../internal/BlueprintResourceProvider.java | 37 +- .../internal/ClientConfigResourceProvider.java | 31 +- ...usterKerberosDescriptorResourceProvider.java | 2 +- .../ClusterPrivilegeResourceProvider.java | 31 +- .../internal/ClusterResourceProvider.java | 23 +- .../ClusterStackVersionResourceProvider.java | 2 +- .../internal/ConfigGroupResourceProvider.java | 39 +- .../internal/ConfigurationResourceProvider.java | 2 +- .../internal/CredentialResourceProvider.java | 2 +- .../internal/DefaultProviderModule.java | 17 +- .../internal/ExtensionLinkResourceProvider.java | 33 +- .../internal/ExtensionResourceProvider.java | 27 +- .../ExtensionVersionResourceProvider.java | 32 +- .../internal/FeedResourceProvider.java | 41 +- .../GroupPrivilegeResourceProvider.java | 42 +- .../internal/GroupResourceProvider.java | 32 +- .../HostComponentProcessResourceProvider.java | 38 +- .../internal/HostComponentResourceProvider.java | 49 +- .../HostKerberosIdentityResourceProvider.java | 2 +- .../internal/HostResourceProvider.java | 51 +- .../HostStackVersionResourceProvider.java | 2 +- .../internal/InstanceResourceProvider.java | 35 +- .../internal/JobResourceProvider.java | 57 +- .../KerberosDescriptorResourceProvider.java | 20 +- .../internal/LdapSyncEventResourceProvider.java | 47 +- .../internal/LoggingResourceProvider.java | 9 +- .../internal/MemberResourceProvider.java | 29 +- .../OperatingSystemResourceProvider.java | 2 +- .../internal/PermissionResourceProvider.java | 25 +- .../internal/PrivilegeResourceProvider.java | 2 +- .../QuickLinkArtifactResourceProvider.java | 2 +- .../internal/ReadOnlyResourceProvider.java | 7 - .../RecommendationResourceProvider.java | 65 +- .../internal/RemoteClusterResourceProvider.java | 28 +- .../internal/RequestResourceProvider.java | 25 +- .../RequestScheduleResourceProvider.java | 55 +- .../RoleAuthorizationResourceProvider.java | 2 +- ...eComponentConfigurationResourceProvider.java | 2 +- .../RootServiceComponentResourceProvider.java | 31 +- ...ootServiceHostComponentResourceProvider.java | 34 +- .../internal/RootServiceResourceProvider.java | 26 +- .../ServiceConfigVersionResourceProvider.java | 2 +- .../internal/SettingResourceProvider.java | 2 +- .../internal/StackAdvisorResourceProvider.java | 7 +- .../internal/StackArtifactResourceProvider.java | 2 +- ...ConfigurationDependencyResourceProvider.java | 40 +- .../StackConfigurationResourceProvider.java | 42 +- .../StackDependencyResourceProvider.java | 41 +- ...StackLevelConfigurationResourceProvider.java | 40 +- .../internal/StackResourceProvider.java | 28 +- .../StackServiceComponentResourceProvider.java | 52 +- .../internal/StackServiceResourceProvider.java | 45 +- .../internal/StackVersionResourceProvider.java | 39 +- .../internal/StageResourceProvider.java | 2 +- .../internal/TargetClusterResourceProvider.java | 31 +- .../internal/TaskAttemptResourceProvider.java | 53 +- .../internal/TaskResourceProvider.java | 27 +- .../internal/ThemeArtifactResourceProvider.java | 2 +- .../internal/UpgradeGroupResourceProvider.java | 2 +- .../internal/UpgradeItemResourceProvider.java | 2 +- .../internal/UpgradeResourceProvider.java | 2 +- .../UpgradeSummaryResourceProvider.java | 2 +- .../UserAuthorizationResourceProvider.java | 2 +- .../internal/UserPrivilegeResourceProvider.java | 40 +- .../internal/UserResourceProvider.java | 23 +- .../internal/ValidationResourceProvider.java | 86 ++- .../VersionDefinitionResourceProvider.java | 2 +- .../internal/ViewInstanceResourceProvider.java | 55 +- .../ViewPermissionResourceProvider.java | 29 +- .../internal/ViewPrivilegeResourceProvider.java | 36 +- .../internal/ViewResourceProvider.java | 19 +- .../internal/ViewURLResourceProvider.java | 25 +- .../internal/ViewVersionResourceProvider.java | 45 +- .../internal/WidgetLayoutResourceProvider.java | 2 +- .../internal/WidgetResourceProvider.java | 2 +- .../internal/WorkflowResourceProvider.java | 54 +- .../controller/utilities/PropertyHelper.java | 6 +- .../system/impl/AmbariMetricSinkImpl.java | 2 - .../KAFKA/0.10.0/configuration/kafka-broker.xml | 2 +- .../src/main/resources/key_properties.json | 161 ---- .../src/main/resources/properties.json | 476 ------------ .../HDP/2.0.6/properties/stack_packages.json | 10 +- .../2.6/services/TEZ/configuration/tez-site.xml | 8 + .../HDP/3.0/properties/stack_packages.json | 9 - .../api/query/render/MinimalRendererTest.java | 6 + .../AbstractControllerResourceProviderTest.java | 10 +- .../AbstractDRResourceProviderTest.java | 2 - .../internal/AbstractResourceProviderTest.java | 26 +- .../internal/ActionResourceProviderTest.java | 4 - .../ActiveWidgetLayoutResourceProviderTest.java | 2 - .../internal/BlueprintResourceProviderTest.java | 21 +- .../ClientConfigResourceProviderTest.java | 10 - .../internal/ClusterControllerImplTest.java | 14 +- ...rKerberosDescriptorResourceProviderTest.java | 17 - .../internal/ClusterResourceProviderTest.java | 14 - ...ClusterStackVersionResourceProviderTest.java | 12 +- .../ConfigGroupResourceProviderTest.java | 2 - .../ConfigurationResourceProviderTest.java | 6 - .../CredentialResourceProviderTest.java | 23 - .../internal/ExtensionResourceProviderTest.java | 2 - .../internal/FeedResourceProviderTest.java | 29 +- .../internal/GroupResourceProviderTest.java | 8 - ...ostComponentProcessResourceProviderTest.java | 2 - .../HostComponentResourceProviderTest.java | 49 +- .../internal/HostResourceProviderTest.java | 53 +- .../HostStackVersionResourceProviderTest.java | 14 +- .../internal/InstanceResourceProviderTest.java | 29 +- .../internal/JMXHostProviderTest.java | 5 +- .../internal/JobResourceProviderTest.java | 37 +- .../KerberosDescriptorResourceProviderTest.java | 6 +- .../internal/MemberResourceProviderTest.java | 25 +- .../internal/RequestResourceProviderTest.java | 42 +- .../RequestScheduleResourceProviderTest.java | 2 - ...ootServiceComponentResourceProviderTest.java | 2 - ...erviceHostComponentResourceProviderTest.java | 2 - .../RootServiceResourceProviderTest.java | 2 - .../StackAdvisorResourceProviderTest.java | 12 +- .../StackArtifactResourceProviderTest.java | 2 - ...igurationDependencyResourceProviderTest.java | 2 - .../StackConfigurationResourceProviderTest.java | 4 - .../StackDependencyResourceProviderTest.java | 5 +- ...kLevelConfigurationResourceProviderTest.java | 4 - .../internal/StackResourceProviderTest.java | 2 - .../StackServiceResourceProviderTest.java | 4 - .../TargetClusterResourceProviderTest.java | 28 +- .../TaskAttemptResourceProviderTest.java | 2 +- .../internal/TaskResourceProviderTest.java | 22 +- .../internal/TestIvoryProviderModule.java | 6 +- .../internal/UpgradeResourceProviderTest.java | 4 +- .../ValidationResourceProviderTest.java | 3 +- .../internal/WorkflowResourceProviderTest.java | 30 +- ambari-web/app/assets/test/tests.js | 2 +- .../controllers/main/service/info/configs.js | 5 + ambari-web/app/data/db_properties_info.js | 15 +- ambari-web/app/messages.js | 6 +- .../mixins/common/configs/configs_comparator.js | 6 +- ambari-web/app/styles/application.less | 24 +- ambari-web/app/styles/bootstrap_overrides.less | 2 +- ambari-web/app/styles/config_history_flow.less | 414 ---------- .../app/styles/config_versions_control.less | 144 ++++ ambari-web/app/styles/widgets.less | 7 +- .../configs/config_history_dropdown_row.hbs | 24 - .../common/configs/config_history_flow.hbs | 148 ---- .../common/configs/config_versions_control.hbs | 42 ++ .../common/configs/config_versions_dropdown.hbs | 69 ++ .../templates/common/configs/service_config.hbs | 97 ++- ambari-web/app/views.js | 3 +- .../views/common/configs/config_history_flow.js | 644 ---------------- .../configs/config_versions_control_view.js | 235 ++++++ .../configs/config_versions_dropdown_view.js | 52 ++ .../views/common/configs/service_config_view.js | 66 ++ ambari-web/app/views/common/controls_view.js | 5 +- .../common/configs/config_history_flow_test.js | 756 ------------------- .../config_versions_control_view_test.js | 152 ++++ .../common/configs/service_config_view_test.js | 52 +- .../test/views/common/controls_view_test.js | 46 +- .../host_progress_popup_body_view_test.js | 9 +- 171 files changed, 2407 insertions(+), 4025 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/de4deaf0/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java ---------------------------------------------------------------------- diff --cc ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java index 523e21c,5b4967d..5849212 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ResourceProviderFactory.java @@@ -49,15 -42,8 +42,14 @@@ public interface ResourceProviderFactor ResourceProvider getComponentResourceProvider(AmbariManagementController managementController); @Named("member") - ResourceProvider getMemberResourceProvider(Set<String> propertyIds, Map<Type, String> keyPropertyIds, - AmbariManagementController managementController); + ResourceProvider getMemberResourceProvider(AmbariManagementController managementController); + @Named("user") + ResourceProvider getUserResourceProvider(AmbariManagementController managementController); + + @Named("userAuthenticationSource") + ResourceProvider getUserAuthenticationSourceResourceProvider(); + @Named("hostKerberosIdentity") ResourceProvider getHostKerberosIdentityResourceProvider(AmbariManagementController managementController); http://git-wip-us.apache.org/repos/asf/ambari/blob/de4deaf0/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java ---------------------------------------------------------------------- diff --cc ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java index a0a6eb1,f5e61ef..15006b0 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/AbstractControllerResourceProvider.java @@@ -165,19 -146,17 +146,19 @@@ public abstract class AbstractControlle case ServiceConfigVersion: return new ServiceConfigVersionResourceProvider(managementController); case Action: - return new ActionResourceProvider(propertyIds, keyPropertyIds, managementController); + return new ActionResourceProvider(managementController); case Request: - return new RequestResourceProvider(propertyIds, keyPropertyIds, managementController); + return new RequestResourceProvider(managementController); case Task: - return new TaskResourceProvider(propertyIds, keyPropertyIds, managementController); + return new TaskResourceProvider(managementController); case User: - return new UserResourceProvider(managementController); + return resourceProviderFactory.getUserResourceProvider(managementController); + case UserAuthenticationSource: + return resourceProviderFactory.getUserAuthenticationSourceResourceProvider(); case Group: - return new GroupResourceProvider(propertyIds, keyPropertyIds, managementController); + return new GroupResourceProvider(managementController); case Member: - return resourceProviderFactory.getMemberResourceProvider(propertyIds, keyPropertyIds, managementController); + return resourceProviderFactory.getMemberResourceProvider(managementController); case Upgrade: return resourceProviderFactory.getUpgradeResourceProvider(managementController); case Stack: http://git-wip-us.apache.org/repos/asf/ambari/blob/de4deaf0/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProvider.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/de4deaf0/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserPrivilegeResourceProvider.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/de4deaf0/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java ---------------------------------------------------------------------- diff --cc ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java index 90effac,f0709aa..6c26c9d --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/UserResourceProvider.java @@@ -58,10 -44,7 +58,10 @@@ import org.slf4j.Logger import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableMap; - import com.google.common.collect.ImmutableSet; + import com.google.common.collect.Sets; +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; +import com.google.inject.assistedinject.AssistedInject; /** * Resource provider for user resources. @@@ -72,80 -55,40 +72,81 @@@ public class UserResourceProvider exten // ----- Property ID constants --------------------------------------------- + public static final String USER_RESOURCE_CATEGORY = "Users"; + // Users - public static final String USER_USERNAME_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "user_name"); - public static final String USER_PASSWORD_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "password"); - public static final String USER_OLD_PASSWORD_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "old_password"); - public static final String USER_LDAP_USER_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "ldap_user"); - public static final String USER_TYPE_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "user_type"); - public static final String USER_ACTIVE_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "active"); - public static final String USER_GROUPS_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "groups"); - public static final String USER_ADMIN_PROPERTY_ID = PropertyHelper.getPropertyId("Users", "admin"); + public static final String USERNAME_PROPERTY_ID = "user_name"; + public static final String DISPLAY_NAME_PROPERTY_ID = "display_name"; + public static final String LOCAL_USERNAME_PROPERTY_ID = "local_user_name"; + public static final String ACTIVE_PROPERTY_ID = "active"; + public static final String CREATE_TIME_PROPERTY_ID = "created"; + public static final String CONSECUTIVE_FAILURES_PROPERTY_ID = "consecutive_failures"; + public static final String ADMIN_PROPERTY_ID = "admin"; + public static final String GROUPS_PROPERTY_ID = "groups"; + + public static final String USER_USERNAME_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + USERNAME_PROPERTY_ID; + public static final String USER_DISPLAY_NAME_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + DISPLAY_NAME_PROPERTY_ID; + public static final String USER_LOCAL_USERNAME_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + LOCAL_USERNAME_PROPERTY_ID; + public static final String USER_ACTIVE_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + ACTIVE_PROPERTY_ID; + public static final String USER_CREATE_TIME_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + CREATE_TIME_PROPERTY_ID; + public static final String USER_CONSECUTIVE_FAILURES_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + CONSECUTIVE_FAILURES_PROPERTY_ID; + public static final String USER_ADMIN_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + ADMIN_PROPERTY_ID; + public static final String USER_GROUPS_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + GROUPS_PROPERTY_ID; + + /* ******************************************************* + * Deprecated properties, kept for backwards compatibility and to maintain API V1 contract. + * These properties are related to a user's authentication resource. + * ******************************************************* */ + @Deprecated + public static final String PASSWORD_PROPERTY_ID = "password"; + @Deprecated + public static final String OLD_PASSWORD_PROPERTY_ID = "old_password"; + @Deprecated + public static final String LDAP_USER_PROPERTY_ID = "ldap_user"; + @Deprecated + public static final String USER_TYPE_PROPERTY_ID = "user_type"; + + @Deprecated + public static final String USER_PASSWORD_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + PASSWORD_PROPERTY_ID; + @Deprecated + public static final String USER_OLD_PASSWORD_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + OLD_PASSWORD_PROPERTY_ID; + @Deprecated + public static final String USER_LDAP_USER_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + LDAP_USER_PROPERTY_ID; + @Deprecated + public static final String USER_USER_TYPE_PROPERTY_ID = USER_RESOURCE_CATEGORY + "/" + USER_TYPE_PROPERTY_ID; + /* ******************************************************* */ - private static final Set<String> PK_PROPERTY_IDS = ImmutableSet.of( - USER_USERNAME_PROPERTY_ID - ); - private static final Set<String> PROPERTY_IDS = ImmutableSet.of( + /** + * The key property ids for a User resource. + */ + private static Map<Resource.Type, String> keyPropertyIds = ImmutableMap.<Resource.Type, String>builder() + .put(Resource.Type.User, USER_USERNAME_PROPERTY_ID) + .build(); + - /** - * The property ids for a User resource. - */ + private static Set<String> propertyIds = Sets.newHashSet( USER_USERNAME_PROPERTY_ID, + USER_DISPLAY_NAME_PROPERTY_ID, + USER_LOCAL_USERNAME_PROPERTY_ID, + USER_ACTIVE_PROPERTY_ID, + USER_CREATE_TIME_PROPERTY_ID, + USER_CONSECUTIVE_FAILURES_PROPERTY_ID, + USER_GROUPS_PROPERTY_ID, USER_PASSWORD_PROPERTY_ID, USER_OLD_PASSWORD_PROPERTY_ID, USER_LDAP_USER_PROPERTY_ID, - USER_TYPE_PROPERTY_ID, - USER_ACTIVE_PROPERTY_ID, - USER_GROUPS_PROPERTY_ID, - USER_ADMIN_PROPERTY_ID); + USER_USER_TYPE_PROPERTY_ID, + USER_ADMIN_PROPERTY_ID + ); - private static final Map<Resource.Type, String> KEY_PROPERTY_IDS = ImmutableMap.of( - Resource.Type.User, USER_USERNAME_PROPERTY_ID - ); + + @Inject + private Users users; + /** * Create a new resource provider for the given management controller. */ - UserResourceProvider(AmbariManagementController managementController) { + @AssistedInject + UserResourceProvider(@Assisted AmbariManagementController managementController) { - super(Resource.Type.User, PROPERTY_IDS, KEY_PROPERTY_IDS, managementController); + super(Resource.Type.User, propertyIds, keyPropertyIds, managementController); setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_USERS)); setRequiredDeleteAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_USERS)); @@@ -337,348 -260,6 +338,346 @@@ request.setAdmin(Boolean.valueOf(properties.get(USER_ADMIN_PROPERTY_ID).toString())); } + if (null != properties.get(USER_CONSECUTIVE_FAILURES_PROPERTY_ID)) { + request.setConsecutiveFailures(Integer.parseInt(properties.get(USER_CONSECUTIVE_FAILURES_PROPERTY_ID).toString())); + } + return request; } + + + /** + * Creates users. + * + * @param requests the request objects which define the user. + * @throws AmbariException when the user cannot be created. + */ + private void createUsers(Set<UserRequest> requests) throws AmbariException, ResourceAlreadyExistsException, AuthorizationException { + // First check for obvious issues... then try to create the accounts. This will help to avoid + // some accounts being created and some not due to an issue with one or more of the users. + for (UserRequest request : requests) { + String username = request.getUsername(); + + if (StringUtils.isEmpty(username)) { + throw new AmbariException("Username must be supplied."); + } + + if (users.getUser(username) != null) { + String message; + if (requests.size() == 1) { + message = "The requested username already exists."; + } else { + message = "One or more of the requested usernames already exists."; + } + throw new ResourceAlreadyExistsException(message); + } + } + + for (UserRequest request : requests) { + String username = request.getUsername(); + String displayName = StringUtils.defaultIfEmpty(request.getDisplayName(), username); + String localUserName = StringUtils.defaultIfEmpty(request.getLocalUserName(), username); + + UserEntity userEntity = users.createUser(username, localUserName, displayName, request.isActive()); + if (userEntity != null) { + if (Boolean.TRUE.equals(request.isAdmin())) { + users.grantAdminPrivilege(userEntity); + } + + // Setting a user's the password here is to allow for backward compatibility with pre-Ambari-3.0 + // versions so that the contract for REST API V1 is maintained. + if (!StringUtils.isEmpty(request.getPassword())) { + // This is performed as a user administrator since the authorization check was done prior + // to executing #createResourcesAuthorized. + addOrUpdateLocalAuthenticationSource(true, userEntity, request.getPassword(), null); + } + } + } + } + + /** + * Updates the users specified. + * + * @param requests the users to modify + * @throws AmbariException if the resources cannot be updated + * @throws IllegalArgumentException if the authenticated user is not authorized to update all of + * the requested properties + */ + private void updateUsers(Set<UserRequest> requests) throws AmbariException, AuthorizationException { + boolean asUserAdministrator = AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, + RoleAuthorization.AMBARI_MANAGE_USERS); + String authenticatedUsername = AuthorizationHelper.getAuthenticatedName(); + + for (final UserRequest request : requests) { + String requestedUsername = request.getUsername(); + + // An administrator can modify any user, else a user can only modify themself. + if (!asUserAdministrator && (!authenticatedUsername.equalsIgnoreCase(requestedUsername))) { + throw new AuthorizationException(); + } + + UserEntity userEntity = users.getUserEntity(requestedUsername); + if (null == userEntity) {// Only an user with the privs to manage users can update a user's active status + continue; + } + + boolean hasUpdates = false; + if (isValueChanged(request.isActive(), userEntity.getActive())) { + // If this value is being set, make sure the authenticated user is an administrator before + // allowing to change it. Only administrators should be able to change a user's active state + if (!asUserAdministrator) { + throw new AuthorizationException("The authenticated user is not authorized to update the requested user's active property"); + } + + hasUpdates = true; + } + + // Only an user with the privs to manage users can update a user's local username + if (isValueChanged(request.getLocalUserName(), userEntity.getLocalUsername())) { + // If this value is being set, make sure the authenticated user is an administrator before + // allowing to change it. Only administrators should be able to change a user's active state + if (!asUserAdministrator) { + throw new AuthorizationException("The authenticated user is not authorized to update the requested user's local username property"); + } + + hasUpdates = true; + } + + hasUpdates = hasUpdates || isValueChanged(request.getDisplayName(), userEntity.getDisplayName()); + + if (hasUpdates) { + users.safelyUpdateUserEntity(userEntity, + new Users.Command() { + @Override + public void perform(UserEntity userEntity) { + if (isValueChanged(request.isActive(), userEntity.getActive())) { + userEntity.setActive(request.isActive()); + } + + if (isValueChanged(request.getLocalUserName(), userEntity.getLocalUsername())) { + userEntity.setLocalUsername(request.getLocalUserName()); + } + + if (isValueChanged(request.getDisplayName(), userEntity.getDisplayName())) { + userEntity.setDisplayName(request.getDisplayName()); + } + } + }); + } + + // Only an user with the privs to manage users can update a user's roles + if (null != request.isAdmin()) { + // If this value is being set, make sure the authenticated user is an administrator before + // allowing to change it. Only administrators should be able to change a user's administrative + // privileges + if (!asUserAdministrator) { + throw new AuthorizationException("The authenticated user is not authorized to update the requested resource property"); + } + + if (request.isAdmin()) { + users.grantAdminPrivilege(userEntity); + } else { + users.revokeAdminPrivilege(userEntity); + } + } + + // Setting/Changing a user's password here is for backward compatibility to maintain API V1 contract + if (request.getPassword() != null) { + addOrUpdateLocalAuthenticationSource(asUserAdministrator, userEntity, request.getPassword(), request.getOldPassword()); + } + + if (request.getConsecutiveFailures() != null) { + if (!asUserAdministrator) { + throw new AuthorizationException("The authenticated user is not authorized to update the requested resource property"); + } + users.safelyUpdateUserEntity(userEntity, user -> user.setConsecutiveFailures(request.getConsecutiveFailures())); + } + } + } + + /** + * Adds to updates a user's local authentication source by issuing a call to the {@link UserAuthenticationSourceResourceProvider}. + * <p> + * This is for backward compatibility to maintain the contract for Ambari's REST API version V1. + * + * @param asUserAdministrator true if the authenticated user have privs to manage user; false otherwise + * @param subjectUserEntity the user to update + * @param password the password to set, it is expected that this value is not <code>null</code> + * @param oldPassword the old/current password to use for verification is needed, this value may be <code>null</code> + */ + private void addOrUpdateLocalAuthenticationSource(boolean asUserAdministrator, UserEntity subjectUserEntity, String password, String oldPassword) + throws AuthorizationException, AmbariException { + ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(Resource.Type.UserAuthenticationSource, - PropertyHelper.getPropertyIds(Resource.Type.UserAuthenticationSource), - PropertyHelper.getKeyPropertyIds(Resource.Type.UserAuthenticationSource), + getManagementController()); + + if (provider != null) { + // Determine if the user already has an LOCAL authentication source setup... + UserAuthenticationEntity userAuthenticationEntity = null; + List<UserAuthenticationEntity> authenticationEntities = subjectUserEntity.getAuthenticationEntities(); + for (UserAuthenticationEntity authenticationEntity : authenticationEntities) { + if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LOCAL) { + userAuthenticationEntity = authenticationEntity; + break; + } + } + if (userAuthenticationEntity == null) { + // a new authentication source needs to be create... only a privileged user can do this... + if (!asUserAdministrator) { + throw new AuthorizationException("The authenticated user is not authorized to create a local authentication source."); + } else { + Set<Map<String, Object>> propertiesSet = new HashSet<>(); + Map<String, Object> properties; + properties = new LinkedHashMap<>(); + properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID, subjectUserEntity.getUserName()); + properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_TYPE_PROPERTY_ID, UserAuthenticationType.LOCAL.name()); + properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID, password); + propertiesSet.add(properties); + + try { + provider.createResources(PropertyHelper.getCreateRequest(propertiesSet, null)); + } catch (Exception e) { + throw new AmbariException(e.getMessage(), e); + } + } + } else { + Map<String, Object> properties = new LinkedHashMap<>(); + properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_OLD_KEY_PROPERTY_ID, oldPassword); + properties.put(UserAuthenticationSourceResourceProvider.AUTHENTICATION_KEY_PROPERTY_ID, password); + + Predicate predicate1 = new PredicateBuilder() + .property(UserAuthenticationSourceResourceProvider.AUTHENTICATION_USER_NAME_PROPERTY_ID) + .equals(subjectUserEntity.getUserName()) + .toPredicate(); + Predicate predicate2 = new PredicateBuilder() + .property(UserAuthenticationSourceResourceProvider.AUTHENTICATION_AUTHENTICATION_SOURCE_ID_PROPERTY_ID) + .equals(userAuthenticationEntity.getUserAuthenticationId()) + .toPredicate(); + + try { + provider.updateResources(PropertyHelper.getUpdateRequest(properties, null), new AndPredicate(predicate1, predicate2)); + } catch (Exception e) { + throw new AmbariException(e.getMessage(), e); + } + } + } + } + + private boolean isValueChanged(Object newValue, Object currentValue) { + return (newValue != null) && !newValue.equals(currentValue); + } + + /** + * Deletes the users specified. + * + * @param requests the users to delete + * @throws AmbariException if the resources cannot be deleted + */ + private void deleteUsers(Set<UserRequest> requests) + throws AmbariException { + + for (UserRequest r : requests) { + String username = r.getUsername(); + if (!StringUtils.isEmpty(username)) { + + if (LOG.isDebugEnabled()) { + LOG.debug("Received a delete user request, username= {}", username); + } + + users.removeUser(users.getUserEntity(username)); + } + } + } + + /** + * Gets the users identified by the given request objects. + * + * @param requests the request objects + * @return a set of user responses + * @throws AmbariException if the users could not be read + */ + private Set<UserResponse> getUsers(Set<UserRequest> requests) + throws AmbariException, AuthorizationException { + + Set<UserResponse> responses = new HashSet<>(); + + for (UserRequest r : requests) { + + if (LOG.isDebugEnabled()) { + LOG.debug("Received a getUsers request, userRequest={}", r.toString()); + } + + String requestedUsername = r.getUsername(); + String authenticatedUsername = AuthorizationHelper.getAuthenticatedName(); + + // A user resource may be retrieved by an administrator or the same user. + if (!AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.AMBARI_MANAGE_USERS)) { + if (null == requestedUsername) { + // Since the authenticated user is not the administrator, force only that user's resource + // to be returned + requestedUsername = authenticatedUsername; + } else if (!requestedUsername.equalsIgnoreCase(authenticatedUsername)) { + // Since the authenticated user is not the administrator and is asking for a different user, + // throw an AuthorizationException + throw new AuthorizationException(); + } + } + + // get them all + if (null == requestedUsername) { + for (UserEntity u : users.getAllUserEntities()) { + responses.add(createUserResponse(u)); + } + } else { + + UserEntity u = users.getUserEntity(requestedUsername); + if (null == u) { + if (requests.size() == 1) { + // only throw exceptin if there is a single request + // if there are multiple requests, this indicates an OR predicate + throw new ObjectNotFoundException("Cannot find user '" + + requestedUsername + "'"); + } + } else { + responses.add(createUserResponse(u)); + } + } + } + + return responses; + } + + private UserResponse createUserResponse(UserEntity userEntity) { + List<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities(); + boolean isLdapUser = false; + UserAuthenticationType userType = UserAuthenticationType.LOCAL; + + for (UserAuthenticationEntity authenticationEntity : authenticationEntities) { + if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.LDAP) { + isLdapUser = true; + userType = UserAuthenticationType.LDAP; + } else if (authenticationEntity.getAuthenticationType() == UserAuthenticationType.PAM) { + userType = UserAuthenticationType.PAM; + } + } + + Set<String> groups = new HashSet<>(); + for (MemberEntity memberEntity : userEntity.getMemberEntities()) { + groups.add(memberEntity.getGroup().getGroupName()); + } + + boolean isAdmin = users.hasAdminPrivilege(userEntity); + + UserResponse userResponse = new UserResponse(userEntity.getUserName(), + userEntity.getDisplayName(), + userEntity.getLocalUsername(), + userType, + isLdapUser, + userEntity.getActive(), + isAdmin, + userEntity.getConsecutiveFailures(), + userEntity.getCreateTime()); + userResponse.setGroups(groups); + return userResponse; + } + } http://git-wip-us.apache.org/repos/asf/ambari/blob/de4deaf0/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ActiveWidgetLayoutResourceProviderTest.java ----------------------------------------------------------------------
