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
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
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.
17   */
18  
19  package org.apache.hadoop.hbase.security.token;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.security.PrivilegedExceptionAction;
25  import java.util.UUID;
26  
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.HBaseTestingUtility;
29  import org.apache.hadoop.hbase.HConstants;
30  import org.apache.hadoop.hbase.LargeTests;
31  import org.apache.hadoop.hbase.client.HTable;
32  import org.apache.hadoop.hbase.coprocessor.BaseEndpointCoprocessor;
33  import org.apache.hadoop.hbase.ipc.CoprocessorProtocol;
34  import org.apache.hadoop.hbase.ipc.HBaseRPC;
35  import org.apache.hadoop.hbase.ipc.RequestContext;
36  import org.apache.hadoop.hbase.ipc.RpcServer;
37  import org.apache.hadoop.hbase.ipc.SecureRpcEngine;
38  import org.apache.hadoop.hbase.ipc.SecureServer;
39  import org.apache.hadoop.hbase.regionserver.HRegionServer;
40  import org.apache.hadoop.hbase.security.User;
41  import org.apache.hadoop.hbase.util.Bytes;
42  import org.apache.hadoop.hbase.util.Writables;
43  import org.apache.hadoop.security.UserGroupInformation;
44  import org.apache.hadoop.security.token.SecretManager;
45  import org.apache.hadoop.security.token.Token;
46  import org.junit.AfterClass;
47  import org.junit.BeforeClass;
48  import org.junit.Test;
49  import org.junit.experimental.categories.Category;
50  
51  /**
52   * Tests for authentication token creation and usage
53   */
54  @Category(LargeTests.class)
55  public class TestTokenAuthentication {
56    public static interface IdentityProtocol extends CoprocessorProtocol {
57      public String whoami();
58      public String getAuthMethod();
59    }
60  
61    public static class IdentityCoprocessor extends BaseEndpointCoprocessor
62        implements IdentityProtocol {
63      public String whoami() {
64        return RequestContext.getRequestUserName();
65      }
66  
67      public String getAuthMethod() {
68        UserGroupInformation ugi = null;
69        User user = RequestContext.getRequestUser();
70        if (user != null) {
71          ugi = user.getUGI();
72        }
73        if (ugi != null) {
74          return ugi.getAuthenticationMethod().toString();
75        }
76        return null;
77      }
78    }
79  
80    private static HBaseTestingUtility TEST_UTIL;
81    private static AuthenticationTokenSecretManager secretManager;
82  
83    @BeforeClass
84    public static void setupBeforeClass() throws Exception {
85      TEST_UTIL = new HBaseTestingUtility();
86      Configuration conf = TEST_UTIL.getConfiguration();
87      conf.set(HBaseRPC.RPC_ENGINE_PROP, SecureRpcEngine.class.getName());
88      conf.set("hbase.coprocessor.region.classes",
89          IdentityCoprocessor.class.getName());
90      TEST_UTIL.startMiniCluster();
91      HRegionServer rs = TEST_UTIL.getMiniHBaseCluster().getRegionServer(0);
92      RpcServer server = rs.getRpcServer();
93      assertTrue(server instanceof SecureServer);
94      SecretManager mgr =
95          ((SecureServer)server).getSecretManager();
96      assertTrue(mgr instanceof AuthenticationTokenSecretManager);
97      secretManager = (AuthenticationTokenSecretManager)mgr;
98    }
99  
100   @AfterClass
101   public static void tearDownAfterClass() throws Exception {
102     TEST_UTIL.shutdownMiniCluster();
103   }
104 
105   @Test
106   public void testTokenCreation() throws Exception {
107     Token<AuthenticationTokenIdentifier> token =
108         secretManager.generateToken("testuser");
109 
110     AuthenticationTokenIdentifier ident = new AuthenticationTokenIdentifier();
111     Writables.getWritable(token.getIdentifier(), ident);
112     assertEquals("Token username should match", "testuser",
113         ident.getUsername());
114     byte[] passwd = secretManager.retrievePassword(ident);
115     assertTrue("Token password and password from secret manager should match",
116         Bytes.equals(token.getPassword(), passwd));
117   }
118 
119   // @Test - Disable due to kerberos requirement
120   public void testTokenAuthentication() throws Exception {
121     UserGroupInformation testuser =
122         UserGroupInformation.createUserForTesting("testuser", new String[]{"testgroup"});
123 
124     testuser.setAuthenticationMethod(
125         UserGroupInformation.AuthenticationMethod.TOKEN);
126     final Configuration conf = TEST_UTIL.getConfiguration();
127     conf.set("hadoop.security.authentication", "kerberos");
128     conf.set("randomkey", UUID.randomUUID().toString());
129     testuser.setConfiguration(conf);
130     Token<AuthenticationTokenIdentifier> token =
131         secretManager.generateToken("testuser");
132     testuser.addToken(token);
133 
134     // verify the server authenticates us as this token user
135     testuser.doAs(new PrivilegedExceptionAction<Object>() {
136       public Object run() throws Exception {
137         HTable table = new HTable(conf, ".META.");
138         IdentityProtocol prot = table.coprocessorProxy(
139             IdentityProtocol.class, HConstants.EMPTY_START_ROW);
140         String myname = prot.whoami();
141         assertEquals("testuser", myname);
142         String authMethod = prot.getAuthMethod();
143         assertEquals("TOKEN", authMethod);
144         return null;
145       }
146     });
147   }
148 }