You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2016/06/08 15:52:08 UTC

ambari git commit: AMBARI-16247. Authorizations given to role-based principals must be dereferenced upon user login (rlevas)

Repository: ambari
Updated Branches:
  refs/heads/trunk 671f3bde8 -> 8c1564e08


AMBARI-16247. Authorizations given to role-based principals must be dereferenced upon user login (rlevas)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/8c1564e0
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8c1564e0
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8c1564e0

Branch: refs/heads/trunk
Commit: 8c1564e083169196cf53b8c1a570bcf3c5f65e68
Parents: 671f3bd
Author: Robert Levas <rl...@hortonworks.com>
Authored: Wed Jun 8 11:52:01 2016 -0400
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Wed Jun 8 11:52:01 2016 -0400

----------------------------------------------------------------------
 .../server/security/authorization/Users.java    |  46 +++++-
 .../security/authorization/UsersTest.java       | 145 +++++++++++++++++++
 2 files changed, 188 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/8c1564e0/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 545095d..f1abb90 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
@@ -44,7 +44,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.crypto.password.PasswordEncoder;
@@ -447,7 +446,7 @@ public class Users {
   /**
    * Grants AMBARI.ADMINISTRATOR privilege to provided user.
    *
-   * @param user user
+   * @param userId user id
    */
   public synchronized void grantAdminPrivilege(Integer userId) {
     final UserEntity user = userDAO.findByPK(userId);
@@ -466,7 +465,7 @@ public class Users {
   /**
    * Revokes AMBARI.ADMINISTRATOR privilege from provided user.
    *
-   * @param user user
+   * @param userId user id
    */
   public synchronized void revokeAdminPrivilege(Integer userId) {
     final UserEntity user = userDAO.findByPK(userId);
@@ -711,6 +710,23 @@ public class Users {
     entityManagerProvider.get().getEntityManagerFactory().getCache().evictAll();
   }
 
+  /**
+   * Gets the explicit and implicit authorities for the given user.
+   * <p>
+   * The explicit authorities are the authorities that have be explicitly set by assigning roles to
+   * a user.  For example the Cluster Operator role on a given cluster gives that the ability to
+   * start and stop services in that cluster, among other privileges for that particular cluster.
+   * <p>
+   * The implicit authorities are the authorities that have been given to the roles themselves which
+   * in turn are granted to the users that have been assigned those roles. For example if the
+   * Cluster User role for a given cluster has been given View User access on a specified File View
+   * instance, then all users who have the Cluster User role for that cluster will implicitly be
+   * granted View User access on that File View instance.
+   *
+   * @param userName the username for the relevant user
+   * @param userType the user type for the relevant user
+   * @return the users collection of implicit and explicit granted authorities
+   */
   public Collection<AmbariGrantedAuthority> getUserAuthorities(String userName, UserType userType) {
     UserEntity userEntity = userDAO.findUserByNameAndType(userName, userType);
     if (userEntity == null) {
@@ -730,12 +746,36 @@ public class Users {
 
     List<PrivilegeEntity> privilegeEntities = privilegeDAO.findAllByPrincipal(principalEntities);
 
+    // A list of principals representing roles/permissions. This collection of roles will be used to
+    // find additional authorizations inherited by the authenticated user based on the assigned roles.
+    // For example a File View instance may be set to be accessible to all authenticated user with
+    // the Cluster User role.
+    List<PrincipalEntity> rolePrincipals = new ArrayList<PrincipalEntity>();
+
     Set<AmbariGrantedAuthority> authorities = new HashSet<>(privilegeEntities.size());
 
     for (PrivilegeEntity privilegeEntity : privilegeEntities) {
+      // Add the principal representing the role associated with this PrivilegeEntity to the collection
+      // of roles for the authenticated user.
+      PrincipalEntity rolePrincipal = privilegeEntity.getPermission().getPrincipal();
+      if(rolePrincipal != null) {
+        rolePrincipals.add(rolePrincipal);
+      }
+
       authorities.add(new AmbariGrantedAuthority(privilegeEntity));
     }
 
+    // If the collections of assigned roles is not empty find the inherited authorizations that are
+    // give to the roles and add them to the collection of (Granted) authorities for the user.
+    if(!rolePrincipals.isEmpty()) {
+      // For each "role" see if any privileges have been granted...
+      List<PrivilegeEntity> rolePrivilegeEntities = privilegeDAO.findAllByPrincipal(rolePrincipals);
+
+      for (PrivilegeEntity privilegeEntity : rolePrivilegeEntities) {
+        authorities.add(new AmbariGrantedAuthority(privilegeEntity));
+      }
+    }
+
     return authorities;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/8c1564e0/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java
new file mode 100644
index 0000000..f059abc
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/UsersTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import junit.framework.Assert;
+import org.apache.ambari.server.orm.DBAccessor;
+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.GroupEntity;
+import org.apache.ambari.server.orm.entities.MemberEntity;
+import org.apache.ambari.server.orm.entities.PermissionEntity;
+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.ambari.server.state.stack.OsFamily;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
+import org.easymock.EasyMockSupport;
+import org.junit.Test;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import javax.persistence.EntityManager;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.newCapture;
+
+public class UsersTest extends EasyMockSupport {
+  @Test
+  public void testGetUserAuthorities() throws Exception {
+    Injector injector = getInjector();
+
+    PrincipalEntity userPrincipalEntity = createMock(PrincipalEntity.class);
+
+    UserEntity userEntity = createMock(UserEntity.class);
+    expect(userEntity.getPrincipal()).andReturn(userPrincipalEntity).times(1);
+
+    UserDAO userDAO = injector.getInstance(UserDAO.class);
+    expect(userDAO.findUserByNameAndType("user1", UserType.LOCAL)).andReturn(userEntity).times(1);
+
+    PrincipalEntity groupPrincipalEntity = createMock(PrincipalEntity.class);
+
+    GroupEntity groupEntity = createMock(GroupEntity.class);
+    expect(groupEntity.getPrincipal()).andReturn(groupPrincipalEntity).times(1);
+
+    MemberEntity memberEntity = createMock(MemberEntity.class);
+    expect(memberEntity.getGroup()).andReturn(groupEntity).times(1);
+
+    MemberDAO memberDAO = injector.getInstance(MemberDAO.class);
+    expect(memberDAO.findAllMembersByUser(userEntity)).andReturn(Collections.singletonList(memberEntity)).times(1);
+
+    PrincipalEntity clusterUserPrivilegePermissionPrincipalEntity = createMock(PrincipalEntity.class);
+
+    PermissionEntity clusterUserPrivilegePermissionEntity = createMock(PermissionEntity.class);
+    expect(clusterUserPrivilegePermissionEntity.getPrincipal()).andReturn(clusterUserPrivilegePermissionPrincipalEntity).times(1);
+
+    PrivilegeEntity clusterUserPrivilegeEntity = createMock(PrivilegeEntity.class);
+    expect(clusterUserPrivilegeEntity.getPermission()).andReturn(clusterUserPrivilegePermissionEntity).times(1);
+
+    PrincipalEntity clusterOperatorPrivilegePermissionPrincipalEntity = createMock(PrincipalEntity.class);
+
+    PermissionEntity clusterOperatorPrivilegePermissionEntity = createMock(PermissionEntity.class);
+    expect(clusterOperatorPrivilegePermissionEntity.getPrincipal()).andReturn(clusterOperatorPrivilegePermissionPrincipalEntity).times(1);
+
+    PrivilegeEntity clusterOperatorPrivilegeEntity = createMock(PrivilegeEntity.class);
+    expect(clusterOperatorPrivilegeEntity.getPermission()).andReturn(clusterOperatorPrivilegePermissionEntity).times(1);
+
+    List<PrivilegeEntity> privilegeEntities = new ArrayList<PrivilegeEntity>();
+    privilegeEntities.add(clusterUserPrivilegeEntity);
+    privilegeEntities.add(clusterOperatorPrivilegeEntity);
+
+    PrivilegeEntity clusterUserViewUserPrivilegeEntity = createMock(PrivilegeEntity.class);
+
+    List<PrivilegeEntity> rolePrivilegeEntities = new ArrayList<PrivilegeEntity>();
+    rolePrivilegeEntities.add(clusterUserViewUserPrivilegeEntity);
+
+    Capture<? extends List<PrincipalEntity>> principalEntitiesCapture = newCapture();
+    Capture<? extends List<PrincipalEntity>> rolePrincipalEntitiesCapture = newCapture();
+
+    PrivilegeDAO privilegeDAO = injector.getInstance(PrivilegeDAO.class);
+    expect(privilegeDAO.findAllByPrincipal(capture(principalEntitiesCapture))).andReturn(privilegeEntities).times(1);
+    expect(privilegeDAO.findAllByPrincipal(capture(rolePrincipalEntitiesCapture))).andReturn(rolePrivilegeEntities).times(1);
+
+    replayAll();
+
+    Users user = injector.getInstance(Users.class);
+    Collection<AmbariGrantedAuthority> authorities = user.getUserAuthorities("user1", UserType.LOCAL);
+
+    verifyAll();
+
+    Assert.assertEquals(2, principalEntitiesCapture.getValue().size());
+    Assert.assertTrue(principalEntitiesCapture.getValue().contains(userPrincipalEntity));
+    Assert.assertTrue(principalEntitiesCapture.getValue().contains(groupPrincipalEntity));
+
+    Assert.assertEquals(2, rolePrincipalEntitiesCapture.getValue().size());
+    Assert.assertTrue(rolePrincipalEntitiesCapture.getValue().contains(clusterUserPrivilegePermissionPrincipalEntity));
+    Assert.assertTrue(rolePrincipalEntitiesCapture.getValue().contains(clusterOperatorPrivilegePermissionPrincipalEntity));
+
+
+    Assert.assertEquals(3, authorities.size());
+    Assert.assertTrue(authorities.contains(new AmbariGrantedAuthority(clusterUserPrivilegeEntity)));
+    Assert.assertTrue(authorities.contains(new AmbariGrantedAuthority(clusterOperatorPrivilegeEntity)));
+    Assert.assertTrue(authorities.contains(new AmbariGrantedAuthority(clusterUserViewUserPrivilegeEntity)));
+  }
+
+  private Injector getInjector() {
+    return Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(EntityManager.class).toInstance(createMock(EntityManager.class));
+        bind(DBAccessor.class).toInstance(createMock(DBAccessor.class));
+        bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
+        bind(UserDAO.class).toInstance(createMock(UserDAO.class));
+        bind(MemberDAO.class).toInstance(createMock(MemberDAO.class));
+        bind(PrivilegeDAO.class).toInstance(createMock(PrivilegeDAO.class));
+        bind(PasswordEncoder.class).toInstance(createMock(PasswordEncoder.class));
+      }
+    });
+  }
+}
\ No newline at end of file