You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@falcon.apache.org by ve...@apache.org on 2014/08/08 19:43:47 UTC
[8/9] git commit: FALCON-557 Add super-user who is authorized for
all. Contributed by Venkatesh Seetharam
FALCON-557 Add super-user who is authorized for all. Contributed by Venkatesh Seetharam
Project: http://git-wip-us.apache.org/repos/asf/incubator-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-falcon/commit/84cc3684
Tree: http://git-wip-us.apache.org/repos/asf/incubator-falcon/tree/84cc3684
Diff: http://git-wip-us.apache.org/repos/asf/incubator-falcon/diff/84cc3684
Branch: refs/heads/master
Commit: 84cc3684de2b29bfd50fcaba755692dbf03cf478
Parents: 7b3e510
Author: Venkatesh Seetharam <ve...@apache.org>
Authored: Fri Aug 8 10:20:47 2014 -0700
Committer: Venkatesh Seetharam <ve...@apache.org>
Committed: Fri Aug 8 10:22:56 2014 -0700
----------------------------------------------------------------------
.../security/DefaultAuthorizationProvider.java | 106 ++++++++++++++-----
common/src/main/resources/startup.properties | 7 +-
.../DefaultAuthorizationProviderTest.java | 35 +++++-
docs/src/site/twiki/Security.twiki | 25 ++++-
src/conf/startup.properties | 7 +-
5 files changed, 145 insertions(+), 35 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/84cc3684/common/src/main/java/org/apache/falcon/security/DefaultAuthorizationProvider.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/falcon/security/DefaultAuthorizationProvider.java b/common/src/main/java/org/apache/falcon/security/DefaultAuthorizationProvider.java
index 5561429..c7e87f4 100644
--- a/common/src/main/java/org/apache/falcon/security/DefaultAuthorizationProvider.java
+++ b/common/src/main/java/org/apache/falcon/security/DefaultAuthorizationProvider.java
@@ -70,10 +70,26 @@ public class DefaultAuthorizationProvider implements AuthorizationProvider {
private static final String ADMIN_USERS_KEY = FALCON_PREFIX + "admin.users";
private static final String ADMIN_GROUPS_KEY = FALCON_PREFIX + "admin.groups";
+ /**
+ * The super-user is the user with the same identity as falcon process itself.
+ * Loosely, if you started falcon, then you are the super-user.
+ */
+ protected static final String SUPER_USER = System.getProperty("user.name");
+
+ /**
+ * Constant for the configuration property that indicates the super user group.
+ */
+ private static final String SUPER_USER_GROUP_KEY = FALCON_PREFIX + "superusergroup";
+
+ /**
+ * Super ser group.
+ */
+ private String superUserGroup;
private Set<String> adminUsers;
private Set<String> adminGroups;
public DefaultAuthorizationProvider() {
+ superUserGroup = StartupProperties.get().getProperty(SUPER_USER_GROUP_KEY);
adminUsers = getAdminNamesFromConfig(ADMIN_USERS_KEY);
adminGroups = getAdminNamesFromConfig(ADMIN_GROUPS_KEY);
}
@@ -104,25 +120,42 @@ public class DefaultAuthorizationProvider implements AuthorizationProvider {
String entityType, String entityName,
UserGroupInformation proxyUgi) throws AuthorizationException {
Validate.notEmpty(resource, "Resource cannot be empty or null");
+ Validate.isTrue(RESOURCES.contains(resource), "Illegal resource: " + resource);
Validate.notEmpty(action, "Action cannot be empty or null");
- Set<String> groups = getGroupNames(proxyUgi);
- String authenticatedUser = proxyUgi.getShortUserName();
- LOG.info("Authorizing authenticatedUser={}, groups={} against resource={}, action={}, entity name={}, "
- + "entity type={}", authenticatedUser, groups, resource, action, entityName, entityType);
+ LOG.info("Authorizing authenticatedUser={}, against resource={}, action={}, entity name={}, "
+ + "entity type={}", proxyUgi.getShortUserName(), resource, action, entityName, entityType);
+
+ if (isSuperUser(proxyUgi)) {
+ return;
+ }
if ("admin".equals(resource)) {
- authorizeAdminResource(authenticatedUser, groups, action);
+ if (!"version".equals(action)) {
+ authorizeAdminResource(proxyUgi, action);
+ }
} else if ("entities".equals(resource) || "instance".equals(resource)) {
- authorizeEntityResource(authenticatedUser, proxyUgi, entityName, entityType, action);
+ authorizeEntityResource(proxyUgi, entityName, entityType, action);
} else if ("lineage".equals(resource)) {
- authorizeLineageResource(authenticatedUser, action);
- } else {
- throw new AuthorizationException("Unknown resource: " + resource);
+ authorizeLineageResource(proxyUgi.getShortUserName(), action);
}
}
- private Set<String> getGroupNames(UserGroupInformation proxyUgi) {
+ /**
+ * Determines if the authenticated user is the user who started this process
+ * or belongs to the super user group.
+ *
+ * @param authenticatedUGI UGI
+ * @return true if super user else false.
+ */
+ protected boolean isSuperUser(UserGroupInformation authenticatedUGI) {
+ final String authenticatedUser = authenticatedUGI.getShortUserName();
+ return SUPER_USER.equals(authenticatedUser)
+ || (!StringUtils.isEmpty(superUserGroup)
+ && isUserInGroup(superUserGroup, authenticatedUGI));
+ }
+
+ protected Set<String> getGroupNames(UserGroupInformation proxyUgi) {
HashSet<String> s = new HashSet<String>(Arrays.asList(proxyUgi.getGroupNames()));
return Collections.unmodifiableSet(s);
}
@@ -146,6 +179,10 @@ public class DefaultAuthorizationProvider implements AuthorizationProvider {
LOG.info("Authorizing authenticatedUser={}, action={}, entity={}, type{}",
authenticatedUser, action, entityName, entityType);
+ if (isSuperUser(proxyUgi)) {
+ return;
+ }
+
checkUser(entityName, acl.getOwner(), acl.getGroup(), action, authenticatedUser, proxyUgi);
}
@@ -164,7 +201,7 @@ public class DefaultAuthorizationProvider implements AuthorizationProvider {
String action, String authenticatedUser,
UserGroupInformation proxyUgi) throws AuthorizationException {
if (isUserACLOwner(authenticatedUser, aclOwner)
- || isUserInAclGroup(aclGroup, proxyUgi)) {
+ || isUserInGroup(aclGroup, proxyUgi)) {
return;
}
@@ -179,37 +216,52 @@ public class DefaultAuthorizationProvider implements AuthorizationProvider {
throw new AuthorizationException(message.toString());
}
+ /**
+ * Determines if the authenticated user is the entity ACL owner.
+ *
+ * @param authenticatedUser authenticated user
+ * @param aclOwner entity ACL owner
+ * @return true if authenticated user is the entity acl owner, false otherwise.
+ */
protected boolean isUserACLOwner(String authenticatedUser, String aclOwner) {
return authenticatedUser.equals(aclOwner);
}
- protected boolean isUserInAclGroup(String aclGroup, UserGroupInformation proxyUgi) {
+ /**
+ * Checks if the user's group matches the entity ACL group.
+ *
+ * @param group Entity ACL group.
+ * @param proxyUgi proxy ugi for the authenticated user.
+ * @return true if user groups contains entity acl group.
+ */
+ protected boolean isUserInGroup(String group, UserGroupInformation proxyUgi) {
Set<String> groups = getGroupNames(proxyUgi);
- return groups.contains(aclGroup);
+ return groups.contains(group);
}
/**
* Check if the user has admin privileges.
*
- * @param user user name.
- * @param groups groups that the user belongs to.
- * @param action admin action on the resource
+ * @param proxyUgi proxy ugi for the authenticated user.
+ * @param action admin action on the resource.
* @throws AuthorizationException if the user does not have admin privileges.
*/
- protected void authorizeAdminResource(String user, Set<String> groups,
+ protected void authorizeAdminResource(UserGroupInformation proxyUgi,
String action) throws AuthorizationException {
- LOG.debug("Authorizing user={} for admin, action={}", user, action);
- if (adminUsers.contains(user) || isUserInAdminGroups(groups)) {
+ final String authenticatedUser = proxyUgi.getShortUserName();
+ LOG.debug("Authorizing user={} for admin, action={}", authenticatedUser, action);
+ if (adminUsers.contains(authenticatedUser) || isUserInAdminGroups(proxyUgi)) {
return;
}
LOG.error("Permission denied: user {} does not have admin privilege for action={}",
- user, action);
- throw new AuthorizationException("Permission denied: user=" + user
+ authenticatedUser, action);
+ throw new AuthorizationException("Permission denied: user=" + authenticatedUser
+ " does not have admin privilege for action=" + action);
}
- protected boolean isUserInAdminGroups(Set<String> groups) {
+ protected boolean isUserInAdminGroups(UserGroupInformation proxyUgi) {
+ Set<String> groups = getGroupNames(proxyUgi);
boolean isUserGroupInAdmin = false;
for (String group : groups) {
if (adminGroups.contains(group)) {
@@ -221,13 +273,13 @@ public class DefaultAuthorizationProvider implements AuthorizationProvider {
return isUserGroupInAdmin;
}
- protected void authorizeEntityResource(String authenticatedUser, UserGroupInformation proxyUgi,
+ protected void authorizeEntityResource(UserGroupInformation proxyUgi,
String entityName, String entityType,
String action) throws AuthorizationException {
Validate.notEmpty(entityType, "Entity type cannot be empty or null");
LOG.debug("Authorizing authenticatedUser={} against entity/instance action={}, "
- + "entity name={}, entity type={}", authenticatedUser, action, entityName,
- entityType);
+ + "entity name={}, entity type={}",
+ proxyUgi.getShortUserName(), action, entityName, entityType);
if (entityName != null) { // lifecycle actions
Entity entity = getEntity(entityName, entityType);
@@ -260,8 +312,10 @@ public class DefaultAuthorizationProvider implements AuthorizationProvider {
return ((org.apache.falcon.entity.v0.process.Process) entity).getACL();
default:
- throw new AuthorizationException("Cannot get owner for entity: " + entity.getName());
+ break;
}
+
+ throw new AuthorizationException("Cannot get owner for entity: " + entity.getName());
}
protected void authorizeLineageResource(String authenticatedUser, String action) {
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/84cc3684/common/src/main/resources/startup.properties
----------------------------------------------------------------------
diff --git a/common/src/main/resources/startup.properties b/common/src/main/resources/startup.properties
index 808fed6..0d49b4b 100644
--- a/common/src/main/resources/startup.properties
+++ b/common/src/main/resources/startup.properties
@@ -142,11 +142,14 @@ debug.libext.process.paths=${falcon.libext}
# Authorization Enabled flag: false (default)|true
*.falcon.security.authorization.enabled=false
+# The name of the group of super-users
+*.falcon.security.authorization.superusergroup=falcon
+
# Admin Users, comma separated users
-*.falcon.security.authorization.admin.users=falcon,ambari-qa,seetharam
+*.falcon.security.authorization.admin.users=falcon,ambari-qa
# Admin Group Membership, comma separated users
-*.falcon.security.authorization.admin.groups=falcon,testgroup,staff
+*.falcon.security.authorization.admin.groups=falcon,staff
# Authorization Provider Implementation Fully Qualified Class Name
*.falcon.security.authorization.provider=org.apache.falcon.security.DefaultAuthorizationProvider
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/84cc3684/common/src/test/java/org/apache/falcon/security/DefaultAuthorizationProviderTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/falcon/security/DefaultAuthorizationProviderTest.java b/common/src/test/java/org/apache/falcon/security/DefaultAuthorizationProviderTest.java
index 0fd869e..125aa85 100644
--- a/common/src/test/java/org/apache/falcon/security/DefaultAuthorizationProviderTest.java
+++ b/common/src/test/java/org/apache/falcon/security/DefaultAuthorizationProviderTest.java
@@ -121,6 +121,35 @@ public class DefaultAuthorizationProviderTest {
}
}
+ @Test
+ public void testAuthorizeAdminResourceVersionAction() throws Exception {
+ UserGroupInformation proxyUgi = UserGroupInformation.createProxyUserForTesting(
+ "blah", realUser, new String[]{"blah-group", });
+
+ DefaultAuthorizationProvider provider = new DefaultAuthorizationProvider();
+ provider.authorizeResource("admin", "version", null, null, proxyUgi);
+ }
+
+ @Test
+ public void testAuthorizeSuperUser() throws Exception {
+ UserGroupInformation proxyUgi = UserGroupInformation.createProxyUserForTesting(
+ EntityBuilderTestUtil.USER, realUser, new String[]{"group", });
+
+ DefaultAuthorizationProvider provider = new DefaultAuthorizationProvider();
+ provider.authorizeResource("entities", "schedule", "feed", feedEntity.getName(), proxyUgi);
+ provider.authorizeResource("instance", "status", "feed", feedEntity.getName(), proxyUgi);
+ }
+
+ @Test
+ public void testAuthorizeSuperUserGroup() throws Exception {
+ UserGroupInformation proxyUgi = UserGroupInformation.createProxyUserForTesting(
+ "blah", realUser, new String[]{"falcon", });
+
+ DefaultAuthorizationProvider provider = new DefaultAuthorizationProvider();
+ provider.authorizeResource("entities", "schedule", "feed", feedEntity.getName(), proxyUgi);
+ provider.authorizeResource("instance", "status", "feed", feedEntity.getName(), proxyUgi);
+ }
+
@DataProvider(name = "adminResourceActions")
private Object[][] createAdminResourceActions() {
return new Object[][] {
@@ -175,7 +204,7 @@ public class DefaultAuthorizationProviderTest {
"admin-user", realUser, new String[]{"admin-group", });
DefaultAuthorizationProvider provider = new DefaultAuthorizationProvider();
- provider.authorizeResource("admin", "version", null, null, proxyUgi);
+ provider.authorizeResource("admin", "stack", null, null, proxyUgi);
Assert.fail("User does not belong to both admin-users not groups");
}
@@ -236,7 +265,7 @@ public class DefaultAuthorizationProviderTest {
provider.authorizeResource(resource, action, entityType, entityName, proxyUgi);
}
- @Test (expectedExceptions = AuthorizationException.class)
+ @Test (expectedExceptions = IllegalArgumentException.class)
public void testAuthorizeBadResource() throws Exception {
StartupProperties.get().setProperty("falcon.security.authorization.admin.users", "admin");
StartupProperties.get().setProperty("falcon.security.authorization.admin.groups", "admin");
@@ -324,7 +353,7 @@ public class DefaultAuthorizationProviderTest {
"admin", realUser, new String[]{"admin", });
DefaultAuthorizationProvider provider = new DefaultAuthorizationProvider();
- provider.authorizeResource("entities", "status", "feed", processEntity.getName(), proxyUgi);
+ provider.authorizeResource("entities", "status", "process", feedEntity.getName(), proxyUgi);
Assert.fail("Bad entity");
}
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/84cc3684/docs/src/site/twiki/Security.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/Security.twiki b/docs/src/site/twiki/Security.twiki
index 4dc0f4d..f91c350 100644
--- a/docs/src/site/twiki/Security.twiki
+++ b/docs/src/site/twiki/Security.twiki
@@ -55,6 +55,19 @@ owner is the Owner of this entity.
group is the one which has access to read.
permission indicates the rwx is not enforced at this time.
+---+++ Super-User
+
+The super-user is the user with the same identity as falcon process itself. Loosely, if you
+started the falcon, then you are the super-user. The super-user can do anything in that
+permissions checks never fail for the super-user. There is no persistent notion of who was the
+super-user; when the falcon is started the process identity determines who is the super-user
+for now. The Falcon super-user does not have to be the super-user of the falcon host, nor is it
+necessary that all clusters have the same super-user. Also, an experimenter running Falcon on a
+personal workstation, conveniently becomes that installation's super-user without any configuration.
+
+Falcon also allows users to configure a super user group and allows users belonging to this
+group to be a super user.
+
---+++ Group Memberships
Once a user has been authenticated and a username has been determined, the list of groups is
@@ -126,8 +139,8 @@ Only users belonging to admin users or groups have access to this resource. Admi
determined by a static configuration parameter.
| *Resource* | *Description* | *Authorization* |
+| [[restapi/AdminVersion][api/admin/version]] | Get version of the server | No restriction |
| [[restapi/AdminStack][api/admin/stack]] | Get stack of the server | Admin User/Group |
-| [[restapi/AdminVersion][api/admin/version]] | Get version of the server | Admin User/Group |
| [[restapi/AdminConfig][api/admin/config/:config-type]] | Get configuration information of the server | Admin User/Group |
@@ -230,7 +243,6 @@ startup configuration.
*.falcon.security.authorization.enabled=true
</verbatim>
-
---+++ Authorization Provider
Falcon provides a basic implementation for Authorization bundled, org.apache.falcon.security .DefaultFalconAuthorizationProvider.
@@ -241,6 +253,15 @@ This can be overridden by custom implementations in the startup configuration.
*.falcon.security.authorization.provider=org.apache.falcon.security.DefaultAuthorizationProvider
</verbatim>
+---+++ Super User Group
+
+Super user group is determined by the configuration:
+
+<verbatim>
+# The name of the group of super-users
+*.falcon.security.authorization.superusergroup=falcon
+</verbatim>
+
---+++ Admin Membership
Administrative users are determined by the configuration:
http://git-wip-us.apache.org/repos/asf/incubator-falcon/blob/84cc3684/src/conf/startup.properties
----------------------------------------------------------------------
diff --git a/src/conf/startup.properties b/src/conf/startup.properties
index 526656f..2c0bbbc 100644
--- a/src/conf/startup.properties
+++ b/src/conf/startup.properties
@@ -147,11 +147,14 @@ prism.configstore.listeners=org.apache.falcon.entity.v0.EntityGraph,\
# Authorization Enabled flag: false (default)|true
*.falcon.security.authorization.enabled=false
+# The name of the group of super-users
+*.falcon.security.authorization.superusergroup=falcon
+
# Admin Users, comma separated users
-*.falcon.security.authorization.admin.users=falcon,ambari-qa,seetharam
+*.falcon.security.authorization.admin.users=falcon,ambari-qa
# Admin Group Membership, comma separated users
-*.falcon.security.authorization.admin.groups=falcon,testgroup,staff
+*.falcon.security.authorization.admin.groups=falcon,staff
# Authorization Provider Implementation Fully Qualified Class Name
*.falcon.security.authorization.provider=org.apache.falcon.security.DefaultAuthorizationProvider