NIFI-5945 Add support for password login to kerberos code in nifi-security-utils

Fixing solr test

Signed-off-by: Matthew Burgess <mattyb149@apache.org>

This closes #3256
This commit is contained in:
Bryan Bende 2019-01-09 17:37:10 -05:00 committed by Matthew Burgess
parent cf7ab0ce18
commit 2bbfb3217b
12 changed files with 320 additions and 112 deletions

View File

@ -23,7 +23,6 @@ import org.slf4j.LoggerFactory;
import javax.security.auth.Subject;
import javax.security.auth.kerberos.KerberosPrincipal;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.security.PrivilegedAction;
@ -34,14 +33,9 @@ import java.util.Date;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Used to authenticate and execute actions when Kerberos is enabled and a keytab is being used.
*
* Some of the functionality in this class is adapted from Hadoop's UserGroupInformation.
*/
public class StandardKeytabUser implements KeytabUser {
public abstract class AbstractKerberosUser implements KerberosUser {
private static final Logger LOGGER = LoggerFactory.getLogger(StandardKeytabUser.class);
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractKerberosUser.class);
static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
@ -50,18 +44,15 @@ public class StandardKeytabUser implements KeytabUser {
*/
static final float TICKET_RENEW_WINDOW = 0.80f;
private final String principal;
private final String keytabFile;
private final AtomicBoolean loggedIn = new AtomicBoolean(false);
protected final String principal;
protected final AtomicBoolean loggedIn = new AtomicBoolean(false);
private Subject subject;
private LoginContext loginContext;
protected Subject subject;
protected LoginContext loginContext;
public StandardKeytabUser(final String principal, final String keytabFile) {
public AbstractKerberosUser(final String principal) {
this.principal = principal;
this.keytabFile = keytabFile;
Validate.notBlank(principal);
Validate.notBlank(keytabFile);
Validate.notBlank(this.principal);
}
/**
@ -80,19 +71,19 @@ public class StandardKeytabUser implements KeytabUser {
if (loginContext == null) {
LOGGER.debug("Initializing new login context...");
this.subject = new Subject();
final Configuration config = new KeytabConfiguration(principal, keytabFile);
this.loginContext = new LoginContext("KeytabConf", subject, null, config);
this.loginContext = createLoginContext(subject);
}
loginContext.login();
loggedIn.set(true);
LOGGER.debug("Successful login for {}", new Object[]{principal});
} catch (LoginException le) {
throw new LoginException("Unable to login with " + principal + " and " + keytabFile + " due to: " + le.getMessage());
throw new LoginException("Unable to login with " + principal + " due to: " + le.getMessage());
}
}
protected abstract LoginContext createLoginContext(final Subject subject) throws LoginException;
/**
* Performs a logout of the current user.
*
@ -244,14 +235,6 @@ public class StandardKeytabUser implements KeytabUser {
return principal;
}
/**
* @return the keytab file for this user
*/
@Override
public String getKeytabFile() {
return keytabFile;
}
// Visible for testing
Subject getSubject() {
return this.subject;

View File

@ -0,0 +1,25 @@
/*
* 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.nifi.security.krb;
public interface ConfigurationUtil {
boolean IS_IBM = System.getProperty("java.vendor", "").contains("IBM");
String IBM_KRB5_LOGIN_MODULE = "com.ibm.security.auth.module.Krb5LoginModule";
String SUN_KRB5_LOGIN_MODULE = "com.sun.security.auth.module.Krb5LoginModule";
}

View File

@ -25,24 +25,24 @@ import javax.security.auth.login.LoginException;
import java.security.PrivilegedAction;
/**
* Helper class for processors to perform an action as a KeytabUser.
* Helper class for processors to perform an action as a KerberosUser.
*/
public class KeytabAction {
public class KerberosAction {
private final KeytabUser keytabUser;
private final KerberosUser kerberosUser;
private final PrivilegedAction action;
private final ProcessContext context;
private final ComponentLog logger;
public KeytabAction(final KeytabUser keytabUser,
final PrivilegedAction action,
final ProcessContext context,
final ComponentLog logger) {
this.keytabUser = keytabUser;
public KerberosAction(final KerberosUser kerberosUser,
final PrivilegedAction action,
final ProcessContext context,
final ComponentLog logger) {
this.kerberosUser = kerberosUser;
this.action = action;
this.context = context;
this.logger = logger;
Validate.notNull(this.keytabUser);
Validate.notNull(this.kerberosUser);
Validate.notNull(this.action);
Validate.notNull(this.context);
Validate.notNull(this.logger);
@ -50,10 +50,10 @@ public class KeytabAction {
public void execute() {
// lazily login the first time the processor executes
if (!keytabUser.isLoggedIn()) {
if (!kerberosUser.isLoggedIn()) {
try {
keytabUser.login();
logger.info("Successful login for {}", new Object[]{keytabUser.getPrincipal()});
kerberosUser.login();
logger.info("Successful login for {}", new Object[]{kerberosUser.getPrincipal()});
} catch (LoginException e) {
// make sure to yield so the processor doesn't keep retrying the rolled back flow files immediately
context.yield();
@ -63,7 +63,7 @@ public class KeytabAction {
// check if we need to re-login, will only happen if re-login window is reached (80% of TGT life)
try {
keytabUser.checkTGTAndRelogin();
kerberosUser.checkTGTAndRelogin();
} catch (LoginException e) {
// make sure to yield so the processor doesn't keep retrying the rolled back flow files immediately
context.yield();
@ -72,15 +72,15 @@ public class KeytabAction {
// attempt to execute the action, if an exception is caught attempt to logout/login and retry
try {
keytabUser.doAs(action);
kerberosUser.doAs(action);
} catch (SecurityException se) {
logger.info("Privileged action failed, attempting relogin and retrying...");
logger.debug("", se);
try {
keytabUser.logout();
keytabUser.login();
keytabUser.doAs(action);
kerberosUser.logout();
kerberosUser.login();
kerberosUser.doAs(action);
} catch (Exception e) {
// make sure to yield so the processor doesn't keep retrying the rolled back flow files immediately
context.yield();

View File

@ -0,0 +1,59 @@
/*
* 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.nifi.security.krb;
import org.apache.commons.lang3.Validate;
import javax.security.auth.Subject;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
/**
* Used to authenticate and execute actions when Kerberos is enabled and a keytab is being used.
*
* Some of the functionality in this class is adapted from Hadoop's UserGroupInformation.
*/
public class KerberosKeytabUser extends AbstractKerberosUser {
private final String keytabFile;
public KerberosKeytabUser(final String principal, final String keytabFile) {
super(principal);
this.keytabFile = keytabFile;
Validate.notBlank(keytabFile);
}
@Override
protected LoginContext createLoginContext(Subject subject) throws LoginException {
final Configuration config = new KeytabConfiguration(principal, keytabFile);
return new LoginContext("KeytabConf", subject, null, config);
}
/**
* @return the keytab file for this user
*/
public String getKeytabFile() {
return keytabFile;
}
// Visible for testing
Subject getSubject() {
return this.subject;
}
}

View File

@ -0,0 +1,110 @@
/*
* 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.nifi.security.krb;
import org.apache.commons.lang3.Validate;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.io.IOException;
import java.util.HashMap;
/**
* KerberosUser that authenticates via username and password instead of keytab.
*/
public class KerberosPasswordUser extends AbstractKerberosUser {
private final String password;
public KerberosPasswordUser(final String principal, final String password) {
super(principal);
this.password = password;
Validate.notBlank(this.password);
}
@Override
protected LoginContext createLoginContext(final Subject subject) throws LoginException {
final Configuration configuration = new PasswordConfig();
final CallbackHandler callbackHandler = new UsernamePasswordCallbackHandler(principal, password);
return new LoginContext("PasswordConf", subject, callbackHandler, configuration);
}
/**
* JAAS Configuration to use when logging in with username/password.
*/
private static class PasswordConfig extends Configuration {
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
HashMap<String, String> options = new HashMap<String, String>();
options.put("storeKey", "true");
options.put("refreshKrb5Config", "true");
final String krbLoginModuleName = ConfigurationUtil.IS_IBM
? ConfigurationUtil.IBM_KRB5_LOGIN_MODULE : ConfigurationUtil.SUN_KRB5_LOGIN_MODULE;
return new AppConfigurationEntry[] {
new AppConfigurationEntry(
krbLoginModuleName,
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
options
)
};
}
}
/**
* CallbackHandler that provides the given username and password.
*/
private static class UsernamePasswordCallbackHandler implements CallbackHandler {
private final String username;
private final String password;
public UsernamePasswordCallbackHandler(final String username, final String password) {
this.username = username;
this.password = password;
Validate.notBlank(this.username);
Validate.notBlank(this.password);
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (final Callback callback : callbacks) {
if (callback instanceof NameCallback) {
final NameCallback nameCallback = (NameCallback) callback;
nameCallback.setName(username);
} else if (callback instanceof PasswordCallback) {
final PasswordCallback passwordCallback = (PasswordCallback) callback;
passwordCallback.setPassword(password.toCharArray());
} else {
throw new IllegalStateException("Unexpected callback type: " + callback.getClass().getCanonicalName());
}
}
}
}
}

View File

@ -24,7 +24,7 @@ import java.security.PrivilegedExceptionAction;
/**
* A keytab-based user that can login/logout and perform actions as the given user.
*/
public interface KeytabUser {
public interface KerberosUser {
/**
* Performs a login for the given user.
@ -80,9 +80,4 @@ public interface KeytabUser {
*/
String getPrincipal();
/**
* @return the keytab file for this user
*/
String getKeytabFile();
}

View File

@ -28,10 +28,6 @@ import java.util.Map;
*/
public class KeytabConfiguration extends Configuration {
static final boolean IS_IBM = System.getProperty("java.vendor", "").contains("IBM");
static final String IBM_KRB5_LOGIN_MODULE = "com.ibm.security.auth.module.Krb5LoginModule";
static final String SUN_KRB5_LOGIN_MODULE = "com.sun.security.auth.module.Krb5LoginModule";
private final String principal;
private final String keytabFile;
@ -53,7 +49,7 @@ public class KeytabConfiguration extends Configuration {
options.put("principal", principal);
options.put("refreshKrb5Config", "true");
if (IS_IBM) {
if (ConfigurationUtil.IS_IBM) {
options.put("useKeytab", keytabFile);
options.put("credsType", "both");
} else {
@ -64,7 +60,8 @@ public class KeytabConfiguration extends Configuration {
options.put("storeKey", "true");
}
final String krbLoginModuleName = IS_IBM ? IBM_KRB5_LOGIN_MODULE : SUN_KRB5_LOGIN_MODULE;
final String krbLoginModuleName = ConfigurationUtil.IS_IBM
? ConfigurationUtil.IBM_KRB5_LOGIN_MODULE : ConfigurationUtil.SUN_KRB5_LOGIN_MODULE;
this.kerberosKeytabConfigEntry = new AppConfigurationEntry(
krbLoginModuleName, AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);

View File

@ -67,8 +67,11 @@ public class KDCServer {
return kdc.getRealm();
}
public void createKeytabFile(final File keytabFile, final String... names) throws Exception {
public void createKeytabPrincipal(final File keytabFile, final String... names) throws Exception {
kdc.createPrincipal(keytabFile, names);
}
public void createPasswordPrincipal(final String principal, final String password) throws Exception {
kdc.createPrincipal(principal, password);
}
}

View File

@ -37,7 +37,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
public class KeytabUserIT {
public class KerberosUserIT {
@ClassRule
public static TemporaryFolder tmpDir = new TemporaryFolder();
@ -50,6 +50,9 @@ public class KeytabUserIT {
private static KerberosPrincipal principal2;
private static File principal2KeytabFile;
private static KerberosPrincipal principal3;
private static final String principal3Password = "changeme";
@BeforeClass
public static void setupClass() throws Exception {
kdc = new KDCServer(tmpDir.newFolder("mini-kdc_"));
@ -58,31 +61,34 @@ public class KeytabUserIT {
principal1 = new KerberosPrincipal("user1@" + kdc.getRealm());
principal1KeytabFile = tmpDir.newFile("user1.keytab");
kdc.createKeytabFile(principal1KeytabFile, "user1");
kdc.createKeytabPrincipal(principal1KeytabFile, "user1");
principal2 = new KerberosPrincipal("user2@" + kdc.getRealm());
principal2KeytabFile = tmpDir.newFile("user2.keytab");
kdc.createKeytabFile(principal2KeytabFile, "user2");
kdc.createKeytabPrincipal(principal2KeytabFile, "user2");
principal3 = new KerberosPrincipal("user3@" + kdc.getRealm());
kdc.createPasswordPrincipal("user3", principal3Password);
}
@Test
public void testSuccessfulLoginAndLogout() throws LoginException {
public void testKeytabUserSuccessfulLoginAndLogout() throws LoginException {
// perform login for user1
final KeytabUser user1 = new StandardKeytabUser(principal1.getName(), principal1KeytabFile.getAbsolutePath());
final KerberosUser user1 = new KerberosKeytabUser(principal1.getName(), principal1KeytabFile.getAbsolutePath());
user1.login();
// perform login for user2
final KeytabUser user2 = new StandardKeytabUser(principal2.getName(), principal2KeytabFile.getAbsolutePath());
final KerberosUser user2 = new KerberosKeytabUser(principal2.getName(), principal2KeytabFile.getAbsolutePath());
user2.login();
// verify user1 Subject only has user1 principal
final Subject user1Subject = ((StandardKeytabUser) user1).getSubject();
final Subject user1Subject = ((KerberosKeytabUser) user1).getSubject();
final Set<Principal> user1SubjectPrincipals = user1Subject.getPrincipals();
assertEquals(1, user1SubjectPrincipals.size());
assertEquals(principal1.getName(), user1SubjectPrincipals.iterator().next().getName());
// verify user2 Subject only has user2 principal
final Subject user2Subject = ((StandardKeytabUser) user2).getSubject();
final Subject user2Subject = ((KerberosKeytabUser) user2).getSubject();
final Set<Principal> user2SubjectPrincipals = user2Subject.getPrincipals();
assertEquals(1, user2SubjectPrincipals.size());
assertEquals(principal2.getName(), user2SubjectPrincipals.iterator().next().getName());
@ -101,9 +107,9 @@ public class KeytabUserIT {
}
@Test
public void testLoginWithUnknownPrincipal() throws LoginException {
public void testKeytabLoginWithUnknownPrincipal() throws LoginException {
final String unknownPrincipal = "doesnotexist@" + kdc.getRealm();
final KeytabUser user1 = new StandardKeytabUser(unknownPrincipal, principal1KeytabFile.getAbsolutePath());
final KerberosUser user1 = new KerberosKeytabUser(unknownPrincipal, principal1KeytabFile.getAbsolutePath());
try {
user1.login();
fail("Login should have failed");
@ -113,9 +119,38 @@ public class KeytabUserIT {
}
}
@Test
public void testPasswordUserSuccessfulLoginAndLogout() throws LoginException {
// perform login for user
final KerberosUser user = new KerberosPasswordUser(principal3.getName(), principal3Password);
user.login();
// verify user Subject only has user principal
final Subject userSubject = ((KerberosPasswordUser) user).getSubject();
final Set<Principal> userSubjectPrincipals = userSubject.getPrincipals();
assertEquals(1, userSubjectPrincipals.size());
assertEquals(principal3.getName(), userSubjectPrincipals.iterator().next().getName());
// call check/relogin and verify neither user performed a relogin
assertFalse(user.checkTGTAndRelogin());
// perform logout for both users
user.logout();
// verify subjects have no more principals
assertEquals(0, userSubject.getPrincipals().size());
}
@Test(expected = LoginException.class)
public void testPasswordUserLoginWithInvalidPassword() throws LoginException {
// perform login for user
final KerberosUser user = new KerberosPasswordUser("user3", "NOT THE PASSWORD");
user.login();
}
@Test
public void testCheckTGTAndRelogin() throws LoginException, InterruptedException {
final KeytabUser user1 = new StandardKeytabUser(principal1.getName(), principal1KeytabFile.getAbsolutePath());
final KerberosUser user1 = new KerberosKeytabUser(principal1.getName(), principal1KeytabFile.getAbsolutePath());
user1.login();
// Since we set the lifetime to 15 seconds we should hit a relogin before 15 attempts
@ -136,7 +171,7 @@ public class KeytabUserIT {
@Test
public void testKeytabAction() {
final KeytabUser user1 = new StandardKeytabUser(principal1.getName(), principal1KeytabFile.getAbsolutePath());
final KerberosUser user1 = new KerberosKeytabUser(principal1.getName(), principal1KeytabFile.getAbsolutePath());
final AtomicReference<String> resultHolder = new AtomicReference<>(null);
final PrivilegedAction privilegedAction = () -> {
@ -148,8 +183,8 @@ public class KeytabUserIT {
final ComponentLog logger = Mockito.mock(ComponentLog.class);
// create the action to test and execute it
final KeytabAction keytabAction = new KeytabAction(user1, privilegedAction, context, logger);
keytabAction.execute();
final KerberosAction kerberosAction = new KerberosAction(user1, privilegedAction, context, logger);
kerberosAction.execute();
// if the result holder has the string success then we know the action executed
assertEquals("SUCCESS", resultHolder.get());

View File

@ -39,7 +39,7 @@ public class TestKeytabConfiguration {
assertEquals(1, entries.length);
final AppConfigurationEntry entry = entries[0];
assertEquals(KeytabConfiguration.SUN_KRB5_LOGIN_MODULE, entry.getLoginModuleName());
assertEquals(ConfigurationUtil.SUN_KRB5_LOGIN_MODULE, entry.getLoginModuleName());
assertEquals(principal, entry.getOptions().get("principal"));
assertEquals(keytab, entry.getOptions().get("keyTab"));
}

View File

@ -28,9 +28,9 @@ import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.security.krb.KeytabAction;
import org.apache.nifi.security.krb.KeytabUser;
import org.apache.nifi.security.krb.StandardKeytabUser;
import org.apache.nifi.security.krb.KerberosAction;
import org.apache.nifi.security.krb.KerberosUser;
import org.apache.nifi.security.krb.KerberosKeytabUser;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.solr.client.solrj.SolrClient;
@ -63,7 +63,7 @@ public abstract class SolrProcessor extends AbstractProcessor {
private volatile String basicPassword;
private volatile boolean basicAuthEnabled = false;
private volatile KeytabUser keytabUser;
private volatile KerberosUser kerberosUser;
@OnScheduled
public final void onScheduled(final ProcessContext context) throws IOException {
@ -78,12 +78,12 @@ public abstract class SolrProcessor extends AbstractProcessor {
final KerberosCredentialsService kerberosCredentialsService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
if (kerberosCredentialsService != null) {
this.keytabUser = createKeytabUser(kerberosCredentialsService);
this.kerberosUser = createKeytabUser(kerberosCredentialsService);
}
}
protected KeytabUser createKeytabUser(final KerberosCredentialsService kerberosCredentialsService) {
return new StandardKeytabUser(kerberosCredentialsService.getPrincipal(), kerberosCredentialsService.getKeytab());
protected KerberosUser createKeytabUser(final KerberosCredentialsService kerberosCredentialsService) {
return new KerberosKeytabUser(kerberosCredentialsService.getPrincipal(), kerberosCredentialsService.getKeytab());
}
@OnStopped
@ -96,10 +96,10 @@ public abstract class SolrProcessor extends AbstractProcessor {
}
}
if (keytabUser != null) {
if (kerberosUser != null) {
try {
keytabUser.logout();
keytabUser = null;
kerberosUser.logout();
kerberosUser = null;
} catch (LoginException e) {
getLogger().debug("Error logging out keytab user", e);
}
@ -108,8 +108,8 @@ public abstract class SolrProcessor extends AbstractProcessor {
@Override
public final void onTrigger(final ProcessContext context, final ProcessSession session) throws ProcessException {
final KeytabUser keytabUser = getKerberosKeytabUser();
if (keytabUser == null) {
final KerberosUser kerberosUser = getKerberosKeytabUser();
if (kerberosUser == null) {
doOnTrigger(context, session);
} else {
// wrap doOnTrigger in a privileged action
@ -119,8 +119,8 @@ public abstract class SolrProcessor extends AbstractProcessor {
};
// execute the privileged action as the given keytab user
final KeytabAction keytabAction = new KeytabAction(keytabUser, action, context, getLogger());
keytabAction.execute();
final KerberosAction kerberosAction = new KerberosAction(kerberosUser, action, context, getLogger());
kerberosAction.execute();
}
}
@ -168,8 +168,8 @@ public abstract class SolrProcessor extends AbstractProcessor {
return basicAuthEnabled;
}
protected final KeytabUser getKerberosKeytabUser() {
return keytabUser;
protected final KerberosUser getKerberosKeytabUser() {
return kerberosUser;
}
@Override

View File

@ -21,7 +21,8 @@ import org.apache.nifi.kerberos.KerberosCredentialsService;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.security.krb.KeytabUser;
import org.apache.nifi.security.krb.KerberosKeytabUser;
import org.apache.nifi.security.krb.KerberosUser;
import org.apache.nifi.ssl.SSLContextService;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
@ -451,10 +452,10 @@ public class TestPutSolrContentStream {
runner.assertValid();
proc.onScheduled(runner.getProcessContext());
final KeytabUser keytabUser = proc.getMockKerberosKeytabUser();
Assert.assertNotNull(keytabUser);
Assert.assertEquals(principal, keytabUser.getPrincipal());
Assert.assertEquals(keytab, keytabUser.getKeytabFile());
final KerberosUser kerberosUser = proc.getMockKerberosKeytabUser();;
Assert.assertNotNull(kerberosUser);
Assert.assertEquals(principal, kerberosUser.getPrincipal());
Assert.assertEquals(keytab, ((KerberosKeytabUser)kerberosUser).getKeytabFile());
}
@Test
@ -462,20 +463,20 @@ public class TestPutSolrContentStream {
final String principal = "nifi@FOO.COM";
final String keytab = "src/test/resources/foo.keytab";
// Setup a mock KeytabUser that will still execute the privileged action
final KeytabUser keytabUser = Mockito.mock(KeytabUser.class);
when(keytabUser.getPrincipal()).thenReturn(principal);
when(keytabUser.getKeytabFile()).thenReturn(keytab);
when(keytabUser.doAs(any(PrivilegedAction.class))).thenAnswer((invocation -> {
// Setup a mock KerberosUser that will still execute the privileged action
final KerberosKeytabUser kerberosUser = Mockito.mock(KerberosKeytabUser.class);
when(kerberosUser.getPrincipal()).thenReturn(principal);
when(kerberosUser.getKeytabFile()).thenReturn(keytab);
when(kerberosUser.doAs(any(PrivilegedAction.class))).thenAnswer((invocation -> {
final PrivilegedAction action = (PrivilegedAction) invocation.getArguments()[0];
action.run();
return null;
})
);
// Configure the processor with the mock KeytabUser and with a credentials service
// Configure the processor with the mock KerberosUser and with a credentials service
final SolrClient solrClient = createEmbeddedSolrClient(DEFAULT_SOLR_CORE);
final TestableProcessor proc = new TestableProcessor(solrClient, keytabUser);
final TestableProcessor proc = new TestableProcessor(solrClient, kerberosUser);
final TestRunner runner = createDefaultTestRunner(proc);
final KerberosCredentialsService kerberosCredentialsService = new MockKerberosCredentialsService(principal, keytab);
@ -499,9 +500,9 @@ public class TestPutSolrContentStream {
}
// Verify that during the update the user was logged in, TGT was checked, and the action was executed
verify(keytabUser, times(1)).login();
verify(keytabUser, times(1)).checkTGTAndRelogin();
verify(keytabUser, times(1)).doAs(any(PrivilegedAction.class));
verify(kerberosUser, times(1)).login();
verify(kerberosUser, times(1)).checkTGTAndRelogin();
verify(kerberosUser, times(1)).doAs(any(PrivilegedAction.class));
}
@ -647,15 +648,15 @@ public class TestPutSolrContentStream {
// Override createSolrClient and return the passed in SolrClient
private class TestableProcessor extends PutSolrContentStream {
private SolrClient solrClient;
private KeytabUser keytabUser;
private KerberosUser kerberosUser;
public TestableProcessor(SolrClient solrClient) {
this.solrClient = solrClient;
}
public TestableProcessor(SolrClient solrClient, KeytabUser keytabUser) {
public TestableProcessor(SolrClient solrClient, KerberosUser kerberosUser) {
this.solrClient = solrClient;
this.keytabUser = keytabUser;
this.kerberosUser = kerberosUser;
}
@Override
@ -664,15 +665,15 @@ public class TestPutSolrContentStream {
}
@Override
protected KeytabUser createKeytabUser(KerberosCredentialsService kerberosCredentialsService) {
if (keytabUser != null) {
return keytabUser;
protected KerberosUser createKeytabUser(KerberosCredentialsService kerberosCredentialsService) {
if (kerberosUser != null) {
return kerberosUser;
} else {
return super.createKeytabUser(kerberosCredentialsService);
}
}
public KeytabUser getMockKerberosKeytabUser() {
public KerberosUser getMockKerberosKeytabUser() {
return super.getKerberosKeytabUser();
}
}