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.registry.secure; 20 21 22 23 import com.sun.security.auth.module.Krb5LoginModule; 24 import org.apache.commons.io.FileUtils; 25 import org.apache.hadoop.security.HadoopKerberosName; 26 import org.apache.hadoop.security.UserGroupInformation; 27 import org.apache.hadoop.security.authentication.util.KerberosName; 28 import org.apache.hadoop.security.authentication.util.KerberosUtil; 29 import org.apache.hadoop.util.Shell; 30 import org.apache.hadoop.registry.client.impl.zk.RegistrySecurity; 31 import org.apache.hadoop.registry.client.impl.zk.ZookeeperConfigOptions; 32 import org.apache.zookeeper.Environment; 33 import org.apache.zookeeper.data.ACL; 34 import org.junit.Assume; 35 import org.junit.Test; 36 import org.slf4j.Logger; 37 import org.slf4j.LoggerFactory; 38 39 import javax.security.auth.Subject; 40 import javax.security.auth.kerberos.KerberosPrincipal; 41 import javax.security.auth.login.LoginContext; 42 import javax.security.auth.login.LoginException; 43 import java.io.File; 44 import java.io.IOException; 45 import java.security.Principal; 46 import java.security.PrivilegedExceptionAction; 47 import java.util.HashMap; 48 import java.util.HashSet; 49 import java.util.Map; 50 import java.util.Set; 51 52 /** 53 * Verify that logins work 54 */ 55 public class TestSecureLogins extends AbstractSecureRegistryTest { 56 private static final Logger LOG = 57 LoggerFactory.getLogger(TestSecureLogins.class); 58 59 @Test testHasRealm()60 public void testHasRealm() throws Throwable { 61 assertNotNull(getRealm()); 62 LOG.info("ZK principal = {}", getPrincipalAndRealm(ZOOKEEPER_LOCALHOST)); 63 } 64 65 @Test testJaasFileSetup()66 public void testJaasFileSetup() throws Throwable { 67 // the JVM has seemed inconsistent on setting up here 68 assertNotNull("jaasFile", jaasFile); 69 String confFilename = System.getProperty(Environment.JAAS_CONF_KEY); 70 assertEquals(jaasFile.getAbsolutePath(), confFilename); 71 } 72 73 @Test testJaasFileBinding()74 public void testJaasFileBinding() throws Throwable { 75 // the JVM has seemed inconsistent on setting up here 76 assertNotNull("jaasFile", jaasFile); 77 RegistrySecurity.bindJVMtoJAASFile(jaasFile); 78 String confFilename = System.getProperty(Environment.JAAS_CONF_KEY); 79 assertEquals(jaasFile.getAbsolutePath(), confFilename); 80 } 81 82 83 @Test testClientLogin()84 public void testClientLogin() throws Throwable { 85 LoginContext client = login(ALICE_LOCALHOST, 86 ALICE_CLIENT_CONTEXT, 87 keytab_alice); 88 89 try { 90 logLoginDetails(ALICE_LOCALHOST, client); 91 String confFilename = System.getProperty(Environment.JAAS_CONF_KEY); 92 assertNotNull("Unset: "+ Environment.JAAS_CONF_KEY, confFilename); 93 String config = FileUtils.readFileToString(new File(confFilename)); 94 LOG.info("{}=\n{}", confFilename, config); 95 RegistrySecurity.setZKSaslClientProperties(ALICE, ALICE_CLIENT_CONTEXT); 96 } finally { 97 client.logout(); 98 } 99 } 100 101 @Test testZKServerContextLogin()102 public void testZKServerContextLogin() throws Throwable { 103 LoginContext client = login(ZOOKEEPER_LOCALHOST, 104 ZOOKEEPER_SERVER_CONTEXT, 105 keytab_zk); 106 logLoginDetails(ZOOKEEPER_LOCALHOST, client); 107 108 client.logout(); 109 } 110 111 112 @Test testServerLogin()113 public void testServerLogin() throws Throwable { 114 LoginContext loginContext = createLoginContextZookeeperLocalhost(); 115 loginContext.login(); 116 loginContext.logout(); 117 } 118 createLoginContextZookeeperLocalhost()119 public LoginContext createLoginContextZookeeperLocalhost() throws 120 LoginException { 121 String principalAndRealm = getPrincipalAndRealm(ZOOKEEPER_LOCALHOST); 122 Set<Principal> principals = new HashSet<Principal>(); 123 principals.add(new KerberosPrincipal(ZOOKEEPER_LOCALHOST)); 124 Subject subject = new Subject(false, principals, new HashSet<Object>(), 125 new HashSet<Object>()); 126 return new LoginContext("", subject, null, 127 KerberosConfiguration.createServerConfig(ZOOKEEPER_LOCALHOST, keytab_zk)); 128 } 129 130 131 @Test testKerberosAuth()132 public void testKerberosAuth() throws Throwable { 133 File krb5conf = getKdc().getKrb5conf(); 134 String krbConfig = FileUtils.readFileToString(krb5conf); 135 LOG.info("krb5.conf at {}:\n{}", krb5conf, krbConfig); 136 Subject subject = new Subject(); 137 138 final Krb5LoginModule krb5LoginModule = new Krb5LoginModule(); 139 final Map<String, String> options = new HashMap<String, String>(); 140 options.put("keyTab", keytab_alice.getAbsolutePath()); 141 options.put("principal", ALICE_LOCALHOST); 142 options.put("debug", "true"); 143 options.put("doNotPrompt", "true"); 144 options.put("isInitiator", "true"); 145 options.put("refreshKrb5Config", "true"); 146 options.put("renewTGT", "true"); 147 options.put("storeKey", "true"); 148 options.put("useKeyTab", "true"); 149 options.put("useTicketCache", "true"); 150 151 krb5LoginModule.initialize(subject, null, 152 new HashMap<String, String>(), 153 options); 154 155 boolean loginOk = krb5LoginModule.login(); 156 assertTrue("Failed to login", loginOk); 157 boolean commitOk = krb5LoginModule.commit(); 158 assertTrue("Failed to Commit", commitOk); 159 } 160 161 @Test testDefaultRealmValid()162 public void testDefaultRealmValid() throws Throwable { 163 String defaultRealm = KerberosUtil.getDefaultRealm(); 164 assertNotEmpty("No default Kerberos Realm", 165 defaultRealm); 166 LOG.info("Default Realm '{}'", defaultRealm); 167 } 168 169 @Test testKerberosRulesValid()170 public void testKerberosRulesValid() throws Throwable { 171 assertTrue("!KerberosName.hasRulesBeenSet()", 172 KerberosName.hasRulesBeenSet()); 173 String rules = KerberosName.getRules(); 174 assertEquals(kerberosRule, rules); 175 LOG.info(rules); 176 } 177 178 @Test testValidKerberosName()179 public void testValidKerberosName() throws Throwable { 180 181 new HadoopKerberosName(ZOOKEEPER).getShortName(); 182 new HadoopKerberosName(ZOOKEEPER_LOCALHOST).getShortName(); 183 new HadoopKerberosName(ZOOKEEPER_REALM).getShortName(); 184 // standard rules don't pick this up 185 // new HadoopKerberosName(ZOOKEEPER_LOCALHOST_REALM).getShortName(); 186 } 187 188 189 @Test testUGILogin()190 public void testUGILogin() throws Throwable { 191 192 UserGroupInformation ugi = loginUGI(ZOOKEEPER, keytab_zk); 193 RegistrySecurity.UgiInfo ugiInfo = 194 new RegistrySecurity.UgiInfo(ugi); 195 LOG.info("logged in as: {}", ugiInfo); 196 assertTrue("security is not enabled: " + ugiInfo, 197 UserGroupInformation.isSecurityEnabled()); 198 assertTrue("login is keytab based: " + ugiInfo, 199 ugi.isFromKeytab()); 200 201 // now we are here, build a SASL ACL 202 ACL acl = ugi.doAs(new PrivilegedExceptionAction<ACL>() { 203 @Override 204 public ACL run() throws Exception { 205 return registrySecurity.createSaslACLFromCurrentUser(0); 206 } 207 }); 208 assertEquals(ZOOKEEPER_REALM, acl.getId().getId()); 209 assertEquals(ZookeeperConfigOptions.SCHEME_SASL, acl.getId().getScheme()); 210 registrySecurity.addSystemACL(acl); 211 212 } 213 214 } 215