Repository: ambari Updated Branches: refs/heads/branch-2.4 e42a0f3fe -> 0480c6bec refs/heads/trunk 5f704b1f5 -> 920f49c19
AMBARI-17010. Scheduled requests should be executed using issuer role. (mpapirkovskyy) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/81842ee8 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/81842ee8 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/81842ee8 Branch: refs/heads/trunk Commit: 81842ee888e16b7c20e134c7e783f198c171cc58 Parents: 5f704b1 Author: Myroslav Papirkovskyi <[email protected]> Authored: Thu Jun 2 18:33:50 2016 +0300 Committer: Myroslav Papirkovskyi <[email protected]> Committed: Thu Jun 2 18:33:59 2016 +0300 ---------------------------------------------------------------------- .../controller/AmbariManagementController.java | 7 + .../AmbariManagementControllerImpl.java | 5 + .../ambari/server/controller/AmbariServer.java | 9 +- .../controller/RequestScheduleResponse.java | 13 +- .../RequestScheduleResourceProvider.java | 11 +- .../orm/entities/RequestScheduleEntity.java | 11 + .../scheduler/ExecutionScheduleManager.java | 8 +- .../AmbariLocalUserDetailsService.java | 99 --------- .../authorization/AmbariLocalUserProvider.java | 113 ++++++++++ .../authorization/AmbariUserAuthentication.java | 71 ++++++ .../AmbariUserAuthorizationFilter.java | 98 +++++++++ .../authorization/AuthorizationHelper.java | 20 ++ .../server/security/authorization/Users.java | 5 + .../state/scheduler/RequestExecution.java | 10 + .../state/scheduler/RequestExecutionImpl.java | 14 +- .../server/upgrade/UpgradeCatalog240.java | 8 + .../main/resources/Ambari-DDL-Derby-CREATE.sql | 1 + .../main/resources/Ambari-DDL-MySQL-CREATE.sql | 1 + .../main/resources/Ambari-DDL-Oracle-CREATE.sql | 1 + .../resources/Ambari-DDL-Postgres-CREATE.sql | 1 + .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql | 1 + .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 1 + .../resources/Ambari-DDL-SQLServer-CREATE.sql | 1 + .../webapp/WEB-INF/spring-security.xml | 5 +- .../RequestScheduleResourceProviderTest.java | 2 + .../scheduler/ExecutionScheduleManagerTest.java | 4 +- ...ariAuthorizationProviderDisableUserTest.java | 25 ++- .../AmbariLocalUserDetailsServiceTest.java | 74 ------- .../AmbariLocalUserProviderTest.java | 159 ++++++++++++++ .../AmbariUserAuthenticationFilterTest.java | 217 +++++++++++++++++++ .../authorization/AuthorizationHelperTest.java | 27 +++ .../security/authorization/TestUsers.java | 18 ++ .../server/upgrade/UpgradeCatalog240Test.java | 13 +- 33 files changed, 853 insertions(+), 200 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java index 10a1f8c..9f221d5 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java @@ -549,6 +549,13 @@ public interface AmbariManagementController { String getAuthName(); /** + * Get the authenticated user's id. + * + * @return the authenticated user's name + */ + int getAuthId(); + + /** * Create and persist the request stages and return a response containing the * associated request and resulting tasks. * http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java index 411b494..fe9204d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java @@ -4327,6 +4327,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle } @Override + public int getAuthId() { + return AuthorizationHelper.getAuthenticatedId(); + } + + @Override public Set<RootServiceResponse> getRootServices( Set<RootServiceRequest> requests) throws AmbariException { Set<RootServiceResponse> response = new HashSet<RootServiceResponse>(); http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java index cdc8185..961b6fe 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java @@ -99,8 +99,9 @@ import org.apache.ambari.server.security.CertificateManager; import org.apache.ambari.server.security.SecurityFilter; import org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter; import org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter; +import org.apache.ambari.server.security.authorization.AmbariLocalUserProvider; +import org.apache.ambari.server.security.authorization.AmbariUserAuthorizationFilter; import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider; -import org.apache.ambari.server.security.authorization.AmbariLocalUserDetailsService; import org.apache.ambari.server.security.authorization.PermissionHelper; import org.apache.ambari.server.security.authorization.Users; import org.apache.ambari.server.security.authorization.internal.AmbariInternalAuthenticationProvider; @@ -319,14 +320,16 @@ public class AmbariServer { injector.getInstance(AuditLogger.class)); factory.registerSingleton("permissionHelper", injector.getInstance(PermissionHelper.class)); - factory.registerSingleton("ambariLocalUserService", - injector.getInstance(AmbariLocalUserDetailsService.class)); factory.registerSingleton("ambariLdapAuthenticationProvider", injector.getInstance(AmbariLdapAuthenticationProvider.class)); + factory.registerSingleton("ambariLocalAuthenticationProvider", + injector.getInstance(AmbariLocalUserProvider.class)); factory.registerSingleton("ambariLdapDataPopulator", injector.getInstance(AmbariLdapDataPopulator.class)); factory.registerSingleton("ambariAuthorizationFilter", injector.getInstance(AmbariAuthorizationFilter.class)); + factory.registerSingleton("ambariUserAuthorizationFilter", + injector.getInstance(AmbariUserAuthorizationFilter.class)); factory.registerSingleton("ambariInternalAuthenticationProvider", injector.getInstance(AmbariInternalAuthenticationProvider.class)); factory.registerSingleton("ambariJwtAuthenticationFilter", http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java index 17f69c9..5516d46 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/RequestScheduleResponse.java @@ -33,13 +33,15 @@ public class RequestScheduleResponse { private String createTime; private String updateUser; private String updateTime; + private Integer authenticatedUserId; public RequestScheduleResponse(Long id, String clusterName, String description, String status, String lastExecutionStatus, Batch batch, Schedule schedule, String createUser, String createTime, - String updateUser, String updateTime) { + String updateUser, String updateTime, + Integer authenticatedUserId) { this.id = id; this.clusterName = clusterName; this.description = description; @@ -51,6 +53,7 @@ public class RequestScheduleResponse { this.createTime = createTime; this.updateUser = updateUser; this.updateTime = updateTime; + this.authenticatedUserId = authenticatedUserId; } public Long getId() { @@ -140,4 +143,12 @@ public class RequestScheduleResponse { public void setLastExecutionStatus(String lastExecutionStatus) { this.lastExecutionStatus = lastExecutionStatus; } + + public Integer getAuthenticatedUserId() { + return authenticatedUserId; + } + + public void setAuthenticatedUserId(Integer authenticatedUserId) { + this.authenticatedUserId = authenticatedUserId; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java index e21193d..ce9168b 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProvider.java @@ -73,6 +73,8 @@ public class RequestScheduleResourceProvider extends AbstractControllerResourceP PropertyHelper.getPropertyId("RequestSchedule", "schedule"); protected static final String REQUEST_SCHEDULE_CREATE_USER_PROPERTY_ID = PropertyHelper.getPropertyId("RequestSchedule", "create_user"); + protected static final String REQUEST_SCHEDULE_AUTHENTICATED_USER_PROPERTY_ID = + PropertyHelper.getPropertyId("RequestSchedule", "authenticated_user"); protected static final String REQUEST_SCHEDULE_UPDATE_USER_PROPERTY_ID = PropertyHelper.getPropertyId("RequestSchedule", "update_user"); protected static final String REQUEST_SCHEDULE_CREATE_TIME_PROPERTY_ID = @@ -207,6 +209,8 @@ public class RequestScheduleResourceProvider extends AbstractControllerResourceP response.getSchedule(), requestedIds); setResourceProperty(resource, REQUEST_SCHEDULE_CREATE_USER_PROPERTY_ID, response.getCreateUser(), requestedIds); + setResourceProperty(resource, REQUEST_SCHEDULE_AUTHENTICATED_USER_PROPERTY_ID, + response.getAuthenticatedUserId(), requestedIds); setResourceProperty(resource, REQUEST_SCHEDULE_CREATE_TIME_PROPERTY_ID, response.getCreateTime(), requestedIds); setResourceProperty(resource, REQUEST_SCHEDULE_UPDATE_USER_PROPERTY_ID, @@ -365,6 +369,7 @@ public class RequestScheduleResourceProvider extends AbstractControllerResourceP } String username = getManagementController().getAuthName(); + Integer userId = getManagementController().getAuthId(); requestExecution.setBatch(request.getBatch()); requestExecution.setDescription(request.getDescription()); @@ -374,6 +379,7 @@ public class RequestScheduleResourceProvider extends AbstractControllerResourceP requestExecution.setStatus(RequestExecution.Status.valueOf(request.getStatus())); } requestExecution.setUpdateUser(username); + requestExecution.setAuthenticatedUserId(userId); LOG.info("Persisting updated Request Schedule " + ", clusterName = " + request.getClusterName() @@ -417,12 +423,14 @@ public class RequestScheduleResourceProvider extends AbstractControllerResourceP } String username = getManagementController().getAuthName(); + Integer userId = getManagementController().getAuthId(); RequestExecution requestExecution = requestExecutionFactory.createNew (cluster, request.getBatch(), request.getSchedule()); requestExecution.setCreateUser(username); requestExecution.setUpdateUser(username); + requestExecution.setAuthenticatedUserId(userId); requestExecution.setStatus(RequestExecution.Status.SCHEDULED); LOG.info("Persisting new Request Schedule " @@ -443,7 +451,8 @@ public class RequestScheduleResourceProvider extends AbstractControllerResourceP requestExecution.getLastExecutionStatus(), requestExecution.getBatch(), request.getSchedule(), requestExecution.getCreateUser(), requestExecution.getCreateTime(), - requestExecution.getUpdateUser(), requestExecution.getUpdateTime()); + requestExecution.getUpdateUser(), requestExecution.getUpdateTime(), + requestExecution.getAuthenticatedUserId()); responses.add(response); } http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleEntity.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleEntity.java index fa7094e..b1bc20a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleEntity.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/RequestScheduleEntity.java @@ -69,6 +69,9 @@ public class RequestScheduleEntity { @Column(name = "batch_toleration_limit") private Integer batchTolerationLimit; + @Column(name = "authenticated_user_id") + private Integer authenticatedUserId; + @Column(name = "create_user") private String createUser; @@ -296,6 +299,14 @@ public class RequestScheduleEntity { this.requestEntities = requestEntities; } + public Integer getAuthenticatedUserId() { + return authenticatedUserId; + } + + public void setAuthenticatedUserId(Integer authenticatedUser) { + this.authenticatedUserId = authenticatedUser; + } + @Override public boolean equals(Object o) { if (this == o) return true; http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/scheduler/ExecutionScheduleManager.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/scheduler/ExecutionScheduleManager.java b/ambari-server/src/main/java/org/apache/ambari/server/scheduler/ExecutionScheduleManager.java index 2472fe0..dbce272 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/scheduler/ExecutionScheduleManager.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/scheduler/ExecutionScheduleManager.java @@ -96,6 +96,8 @@ public class ExecutionScheduleManager { "RequestExecution"; protected static final String DEFAULT_API_PATH = "api/v1"; + public static final String USER_ID_HEADER = "X-Authenticated-User-ID"; + protected Client ambariClient; protected WebResource ambariWebResource; @@ -521,7 +523,7 @@ public class ExecutionScheduleManager { body = requestExecution.getRequestBody(batchId); - BatchRequestResponse batchRequestResponse = performApiRequest(uri, body, type); + BatchRequestResponse batchRequestResponse = performApiRequest(uri, body, type, requestExecution.getAuthenticatedUserId()); updateBatchRequest(executionId, batchId, clusterName, batchRequestResponse, false); @@ -668,10 +670,10 @@ public class ExecutionScheduleManager { return convertToBatchRequestResponse(response); } - protected BatchRequestResponse performApiRequest(String relativeUri, String body, String method) { + protected BatchRequestResponse performApiRequest(String relativeUri, String body, String method, Integer userId) { ClientResponse response; try { - response = ambariWebResource.path(relativeUri).method(method, ClientResponse.class, body); + response = ambariWebResource.path(relativeUri).header(USER_ID_HEADER, userId).method(method, ClientResponse.class, body); } catch (UniformInterfaceException e) { response = e.getResponse(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserDetailsService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserDetailsService.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserDetailsService.java deleted file mode 100644 index 5607cc5..0000000 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserDetailsService.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.ambari.server.security.authorization; - -import com.google.inject.Inject; -import com.google.inject.Injector; -import org.apache.ambari.server.configuration.Configuration; -import org.apache.ambari.server.orm.dao.MemberDAO; -import org.apache.ambari.server.orm.dao.PrivilegeDAO; -import org.apache.ambari.server.orm.dao.UserDAO; -import org.apache.ambari.server.orm.entities.MemberEntity; -import org.apache.ambari.server.orm.entities.PrincipalEntity; -import org.apache.ambari.server.orm.entities.PrivilegeEntity; -import org.apache.ambari.server.orm.entities.UserEntity; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - -import java.util.LinkedList; -import java.util.List; - - -public class AmbariLocalUserDetailsService implements UserDetailsService { - private static final Logger log = LoggerFactory.getLogger(AmbariLocalUserDetailsService.class); - - Injector injector; - Configuration configuration; - private AuthorizationHelper authorizationHelper; - UserDAO userDAO; - MemberDAO memberDAO; - PrivilegeDAO privilegeDAO; - - @Inject - public AmbariLocalUserDetailsService(Injector injector, Configuration configuration, - AuthorizationHelper authorizationHelper, UserDAO userDAO, - MemberDAO memberDAO, PrivilegeDAO privilegeDAO) { - this.injector = injector; - this.configuration = configuration; - this.authorizationHelper = authorizationHelper; - this.userDAO = userDAO; - this.memberDAO = memberDAO; - this.privilegeDAO = privilegeDAO; - } - - /** - * Loads Spring Security UserDetails from identity storage according to Configuration - * - * @param username username - * @return UserDetails - * @throws UsernameNotFoundException when user not found or have empty roles - */ - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - log.info("Loading user by name: " + username); - - UserEntity user = userDAO.findLocalUserByName(username); - - if (user == null || !StringUtils.equals(user.getUserName(), username)) { - //TODO case insensitive name comparison is a temporary solution, until users API will change to use id as PK - log.info("user not found "); - throw new UsernameNotFoundException("Username " + username + " not found"); - } - - // get all of the privileges for the user - List<PrincipalEntity> principalEntities = new LinkedList<PrincipalEntity>(); - - principalEntities.add(user.getPrincipal()); - - List<MemberEntity> memberEntities = memberDAO.findAllMembersByUser(user); - - for (MemberEntity memberEntity : memberEntities) { - principalEntities.add(memberEntity.getGroup().getPrincipal()); - } - - List<PrivilegeEntity> privilegeEntities = privilegeDAO.findAllByPrincipal(principalEntities); - - return new User(user.getUserName(), user.getUserPassword(), user.getActive(), - true, true, true, authorizationHelper.convertPrivilegesToAuthorities(privilegeEntities)); - } -} http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java new file mode 100644 index 0000000..a8c9b19 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProvider.java @@ -0,0 +1,113 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.security.authorization; + +import com.google.inject.Inject; +import org.apache.ambari.server.orm.dao.UserDAO; +import org.apache.ambari.server.orm.entities.UserEntity; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +import java.util.Collection; + +public class AmbariLocalUserProvider extends AbstractUserDetailsAuthenticationProvider { + private static final Logger LOG = LoggerFactory.getLogger(AmbariLocalUserProvider.class); + + private UserDAO userDAO; + private Users users; + private PasswordEncoder passwordEncoder; + + + @Inject + public AmbariLocalUserProvider(UserDAO userDAO, Users users, PasswordEncoder passwordEncoder) { + this.userDAO = userDAO; + this.users = users; + this.passwordEncoder = passwordEncoder; + } + + @Override + protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + // do nothing + } + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + String userName = authentication.getName().trim(); + + LOG.info("Loading user by name: " + userName); + + UserEntity userEntity = userDAO.findLocalUserByName(userName); + + if (userEntity == null || !StringUtils.equals(userEntity.getUserName(), userName)) { + //TODO case insensitive name comparison is a temporary solution, until users API will change to use id as PK + LOG.info("user not found "); + throw new UsernameNotFoundException("Username " + userName + " not found"); + } + + if (!userEntity.getActive()) { + logger.debug("User account is disabled"); + + throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", + "User is disabled")); + } + + if (authentication.getCredentials() == null) { + logger.debug("Authentication failed: no credentials provided"); + + throw new BadCredentialsException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + } + + String password = userEntity.getUserPassword(); + String presentedPassword = authentication.getCredentials().toString(); + + if (!passwordEncoder.matches(presentedPassword, password)) { + logger.debug("Authentication failed: password does not match stored value"); + + throw new BadCredentialsException(messages.getMessage( + "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials")); + } + Collection<AmbariGrantedAuthority> userAuthorities = + users.getUserAuthorities(userEntity.getUserName(), userEntity.getUserType()); + + User user = new User(userEntity); + Authentication auth = new AmbariUserAuthentication(userEntity.getUserPassword(), user, userAuthorities); + auth.setAuthenticated(true); + return auth; + } + + @Override + protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { + return null; + } + + @Override + public boolean supports(Class<?> authentication) { + return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthentication.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthentication.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthentication.java new file mode 100644 index 0000000..f9c5cf4 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthentication.java @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.security.authorization; + +import org.springframework.security.core.Authentication; + +import java.util.Collection; + +public class AmbariUserAuthentication implements Authentication { + + private String serializedToken; + private User user; + private Collection<AmbariGrantedAuthority> userAuthorities; + private boolean authenticated = false; + + public AmbariUserAuthentication(String token, User user, Collection<AmbariGrantedAuthority> userAuthorities) { + this.serializedToken = token; + this.user = user; + this.userAuthorities = userAuthorities; + } + + @Override + public Collection<? extends AmbariGrantedAuthority> getAuthorities() { + return userAuthorities; + } + + @Override + public String getCredentials() { + return serializedToken; + } + + @Override + public Object getDetails() { + return null; + } + + @Override + public User getPrincipal() { + return user; + } + + @Override + public boolean isAuthenticated() { + return authenticated; + } + + @Override + public void setAuthenticated(boolean authenticated) throws IllegalArgumentException { + this.authenticated = authenticated; + } + + @Override + public String getName() { + return user.getUserName(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java new file mode 100644 index 0000000..b7a1610 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.security.authorization; + +import com.google.inject.Inject; +import org.apache.ambari.server.scheduler.ExecutionScheduleManager; +import org.apache.ambari.server.security.authorization.internal.InternalTokenClientFilter; +import org.apache.ambari.server.security.authorization.internal.InternalTokenStorage; +import org.apache.commons.lang.math.NumberUtils; +import org.springframework.security.core.context.SecurityContextHolder; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collection; + +public class AmbariUserAuthorizationFilter implements Filter { + + private final InternalTokenStorage internalTokenStorage; + private final Users users; + + @Inject + public AmbariUserAuthorizationFilter(InternalTokenStorage internalTokenStorage, Users users) { + this.internalTokenStorage = internalTokenStorage; + this.users = users; + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // do nothing + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + String token = httpRequest.getHeader(InternalTokenClientFilter.INTERNAL_TOKEN_HEADER); + if (token != null) { + if (internalTokenStorage.isValidInternalToken(token)) { + String userToken = httpRequest.getHeader(ExecutionScheduleManager.USER_ID_HEADER); + if (userToken != null) { + if (!NumberUtils.isDigits(userToken)) { + httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid user ID"); + httpResponse.flushBuffer(); + return; + } + Integer userId = Integer.parseInt(userToken); + User user = users.getUser(userId); + if (user == null) { + httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Authentication required"); + httpResponse.flushBuffer(); + return; + } if (!user.isActive()) { + httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not active"); + httpResponse.flushBuffer(); + return; + } else { + Collection<AmbariGrantedAuthority> userAuthorities = + users.getUserAuthorities(user.getUserName(), user.getUserType()); + AmbariUserAuthentication authentication = new AmbariUserAuthentication(token, user, userAuthorities); + authentication.setAuthenticated(true); + SecurityContextHolder.getContext().setAuthentication(authentication); + httpResponse.setHeader("User", AuthorizationHelper.getAuthenticatedName()); + } + } + } + } + chain.doFilter(request, response); + } + + @Override + public void destroy() { + // do nothing + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java index f9f0611..8befc3f 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java @@ -98,6 +98,26 @@ public class AuthorizationHelper { } /** + * Gets the ID of the logged-in user. Thread-safe due to use of + * thread-local. + * + * @return the ID of the logged-in user + */ + public static int getAuthenticatedId() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + + Authentication authentication = securityContext.getAuthentication(); + AmbariUserAuthentication auth; + if (authentication instanceof AmbariUserAuthentication) { + auth = (AmbariUserAuthentication) authentication; + } else { + return -1; + } + + return auth.getPrincipal().getUserId(); + } + + /** * Determines if the authenticated user (from application's security context) is authorized to * perform an operation on the specific resource by matching the authenticated user's * authorizations with the one indicated. http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java index d80edf3..545095d 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/Users.java @@ -119,6 +119,11 @@ public class Users { return (null == userEntity) ? null : new User(userEntity); } + public User getUser(Integer userId) { + UserEntity userEntity = userDAO.findByPK(userId); + return (null == userEntity) ? null : new User(userEntity); + } + /** * Modifies password of local user * @throws AmbariException http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecution.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecution.java b/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecution.java index 06a46c7..8a325f4 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecution.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecution.java @@ -105,6 +105,11 @@ public interface RequestExecution { public void setLastExecutionStatus(String status); /** + * Set authenticated user + */ + public void setAuthenticatedUserId(Integer username); + + /** * Set create username */ public void setCreateUser(String username); @@ -125,6 +130,11 @@ public interface RequestExecution { public String getUpdateTime(); /** + * Get authenticated user + */ + public Integer getAuthenticatedUserId(); + + /** * Get create user */ public String getCreateUser(); http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecutionImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecutionImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecutionImpl.java index 895579e..8c952a7 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecutionImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/state/scheduler/RequestExecutionImpl.java @@ -30,7 +30,6 @@ import org.apache.ambari.server.orm.dao.RequestScheduleBatchRequestDAO; import org.apache.ambari.server.orm.dao.RequestScheduleDAO; import org.apache.ambari.server.orm.entities.ClusterEntity; import org.apache.ambari.server.orm.entities.RequestScheduleBatchRequestEntity; -import org.apache.ambari.server.orm.entities.RequestScheduleBatchRequestEntityPK; import org.apache.ambari.server.orm.entities.RequestScheduleEntity; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; @@ -174,7 +173,8 @@ public class RequestExecutionImpl implements RequestExecution { requestScheduleEntity.getCreateUser(), DateUtils.convertToReadableTime(requestScheduleEntity.getCreateTimestamp()), requestScheduleEntity.getUpdateUser(), - DateUtils.convertToReadableTime(requestScheduleEntity.getUpdateTimestamp()) + DateUtils.convertToReadableTime(requestScheduleEntity.getUpdateTimestamp()), + requestScheduleEntity.getAuthenticatedUserId() ); return response; } finally { @@ -340,6 +340,11 @@ public class RequestExecutionImpl implements RequestExecution { } @Override + public void setAuthenticatedUserId(Integer username) { + requestScheduleEntity.setAuthenticatedUserId(username); + } + + @Override public void setCreateUser(String username) { requestScheduleEntity.setCreateUser(username); } @@ -362,6 +367,11 @@ public class RequestExecutionImpl implements RequestExecution { } @Override + public Integer getAuthenticatedUserId() { + return requestScheduleEntity.getAuthenticatedUserId(); + } + + @Override public String getCreateUser() { return requestScheduleEntity.getCreateUser(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java index 7226859..01322b2 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java @@ -154,6 +154,8 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog { public static final String VIEWINSTANCE_TABLE = "viewinstance"; public static final String SHORT_URL_COLUMN = "short_url"; public static final String CLUSTER_HANDLE_COLUMN = "cluster_handle"; + public static final String REQUESTSCHEDULE_TABLE = "requestschedule"; + public static final String AUTHENTICATED_USER_ID_COLUMN = "authenticated_user_id"; protected static final String CLUSTER_VERSION_TABLE = "cluster_version"; protected static final String HOST_VERSION_TABLE = "host_version"; protected static final String PHOENIX_QUERY_SERVER_PRINCIPAL_KEY = "phoenix.queryserver.kerberos.principal"; @@ -275,6 +277,7 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog { updateViewInstanceEntityTable(); createRemoteClusterTable(); updateViewInstanceTable(); + updateRequestScheduleEntityTable(); } private void createRemoteClusterTable() throws SQLException { @@ -324,6 +327,11 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog { new DBColumnInfo(CLUSTER_TYPE_COLUMN, String.class, 100, ClusterType.LOCAL_AMBARI.name(), false)); } + private void updateRequestScheduleEntityTable() throws SQLException { + dbAccessor.addColumn(REQUESTSCHEDULE_TABLE, + new DBColumnInfo(AUTHENTICATED_USER_ID_COLUMN, Integer.class, null, null, true)); + } + private void updateClusterTableDDL() throws SQLException { dbAccessor.addColumn(CLUSTER_TABLE, new DBColumnInfo(CLUSTER_UPGRADE_ID_COLUMN, Long.class, null, null, true)); http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql index 175fd59..940542d 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql @@ -296,6 +296,7 @@ CREATE TABLE requestschedule ( status varchar(255), batch_separation_seconds smallint, batch_toleration_limit smallint, + authenticated_user_id INTEGER, create_user varchar(255), create_timestamp bigint, update_user varchar(255), http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql index ffc47fa..eb2b349 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql @@ -296,6 +296,7 @@ CREATE TABLE requestschedule ( status varchar(255), batch_separation_seconds smallint, batch_toleration_limit smallint, + authenticated_user_id INTEGER, create_user varchar(255), create_timestamp bigint, update_user varchar(255), http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql index e646ac5..de8c2e6 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql @@ -287,6 +287,7 @@ CREATE TABLE requestschedule ( status VARCHAR2(255), batch_separation_seconds smallint, batch_toleration_limit smallint, + authenticated_user_id NUMBER(10), create_user VARCHAR2(255), create_timestamp NUMBER(19), update_user VARCHAR2(255), http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql index c5734a7..0a8d6c9 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql @@ -296,6 +296,7 @@ CREATE TABLE requestschedule ( status varchar(255), batch_separation_seconds smallint, batch_toleration_limit smallint, + authenticated_user_id INTEGER, create_user varchar(255), create_timestamp bigint, update_user varchar(255), http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql index 4b3c6e7..4b65a69 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql @@ -356,6 +356,7 @@ CREATE TABLE ambari.requestschedule ( status varchar(255), batch_separation_seconds smallint, batch_toleration_limit smallint, + authenticated_user_id INTEGER, create_user varchar(255), create_timestamp bigint, update_user varchar(255), http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql index 74e85ef..5ef07d0 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql @@ -285,6 +285,7 @@ CREATE TABLE requestschedule ( status VARCHAR(255), batch_separation_seconds smallint, batch_toleration_limit smallint, + authenticated_user_id INTEGER, create_user VARCHAR(255), create_timestamp NUMERIC(19), update_user VARCHAR(255), http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql index bd33290..0b5f3b8 100644 --- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql +++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql @@ -301,6 +301,7 @@ CREATE TABLE requestschedule ( STATUS VARCHAR(255), batch_separation_seconds SMALLINT, batch_toleration_limit SMALLINT, + authenticated_user_id INTEGER, create_user VARCHAR(255), create_timestamp BIGINT, update_user VARCHAR(255), http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml index 01243ef..e1697e2 100644 --- a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml +++ b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml @@ -25,6 +25,7 @@ <http use-expressions="true" disable-url-rewriting="true" entry-point-ref="ambariEntryPoint"> <intercept-url pattern="/**" access="isAuthenticated()"/> + <custom-filter ref="ambariUserAuthorizationFilter" before="BASIC_AUTH_FILTER"/> <custom-filter ref="ambariAuthenticationFilter" position="BASIC_AUTH_FILTER"/> <custom-filter ref="ambariJwtAuthenticationFilter" after="BASIC_AUTH_FILTER" /> <custom-filter ref="ambariAuthorizationFilter" before="FILTER_SECURITY_INTERCEPTOR"/> @@ -34,9 +35,7 @@ <authentication-manager alias="authenticationManager"> - <authentication-provider user-service-ref="ambariLocalUserService"> - <password-encoder ref="passwordEncoder"/> - </authentication-provider> + <authentication-provider ref="ambariLocalAuthenticationProvider"/> <authentication-provider ref="ambariLdapAuthenticationProvider"/> http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProviderTest.java index daeea27..51650c0 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/RequestScheduleResourceProviderTest.java @@ -88,6 +88,7 @@ public class RequestScheduleResourceProviderTest { expect(managementController.getRequestExecutionFactory()).andReturn (executionFactory); expect(managementController.getAuthName()).andReturn("admin").anyTimes(); + expect(managementController.getAuthId()).andReturn(1).anyTimes(); Capture<Cluster> clusterCapture = new Capture<Cluster>(); Capture<Batch> batchCapture = new Capture<Batch>(); @@ -196,6 +197,7 @@ public class RequestScheduleResourceProviderTest { expect(managementController.getClusters()).andReturn(clusters).anyTimes(); expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes(); expect(managementController.getAuthName()).andReturn("admin").anyTimes(); + expect(managementController.getAuthId()).andReturn(1).anyTimes(); expect(managementController.getExecutionScheduleManager()).andReturn (executionScheduleManager).anyTimes(); http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/scheduler/ExecutionScheduleManagerTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/scheduler/ExecutionScheduleManagerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/scheduler/ExecutionScheduleManagerTest.java index 2f97eeb..860e647 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/scheduler/ExecutionScheduleManagerTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/scheduler/ExecutionScheduleManagerTest.java @@ -356,6 +356,7 @@ public class ExecutionScheduleManagerTest { String uri = "clusters"; String type = "post"; String body = "body"; + Integer userId = 1; Map<Long, RequestExecution> executionMap = new HashMap<Long, RequestExecution>(); executionMap.put(executionId, requestExecutionMock); @@ -378,11 +379,12 @@ public class ExecutionScheduleManagerTest { expect(requestExecutionMock.getBatchRequest(eq(batchId))).andReturn(batchRequestMock).once(); expect(requestExecutionMock.getRequestBody(eq(batchId))).andReturn(body).once(); + expect(requestExecutionMock.getAuthenticatedUserId()).andReturn(userId).once(); expect(batchRequestMock.getUri()).andReturn(uri).once(); expect(batchRequestMock.getType()).andReturn(type).once(); - expect(scheduleManager.performApiRequest(eq(uri), eq(body), eq(type))).andReturn(batchRequestResponse).once(); + expect(scheduleManager.performApiRequest(eq(uri), eq(body), eq(type), eq(userId))).andReturn(batchRequestResponse).once(); scheduleManager.updateBatchRequest(eq(executionId), eq(batchId), eq(clusterName), eq(batchRequestResponse), eq(false)); expectLastCall().once(); http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java index c3e5990..16cba8b 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationProviderDisableUserTest.java @@ -21,6 +21,7 @@ package org.apache.ambari.server.security.authorization; import org.apache.ambari.server.orm.dao.MemberDAO; import org.apache.ambari.server.orm.dao.PrivilegeDAO; import org.apache.ambari.server.orm.dao.UserDAO; +import org.apache.ambari.server.orm.entities.PrincipalEntity; import org.apache.ambari.server.orm.entities.UserEntity; import org.junit.Assert; import org.junit.Before; @@ -28,36 +29,35 @@ import org.junit.Test; import org.mockito.Mockito; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.StandardPasswordEncoder; public class AmbariAuthorizationProviderDisableUserTest { + private Users users; + private UserDAO userDAO; private PasswordEncoder encoder = new StandardPasswordEncoder(); - - private DaoAuthenticationProvider daoProvider; + + private AmbariLocalUserProvider alup; private AmbariLdapAuthoritiesPopulator ldapPopulator; @Before public void setUp() { userDAO = Mockito.mock(UserDAO.class); - + users = Mockito.mock(Users.class); + createUser("activeUser", true); createUser("disabledUser", false); MemberDAO memberDao = Mockito.mock(MemberDAO.class); PrivilegeDAO privilegeDao = Mockito.mock(PrivilegeDAO.class); AuthorizationHelper authorizationHelper = new AuthorizationHelper(); - - AmbariLocalUserDetailsService uds = new AmbariLocalUserDetailsService(null,null,authorizationHelper,userDAO,memberDao,privilegeDao); - daoProvider = new DaoAuthenticationProvider(); - daoProvider.setUserDetailsService(uds); - daoProvider.setPasswordEncoder(encoder); + + alup = new AmbariLocalUserProvider(userDAO, users, encoder); ldapPopulator = new AmbariLdapAuthoritiesPopulator(authorizationHelper, userDAO, memberDao, privilegeDao); @@ -65,13 +65,13 @@ public class AmbariAuthorizationProviderDisableUserTest { @Test public void testDisabledUserViaDaoProvider(){ try{ - daoProvider.authenticate(new UsernamePasswordAuthenticationToken("disabledUser","pwd")); + alup.authenticate(new UsernamePasswordAuthenticationToken("disabledUser","pwd")); Assert.fail("Disabled user passes authentication"); }catch(DisabledException e){ //expected Assert.assertEquals("User is disabled", e.getMessage());//UI depends on this } - Authentication auth = daoProvider.authenticate(new UsernamePasswordAuthenticationToken("activeUser","pwd")); + Authentication auth = alup.authenticate(new UsernamePasswordAuthenticationToken("activeUser","pwd")); Assert.assertNotNull(auth); Assert.assertTrue(auth.isAuthenticated()); } @@ -87,10 +87,13 @@ public class AmbariAuthorizationProviderDisableUserTest { } private void createUser(String login, boolean isActive) { + PrincipalEntity principalEntity = new PrincipalEntity(); UserEntity activeUser = new UserEntity(); + activeUser.setUserId(1); activeUser.setActive(isActive); activeUser.setUserName(login); activeUser.setUserPassword(encoder.encode("pwd")); + activeUser.setPrincipal(principalEntity); Mockito.when(userDAO.findLocalUserByName(login)).thenReturn(activeUser); Mockito.when(userDAO.findLdapUserByName(login)).thenReturn(activeUser); } http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserDetailsServiceTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserDetailsServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserDetailsServiceTest.java deleted file mode 100644 index b77f4bc..0000000 --- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserDetailsServiceTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.ambari.server.security.authorization; - -import com.google.inject.Guice; -import com.google.inject.Inject; -import com.google.inject.Injector; - -import org.apache.ambari.server.audit.AuditLoggerModule; -import org.apache.ambari.server.orm.GuiceJpaInitializer; -import org.apache.ambari.server.orm.OrmTestHelper; -import org.apache.ambari.server.orm.dao.UserDAO; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.password.PasswordEncoder; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class AmbariLocalUserDetailsServiceTest { - - private static Injector injector; - - @Inject - AmbariLocalUserDetailsService userDetailsService; - @Inject - PasswordEncoder passwordEncoder; - @Inject - UserDAO userDAO; - - @BeforeClass - public static void prepareData() { - injector = Guice.createInjector(new AuditLoggerModule(), new AuthorizationTestModule()); - injector.getInstance(GuiceJpaInitializer.class); - injector.getInstance(OrmTestHelper.class).createTestUsers(); - } - - @Before - public void setUp() throws Exception { - injector.injectMembers(this); - } - - @Test - public void testLoadUserByUsername() throws Exception { - UserDetails userDetails = userDetailsService.loadUserByUsername("administrator"); - assertEquals("Wrong username", "administrator", userDetails.getUsername()); - assertTrue("Password not matches", passwordEncoder.matches("admin", userDetails.getPassword())); - assertFalse("Wrong password accepted", passwordEncoder.matches("wrong", userDetails.getPassword())); - } - - @Test(expected = UsernameNotFoundException.class) - public void testUsernameNotFound() throws Exception { - userDetailsService.loadUserByUsername("notExists_123123123"); - } -} http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java new file mode 100644 index 0000000..6dda3f2 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariLocalUserProviderTest.java @@ -0,0 +1,159 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.security.authorization; + +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.Injector; +import org.apache.ambari.server.audit.AuditLoggerModule; +import org.apache.ambari.server.orm.GuiceJpaInitializer; +import org.apache.ambari.server.orm.OrmTestHelper; +import org.apache.ambari.server.orm.dao.UserDAO; +import org.apache.ambari.server.orm.entities.PrincipalEntity; +import org.apache.ambari.server.orm.entities.UserEntity; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class AmbariLocalUserProviderTest { + private static Injector injector; + + @Inject + PasswordEncoder passwordEncoder; + + private static final String TEST_USER_NAME = "userName"; + private static final String TEST_USER_PASS = "userPass"; + private static final String TEST_USER_INCORRECT_PASS = "userIncorrectPass"; + + @BeforeClass + public static void prepareData() { + injector = Guice.createInjector(new AuditLoggerModule(), new AuthorizationTestModule()); + injector.getInstance(GuiceJpaInitializer.class); + injector.getInstance(OrmTestHelper.class).createTestUsers(); + } + + @Before + public void setUp() throws Exception { + injector.injectMembers(this); + SecurityContextHolder.getContext().setAuthentication(null); + } + + @Test + public void testSuccessfulAuth() { + Users users = createMock(Users.class); + UserDAO userDAO = createMock(UserDAO.class); + Authentication authentication = createMock(Authentication.class); + + UserEntity userEntity = combineUserEntity(); + + expect(authentication.getName()).andReturn(TEST_USER_NAME); + expect(userDAO.findLocalUserByName(TEST_USER_NAME)).andReturn(userEntity); + expect(authentication.getCredentials()).andReturn(TEST_USER_PASS).anyTimes(); + expect(users.getUserAuthorities(userEntity.getUserName(), userEntity.getUserType())).andReturn(null); + + replay(users, userDAO, authentication); + + AmbariLocalUserProvider ambariLocalUserProvider = new AmbariLocalUserProvider(userDAO, users, passwordEncoder); + Authentication resultedAuth = ambariLocalUserProvider.authenticate(authentication); + + verify(users, userDAO, authentication); + + assertNotNull(resultedAuth); + assertEquals(true, resultedAuth.isAuthenticated()); + assertTrue(resultedAuth instanceof AmbariUserAuthentication); + assertEquals(1, ((User) resultedAuth.getPrincipal()).getUserId()); + } + + @Test(expected = UsernameNotFoundException.class) + public void testAuthWithIncorrectName() { + Users users = createMock(Users.class); + UserDAO userDAO = createMock(UserDAO.class); + Authentication authentication = createMock(Authentication.class); + + expect(authentication.getName()).andReturn(TEST_USER_NAME); + expect(userDAO.findLocalUserByName(TEST_USER_NAME)).andReturn(null); + + replay(users, userDAO, authentication); + + AmbariLocalUserProvider ambariLocalUserProvider = new AmbariLocalUserProvider(userDAO, users, passwordEncoder); + ambariLocalUserProvider.authenticate(authentication); + } + + @Test(expected = BadCredentialsException.class) + public void testAuthWithoutPass() { + Users users = createMock(Users.class); + UserDAO userDAO = createMock(UserDAO.class); + Authentication authentication = createMock(Authentication.class); + + UserEntity userEntity = combineUserEntity(); + + expect(authentication.getName()).andReturn(TEST_USER_NAME); + expect(userDAO.findLocalUserByName(TEST_USER_NAME)).andReturn(userEntity); + expect(authentication.getCredentials()).andReturn(null); + + replay(users, userDAO, authentication); + + AmbariLocalUserProvider ambariLocalUserProvider = new AmbariLocalUserProvider(userDAO, users, passwordEncoder); + ambariLocalUserProvider.authenticate(authentication); + } + + @Test(expected = BadCredentialsException.class) + public void testAuthWithIncorrectPass() { + Users users = createMock(Users.class); + UserDAO userDAO = createMock(UserDAO.class); + Authentication authentication = createMock(Authentication.class); + + UserEntity userEntity = combineUserEntity(); + + expect(authentication.getName()).andReturn(TEST_USER_NAME); + expect(userDAO.findLocalUserByName(TEST_USER_NAME)).andReturn(userEntity); + expect(authentication.getCredentials()).andReturn(TEST_USER_INCORRECT_PASS).anyTimes(); + + replay(users, userDAO, authentication); + + AmbariLocalUserProvider ambariLocalUserProvider = new AmbariLocalUserProvider(userDAO, users, passwordEncoder); + ambariLocalUserProvider.authenticate(authentication); + } + + + + private UserEntity combineUserEntity() { + PrincipalEntity principalEntity = new PrincipalEntity(); + UserEntity userEntity = new UserEntity(); + userEntity.setUserId(1); + userEntity.setUserName(TEST_USER_NAME); + userEntity.setUserPassword(passwordEncoder.encode(TEST_USER_PASS)); + userEntity.setUserType(UserType.LOCAL); + userEntity.setPrincipal(principalEntity); + + return userEntity; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java new file mode 100644 index 0000000..b206078 --- /dev/null +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariUserAuthenticationFilterTest.java @@ -0,0 +1,217 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.security.authorization; + +import org.apache.ambari.server.orm.entities.PrincipalEntity; +import org.apache.ambari.server.orm.entities.UserEntity; +import org.apache.ambari.server.scheduler.ExecutionScheduleManager; +import org.apache.ambari.server.security.authorization.internal.InternalTokenClientFilter; +import org.apache.ambari.server.security.authorization.internal.InternalTokenStorage; +import org.easymock.Capture; +import org.junit.Before; +import org.junit.Test; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashSet; + +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.eq; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.easymock.EasyMock.newCapture; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class AmbariUserAuthenticationFilterTest { + private static final String TEST_INTERNAL_TOKEN = "test token"; + private static final String TEST_USER_ID_HEADER = "1"; + private static final String TEST_USER_NAME = "userName"; + private static final int TEST_USER_ID = 1; + + @Before + public void setUp() throws Exception { + SecurityContextHolder.getContext().setAuthentication(null); + } + + @Test + public void testDoFilterValid() throws IOException, ServletException { + final Users users = createMock(Users.class); + HttpServletRequest request = createMock(HttpServletRequest.class); + HttpServletResponse response = createMock(HttpServletResponse.class); + FilterChain chain = createMock(FilterChain.class); + InternalTokenStorage tokenStorage = createMock(InternalTokenStorage.class); + + expect(request.getHeader(InternalTokenClientFilter.INTERNAL_TOKEN_HEADER)).andReturn(TEST_INTERNAL_TOKEN); + expect(tokenStorage.isValidInternalToken(TEST_INTERNAL_TOKEN)).andReturn(true); + expect(request.getHeader(ExecutionScheduleManager.USER_ID_HEADER)).andReturn(TEST_USER_ID_HEADER); + + User user = combineUser(); + + expect(users.getUser(TEST_USER_ID)).andReturn(user); + expect(users.getUserAuthorities(user.getUserName(), user.getUserType())).andReturn(new HashSet<AmbariGrantedAuthority>()); + Capture<String> userHeaderValue = newCapture(); + response.setHeader(eq("User"), capture(userHeaderValue)); + expectLastCall(); + + chain.doFilter(request, response); + expectLastCall(); + + replay(users, request, response, chain, tokenStorage); + + AmbariUserAuthorizationFilter filter = new AmbariUserAuthorizationFilter(tokenStorage, users); + filter.doFilter(request, response, chain); + + verify(users, request, response, chain, tokenStorage); + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + assertNotNull(authentication); + assertEquals(true, authentication.isAuthenticated()); + assertEquals(TEST_USER_NAME, userHeaderValue.getValue()); + } + + @Test + public void testDoFilterWithoutInternalToken() throws IOException, ServletException { + final Users users = createMock(Users.class); + HttpServletRequest request = createMock(HttpServletRequest.class); + HttpServletResponse response = createMock(HttpServletResponse.class); + FilterChain chain = createMock(FilterChain.class); + InternalTokenStorage tokenStorage = createMock(InternalTokenStorage.class); + + expect(request.getHeader(InternalTokenClientFilter.INTERNAL_TOKEN_HEADER)).andReturn(null); + + chain.doFilter(request, response); + expectLastCall(); + + replay(users, request, response, chain, tokenStorage); + + AmbariUserAuthorizationFilter filter = new AmbariUserAuthorizationFilter(tokenStorage, users); + filter.doFilter(request, response, chain); + + verify(users, request, response, chain, tokenStorage); + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + assertNull(authentication); + } + + @Test + public void testDoFilterWithoutUserToken() throws IOException, ServletException { + final Users users = createMock(Users.class); + HttpServletRequest request = createMock(HttpServletRequest.class); + HttpServletResponse response = createMock(HttpServletResponse.class); + FilterChain chain = createMock(FilterChain.class); + InternalTokenStorage tokenStorage = createMock(InternalTokenStorage.class); + + expect(request.getHeader(InternalTokenClientFilter.INTERNAL_TOKEN_HEADER)).andReturn(TEST_INTERNAL_TOKEN); + expect(tokenStorage.isValidInternalToken(TEST_INTERNAL_TOKEN)).andReturn(true); + expect(request.getHeader(ExecutionScheduleManager.USER_ID_HEADER)).andReturn(null); + + chain.doFilter(request, response); + expectLastCall(); + + replay(users, request, response, chain, tokenStorage); + + AmbariUserAuthorizationFilter filter = new AmbariUserAuthorizationFilter(tokenStorage, users); + filter.doFilter(request, response, chain); + + verify(users, request, response, chain, tokenStorage); + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + assertNull(authentication); + } + + @Test + public void testDoFilterWithIncorrectUser() throws IOException, ServletException { + final Users users = createMock(Users.class); + HttpServletRequest request = createMock(HttpServletRequest.class); + HttpServletResponse response = createMock(HttpServletResponse.class); + FilterChain chain = createMock(FilterChain.class); + InternalTokenStorage tokenStorage = createMock(InternalTokenStorage.class); + + expect(request.getHeader(InternalTokenClientFilter.INTERNAL_TOKEN_HEADER)).andReturn(TEST_INTERNAL_TOKEN); + expect(tokenStorage.isValidInternalToken(TEST_INTERNAL_TOKEN)).andReturn(true); + expect(request.getHeader(ExecutionScheduleManager.USER_ID_HEADER)).andReturn(TEST_USER_ID_HEADER); + + expect(users.getUser(TEST_USER_ID)).andReturn(null); + + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Authentication required"); + expectLastCall(); + response.flushBuffer(); + expectLastCall(); + + replay(users, request, response, chain, tokenStorage); + + AmbariUserAuthorizationFilter filter = new AmbariUserAuthorizationFilter(tokenStorage, users); + filter.doFilter(request, response, chain); + + verify(users, request, response, chain, tokenStorage); + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + assertNull(authentication); + } + + @Test + public void testDoFilterWithInvalidUserID() throws IOException, ServletException { + final Users users = createMock(Users.class); + HttpServletRequest request = createMock(HttpServletRequest.class); + HttpServletResponse response = createMock(HttpServletResponse.class); + FilterChain chain = createMock(FilterChain.class); + InternalTokenStorage tokenStorage = createMock(InternalTokenStorage.class); + + expect(request.getHeader(InternalTokenClientFilter.INTERNAL_TOKEN_HEADER)).andReturn(TEST_INTERNAL_TOKEN); + expect(tokenStorage.isValidInternalToken(TEST_INTERNAL_TOKEN)).andReturn(true); + expect(request.getHeader(ExecutionScheduleManager.USER_ID_HEADER)).andReturn("admin"); + + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid user ID"); + expectLastCall(); + response.flushBuffer(); + expectLastCall(); + + replay(users, request, response, chain, tokenStorage); + + AmbariUserAuthorizationFilter filter = new AmbariUserAuthorizationFilter(tokenStorage, users); + filter.doFilter(request, response, chain); + + verify(users, request, response, chain, tokenStorage); + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + assertNull(authentication); + } + + private User combineUser() { + PrincipalEntity principalEntity = new PrincipalEntity(); + UserEntity userEntity = new UserEntity(); + userEntity.setUserId(TEST_USER_ID); + userEntity.setUserName(TEST_USER_NAME); + userEntity.setUserType(UserType.LOCAL); + userEntity.setPrincipal(principalEntity); + User user = new User(userEntity); + + return user; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java index 9f38841..56f224c 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AuthorizationHelperTest.java @@ -30,6 +30,7 @@ import org.apache.ambari.server.orm.entities.ResourceEntity; import org.apache.ambari.server.orm.entities.ResourceTypeEntity; import org.apache.ambari.server.orm.entities.RoleAuthorizationEntity; import org.apache.ambari.server.orm.entities.ViewInstanceEntity; +import org.apache.ambari.server.orm.entities.UserEntity; import org.easymock.EasyMockRule; import org.easymock.EasyMockSupport; import org.easymock.Mock; @@ -147,6 +148,32 @@ public class AuthorizationHelperTest extends EasyMockSupport { } @Test + public void testAuthId() throws Exception { + Integer userId = AuthorizationHelper.getAuthenticatedId(); + Assert.assertEquals(Integer.valueOf(-1), userId); + + PrincipalEntity principalEntity = new PrincipalEntity(); + UserEntity userEntity = new UserEntity(); + userEntity.setUserId(1); + userEntity.setPrincipal(principalEntity); + User user = new User(userEntity); + Authentication auth = new AmbariUserAuthentication(null, user, null); + SecurityContextHolder.getContext().setAuthentication(auth); + + userId = AuthorizationHelper.getAuthenticatedId(); + Assert.assertEquals(Integer.valueOf(1), userId); + } + + @Test + public void testAuthWithoutId() throws Exception { + Authentication auth = new UsernamePasswordAuthenticationToken("admin", null); + SecurityContextHolder.getContext().setAuthentication(auth); + + Integer userId = AuthorizationHelper.getAuthenticatedId(); + Assert.assertEquals(Integer.valueOf(-1), userId); + } + + @Test public void testLoginAliasAuthName() throws Exception { reset(servletRequestAttributes); http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java index dee4490..bcff6b4 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/TestUsers.java @@ -20,6 +20,7 @@ package org.apache.ambari.server.security.authorization; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.List; @@ -168,6 +169,23 @@ public class TestUsers { } @Test + public void testGetUserById() throws Exception { + users.createUser("user", "user", true, false, false); + User createdUser = users.getUser("user", UserType.LOCAL); + User userById = users.getUser(createdUser.getUserId()); + + assertNotNull(userById); + assertEquals(createdUser.getUserId(), userById.getUserId()); + } + + @Test + public void testGetUserByInvalidId() throws Exception { + User userById = users.getUser(-1); + + assertNull(userById); + } + + @Test public void testSetUserActive() throws Exception { users.createUser("user", "user"); http://git-wip-us.apache.org/repos/asf/ambari/blob/81842ee8/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java index 9b1c16c..670200c 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java @@ -285,6 +285,8 @@ public class UpgradeCatalog240Test { Capture<DBAccessor.DBColumnInfo> capturedClusterHandleColumn = EasyMock.newCapture(); dbAccessor.renameColumn(eq(UpgradeCatalog240.VIEWINSTANCE_TABLE), anyString() , capture(capturedClusterHandleColumn)); + Capture<DBAccessor.DBColumnInfo> requestScheduleUserIdInfo = newCapture(); + dbAccessor.addColumn(eq(UpgradeCatalog240.REQUESTSCHEDULE_TABLE), capture(requestScheduleUserIdInfo)); replay(dbAccessor, configuration, connection, statement, resultSet); @@ -411,8 +413,8 @@ public class UpgradeCatalog240Test { Assert.assertEquals(UpgradeCatalog240.ALERT_TARGET_ENABLED_COLUMN, targetEnabledColumnInfo.getName()); Assert.assertEquals(Short.class, targetEnabledColumnInfo.getType()); Assert.assertEquals(1, targetEnabledColumnInfo.getDefaultValue()); - Assert.assertEquals(false, targetEnabledColumnInfo.isNullable()); - + Assert.assertEquals(false, targetEnabledColumnInfo.isNullable()); + assertEquals(expectedCaptures, actualCaptures); // Verify blueprint_setting columns @@ -463,6 +465,13 @@ public class UpgradeCatalog240Test { Assert.assertEquals(UpgradeCatalog240.CLUSTER_HANDLE_COLUMN, clusterHandleColumn.getName()); Assert.assertEquals(Long.class, clusterHandleColumn.getType()); + // Verify authenticated_user_id column + DBAccessor.DBColumnInfo requestScheduleUserIdInfoValue = requestScheduleUserIdInfo.getValue(); + Assert.assertNotNull(requestScheduleUserIdInfoValue); + Assert.assertEquals("authenticated_user_id", requestScheduleUserIdInfoValue.getName()); + Assert.assertEquals(Integer.class, requestScheduleUserIdInfoValue.getType()); + Assert.assertEquals(null, requestScheduleUserIdInfoValue.getDefaultValue()); + verify(dbAccessor); }
