|
@@ -0,0 +1,262 @@
|
|
|
+/**
|
|
|
+ * Licensed to the Apache Software Foundation (ASF) under one
|
|
|
+ * or more contributor license agreements. See the NOTICE file
|
|
|
+ * distributed with this work for additional information
|
|
|
+ * regarding copyright ownership. The ASF licenses this file
|
|
|
+ * to you under the Apache License, Version 2.0 (the
|
|
|
+ * "License"); you may not use this file except in compliance
|
|
|
+ * with the License. You may obtain a copy of the License at
|
|
|
+ *
|
|
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+ *
|
|
|
+ * Unless required by applicable law or agreed to in writing, software
|
|
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+ * See the License for the specific language governing permissions and
|
|
|
+ * limitations under the License.
|
|
|
+ */
|
|
|
+
|
|
|
+package org.apache.hadoop.security.token.delegation;
|
|
|
+
|
|
|
+import java.io.ByteArrayInputStream;
|
|
|
+import java.io.DataInput;
|
|
|
+import java.io.DataInputStream;
|
|
|
+import java.io.DataOutput;
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+import junit.framework.Assert;
|
|
|
+
|
|
|
+import org.apache.hadoop.io.DataInputBuffer;
|
|
|
+import org.apache.hadoop.io.DataOutputBuffer;
|
|
|
+import org.apache.hadoop.io.Text;
|
|
|
+import org.apache.hadoop.io.Writable;
|
|
|
+import org.apache.hadoop.security.token.Token;
|
|
|
+import org.apache.hadoop.security.token.TokenIdentifier;
|
|
|
+import org.apache.hadoop.security.token.SecretManager.InvalidToken;
|
|
|
+import org.junit.Test;
|
|
|
+import org.mortbay.log.Log;
|
|
|
+
|
|
|
+import static org.junit.Assert.*;
|
|
|
+
|
|
|
+public class TestDelegationToken {
|
|
|
+ private static final Text KIND = new Text("MY KIND");
|
|
|
+
|
|
|
+ public static class TestDelegationTokenIdentifier
|
|
|
+ extends AbstractDelegationTokenIdentifier
|
|
|
+ implements Writable {
|
|
|
+
|
|
|
+ public TestDelegationTokenIdentifier() {
|
|
|
+ }
|
|
|
+
|
|
|
+ public TestDelegationTokenIdentifier(Text owner, Text renewer, Text realUser) {
|
|
|
+ super(owner, renewer, realUser);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Text getKind() {
|
|
|
+ return KIND;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void write(DataOutput out) throws IOException {
|
|
|
+ super.write(out);
|
|
|
+ }
|
|
|
+ public void readFields(DataInput in) throws IOException {
|
|
|
+ super.readFields(in);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class TestDelegationTokenSecretManager
|
|
|
+ extends AbstractDelegationTokenSecretManager<TestDelegationTokenIdentifier> {
|
|
|
+
|
|
|
+ public TestDelegationTokenSecretManager(long delegationKeyUpdateInterval,
|
|
|
+ long delegationTokenMaxLifetime,
|
|
|
+ long delegationTokenRenewInterval,
|
|
|
+ long delegationTokenRemoverScanInterval) {
|
|
|
+ super(delegationKeyUpdateInterval, delegationTokenMaxLifetime,
|
|
|
+ delegationTokenRenewInterval, delegationTokenRemoverScanInterval);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TestDelegationTokenIdentifier createIdentifier() {
|
|
|
+ return new TestDelegationTokenIdentifier();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected byte[] createPassword(TestDelegationTokenIdentifier t) {
|
|
|
+ return super.createPassword(t);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class TokenSelector extends
|
|
|
+ AbstractDelegationTokenSelector<TestDelegationTokenIdentifier>{
|
|
|
+
|
|
|
+ protected TokenSelector() {
|
|
|
+ super(KIND);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testSerialization() throws Exception {
|
|
|
+ TestDelegationTokenIdentifier origToken = new
|
|
|
+ TestDelegationTokenIdentifier(new Text("alice"),
|
|
|
+ new Text("bob"),
|
|
|
+ new Text("colin"));
|
|
|
+ TestDelegationTokenIdentifier newToken = new TestDelegationTokenIdentifier();
|
|
|
+ origToken.setIssueDate(123);
|
|
|
+ origToken.setMasterKeyId(321);
|
|
|
+ origToken.setMaxDate(314);
|
|
|
+ origToken.setSequenceNumber(12345);
|
|
|
+
|
|
|
+ // clone origToken into newToken
|
|
|
+ DataInputBuffer inBuf = new DataInputBuffer();
|
|
|
+ DataOutputBuffer outBuf = new DataOutputBuffer();
|
|
|
+ origToken.write(outBuf);
|
|
|
+ inBuf.reset(outBuf.getData(), 0, outBuf.getLength());
|
|
|
+ newToken.readFields(inBuf);
|
|
|
+
|
|
|
+ // now test the fields
|
|
|
+ assertEquals("alice", newToken.getUser().getUserName());
|
|
|
+ assertEquals(new Text("bob"), newToken.getRenewer());
|
|
|
+ assertEquals("colin", newToken.getUser().getRealUser().getUserName());
|
|
|
+ assertEquals(123, newToken.getIssueDate());
|
|
|
+ assertEquals(321, newToken.getMasterKeyId());
|
|
|
+ assertEquals(314, newToken.getMaxDate());
|
|
|
+ assertEquals(12345, newToken.getSequenceNumber());
|
|
|
+ assertEquals(origToken, newToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Token<TestDelegationTokenIdentifier> generateDelegationToken(
|
|
|
+ TestDelegationTokenSecretManager dtSecretManager,
|
|
|
+ String owner, String renewer) {
|
|
|
+ TestDelegationTokenIdentifier dtId =
|
|
|
+ new TestDelegationTokenIdentifier(new Text(
|
|
|
+ owner), new Text(renewer), null);
|
|
|
+ return new Token<TestDelegationTokenIdentifier>(dtId, dtSecretManager);
|
|
|
+ }
|
|
|
+ @Test
|
|
|
+ public void testDelegationTokenSecretManager() throws Exception {
|
|
|
+ TestDelegationTokenSecretManager dtSecretManager =
|
|
|
+ new TestDelegationTokenSecretManager(24*60*60*1000,
|
|
|
+ 3*1000,1*1000,3600000);
|
|
|
+ try {
|
|
|
+ dtSecretManager.startThreads();
|
|
|
+ Token<TestDelegationTokenIdentifier> token = generateDelegationToken(
|
|
|
+ dtSecretManager, "SomeUser", "JobTracker");
|
|
|
+ // Fake renewer should not be able to renew
|
|
|
+ Assert.assertFalse(dtSecretManager.renewToken(token, "FakeRenewer"));
|
|
|
+ Assert.assertTrue(dtSecretManager.renewToken(token, "JobTracker"));
|
|
|
+ TestDelegationTokenIdentifier identifier =
|
|
|
+ new TestDelegationTokenIdentifier();
|
|
|
+ byte[] tokenId = token.getIdentifier();
|
|
|
+ identifier.readFields(new DataInputStream(
|
|
|
+ new ByteArrayInputStream(tokenId)));
|
|
|
+ Assert.assertTrue(null != dtSecretManager.retrievePassword(identifier));
|
|
|
+ Log.info("Sleep to expire the token");
|
|
|
+ Thread.sleep(2000);
|
|
|
+ //Token should be expired
|
|
|
+ try {
|
|
|
+ dtSecretManager.retrievePassword(identifier);
|
|
|
+ //Should not come here
|
|
|
+ Assert.fail("Token should have expired");
|
|
|
+ } catch (InvalidToken e) {
|
|
|
+ //Success
|
|
|
+ }
|
|
|
+ Assert.assertTrue(dtSecretManager.renewToken(token, "JobTracker"));
|
|
|
+ Log.info("Sleep beyond the max lifetime");
|
|
|
+ Thread.sleep(2000);
|
|
|
+ Assert.assertFalse(dtSecretManager.renewToken(token, "JobTracker"));
|
|
|
+ } finally {
|
|
|
+ dtSecretManager.stopThreads();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @Test
|
|
|
+ public void testCancelDelegationToken() throws Exception {
|
|
|
+ TestDelegationTokenSecretManager dtSecretManager =
|
|
|
+ new TestDelegationTokenSecretManager(24*60*60*1000,
|
|
|
+ 10*1000,1*1000,3600000);
|
|
|
+ try {
|
|
|
+ dtSecretManager.startThreads();
|
|
|
+ Token<TestDelegationTokenIdentifier> token = generateDelegationToken(
|
|
|
+ dtSecretManager, "SomeUser", "JobTracker");
|
|
|
+ //Fake renewer should not be able to renew
|
|
|
+ Assert.assertFalse(dtSecretManager.cancelToken(token, "FakeCanceller"));
|
|
|
+ Assert.assertTrue(dtSecretManager.cancelToken(token, "JobTracker"));
|
|
|
+ Assert.assertFalse(dtSecretManager.renewToken(token, "JobTracker"));
|
|
|
+ } finally {
|
|
|
+ dtSecretManager.stopThreads();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @Test
|
|
|
+ public void testRollMasterKey() throws Exception {
|
|
|
+ TestDelegationTokenSecretManager dtSecretManager =
|
|
|
+ new TestDelegationTokenSecretManager(24*60*60*1000,
|
|
|
+ 10*1000,1*1000,3600000);
|
|
|
+ try {
|
|
|
+ dtSecretManager.startThreads();
|
|
|
+ //generate a token and store the password
|
|
|
+ Token<TestDelegationTokenIdentifier> token = generateDelegationToken(
|
|
|
+ dtSecretManager, "SomeUser", "JobTracker");
|
|
|
+ byte[] oldPasswd = token.getPassword();
|
|
|
+ //store the length of the keys list
|
|
|
+ int prevNumKeys = dtSecretManager.getAllKeys().length;
|
|
|
+
|
|
|
+ dtSecretManager.rollMasterKey();
|
|
|
+
|
|
|
+ //after rolling, the length of the keys list must increase
|
|
|
+ int currNumKeys = dtSecretManager.getAllKeys().length;
|
|
|
+ Assert.assertEquals((currNumKeys - prevNumKeys) >= 1, true);
|
|
|
+
|
|
|
+ //after rolling, the token that was generated earlier must
|
|
|
+ //still be valid (retrievePassword will fail if the token
|
|
|
+ //is not valid)
|
|
|
+ ByteArrayInputStream bi =
|
|
|
+ new ByteArrayInputStream(token.getIdentifier());
|
|
|
+ TestDelegationTokenIdentifier identifier =
|
|
|
+ dtSecretManager.createIdentifier();
|
|
|
+ identifier.readFields(new DataInputStream(bi));
|
|
|
+ byte[] newPasswd =
|
|
|
+ dtSecretManager.retrievePassword(identifier);
|
|
|
+ //compare the passwords
|
|
|
+ Assert.assertEquals(oldPasswd, newPasswd);
|
|
|
+ } finally {
|
|
|
+ dtSecretManager.stopThreads();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @Test
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ public void testDelegationTokenSelector() throws Exception {
|
|
|
+ TestDelegationTokenSecretManager dtSecretManager =
|
|
|
+ new TestDelegationTokenSecretManager(24*60*60*1000,
|
|
|
+ 10*1000,1*1000,3600000);
|
|
|
+ try {
|
|
|
+ dtSecretManager.startThreads();
|
|
|
+ AbstractDelegationTokenSelector ds =
|
|
|
+ new AbstractDelegationTokenSelector<TestDelegationTokenIdentifier>(KIND);
|
|
|
+
|
|
|
+ //Creates a collection of tokens
|
|
|
+ Token<TestDelegationTokenIdentifier> token1 = generateDelegationToken(
|
|
|
+ dtSecretManager, "SomeUser1", "JobTracker");
|
|
|
+ token1.setService(new Text("MY-SERVICE1"));
|
|
|
+
|
|
|
+ Token<TestDelegationTokenIdentifier> token2 = generateDelegationToken(
|
|
|
+ dtSecretManager, "SomeUser2", "JobTracker");
|
|
|
+ token2.setService(new Text("MY-SERVICE2"));
|
|
|
+
|
|
|
+ List<Token<TestDelegationTokenIdentifier>> tokens =
|
|
|
+ new ArrayList<Token<TestDelegationTokenIdentifier>>();
|
|
|
+ tokens.add(token1);
|
|
|
+ tokens.add(token2);
|
|
|
+
|
|
|
+ //try to select a token with a given service name (created earlier)
|
|
|
+ Token<TestDelegationTokenIdentifier> t =
|
|
|
+ ds.selectToken(new Text("MY-SERVICE1"), tokens);
|
|
|
+ Assert.assertEquals(t, token1);
|
|
|
+ } finally {
|
|
|
+ dtSecretManager.stopThreads();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|