blob: a3f5601140a3fb00fe5e68f4c8cd4e31c20990a6 [file] [log] [blame]
/*
* 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.atlas.web.filters;
import org.apache.atlas.RequestContextV1;
import org.apache.atlas.web.security.BaseSecurityTest;
import org.apache.atlas.web.service.EmbeddedServer;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.hdfs.web.URLConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.testng.annotations.Test;
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.LoginContext;
import javax.security.auth.login.LoginException;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.PrivilegedExceptionAction;
import static org.testng.Assert.assertEquals;
/**
*
*/
public class AtlasAuthenticationKerberosFilterTest extends BaseSecurityTest {
public static final String TEST_USER_JAAS_SECTION = "TestUser";
public static final String TESTUSER = "testuser";
public static final String TESTPASS = "testpass";
private File userKeytabFile;
private File httpKeytabFile;
class TestEmbeddedServer extends EmbeddedServer {
public TestEmbeddedServer(int port, String path) throws IOException {
super(ATLAS_DEFAULT_BIND_ADDRESS, port, path);
}
Server getServer() {
return server;
}
@Override
protected WebAppContext getWebAppContext(String path) {
WebAppContext application = new WebAppContext(path, "/");
application.setDescriptor(System.getProperty("projectBaseDir") + "/webapp/src/test/webapp/WEB-INF/web.xml");
application.setClassLoader(Thread.currentThread().getContextClassLoader());
return application;
}
}
@Test(enabled = false)
public void testKerberosBasedLogin() throws Exception {
String originalConf = System.getProperty("atlas.conf");
setupKDCAndPrincipals();
TestEmbeddedServer server = null;
try {
// setup the atlas-application.properties file
String confDirectory = generateKerberosTestProperties();
System.setProperty("atlas.conf", confDirectory);
// need to create the web application programmatically in order to control the injection of the test
// application properties
server = new TestEmbeddedServer(23000, "webapp/target/apache-atlas");
startEmbeddedServer(server.getServer());
final URLConnectionFactory connectionFactory = URLConnectionFactory.DEFAULT_SYSTEM_CONNECTION_FACTORY;
// attempt to hit server and get rejected
URL url = new URL("http://localhost:23000/");
HttpURLConnection connection = (HttpURLConnection) connectionFactory.openConnection(url, false);
connection.setRequestMethod("GET");
connection.connect();
assertEquals(connection.getResponseCode(), 401);
// need to populate the ticket cache with a local user, so logging in...
Subject subject = loginTestUser();
Subject.doAs(subject, new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
// attempt to hit server and get rejected
URL url = new URL("http://localhost:23000/");
HttpURLConnection connection = (HttpURLConnection) connectionFactory.openConnection(url, true);
connection.setRequestMethod("GET");
connection.connect();
assertEquals(connection.getResponseCode(), 200);
assertEquals(RequestContextV1.get().getUser(), TESTUSER);
return null;
}
});
} finally {
server.getServer().stop();
kdc.stop();
if (originalConf != null) {
System.setProperty("atlas.conf", originalConf);
} else {
System.clearProperty("atlas.conf");
}
}
}
protected Subject loginTestUser() throws LoginException, IOException {
LoginContext lc = new LoginContext(TEST_USER_JAAS_SECTION, new CallbackHandler() {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof PasswordCallback) {
PasswordCallback passwordCallback = (PasswordCallback) callback;
passwordCallback.setPassword(TESTPASS.toCharArray());
}
if (callback instanceof NameCallback) {
NameCallback nameCallback = (NameCallback) callback;
nameCallback.setName(TESTUSER);
}
}
}
});
// attempt authentication
lc.login();
return lc.getSubject();
}
protected String generateKerberosTestProperties() throws Exception {
PropertiesConfiguration props = new PropertiesConfiguration();
props.setProperty("atlas.http.authentication.enabled", "true");
props.setProperty("atlas.http.authentication.type", "kerberos");
props.setProperty("atlas.http.authentication.kerberos.principal", "HTTP/localhost@" + kdc.getRealm());
props.setProperty("atlas.http.authentication.kerberos.keytab", httpKeytabFile.getAbsolutePath());
props.setProperty("atlas.http.authentication.kerberos.name.rules",
"RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\nDEFAULT");
return writeConfiguration(props);
}
public void setupKDCAndPrincipals() throws Exception {
// set up the KDC
File kdcWorkDir = startKDC();
userKeytabFile = createKeytab(kdc, kdcWorkDir, "dgi", "dgi.keytab");
httpKeytabFile = createKeytab(kdc, kdcWorkDir, "HTTP", "spnego.service.keytab");
// create a test user principal
kdc.createPrincipal(TESTUSER, TESTPASS);
StringBuilder jaas = new StringBuilder(1024);
jaas.append("TestUser {\n" +
" com.sun.security.auth.module.Krb5LoginModule required\nuseTicketCache=true;\n" +
"};\n");
jaas.append(createJAASEntry("Client", "dgi", userKeytabFile));
jaas.append(createJAASEntry("Server", "HTTP", httpKeytabFile));
File jaasFile = new File(kdcWorkDir, "jaas.txt");
FileUtils.write(jaasFile, jaas.toString());
bindJVMtoJAASFile(jaasFile);
}
}