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.hdfs.security; 20 21 22 23 import java.io.ByteArrayInputStream; 24 import java.io.DataInputStream; 25 import java.io.IOException; 26 import java.net.URI; 27 import java.security.PrivilegedExceptionAction; 28 29 import org.apache.commons.logging.Log; 30 import org.apache.commons.logging.LogFactory; 31 import org.apache.commons.logging.impl.Log4JLogger; 32 import org.apache.hadoop.conf.Configuration; 33 import org.apache.hadoop.fs.FileSystem; 34 import org.apache.hadoop.hdfs.DFSConfigKeys; 35 import org.apache.hadoop.hdfs.DistributedFileSystem; 36 import org.apache.hadoop.hdfs.MiniDFSCluster; 37 import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier; 38 import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenSecretManager; 39 import org.apache.hadoop.hdfs.server.namenode.web.resources.NamenodeWebHdfsMethods; 40 import org.apache.hadoop.hdfs.web.WebHdfsFileSystem; 41 import org.apache.hadoop.io.Text; 42 import org.apache.hadoop.security.AccessControlException; 43 import org.apache.hadoop.security.UserGroupInformation; 44 import org.apache.hadoop.security.token.SecretManager.InvalidToken; 45 import org.apache.hadoop.security.token.Token; 46 import org.apache.log4j.Level; 47 import org.junit.After; 48 import org.junit.Assert; 49 import org.junit.Before; 50 import org.junit.Test; 51 52 public class TestDelegationToken { 53 private static final Log LOG = LogFactory.getLog(TestDelegationToken.class); 54 private MiniDFSCluster cluster; 55 Configuration config; 56 57 @Before setUp()58 public void setUp() throws Exception { 59 config = new Configuration(); 60 config.setBoolean(DFSConfigKeys.DFS_WEBHDFS_ENABLED_KEY, true); 61 config.setLong(DFSConfigKeys.DFS_NAMENODE_DELEGATION_TOKEN_MAX_LIFETIME_KEY, 10000); 62 config.setLong(DFSConfigKeys.DFS_NAMENODE_DELEGATION_TOKEN_RENEW_INTERVAL_KEY, 5000); 63 config.set("hadoop.security.auth_to_local", 64 "RULE:[2:$1@$0](JobTracker@.*FOO.COM)s/@.*//" + 65 "DEFAULT"); 66 67 FileSystem.setDefaultUri(config, "hdfs://localhost:" + "0"); 68 cluster = new MiniDFSCluster(0, config, 0, true, true, true, null, null, null, null); 69 cluster.waitActive(); 70 cluster.getNameNode().getNamesystem().getDelegationTokenSecretManager() 71 .startThreads(); 72 LOG.info("cluster up and running"); 73 } 74 75 @After tearDown()76 public void tearDown() throws Exception { 77 LOG.info("starting shutting down the cluster"); 78 if(cluster!=null) { 79 cluster.shutdown(); 80 } 81 LOG.info("finished shutting down the cluster"); 82 } 83 generateDelegationToken( String owner, String renewer)84 private Token<DelegationTokenIdentifier> generateDelegationToken( 85 String owner, String renewer) { 86 DelegationTokenSecretManager dtSecretManager = cluster.getNameNode() 87 .getNamesystem().getDelegationTokenSecretManager(); 88 DelegationTokenIdentifier dtId = new DelegationTokenIdentifier(new Text( 89 owner), new Text(renewer), null); 90 return new Token<DelegationTokenIdentifier>(dtId, dtSecretManager); 91 } 92 93 @Test testDelegationTokenSecretManager()94 public void testDelegationTokenSecretManager() throws Exception { 95 DelegationTokenSecretManager dtSecretManager = cluster.getNameNode() 96 .getNamesystem().getDelegationTokenSecretManager(); 97 Token<DelegationTokenIdentifier> token = generateDelegationToken( 98 "SomeUser", "JobTracker"); 99 // Fake renewer should not be able to renew 100 try { 101 dtSecretManager.renewToken(token, "FakeRenewer"); 102 Assert.fail("should have failed"); 103 } catch (AccessControlException ace) { 104 // PASS 105 } 106 dtSecretManager.renewToken(token, "JobTracker"); 107 DelegationTokenIdentifier identifier = new DelegationTokenIdentifier(); 108 byte[] tokenId = token.getIdentifier(); 109 identifier.readFields(new DataInputStream( 110 new ByteArrayInputStream(tokenId))); 111 Assert.assertTrue(null != dtSecretManager.retrievePassword(identifier)); 112 LOG.info("Sleep to expire the token"); 113 Thread.sleep(6000); 114 //Token should be expired 115 try { 116 dtSecretManager.retrievePassword(identifier); 117 //Should not come here 118 Assert.fail("Token should have expired"); 119 } catch (InvalidToken e) { 120 //Success 121 } 122 dtSecretManager.renewToken(token, "JobTracker"); 123 LOG.info("Sleep beyond the max lifetime"); 124 Thread.sleep(5000); 125 try { 126 dtSecretManager.renewToken(token, "JobTracker"); 127 Assert.fail("should have been expired"); 128 } catch (InvalidToken it) { 129 // PASS 130 } 131 } 132 133 @Test testCancelDelegationToken()134 public void testCancelDelegationToken() throws Exception { 135 DelegationTokenSecretManager dtSecretManager = cluster.getNameNode() 136 .getNamesystem().getDelegationTokenSecretManager(); 137 Token<DelegationTokenIdentifier> token = generateDelegationToken( 138 "SomeUser", "JobTracker"); 139 //Fake renewer should not be able to renew 140 try { 141 dtSecretManager.cancelToken(token, "FakeCanceller"); 142 Assert.fail("should have failed"); 143 } catch (AccessControlException ace) { 144 // PASS 145 } 146 dtSecretManager.cancelToken(token, "JobTracker"); 147 try { 148 dtSecretManager.renewToken(token, "JobTracker"); 149 Assert.fail("should have failed"); 150 } catch (InvalidToken it) { 151 // PASS 152 } 153 } 154 155 @Test testDelegationTokenDFSApi()156 public void testDelegationTokenDFSApi() throws Exception { 157 DelegationTokenSecretManager dtSecretManager = cluster.getNameNode() 158 .getNamesystem().getDelegationTokenSecretManager(); 159 DistributedFileSystem dfs = (DistributedFileSystem) cluster.getFileSystem(); 160 final Token<DelegationTokenIdentifier> token = dfs.getDelegationToken(new Text("JobTracker")); 161 DelegationTokenIdentifier identifier = new DelegationTokenIdentifier(); 162 byte[] tokenId = token.getIdentifier(); 163 identifier.readFields(new DataInputStream( 164 new ByteArrayInputStream(tokenId))); 165 LOG.info("A valid token should have non-null password, and should be renewed successfully"); 166 Assert.assertTrue(null != dtSecretManager.retrievePassword(identifier)); 167 dtSecretManager.renewToken(token, "JobTracker"); 168 UserGroupInformation.createRemoteUser("JobTracker").doAs( 169 new PrivilegedExceptionAction<Object>() { 170 @Override 171 public Object run() throws Exception { 172 token.renew(config); 173 token.cancel(config); 174 return null; 175 } 176 }); 177 } 178 179 @Test testDelegationTokenWebHdfsApi()180 public void testDelegationTokenWebHdfsApi() throws Exception { 181 ((Log4JLogger)NamenodeWebHdfsMethods.LOG).getLogger().setLevel(Level.ALL); 182 final DelegationTokenSecretManager dtSecretManager = cluster.getNameNode( 183 ).getNamesystem().getDelegationTokenSecretManager(); 184 final String uri = WebHdfsFileSystem.SCHEME + "://" 185 + config.get("dfs.http.address"); 186 //get file system as JobTracker 187 final UserGroupInformation ugi = UserGroupInformation.createUserForTesting( 188 "JobTracker", new String[]{"user"}); 189 final WebHdfsFileSystem webhdfs = ugi.doAs( 190 new PrivilegedExceptionAction<WebHdfsFileSystem>() { 191 @Override 192 public WebHdfsFileSystem run() throws Exception { 193 return (WebHdfsFileSystem)FileSystem.get(new URI(uri), config); 194 } 195 }); 196 197 final Token<DelegationTokenIdentifier> token = webhdfs 198 .getDelegationToken("JobTracker"); 199 DelegationTokenIdentifier identifier = new DelegationTokenIdentifier(); 200 byte[] tokenId = token.getIdentifier(); 201 identifier 202 .readFields(new DataInputStream(new ByteArrayInputStream(tokenId))); 203 LOG.info("A valid token should have non-null password, and should be renewed successfully"); 204 Assert.assertTrue(null != dtSecretManager.retrievePassword(identifier)); 205 dtSecretManager.renewToken(token, "JobTracker"); 206 ugi.doAs(new PrivilegedExceptionAction<Object>() { 207 @Override 208 public Object run() throws Exception { 209 token.renew(config); 210 token.cancel(config); 211 return null; 212 } 213 }); 214 } 215 216 @Test testDelegationTokenWithDoAs()217 public void testDelegationTokenWithDoAs() throws Exception { 218 final DistributedFileSystem dfs = (DistributedFileSystem) cluster.getFileSystem(); 219 final Token<DelegationTokenIdentifier> token = dfs.getDelegationToken(new Text( 220 "JobTracker")); 221 final UserGroupInformation longUgi = UserGroupInformation 222 .createRemoteUser("JobTracker/foo.com@FOO.COM"); 223 final UserGroupInformation shortUgi = UserGroupInformation 224 .createRemoteUser("JobTracker"); 225 LOG.info("cluster at: " + dfs.getUri() + 226 " token for: " + token.getService()); 227 longUgi.doAs(new PrivilegedExceptionAction<Object>() { 228 public Object run() throws IOException { 229 final DistributedFileSystem dfs = (DistributedFileSystem) cluster 230 .getFileSystem(); 231 try { 232 //try renew with long name 233 dfs.renewDelegationToken(token); 234 } catch (IOException e) { 235 LOG.error("caught unexpected exception out of renew", e); 236 Assert.fail("Could not renew delegation token for user "+longUgi); 237 } 238 return null; 239 } 240 }); 241 shortUgi.doAs(new PrivilegedExceptionAction<Object>() { 242 public Object run() throws IOException { 243 final DistributedFileSystem dfs = (DistributedFileSystem) cluster 244 .getFileSystem(); 245 dfs.renewDelegationToken(token); 246 return null; 247 } 248 }); 249 longUgi.doAs(new PrivilegedExceptionAction<Object>() { 250 public Object run() throws IOException { 251 final DistributedFileSystem dfs = (DistributedFileSystem) cluster 252 .getFileSystem(); 253 try { 254 //try cancel with long name 255 dfs.cancelDelegationToken(token); 256 } catch (IOException e) { 257 Assert.fail("Could not cancel delegation token for user "+longUgi); 258 } 259 return null; 260 } 261 }); 262 } 263 264 } 265