This is an automated email from the ASF dual-hosted git repository.

suvasude pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/gobblin.git


The following commit(s) were added to refs/heads/master by this push:
     new 464459b  [GOBBLIN-1418] Add config to make it possible to specify a 
default Authenticator for a job
464459b is described below

commit 464459b24f69e3b26b4b78ae0833d7296a135377
Author: Jack Moseley <[email protected]>
AuthorDate: Thu Apr 15 12:40:38 2021 -0700

    [GOBBLIN-1418] Add config to make it possible to specify a default 
Authenticator for a job
    
    Closes #3254 from jack-moseley/default-
    authenticator
---
 .../gobblin/configuration/ConfigurationKeys.java   |  5 ++
 .../password/EncryptedPasswordAuthenticator.java   | 51 ++++++++++++++++
 .../EncryptedPasswordAuthenticatorTest.java        | 71 ++++++++++++++++++++++
 .../gobblin/password/PasswordManagerTest.java      |  2 +-
 .../gobblin/runtime/AbstractJobLauncher.java       | 17 ++++++
 .../gobblin/runtime/mapreduce/MRJobLauncher.java   |  4 ++
 6 files changed, 149 insertions(+), 1 deletion(-)

diff --git 
a/gobblin-api/src/main/java/org/apache/gobblin/configuration/ConfigurationKeys.java
 
b/gobblin-api/src/main/java/org/apache/gobblin/configuration/ConfigurationKeys.java
index 12f1a76..228d835 100644
--- 
a/gobblin-api/src/main/java/org/apache/gobblin/configuration/ConfigurationKeys.java
+++ 
b/gobblin-api/src/main/java/org/apache/gobblin/configuration/ConfigurationKeys.java
@@ -216,6 +216,11 @@ public class ConfigurationKeys {
   public static final String QUEUED_TASK_TIME_MAX_AGE = 
"taskexecutor.queued_task_time.history.max_age";
   public static final long DEFAULT_QUEUED_TASK_TIME_MAX_AGE = 
TimeUnit.HOURS.toMillis(1);
 
+  /**
+   * Optional property to specify a default Authenticator class for a job
+   */
+  public static final String DEFAULT_AUTHENTICATOR_CLASS = 
"job.default.authenticator.class";
+
   /** Optional, for user to specified which template to use, inside .job file 
*/
   public static final String JOB_TEMPLATE_PATH = "job.template";
 
diff --git 
a/gobblin-api/src/main/java/org/apache/gobblin/password/EncryptedPasswordAuthenticator.java
 
b/gobblin-api/src/main/java/org/apache/gobblin/password/EncryptedPasswordAuthenticator.java
new file mode 100644
index 0000000..7b60cac
--- /dev/null
+++ 
b/gobblin-api/src/main/java/org/apache/gobblin/password/EncryptedPasswordAuthenticator.java
@@ -0,0 +1,51 @@
+/*
+ * 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.gobblin.password;
+
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.util.Properties;
+
+import com.google.common.base.Preconditions;
+
+
+/**
+ * {@link Authenticator} that uses a username and password from the provided 
{@link Properties} to authenticate, and
+ * also decrypts the password using {@link PasswordManager}
+ */
+public class EncryptedPasswordAuthenticator extends Authenticator {
+  public static final String AUTHENTICATOR_USERNAME = "authenticator.username";
+  public static final String AUTHENTICATOR_PASSWORD = "authenticator.password";
+
+  private final String username;
+  private final String password;
+
+  public EncryptedPasswordAuthenticator(Properties props) {
+    this.username = props.getProperty(AUTHENTICATOR_USERNAME);
+    this.password = PasswordManager.getInstance(props)
+        .readPassword(props.getProperty(AUTHENTICATOR_PASSWORD));
+
+    Preconditions.checkNotNull(this.username, AUTHENTICATOR_USERNAME + " must 
be set for EncryptedPasswordAuthenticator");
+    Preconditions.checkNotNull(this.password, AUTHENTICATOR_PASSWORD + " must 
be set for EncryptedPasswordAuthenticator");
+  }
+
+  @Override
+  protected PasswordAuthentication getPasswordAuthentication() {
+    return new PasswordAuthentication(username, password.toCharArray());
+  }
+}
diff --git 
a/gobblin-api/src/test/java/org/apache/gobblin/password/EncryptedPasswordAuthenticatorTest.java
 
b/gobblin-api/src/test/java/org/apache/gobblin/password/EncryptedPasswordAuthenticatorTest.java
new file mode 100644
index 0000000..c7649e2
--- /dev/null
+++ 
b/gobblin-api/src/test/java/org/apache/gobblin/password/EncryptedPasswordAuthenticatorTest.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.gobblin.password;
+
+import java.io.File;
+import java.net.Authenticator;
+import java.util.Properties;
+import java.util.UUID;
+
+import org.jasypt.util.text.BasicTextEncryptor;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import org.apache.gobblin.configuration.ConfigurationKeys;
+
+
+/**
+ * {@link Authenticator} that uses a username and password from the provided 
{@link Properties} to authenticate, and
+ * also decrypts the password using {@link PasswordManager}
+ */
+public class EncryptedPasswordAuthenticatorTest extends Authenticator {
+  @Test (enabled=false)
+  public void testEncryptedPassword() throws Exception {
+    String password = UUID.randomUUID().toString();
+    String masterPassword = UUID.randomUUID().toString();
+    File masterPwdFile = PasswordManagerTest.getMasterPwdFile(masterPassword);
+    BasicTextEncryptor encryptor = new BasicTextEncryptor();
+    encryptor.setPassword(masterPassword);
+
+    Properties props = new Properties();
+    props.put(EncryptedPasswordAuthenticator.AUTHENTICATOR_USERNAME, 
"testuser");
+    props.put(EncryptedPasswordAuthenticator.AUTHENTICATOR_PASSWORD, "ENC(" + 
encryptor.encrypt(password) + ")");
+    props.put(ConfigurationKeys.ENCRYPT_KEY_LOC, masterPwdFile.toString());
+
+    EncryptedPasswordAuthenticator authenticator = new 
EncryptedPasswordAuthenticator(props);
+
+    
Assert.assertEquals(authenticator.getPasswordAuthentication().getUserName(), 
"testuser");
+    
Assert.assertEquals(authenticator.getPasswordAuthentication().getPassword(), 
password.toCharArray());
+
+    masterPwdFile.delete();
+  }
+
+  @Test
+  public void testUnencryptedPassword() {
+    String password = UUID.randomUUID().toString();
+
+    Properties props = new Properties();
+    props.put(EncryptedPasswordAuthenticator.AUTHENTICATOR_USERNAME, 
"testuser");
+    props.put(EncryptedPasswordAuthenticator.AUTHENTICATOR_PASSWORD, password);
+
+    EncryptedPasswordAuthenticator authenticator = new 
EncryptedPasswordAuthenticator(props);
+
+    
Assert.assertEquals(authenticator.getPasswordAuthentication().getUserName(), 
"testuser");
+    
Assert.assertEquals(authenticator.getPasswordAuthentication().getPassword(), 
password.toCharArray());
+  }
+}
diff --git 
a/gobblin-api/src/test/java/org/apache/gobblin/password/PasswordManagerTest.java
 
b/gobblin-api/src/test/java/org/apache/gobblin/password/PasswordManagerTest.java
index 6382982..b352798 100644
--- 
a/gobblin-api/src/test/java/org/apache/gobblin/password/PasswordManagerTest.java
+++ 
b/gobblin-api/src/test/java/org/apache/gobblin/password/PasswordManagerTest.java
@@ -183,7 +183,7 @@ public class PasswordManagerTest {
     Assert.fail("Password Manager decrypted password without correct master 
password.");
   }
 
-  private File getMasterPwdFile(String masterPwd) throws IOException {
+  public static File getMasterPwdFile(String masterPwd) throws IOException {
     File masterPwdFile = File.createTempFile("masterPassword", null);
     Files.write(masterPwd, masterPwdFile, Charset.defaultCharset());
     return masterPwdFile;
diff --git 
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/AbstractJobLauncher.java
 
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/AbstractJobLauncher.java
index 0856415..f7055f9 100644
--- 
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/AbstractJobLauncher.java
+++ 
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/AbstractJobLauncher.java
@@ -18,6 +18,7 @@
 package org.apache.gobblin.runtime;
 
 import java.io.IOException;
+import java.net.Authenticator;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
@@ -31,6 +32,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.gobblin.destination.DestinationDatasetHandlerService;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -41,6 +43,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -99,6 +102,7 @@ import org.apache.gobblin.util.Id;
 import org.apache.gobblin.util.JobLauncherUtils;
 import org.apache.gobblin.util.ParallelRunner;
 import org.apache.gobblin.util.PropertiesUtils;
+import org.apache.gobblin.util.reflection.GobblinConstructorUtils;
 import org.apache.gobblin.writer.initializer.WriterInitializerFactory;
 
 
@@ -196,6 +200,8 @@ public abstract class AbstractJobLauncher implements 
JobLauncher {
     }
 
     try {
+      setDefaultAuthenticator(this.jobProps);
+
       if (instanceBroker == null) {
         instanceBroker = createDefaultInstanceBroker(jobProps);
       }
@@ -231,6 +237,17 @@ public abstract class AbstractJobLauncher implements 
JobLauncher {
     }
   }
 
+  /**
+   * Set default {@link Authenticator} to the one provided in {@link 
ConfigurationKeys#DEFAULT_AUTHENTICATOR_CLASS},
+   * calling the constructor using the provided {@link Properties}
+   */
+  public static void setDefaultAuthenticator(Properties properties) {
+    String authenticatorClass = 
properties.getProperty(ConfigurationKeys.DEFAULT_AUTHENTICATOR_CLASS);
+    if (!Strings.isNullOrEmpty(authenticatorClass)) {
+      Authenticator authenticator = 
GobblinConstructorUtils.invokeConstructor(Authenticator.class, 
authenticatorClass, properties);
+      Authenticator.setDefault(authenticator);
+    }
+  }
 
   /**
    * To supporting 'gobblin.template.uri' in any types of jobLauncher, place 
this resolution as a public-static method
diff --git 
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/MRJobLauncher.java
 
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/MRJobLauncher.java
index 720aa8c..b346a3d 100644
--- 
a/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/MRJobLauncher.java
+++ 
b/gobblin-runtime/src/main/java/org/apache/gobblin/runtime/mapreduce/MRJobLauncher.java
@@ -20,6 +20,7 @@ package org.apache.gobblin.runtime.mapreduce;
 import java.io.DataOutputStream;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.net.Authenticator;
 import java.net.URI;
 import java.util.List;
 import java.util.Map;
@@ -109,6 +110,7 @@ import org.apache.gobblin.util.JobConfigurationUtils;
 import org.apache.gobblin.util.JobLauncherUtils;
 import org.apache.gobblin.util.ParallelRunner;
 import org.apache.gobblin.util.SerializationUtils;
+import org.apache.gobblin.util.reflection.GobblinConstructorUtils;
 import org.apache.gobblin.util.reflection.RestrictedFieldAccessingUtils;
 /**
  * An implementation of {@link JobLauncher} that launches a Gobblin job as a 
Hadoop MR job.
@@ -829,6 +831,8 @@ public class MRJobLauncher extends AbstractJobLauncher {
           }
         }
       }
+
+      
AbstractJobLauncher.setDefaultAuthenticator(this.jobState.getProperties());
     }
 
     @Override

Reply via email to