blob: fcb1e98aeeaf0f573b3f4d060d1e6e134ef235dc [file] [log] [blame]
/**
* 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.tez.common.security;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileSystemTestHelper.MockFileSystem;
import org.apache.hadoop.fs.FilterFileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.security.Credentials;
import org.apache.hadoop.security.token.Token;
import org.apache.hadoop.security.token.TokenIdentifier;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class TestTokenCache {
private static Configuration conf;
private static String renewer;
@BeforeClass
public static void setup() throws Exception {
conf = new Configuration();
conf.set(YarnConfiguration.RM_PRINCIPAL, "mapred/host@REALM");
conf.setSocketAddr(YarnConfiguration.RM_ADDRESS,
InetSocketAddress.createUnresolved("127.0.0.1", 8032));
renewer = Master.getMasterPrincipal(conf);
}
@Test(timeout = 5000)
@SuppressWarnings("deprecation")
public void testBinaryCredentials() throws Exception {
String binaryTokenFile = null;
try {
Path TEST_ROOT_DIR = new Path("target");
binaryTokenFile = FileSystem.getLocal(conf).makeQualified(
new Path(TEST_ROOT_DIR, "tokenFile")).toUri().getPath();
MockFileSystem fs1 = createFileSystemForServiceName("service1");
MockFileSystem fs2 = createFileSystemForServiceName("service2");
// get the tokens for fs1 & fs2 and write out to binary creds file
Credentials creds = new Credentials();
Token<?> token1 = fs1.getDelegationToken(renewer);
Token<?> token2 = fs2.getDelegationToken(renewer);
creds.addToken(token1.getService(), token1);
creds.addToken(token2.getService(), token2);
creds.writeTokenStorageFile(new Path(binaryTokenFile), conf);
Credentials newCreds = new Credentials();
TokenCache.mergeBinaryTokens(newCreds, conf, binaryTokenFile);
Assert.assertTrue(newCreds.getAllTokens().size() > 0);
checkTokens(creds, newCreds);
} finally {
if (binaryTokenFile != null) {
try {
FileSystem.getLocal(conf).delete(new Path(binaryTokenFile));
} catch (IOException e) {
// Ignore
}
}
}
}
@Test(timeout=5000)
public void testObtainTokensForFileSystems() throws Exception {
Path[] paths = makePaths(100, "test://dir/file");
Credentials creds = new Credentials();
Configuration conf = new Configuration(TestTokenCache.conf);
conf.set("fs.test.impl", TestFileSystem.class.getName());
// Cache enabled should be invoked only once
conf.setBoolean("fs.test.impl.disable.cache", false);
TokenCache.obtainTokensForFileSystemsInternal(creds, paths, conf);
verify(TestFileSystem.fs, times(1)).addDelegationTokens(renewer, creds);
// Cache disabled should be invoked for every path.
conf.setBoolean("fs.test.impl.disable.cache", true);
TokenCache.obtainTokensForFileSystemsInternal(creds, paths, conf);
verify(TestFileSystem.fs, times(paths.length + 1)).addDelegationTokens(renewer, creds);
// Excluded filesystem tokens should not be obtained.
conf.set("tez.job.fs-servers.token-renewal.exclude", "dir");
TokenCache.obtainTokensForFileSystemsInternal(creds, paths, conf);
verify(TestFileSystem.fs, times(paths.length + 1)).addDelegationTokens(renewer, creds);
}
private Path[] makePaths(int count, String prefix) throws Exception {
Path[] ps = new Path[count];
for (int i = 0; i < count; ++i) {
ps[i] = new Path(prefix + i);
}
return ps;
}
public static class TestFileSystem extends FilterFileSystem {
static final FileSystem fs = mock(FileSystem.class);
static {
try {
when(fs.getUri()).thenReturn(new URI("test://dir"));
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
public TestFileSystem() {
super(fs);
}
@Override
public Token<?>[] addDelegationTokens(String renewer, Credentials credentials)
throws IOException {
return fs.addDelegationTokens(renewer, credentials);
}
}
private MockFileSystem createFileSystemForServiceName(final String service)
throws IOException {
MockFileSystem mockFs = new MockFileSystem();
when(mockFs.getCanonicalServiceName()).thenReturn(service);
when(mockFs.getDelegationToken(any(String.class))).thenAnswer(
new Answer<Token<?>>() {
int unique = 0;
@Override
public Token<?> answer(InvocationOnMock invocation) throws Throwable {
Token<?> token = new Token<TokenIdentifier>();
token.setService(new Text(service));
// use unique value so when we restore from token storage, we can
// tell if it's really the same token
token.setKind(new Text("token" + unique++));
return token;
}
});
return mockFs;
}
private void checkTokens(Credentials creds, Credentials newCreds) {
Assert.assertEquals(creds.getAllTokens().size(),
newCreds.getAllTokens().size());
for (Token<?> token : newCreds.getAllTokens()) {
Token<?> credsToken = creds.getToken(token.getService());
Assert.assertTrue(credsToken != null);
Assert.assertEquals(token, credsToken);
}
}
}