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