1 /**
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  *   http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License. See accompanying LICENSE file.
13  */
14 package org.apache.hadoop.test;
15 
16 import javax.security.auth.Subject;
17 import javax.security.auth.kerberos.KerberosPrincipal;
18 import javax.security.auth.login.AppConfigurationEntry;
19 import javax.security.auth.login.Configuration;
20 import javax.security.auth.login.LoginContext;
21 
22 import org.apache.hadoop.security.authentication.util.KerberosUtil;
23 
24 import java.io.File;
25 import java.security.Principal;
26 import java.security.PrivilegedActionException;
27 import java.security.PrivilegedExceptionAction;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.concurrent.Callable;
33 
34 /**
35  * Test helper class for Java Kerberos setup.
36  */
37 public class KerberosTestUtils {
38   private static final String PREFIX = "httpfs.test.";
39 
40   public static final String REALM = PREFIX + "kerberos.realm";
41 
42   public static final String CLIENT_PRINCIPAL =
43     PREFIX + "kerberos.client.principal";
44 
45   public static final String SERVER_PRINCIPAL =
46     PREFIX + "kerberos.server.principal";
47 
48   public static final String KEYTAB_FILE = PREFIX + "kerberos.keytab.file";
49 
getRealm()50   public static String getRealm() {
51     return System.getProperty(REALM, "LOCALHOST");
52   }
53 
getClientPrincipal()54   public static String getClientPrincipal() {
55     return System.getProperty(CLIENT_PRINCIPAL, "client") + "@" + getRealm();
56   }
57 
getServerPrincipal()58   public static String getServerPrincipal() {
59     return System.getProperty(SERVER_PRINCIPAL,
60                               "HTTP/localhost") + "@" + getRealm();
61   }
62 
getKeytabFile()63   public static String getKeytabFile() {
64     String keytabFile =
65       new File(System.getProperty("user.home"),
66                System.getProperty("user.name") + ".keytab").toString();
67     return System.getProperty(KEYTAB_FILE, keytabFile);
68   }
69 
70   private static class KerberosConfiguration extends Configuration {
71     private String principal;
72 
KerberosConfiguration(String principal)73     public KerberosConfiguration(String principal) {
74       this.principal = principal;
75     }
76 
77     @Override
getAppConfigurationEntry(String name)78     public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
79       Map<String, String> options = new HashMap<String, String>();
80       options.put("keyTab", KerberosTestUtils.getKeytabFile());
81       options.put("principal", principal);
82       options.put("useKeyTab", "true");
83       options.put("storeKey", "true");
84       options.put("doNotPrompt", "true");
85       options.put("useTicketCache", "true");
86       options.put("renewTGT", "true");
87       options.put("refreshKrb5Config", "true");
88       options.put("isInitiator", "true");
89       String ticketCache = System.getenv("KRB5CCNAME");
90       if (ticketCache != null) {
91         options.put("ticketCache", ticketCache);
92       }
93       options.put("debug", "true");
94 
95       return new AppConfigurationEntry[]{
96         new AppConfigurationEntry(KerberosUtil.getKrb5LoginModuleName(),
97                                   AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
98                                   options),};
99     }
100   }
101 
doAs(String principal, final Callable<T> callable)102   public static <T> T doAs(String principal, final Callable<T> callable)
103     throws Exception {
104     LoginContext loginContext = null;
105     try {
106       Set<Principal> principals = new HashSet<Principal>();
107       principals.add(
108         new KerberosPrincipal(KerberosTestUtils.getClientPrincipal()));
109       Subject subject = new Subject(false, principals, new HashSet<Object>(),
110                                     new HashSet<Object>());
111       loginContext = new LoginContext("", subject, null,
112                                       new KerberosConfiguration(principal));
113       loginContext.login();
114       subject = loginContext.getSubject();
115       return Subject.doAs(subject, new PrivilegedExceptionAction<T>() {
116         @Override
117         public T run() throws Exception {
118           return callable.call();
119         }
120       });
121     } catch (PrivilegedActionException ex) {
122       throw ex.getException();
123     } finally {
124       if (loginContext != null) {
125         loginContext.logout();
126       }
127     }
128   }
129 
130   public static <T> T doAsClient(Callable<T> callable) throws Exception {
131     return doAs(getClientPrincipal(), callable);
132   }
133 
134   public static <T> T doAsServer(Callable<T> callable) throws Exception {
135     return doAs(getServerPrincipal(), callable);
136   }
137 
138 }
139