HBASE-26921 Rewrite the counting cells part in TestMultiVersions (#4316)
[hbase.git] / hbase-http / src / test / java / org / apache / hadoop / hbase / http / TestSpnegoHttpServer.java
blobeb33943000110b09e062ab72d2c9f7d9aec3d59a
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.hadoop.hbase.http;
20 import java.io.File;
21 import java.io.IOException;
22 import java.net.HttpURLConnection;
23 import java.net.URL;
24 import java.security.Principal;
25 import java.security.PrivilegedExceptionAction;
26 import java.util.Set;
27 import javax.security.auth.Subject;
28 import javax.security.auth.kerberos.KerberosTicket;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.HBaseClassTestRule;
31 import org.apache.hadoop.hbase.HBaseCommonTestingUtil;
32 import org.apache.hadoop.hbase.http.TestHttpServer.EchoServlet;
33 import org.apache.hadoop.hbase.http.resource.JerseyResource;
34 import org.apache.hadoop.hbase.testclassification.MiscTests;
35 import org.apache.hadoop.hbase.testclassification.SmallTests;
36 import org.apache.hadoop.hbase.util.SimpleKdcServerUtil;
37 import org.apache.hadoop.security.authentication.util.KerberosName;
38 import org.apache.http.HttpHost;
39 import org.apache.http.HttpResponse;
40 import org.apache.http.auth.AuthSchemeProvider;
41 import org.apache.http.auth.AuthScope;
42 import org.apache.http.auth.KerberosCredentials;
43 import org.apache.http.client.HttpClient;
44 import org.apache.http.client.config.AuthSchemes;
45 import org.apache.http.client.methods.HttpGet;
46 import org.apache.http.client.protocol.HttpClientContext;
47 import org.apache.http.config.Lookup;
48 import org.apache.http.config.RegistryBuilder;
49 import org.apache.http.impl.auth.SPNegoSchemeFactory;
50 import org.apache.http.impl.client.BasicCredentialsProvider;
51 import org.apache.http.impl.client.HttpClients;
52 import org.apache.http.util.EntityUtils;
53 import org.apache.kerby.kerberos.kerb.KrbException;
54 import org.apache.kerby.kerberos.kerb.client.JaasKrbUtil;
55 import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
56 import org.ietf.jgss.GSSCredential;
57 import org.ietf.jgss.GSSManager;
58 import org.ietf.jgss.GSSName;
59 import org.ietf.jgss.Oid;
60 import org.junit.AfterClass;
61 import org.junit.BeforeClass;
62 import org.junit.ClassRule;
63 import org.junit.Test;
64 import org.junit.experimental.categories.Category;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
68 /**
69 * Test class for SPNEGO authentication on the HttpServer. Uses Kerby's MiniKDC and Apache
70 * HttpComponents to verify that a simple Servlet is reachable via SPNEGO and unreachable w/o.
72 @Category({MiscTests.class, SmallTests.class})
73 public class TestSpnegoHttpServer extends HttpServerFunctionalTest {
74 @ClassRule
75 public static final HBaseClassTestRule CLASS_RULE =
76 HBaseClassTestRule.forClass(TestSpnegoHttpServer.class);
78 private static final Logger LOG = LoggerFactory.getLogger(TestSpnegoHttpServer.class);
79 private static final String KDC_SERVER_HOST = "localhost";
80 private static final String CLIENT_PRINCIPAL = "client";
82 private static HttpServer server;
83 private static URL baseUrl;
84 private static SimpleKdcServer kdc;
85 private static File infoServerKeytab;
86 private static File clientKeytab;
88 @BeforeClass
89 public static void setupServer() throws Exception {
90 Configuration conf = new Configuration();
91 HBaseCommonTestingUtil htu = new HBaseCommonTestingUtil(conf);
93 final String serverPrincipal = "HTTP/" + KDC_SERVER_HOST;
95 kdc = SimpleKdcServerUtil.getRunningSimpleKdcServer(new File(htu.getDataTestDir().toString()),
96 HBaseCommonTestingUtil::randomFreePort);
97 File keytabDir = new File(htu.getDataTestDir("keytabs").toString());
98 if (keytabDir.exists()) {
99 deleteRecursively(keytabDir);
101 keytabDir.mkdirs();
103 infoServerKeytab = new File(keytabDir, serverPrincipal.replace('/', '_') + ".keytab");
104 clientKeytab = new File(keytabDir, CLIENT_PRINCIPAL + ".keytab");
106 setupUser(kdc, clientKeytab, CLIENT_PRINCIPAL);
107 setupUser(kdc, infoServerKeytab, serverPrincipal);
109 buildSpnegoConfiguration(conf, serverPrincipal, infoServerKeytab);
111 server = createTestServerWithSecurity(conf);
112 server.addUnprivilegedServlet("echo", "/echo", EchoServlet.class);
113 server.addJerseyResourcePackage(JerseyResource.class.getPackage().getName(), "/jersey/*");
114 server.start();
115 baseUrl = getServerURL(server);
117 LOG.info("HTTP server started: "+ baseUrl);
120 @AfterClass
121 public static void stopServer() throws Exception {
122 try {
123 if (null != server) {
124 server.stop();
126 } catch (Exception e) {
127 LOG.info("Failed to stop info server", e);
129 try {
130 if (null != kdc) {
131 kdc.stop();
133 } catch (Exception e) {
134 LOG.info("Failed to stop mini KDC", e);
138 private static void setupUser(SimpleKdcServer kdc, File keytab, String principal)
139 throws KrbException {
140 kdc.createPrincipal(principal);
141 kdc.exportPrincipal(principal, keytab);
144 private static Configuration buildSpnegoConfiguration(Configuration conf, String serverPrincipal,
145 File serverKeytab) {
146 KerberosName.setRules("DEFAULT");
148 conf.setInt(HttpServer.HTTP_MAX_THREADS, TestHttpServer.MAX_THREADS);
150 // Enable Kerberos (pre-req)
151 conf.set("hbase.security.authentication", "kerberos");
152 conf.set(HttpServer.HTTP_UI_AUTHENTICATION, "kerberos");
153 conf.set(HttpServer.HTTP_SPNEGO_AUTHENTICATION_PRINCIPAL_KEY, serverPrincipal);
154 conf.set(HttpServer.HTTP_SPNEGO_AUTHENTICATION_KEYTAB_KEY, serverKeytab.getAbsolutePath());
156 return conf;
159 @Test
160 public void testUnauthorizedClientsDisallowed() throws IOException {
161 URL url = new URL(getServerURL(server), "/echo?a=b");
162 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
163 assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, conn.getResponseCode());
166 @Test
167 public void testAllowedClient() throws Exception {
168 // Create the subject for the client
169 final Subject clientSubject = JaasKrbUtil.loginUsingKeytab(CLIENT_PRINCIPAL, clientKeytab);
170 final Set<Principal> clientPrincipals = clientSubject.getPrincipals();
171 // Make sure the subject has a principal
172 assertFalse(clientPrincipals.isEmpty());
174 // Get a TGT for the subject (might have many, different encryption types). The first should
175 // be the default encryption type.
176 Set<KerberosTicket> privateCredentials =
177 clientSubject.getPrivateCredentials(KerberosTicket.class);
178 assertFalse(privateCredentials.isEmpty());
179 KerberosTicket tgt = privateCredentials.iterator().next();
180 assertNotNull(tgt);
182 // The name of the principal
183 final String principalName = clientPrincipals.iterator().next().getName();
185 // Run this code, logged in as the subject (the client)
186 HttpResponse resp = Subject.doAs(clientSubject, new PrivilegedExceptionAction<HttpResponse>() {
187 @Override
188 public HttpResponse run() throws Exception {
189 // Logs in with Kerberos via GSS
190 GSSManager gssManager = GSSManager.getInstance();
191 // jGSS Kerberos login constant
192 Oid oid = new Oid("1.2.840.113554.1.2.2");
193 GSSName gssClient = gssManager.createName(principalName, GSSName.NT_USER_NAME);
194 GSSCredential credential = gssManager.createCredential(gssClient,
195 GSSCredential.DEFAULT_LIFETIME, oid, GSSCredential.INITIATE_ONLY);
197 HttpClientContext context = HttpClientContext.create();
198 Lookup<AuthSchemeProvider> authRegistry = RegistryBuilder.<AuthSchemeProvider>create()
199 .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true, true))
200 .build();
202 HttpClient client = HttpClients.custom().setDefaultAuthSchemeRegistry(authRegistry)
203 .build();
204 BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
205 credentialsProvider.setCredentials(AuthScope.ANY, new KerberosCredentials(credential));
207 URL url = new URL(getServerURL(server), "/echo?a=b");
208 context.setTargetHost(new HttpHost(url.getHost(), url.getPort()));
209 context.setCredentialsProvider(credentialsProvider);
210 context.setAuthSchemeRegistry(authRegistry);
212 HttpGet get = new HttpGet(url.toURI());
213 return client.execute(get, context);
217 assertNotNull(resp);
218 assertEquals(HttpURLConnection.HTTP_OK, resp.getStatusLine().getStatusCode());
219 assertEquals("a:b", EntityUtils.toString(resp.getEntity()).trim());
222 @Test(expected = IllegalArgumentException.class)
223 public void testMissingConfigurationThrowsException() throws Exception {
224 Configuration conf = new Configuration();
225 conf.setInt(HttpServer.HTTP_MAX_THREADS, TestHttpServer.MAX_THREADS);
226 // Enable Kerberos (pre-req)
227 conf.set("hbase.security.authentication", "kerberos");
228 // Intentionally skip keytab and principal
230 HttpServer customServer = createTestServerWithSecurity(conf);
231 customServer.addUnprivilegedServlet("echo", "/echo", EchoServlet.class);
232 customServer.addJerseyResourcePackage(JerseyResource.class.getPackage().getName(), "/jersey/*");
233 customServer.start();