| /** |
| * 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.yarn.server.nodemanager.security; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.IOException; |
| |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.security.token.SecretManager.InvalidToken; |
| import org.apache.hadoop.yarn.api.records.ContainerId; |
| import org.apache.hadoop.yarn.api.records.NodeId; |
| import org.apache.hadoop.yarn.api.records.Priority; |
| import org.apache.hadoop.yarn.api.records.Token; |
| import org.apache.hadoop.yarn.conf.YarnConfiguration; |
| import org.apache.hadoop.yarn.security.ContainerTokenIdentifier; |
| import org.apache.hadoop.yarn.server.api.records.MasterKey; |
| import org.apache.hadoop.yarn.server.nodemanager.recovery.NMMemoryStateStoreService; |
| import org.apache.hadoop.yarn.server.security.BaseContainerTokenSecretManager; |
| import org.apache.hadoop.yarn.server.utils.BuilderUtils; |
| import org.junit.Test; |
| |
| public class TestNMContainerTokenSecretManager { |
| |
| @Test |
| public void testRecovery() throws IOException { |
| YarnConfiguration conf = new YarnConfiguration(); |
| conf.setBoolean(YarnConfiguration.NM_RECOVERY_ENABLED, true); |
| final NodeId nodeId = NodeId.newInstance("somehost", 1234); |
| final ContainerId cid1 = BuilderUtils.newContainerId(1, 1, 1, 1); |
| final ContainerId cid2 = BuilderUtils.newContainerId(2, 2, 2, 2); |
| ContainerTokenKeyGeneratorForTest keygen = |
| new ContainerTokenKeyGeneratorForTest(conf); |
| NMMemoryStateStoreService stateStore = new NMMemoryStateStoreService(); |
| stateStore.init(conf); |
| stateStore.start(); |
| NMContainerTokenSecretManager secretMgr = |
| new NMContainerTokenSecretManager(conf, stateStore); |
| secretMgr.setNodeId(nodeId); |
| MasterKey currentKey = keygen.generateKey(); |
| secretMgr.setMasterKey(currentKey); |
| ContainerTokenIdentifier tokenId1 = |
| createContainerTokenId(cid1, nodeId, "user1", secretMgr); |
| ContainerTokenIdentifier tokenId2 = |
| createContainerTokenId(cid2, nodeId, "user2", secretMgr); |
| assertNotNull(secretMgr.retrievePassword(tokenId1)); |
| assertNotNull(secretMgr.retrievePassword(tokenId2)); |
| |
| // restart and verify tokens still valid |
| secretMgr = new NMContainerTokenSecretManager(conf, stateStore); |
| secretMgr.setNodeId(nodeId); |
| secretMgr.recover(); |
| assertEquals(currentKey, secretMgr.getCurrentKey()); |
| assertTrue(secretMgr.isValidStartContainerRequest(tokenId1)); |
| assertTrue(secretMgr.isValidStartContainerRequest(tokenId2)); |
| assertNotNull(secretMgr.retrievePassword(tokenId1)); |
| assertNotNull(secretMgr.retrievePassword(tokenId2)); |
| |
| // roll master key and start a container |
| secretMgr.startContainerSuccessful(tokenId2); |
| currentKey = keygen.generateKey(); |
| secretMgr.setMasterKey(currentKey); |
| |
| // restart and verify tokens still valid due to prev key persist |
| secretMgr = new NMContainerTokenSecretManager(conf, stateStore); |
| secretMgr.setNodeId(nodeId); |
| secretMgr.recover(); |
| assertEquals(currentKey, secretMgr.getCurrentKey()); |
| assertTrue(secretMgr.isValidStartContainerRequest(tokenId1)); |
| assertFalse(secretMgr.isValidStartContainerRequest(tokenId2)); |
| assertNotNull(secretMgr.retrievePassword(tokenId1)); |
| assertNotNull(secretMgr.retrievePassword(tokenId2)); |
| |
| // roll master key again, restart, and verify keys no longer valid |
| currentKey = keygen.generateKey(); |
| secretMgr.setMasterKey(currentKey); |
| secretMgr = new NMContainerTokenSecretManager(conf, stateStore); |
| secretMgr.setNodeId(nodeId); |
| secretMgr.recover(); |
| assertEquals(currentKey, secretMgr.getCurrentKey()); |
| assertTrue(secretMgr.isValidStartContainerRequest(tokenId1)); |
| assertFalse(secretMgr.isValidStartContainerRequest(tokenId2)); |
| try { |
| secretMgr.retrievePassword(tokenId1); |
| fail("token should not be valid"); |
| } catch (InvalidToken e) { |
| // expected |
| } |
| try { |
| secretMgr.retrievePassword(tokenId2); |
| fail("token should not be valid"); |
| } catch (InvalidToken e) { |
| // expected |
| } |
| |
| stateStore.close(); |
| } |
| |
| private static ContainerTokenIdentifier createContainerTokenId( |
| ContainerId cid, NodeId nodeId, String user, |
| NMContainerTokenSecretManager secretMgr) throws IOException { |
| long rmid = cid.getApplicationAttemptId().getApplicationId() |
| .getClusterTimestamp(); |
| ContainerTokenIdentifier ctid = new ContainerTokenIdentifier(cid, |
| nodeId.toString(), user, BuilderUtils.newResource(1024, 1), |
| System.currentTimeMillis() + 100000L, |
| secretMgr.getCurrentKey().getKeyId(), rmid, |
| Priority.newInstance(0), 0); |
| Token token = BuilderUtils.newContainerToken(nodeId, |
| secretMgr.createPassword(ctid), ctid); |
| return BuilderUtils.newContainerTokenIdentifier(token); |
| } |
| |
| private static class ContainerTokenKeyGeneratorForTest extends |
| BaseContainerTokenSecretManager { |
| public ContainerTokenKeyGeneratorForTest(Configuration conf) { |
| super(conf); |
| } |
| |
| public MasterKey generateKey() { |
| return createNewMasterKey().getMasterKey(); |
| } |
| } |
| } |