OOZIE-3217 Enable definition of admin users using oozie-site.xml (orova via andras...
authorAndras Piros <andras.piros@cloudera.com>
Wed, 16 May 2018 08:50:07 +0000 (10:50 +0200)
committerAndras Piros <andras.piros@cloudera.com>
Wed, 16 May 2018 08:50:07 +0000 (10:50 +0200)
core/src/main/java/org/apache/oozie/service/AuthorizationService.java
core/src/main/resources/oozie-default.xml
core/src/test/java/org/apache/oozie/service/TestAuthorizationService.java
core/src/test/java/org/apache/oozie/test/XTestCase.java
docs/src/site/twiki/AG_Install.twiki
release-log.txt

index 33fd9c3..251838c 100644 (file)
@@ -25,12 +25,15 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.URI;
+import java.nio.charset.StandardCharsets;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.ArrayList;
 import java.util.Set;
-
+import java.util.LinkedHashSet;
+import com.google.common.collect.Sets;
+import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
@@ -82,6 +85,11 @@ public class AuthorizationService implements Service {
 
     public static final String CONF_SYSTEM_INFO_AUTHORIZED_USERS = CONF_PREFIX + "system.info.authorized.users";
 
+    /**
+     * Configuration parameter to define admin users in oozie-site.xml.
+     * These admin users shall be added to the admin users found in adminusers.txt
+     */
+    public static final String CONF_ADMIN_USERS = CONF_PREFIX + "admin.users";
 
     /**
      * File that contains list of admin users for Oozie.
@@ -140,7 +148,8 @@ public class AuthorizationService implements Service {
             else {
                 log.info("Admin users will be checked against the 'adminusers.txt' file contents");
                 adminUsers = new HashSet<String>();
-                loadAdminUsers();
+                loadAdminUsersFromFile();
+                loadAdminUsersFromConfiguration();
             }
         }
         else {
@@ -177,13 +186,15 @@ public class AuthorizationService implements Service {
      *
      * @throws ServiceException if the admin user list could not be loaded.
      */
-    private void loadAdminUsers() throws ServiceException {
+    private void loadAdminUsersFromFile() throws ServiceException {
         String configDir = Services.get().get(ConfigurationService.class).getConfigDir();
         if (configDir != null) {
-            File file = new File(configDir, ADMIN_USERS_FILE);
+            File file = new File(FilenameUtils.getFullPath(configDir)+FilenameUtils.getBaseName(configDir),
+                    FilenameUtils.getName(ADMIN_USERS_FILE));
             if (file.exists()) {
                 try {
-                    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
+                    BufferedReader br = new BufferedReader(
+                            new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
                     try {
                         String line = br.readLine();
                         while (line != null) {
@@ -197,13 +208,16 @@ public class AuthorizationService implements Service {
                     catch (IOException ex) {
                         throw new ServiceException(ErrorCode.E0160, file.getAbsolutePath(), ex);
                     }
+                    finally {
+                        br.close();
+                    }
                 }
-                catch (FileNotFoundException ex) {
+                catch (IOException ex) {
                     throw new ServiceException(ErrorCode.E0160, file.getAbsolutePath(), ex);
                 }
             }
             else {
-                log.warn("Admin users file not available in config dir [{0}], running without admin users", configDir);
+                log.warn("Admin users file not available in config dir [{0}]", configDir);
             }
         }
         else {
@@ -211,6 +225,15 @@ public class AuthorizationService implements Service {
         }
     }
 
+    private void loadAdminUsersFromConfiguration() {
+        LinkedHashSet<String> adminsFromOozieSite = Sets.newLinkedHashSet();
+        adminsFromOozieSite.addAll(Services.get().get(ConfigurationService.class).getConf().getStringCollection(CONF_ADMIN_USERS));
+        if (!adminsFromOozieSite.isEmpty()) {
+            log.info("{0} admin users found in oozie-site.xml", adminsFromOozieSite.size());
+            adminUsers.addAll(adminsFromOozieSite);
+        }
+    }
+
     /**
      * Destroy the service. <p> This implementation does a NOP.
      */
index 6f89258..c54db34 100644 (file)
     </property>
 
     <property>
+        <name>oozie.serviceAuthorizationService.admin.users</name>
+        <value></value>
+        <description>
+            Comma separated list of users with admin access for the Authorization service.
+        </description>
+    </property>
+
+    <property>
         <name>oozie.service.AuthorizationService.system.info.authorized.users</name>
         <value></value>
         <description>
index 8df0904..be5242e 100644 (file)
@@ -80,10 +80,12 @@ public class TestAuthorizationService extends XDataTestCase {
     private Services services;
 
     private void init(boolean useDefaultGroup, boolean useAdminUsersFile) throws Exception {
-        init(useDefaultGroup, useAdminUsersFile, StringUtils.EMPTY);
+        boolean useAdminGroups = !useAdminUsersFile;
+        init(useDefaultGroup, StringUtils.EMPTY, useAdminUsersFile, false, useAdminGroups);
     }
 
-    private void init(boolean useDefaultGroup, boolean useAdminUsersFile, String systemInfoAuthUsers) throws
+    private void init(boolean useDefaultGroup, String systemInfoAuthUsers,
+                      boolean useAdminUsersFile, boolean useOozieSiteForAdminUsers, boolean useAdminGroups) throws
             Exception {
         setSystemProperty(SchemaService.WF_CONF_EXT_SCHEMAS, "wf-ext-schema.xsd");
 
@@ -94,14 +96,20 @@ public class TestAuthorizationService extends XDataTestCase {
             Writer adminListWriter = new FileWriter(new File(getTestCaseConfDir(), "adminusers.txt"));
             IOUtils.copyCharStream(adminListReader, adminListWriter);
         }
-        else {
+        if (useAdminGroups) {
             conf.set(AuthorizationService.CONF_ADMIN_GROUPS, getTestGroup());
         }
+
+        if (useOozieSiteForAdminUsers) {
+            conf.set(AuthorizationService.CONF_ADMIN_USERS, getAdminUser());
+        }
+
         conf.set(AuthorizationService.CONF_SYSTEM_INFO_AUTHORIZED_USERS, systemInfoAuthUsers);
         conf.set(Services.CONF_SERVICE_CLASSES,
                 conf.get(Services.CONF_SERVICE_CLASSES) + "," + AuthorizationService.class.getName() + ","
                         + DummyGroupsService.class.getName());
         conf.set(AuthorizationService.CONF_DEFAULT_GROUP_AS_ACL, Boolean.toString(useDefaultGroup));
+        conf.setBoolean(AuthorizationService.CONF_AUTHORIZATION_ENABLED, true);
         services.init();
         services.getConf().setBoolean(AuthorizationService.CONF_SECURITY_ENABLED, true);
         services.get(AuthorizationService.class).init(services);
@@ -311,8 +319,10 @@ public class TestAuthorizationService extends XDataTestCase {
         }
     }
 
-    private void _testAdminUsers(boolean useAdminFile, String adminUser, String regularUser) throws Exception {
-        init(true, useAdminFile);
+
+    private void _testAdminUsers(boolean useAdminFile, String adminUser, String regularUser,
+                                 boolean adminUserFromOozieSite, boolean useAdminGroup) throws Exception {
+        init(true, StringUtils.EMPTY, useAdminFile, adminUserFromOozieSite, useAdminGroup );
 
         AuthorizationService as = services.get(AuthorizationService.class);
         as.authorizeForAdmin(adminUser, false);
@@ -323,31 +333,25 @@ public class TestAuthorizationService extends XDataTestCase {
         }
         catch (AuthorizationException ex) {
         }
-        try {
-            as.authorizeForAdmin(regularUser, true);
-            fail();
-        }
-        catch (AuthorizationException ex) {
-        }
     }
 
     public void testAdminUsersWithAdminFile() throws Exception {
-        _testAdminUsers(true, "admin", getTestUser());
+        _testAdminUsers(true, "admin", getTestUser(), false, false);
     }
 
     public void testAdminUsersWithAdminGroup() throws Exception {
-        _testAdminUsers(false, getTestUser(), getTestUser2());
+        _testAdminUsers(false, getTestUser(), getTestUser2(), false, true);
     }
 
     public void testAuthorizedSystemInfoDefaultSuccess() throws Exception {
         //AuthorizationService.CONF_SYSTEM_INFO_AUTHORIZED_USERS is empty
-        init(true, false, StringUtils.EMPTY);
+        init(true, StringUtils.EMPTY, false, false, true);
         services.get(AuthorizationService.class).authorizeForSystemInfo("regularUser", "proxyUser");
     }
 
     public void testAuthorizedSystemInfoSuccess() throws Exception {
         //Set AuthorizationService.CONF_SYSTEM_INFO_AUTHORIZED_USERS to proxyUser,regularUser
-        init(true, false, "proxyUser,regularUser");
+        init(true, "proxyUser,regularUser", false, false, true);
 
         //Use proxyUser in request
         services.get(AuthorizationService.class).authorizeForSystemInfo("regularUser1", "proxyUser");
@@ -361,7 +365,7 @@ public class TestAuthorizationService extends XDataTestCase {
     }
 
     public void testAuthorizedSystemInfoFailure() throws Exception {
-        init(true, false, "proxyUser,regularUser");
+        init(true, "proxyUser,regularUser", false, false, true);
         try {
             services.get(AuthorizationService.class).authorizeForSystemInfo("regularUser1", "proxyUser1");
             fail("Should have thrown exception because regularUser1 or proxyUser1 are not authorized to access system info");
@@ -371,4 +375,26 @@ public class TestAuthorizationService extends XDataTestCase {
                     "E0503: User [regularUser1] does not have admin " + "privileges", ex.getMessage());
         }
     }
+
+    public void testWhenDefinedInConfigurationThenAdminPrivilegesAllowed() throws Exception {
+        _testAdminUsers(false, getAdminUser(), getTestUser(), true, false);
+    }
+
+    public void testWhenDefinedInAdminFileAndConfigurationThenAllowBothAdmins() throws Exception {
+        init(true, StringUtils.EMPTY, true, true, false );
+
+        AuthorizationService as = services.get(AuthorizationService.class);
+        as.authorizeForAdmin(getAdminUser(), false);
+        as.authorizeForAdmin(getAdminUser(), true);
+        as.authorizeForAdmin("admin", false);
+        as.authorizeForAdmin("admin", true);
+        try {
+            as.authorizeForAdmin(getTestUser(), true);
+            fail();
+        }
+        catch (AuthorizationException ex) {
+        }
+
+
+    }
 }
index f471b88..a8be36b 100644 (file)
@@ -258,6 +258,12 @@ public abstract class XTestCase extends TestCase {
     public static final String TEST_GROUP_PROP = "oozie.test.group";
 
     /**
+     * System property that specifies the test admin user used in the tests.
+     * The default value of this property is myAdmin
+     */
+    public static final String TEST_ADMIN_PROP = "oozie.test.admin.user";
+
+    /**
      * System property that specifies the test groiup used by the tests.
      * The default value of this property is <tt>testg</tt>.
      */
@@ -609,6 +615,14 @@ public abstract class XTestCase extends TestCase {
     }
 
     /**
+     * Return Admin user
+     * @return the admin user
+     */
+    protected static String getAdminUser(){
+        return System.getProperty(TEST_ADMIN_PROP,"myAdmin");
+    }
+
+    /**
      * Return the alternate test group.
      *
      * @return the test group.
index 77ee4ee..2d48d43 100644 (file)
@@ -528,12 +528,20 @@ Admin users are determined from the list of admin groups, specified in
  =oozie.service.AuthorizationService.admin.groups= property. Use commas to separate multiple groups, spaces, tabs
 and ENTER characters are trimmed.
 
-If the above property for admin groups is not set, then the admin users are the users specified in the
- =conf/adminusers.txt= file. The syntax of this file is:
+If the above property for admin groups is not set, then defining the admin users can happen in the following manners.
+The list of admin users can be in the =conf/adminusers.txt= file. The syntax of this file is:
 
    * One user name per line
    * Empty lines and lines starting with '#' are ignored
 
+Admin users can also be defined in
+=oozie.serviceAuthorizationService.admin.users= property. Use commas to separate multiple admin users, spaces, tabs
+and ENTER characters are trimmed.
+
+In case there are admin users defined using both methods, the effective list of admin users will be the union
+of the admin users found in the adminusers.txt and those specified with =oozie.serviceAuthorizationService.admin.users=.
+
+
 ---+++ Oozie System ID Configuration
 
 Oozie has a system ID that is is used to generate the Oozie temporary runtime directory, the workflow job IDs, and the
index e1c359d..5d30c19 100644 (file)
@@ -1,5 +1,6 @@
 -- Oozie 5.1.0 release (trunk - unreleased)
 
+OOZIE-3217 Enable definition of admin users using oozie-site.xml (orova via andras.piros)
 OOZIE-3219 Cannot compile with hadoop 3.1.0 (dbist13, andras.piros)
 OOZIE-3232 Reduce heap waste by reducing duplicate string count (Misha Dmitriev via andras.piros)
 OOZIE-2914 Consolidate trim calls (Jan Hentschel via andras.piros)