static ClientDatanodeProtocolPB createClientDatanodeProtocolProxy( DatanodeID datanodeid, Configuration conf, int socketTimeout, boolean connectToDnViaHostname, LocatedBlock locatedBlock) throws IOException { final String dnAddr = datanodeid.getIpcAddr(connectToDnViaHostname); InetSocketAddress addr = NetUtils.createSocketAddr(dnAddr); if (LOG.isDebugEnabled()) { LOG.debug("Connecting to datanode " + dnAddr + " addr=" + addr); } // Since we're creating a new UserGroupInformation here, we know that no // future RPC proxies will be able to re-use the same connection. And // usages of this proxy tend to be one-off calls. // // This is a temporary fix: callers should really achieve this by using // RPC.stopProxy() on the resulting object, but this is currently not // working in trunk. See the discussion on HDFS-1965. Configuration confWithNoIpcIdle = new Configuration(conf); confWithNoIpcIdle.setInt( CommonConfigurationKeysPublic.IPC_CLIENT_CONNECTION_MAXIDLETIME_KEY, 0); UserGroupInformation ticket = UserGroupInformation.createRemoteUser(locatedBlock.getBlock().getLocalBlock().toString()); ticket.addToken(locatedBlock.getBlockToken()); return createClientDatanodeProtocolProxy( addr, ticket, confWithNoIpcIdle, NetUtils.getDefaultSocketFactory(conf), socketTimeout); }
/** * Obtain the tokens needed by the job and put them in the UGI * * @param conf */ protected void downloadTokensAndSetupUGI(Configuration conf) { try { this.currentUser = UserGroupInformation.getCurrentUser(); if (UserGroupInformation.isSecurityEnabled()) { // Read the file-system tokens from the localized tokens-file. Path jobSubmitDir = FileContext.getLocalFSFileContext() .makeQualified( new Path(new File(DragonJobConfig.JOB_SUBMIT_DIR).getAbsolutePath())); Path jobTokenFile = new Path(jobSubmitDir, DragonJobConfig.APPLICATION_TOKENS_FILE); fsTokens.addAll(Credentials.readTokenStorageFile(jobTokenFile, conf)); LOG.info("jobSubmitDir=" + jobSubmitDir + " jobTokenFile=" + jobTokenFile); for (Token<? extends TokenIdentifier> tk : fsTokens.getAllTokens()) { if (LOG.isDebugEnabled()) { LOG.debug( "Token of kind " + tk.getKind() + "in current ugi in the AppMaster for service " + tk.getService()); } currentUser.addToken(tk); // For use by AppMaster itself. } } } catch (IOException e) { throw new YarnException(e); } }
/** * The function will verify the token with NameNode if available and will create a * UserGroupInformation. * * <p>Code in this function is copied from JspHelper.getTokenUGI * * @param identifier Delegation token identifier * @param password Delegation token password * @param kind the kind of token * @param service the service for this token * @param servletContext Jetty servlet context which contains the NN address * @throws SecurityException Thrown when authentication fails */ private static void verifyToken( byte[] identifier, byte[] password, Text kind, Text service, ServletContext servletContext) { try { Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>(identifier, password, kind, service); ByteArrayInputStream buf = new ByteArrayInputStream(token.getIdentifier()); DataInputStream in = new DataInputStream(buf); DelegationTokenIdentifier id = new DelegationTokenIdentifier(); id.readFields(in); final NameNode nn = NameNodeHttpServer.getNameNodeFromContext(servletContext); if (nn != null) { nn.getNamesystem().verifyToken(id, token.getPassword()); } UserGroupInformation userGroupInformation = id.getUser(); userGroupInformation.addToken(token); LOG.debug( "user " + userGroupInformation.getUserName() + " (" + userGroupInformation.getShortUserName() + ") authenticated"); // re-login if necessary userGroupInformation.checkTGTAndReloginFromKeytab(); } catch (IOException e) { throw new SecurityException("Failed to verify delegation token " + e, e); } }
@SuppressWarnings("unchecked") // from Mockito mocks @Test public <T extends TokenIdentifier> void testUGITokens() throws Exception { UserGroupInformation ugi = UserGroupInformation.createUserForTesting("TheDoctor", new String[] {"TheTARDIS"}); Token<T> t1 = mock(Token.class); Token<T> t2 = mock(Token.class); ugi.addToken(t1); ugi.addToken(t2); Collection<Token<? extends TokenIdentifier>> z = ugi.getTokens(); assertTrue(z.contains(t1)); assertTrue(z.contains(t2)); assertEquals(2, z.size()); try { z.remove(t1); fail("Shouldn't be able to modify token collection from UGI"); } catch (UnsupportedOperationException uoe) { // Can't modify tokens } // ensure that the tokens are passed through doAs Collection<Token<? extends TokenIdentifier>> otherSet = ugi.doAs( new PrivilegedExceptionAction<Collection<Token<?>>>() { public Collection<Token<?>> run() throws IOException { return UserGroupInformation.getCurrentUser().getTokens(); } }); assertTrue(otherSet.contains(t1)); assertTrue(otherSet.contains(t2)); }
private void injectToken() throws IOException { if (UserGroupInformation.isSecurityEnabled()) { Token<DelegationTokenIdentifier> token = params.delegationToken(); token.setKind(HDFS_DELEGATION_KIND); ugi.addToken(token); } }
/** * Getter for proxiedFs, using the passed parameters to create an instance of a proxiedFs. * * @param properties * @param authType is either TOKEN or KEYTAB. * @param authPath is the KEYTAB location if the authType is KEYTAB; otherwise, it is the token * file. * @param uri File system URI. * @throws IOException * @throws InterruptedException * @throws URISyntaxException * @return proxiedFs */ public FileSystem getProxiedFileSystem( State properties, AuthType authType, String authPath, String uri) throws IOException, InterruptedException, URISyntaxException { Preconditions.checkArgument( StringUtils.isNotBlank(properties.getProp(ConfigurationKeys.FS_PROXY_AS_USER_NAME)), "State does not contain a proper proxy user name"); String proxyUserName = properties.getProp(ConfigurationKeys.FS_PROXY_AS_USER_NAME); UserGroupInformation proxyUser; switch (authType) { case KEYTAB: // If the authentication type is KEYTAB, log in a super user first before // creating a proxy user. Preconditions.checkArgument( StringUtils.isNotBlank( properties.getProp(ConfigurationKeys.SUPER_USER_NAME_TO_PROXY_AS_OTHERS)), "State does not contain a proper proxy token file name"); String superUser = properties.getProp(ConfigurationKeys.SUPER_USER_NAME_TO_PROXY_AS_OTHERS); UserGroupInformation.loginUserFromKeytab(superUser, authPath); proxyUser = UserGroupInformation.createProxyUser( proxyUserName, UserGroupInformation.getLoginUser()); break; case TOKEN: // If the authentication type is TOKEN, create a proxy user and then add the token // to the user. proxyUser = UserGroupInformation.createProxyUser( proxyUserName, UserGroupInformation.getLoginUser()); Optional<Token> proxyToken = this.getTokenFromSeqFile(authPath, proxyUserName); if (proxyToken.isPresent()) { proxyUser.addToken(proxyToken.get()); } else { LOG.warn("No delegation token found for the current proxy user."); } break; default: LOG.warn( "Creating a proxy user without authentication, which could not perform File system operations."); proxyUser = UserGroupInformation.createProxyUser( proxyUserName, UserGroupInformation.getLoginUser()); break; } final Configuration conf = new Configuration(); JobConfigurationUtils.putStateIntoConfiguration(properties, conf); final URI fsURI = URI.create(uri); proxyUser.doAs( new PrivilegedExceptionAction<Void>() { @Override public Void run() throws IOException { LOG.debug( "Now performing file system operations as :" + UserGroupInformation.getCurrentUser()); proxiedFs = FileSystem.get(fsURI, conf); return null; } }); return this.proxiedFs; }
private void obtainTokenAndAddIntoUGI(UserGroupInformation clientUgi, String tokenSig) throws Exception { // obtain a token by directly invoking the metastore operation(without going // through the thrift interface). Obtaining a token makes the secret manager // aware of the user and that it gave the token to the user String tokenStrForm; if (tokenSig == null) { tokenStrForm = HiveMetaStore.getDelegationToken(clientUgi.getShortUserName()); } else { tokenStrForm = HiveMetaStore.getDelegationToken(clientUgi.getShortUserName(), tokenSig); conf.set("hive.metastore.token.signature", tokenSig); } Token<DelegationTokenIdentifier> t = new Token<DelegationTokenIdentifier>(); t.decodeFromUrlString(tokenStrForm); // add the token to the clientUgi for securely talking to the metastore clientUgi.addToken(t); // Create the metastore client as the clientUgi. Doing so this // way will give the client access to the token that was added earlier // in the clientUgi HiveMetaStoreClient hiveClient = clientUgi.doAs( new PrivilegedExceptionAction<HiveMetaStoreClient>() { public HiveMetaStoreClient run() throws Exception { HiveMetaStoreClient hiveClient = new HiveMetaStoreClient(conf); return hiveClient; } }); assertTrue("Couldn't connect to metastore", hiveClient != null); // try out some metastore operations createDBAndVerifyExistence(hiveClient); hiveClient.close(); // Now cancel the delegation token HiveMetaStore.cancelDelegationToken(tokenStrForm); // now metastore connection should fail hiveClient = clientUgi.doAs( new PrivilegedExceptionAction<HiveMetaStoreClient>() { public HiveMetaStoreClient run() { try { HiveMetaStoreClient hiveClient = new HiveMetaStoreClient(conf); return hiveClient; } catch (MetaException e) { return null; } } }); assertTrue("Expected metastore operations to fail", hiveClient == null); }
private void updateAMRMToken(Token token) throws IOException { org.apache.hadoop.security.token.Token<AMRMTokenIdentifier> amrmToken = new org.apache.hadoop.security.token.Token<AMRMTokenIdentifier>( token.getIdentifier().array(), token.getPassword().array(), new Text(token.getKind()), new Text(token.getService())); // Preserve the token service sent by the RM when adding the token // to ensure we replace the previous token setup by the RM. // Afterwards we can update the service address for the RPC layer. UserGroupInformation currentUGI = UserGroupInformation.getCurrentUser(); currentUGI.addToken(amrmToken); amrmToken.setService(ClientRMProxy.getAMRMTokenService(getConfig())); }
private WebHdfsFileSystem getWebHdfsFileSystem(UserGroupInformation ugi, Configuration conf) throws IOException { if (UserGroupInformation.isSecurityEnabled()) { DelegationTokenIdentifier dtId = new DelegationTokenIdentifier(new Text(ugi.getUserName()), null, null); FSNamesystem namesystem = mock(FSNamesystem.class); DelegationTokenSecretManager dtSecretManager = new DelegationTokenSecretManager(86400000, 86400000, 86400000, 86400000, namesystem); dtSecretManager.startThreads(); Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>(dtId, dtSecretManager); SecurityUtil.setTokenService(token, NetUtils.createSocketAddr(uri.getAuthority())); token.setKind(WebHdfsConstants.WEBHDFS_TOKEN_KIND); ugi.addToken(token); } return (WebHdfsFileSystem) FileSystem.get(uri, conf); }
/** * Get the currently logged in user. * * @return the logged in user * @throws IOException if login fails */ public static synchronized UserGroupInformation getLoginUser() throws IOException { if (loginUser == null) { try { Subject subject = new Subject(); LoginContext login; if (isSecurityEnabled()) { login = new LoginContext(HadoopConfiguration.USER_KERBEROS_CONFIG_NAME, subject); } else if (useConfiguredFileAuth) { login = new LoginContext(HadoopConfiguration.FILE_CONFIG_NAME, subject); } else { login = new LoginContext(HadoopConfiguration.SIMPLE_CONFIG_NAME, subject); } login.login(); loginUser = new UserGroupInformation(subject); loginUser.setLogin(login); // loginUser.setAuthenticationMethod(isSecurityEnabled() ? // AuthenticationMethod.KERBEROS : // AuthenticationMethod.SIMPLE); AuthenticationMethod authMethod = AuthenticationMethod.SIMPLE; if (isSecurityEnabled()) { authMethod = AuthenticationMethod.KERBEROS; } else if (useConfiguredFileAuth) { authMethod = AuthenticationMethod.CONFIGFILE; } else { authMethod = AuthenticationMethod.SIMPLE; } loginUser.setAuthenticationMethod(authMethod); loginUser = new UserGroupInformation(login.getSubject()); String fileLocation = System.getenv(HADOOP_TOKEN_FILE_LOCATION); if (fileLocation != null && isSecurityEnabled()) { // load the token storage file and put all of the tokens into the // user. Credentials cred = Credentials.readTokenStorageFiles(fileLocation, conf); for (Token<?> token : cred.getAllTokens()) { loginUser.addToken(token); } } loginUser.spawnAutoRenewalThreadForUserCreds(); } catch (LoginException le) { throw new IOException("failure to login", le); } } return loginUser; }
public static void cloneDelegationTokenForLogicalAddress( UserGroupInformation ugi, String haJtAddress, Collection<InetSocketAddress> jtAddresses) { Text haService = HAUtil.buildTokenServiceForLogicalAddress(haJtAddress); Token<DelegationTokenIdentifier> haToken = tokenSelector.selectToken(haService, ugi.getTokens()); if (haToken != null) { for (InetSocketAddress singleJtAddr : jtAddresses) { Token<DelegationTokenIdentifier> specificToken = new Token<DelegationTokenIdentifier>(haToken); SecurityUtil.setTokenService(specificToken, singleJtAddr); ugi.addToken(specificToken); LOG.debug( "Mapped HA service delegation token for logical address " + haJtAddress + " to jt " + singleJtAddr); } } else { LOG.debug("No HA service delegation token found for logical address " + haJtAddress); } }
/** * Get {@link UserGroupInformation} and possibly the delegation token out of the request. * * @param context the Servlet context * @param request the http request * @param conf configuration * @param secureAuthMethod the AuthenticationMethod used in secure mode. * @param tryUgiParameter Should it try the ugi parameter? * @return a new user from the request * @throws AccessControlException if the request has no token */ public static UserGroupInformation getUGI( ServletContext context, HttpServletRequest request, Configuration conf, final AuthenticationMethod secureAuthMethod, final boolean tryUgiParameter) throws IOException { final UserGroupInformation ugi; final String usernameFromQuery = getUsernameFromQuery(request, tryUgiParameter); final String doAsUserFromQuery = request.getParameter(DoAsParam.NAME); if (UserGroupInformation.isSecurityEnabled()) { final String remoteUser = request.getRemoteUser(); String tokenString = request.getParameter(DELEGATION_PARAMETER_NAME); if (tokenString != null) { Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>(); token.decodeFromUrlString(tokenString); SecurityUtil.setTokenService(token, NameNode.getAddress(conf)); token.setKind(DelegationTokenIdentifier.HDFS_DELEGATION_KIND); ByteArrayInputStream buf = new ByteArrayInputStream(token.getIdentifier()); DataInputStream in = new DataInputStream(buf); DelegationTokenIdentifier id = new DelegationTokenIdentifier(); id.readFields(in); if (context != null) { NameNode nn = (NameNode) context.getAttribute("name.node"); if (nn != null) { // Verify the token. nn.getNamesystem() .getDelegationTokenSecretManager() .verifyToken(id, token.getPassword()); } } ugi = id.getUser(); if (ugi.getRealUser() == null) { // non-proxy case checkUsername(ugi.getShortUserName(), usernameFromQuery); checkUsername(null, doAsUserFromQuery); } else { // proxy case checkUsername(ugi.getRealUser().getShortUserName(), usernameFromQuery); checkUsername(ugi.getShortUserName(), doAsUserFromQuery); ProxyUsers.authorize(ugi, request.getRemoteAddr(), conf); } ugi.addToken(token); ugi.setAuthenticationMethod(AuthenticationMethod.TOKEN); } else { if (remoteUser == null) { throw new IOException("Security enabled but user not " + "authenticated by filter"); } final UserGroupInformation realUgi = UserGroupInformation.createRemoteUser(remoteUser); checkUsername(realUgi.getShortUserName(), usernameFromQuery); // This is not necessarily true, could have been auth'ed by user-facing // filter realUgi.setAuthenticationMethod(secureAuthMethod); ugi = initUGI(realUgi, doAsUserFromQuery, request, true, conf); } } else { // Security's not on, pull from url final UserGroupInformation realUgi = usernameFromQuery == null ? getDefaultWebUser(conf) // not specified in request : UserGroupInformation.createRemoteUser(usernameFromQuery); realUgi.setAuthenticationMethod(AuthenticationMethod.SIMPLE); ugi = initUGI(realUgi, doAsUserFromQuery, request, false, conf); } if (LOG.isDebugEnabled()) LOG.debug("getUGI is returning: " + ugi.getShortUserName()); return ugi; }
@Override public void secureBulkLoadHFiles( RpcController controller, SecureBulkLoadHFilesRequest request, RpcCallback<SecureBulkLoadHFilesResponse> done) { final List<Pair<byte[], String>> familyPaths = new ArrayList<Pair<byte[], String>>(); for (ClientProtos.BulkLoadHFileRequest.FamilyPath el : request.getFamilyPathList()) { familyPaths.add(new Pair(el.getFamily().toByteArray(), el.getPath())); } Token userToken = null; if (userProvider.isHadoopSecurityEnabled()) { userToken = new Token( request.getFsToken().getIdentifier().toByteArray(), request.getFsToken().getPassword().toByteArray(), new Text(request.getFsToken().getKind()), new Text(request.getFsToken().getService())); } final String bulkToken = request.getBulkToken(); User user = getActiveUser(); final UserGroupInformation ugi = user.getUGI(); if (userToken != null) { ugi.addToken(userToken); } else if (userProvider.isHadoopSecurityEnabled()) { // we allow this to pass through in "simple" security mode // for mini cluster testing ResponseConverter.setControllerException( controller, new DoNotRetryIOException("User token cannot be null")); done.run(SecureBulkLoadHFilesResponse.newBuilder().setLoaded(false).build()); return; } HRegion region = env.getRegion(); boolean bypass = false; if (region.getCoprocessorHost() != null) { try { bypass = region.getCoprocessorHost().preBulkLoadHFile(familyPaths); } catch (IOException e) { ResponseConverter.setControllerException(controller, e); done.run(SecureBulkLoadHFilesResponse.newBuilder().setLoaded(false).build()); return; } } boolean loaded = false; if (!bypass) { // Get the target fs (HBase region server fs) delegation token // Since we have checked the permission via 'preBulkLoadHFile', now let's give // the 'request user' necessary token to operate on the target fs. // After this point the 'doAs' user will hold two tokens, one for the source fs // ('request user'), another for the target fs (HBase region server principal). if (userProvider.isHadoopSecurityEnabled()) { FsDelegationToken targetfsDelegationToken = new FsDelegationToken(userProvider, "renewer"); try { targetfsDelegationToken.acquireDelegationToken(fs); } catch (IOException e) { ResponseConverter.setControllerException(controller, e); done.run(SecureBulkLoadHFilesResponse.newBuilder().setLoaded(false).build()); return; } Token<?> targetFsToken = targetfsDelegationToken.getUserToken(); if (targetFsToken != null && (userToken == null || !targetFsToken.getService().equals(userToken.getService()))) { ugi.addToken(targetFsToken); } } loaded = ugi.doAs( new PrivilegedAction<Boolean>() { @Override public Boolean run() { FileSystem fs = null; try { Configuration conf = env.getConfiguration(); fs = FileSystem.get(conf); for (Pair<byte[], String> el : familyPaths) { Path p = new Path(el.getSecond()); Path stageFamily = new Path(bulkToken, Bytes.toString(el.getFirst())); if (!fs.exists(stageFamily)) { fs.mkdirs(stageFamily); fs.setPermission(stageFamily, PERM_ALL_ACCESS); } } // We call bulkLoadHFiles as requesting user // To enable access prior to staging return env.getRegion() .bulkLoadHFiles( familyPaths, true, new SecureBulkLoadListener(fs, bulkToken, conf)); } catch (Exception e) { LOG.error("Failed to complete bulk load", e); } return false; } }); } if (region.getCoprocessorHost() != null) { try { loaded = region.getCoprocessorHost().postBulkLoadHFile(familyPaths, loaded); } catch (IOException e) { ResponseConverter.setControllerException(controller, e); done.run(SecureBulkLoadHFilesResponse.newBuilder().setLoaded(false).build()); return; } } done.run(SecureBulkLoadHFilesResponse.newBuilder().setLoaded(loaded).build()); }
@Override protected TaskRunner2Result callInternal() throws Exception { isStarted.set(true); this.startTime = System.currentTimeMillis(); this.threadName = Thread.currentThread().getName(); if (LOG.isDebugEnabled()) { LOG.debug("canFinish: " + taskSpec.getTaskAttemptID() + ": " + canFinish()); } // Unregister from the AMReporter, since the task is now running. this.amReporter.unregisterTask(request.getAmHost(), request.getAmPort()); synchronized (this) { if (!shouldRunTask) { LOG.info("Not starting task {} since it was killed earlier", taskSpec.getTaskAttemptID()); return new TaskRunner2Result(EndReason.KILL_REQUESTED, null, false); } } // TODO This executor seems unnecessary. Here and TezChild ExecutorService executorReal = Executors.newFixedThreadPool( 1, new ThreadFactoryBuilder().setDaemon(true).setNameFormat("TezTaskRunner").build()); executor = MoreExecutors.listeningDecorator(executorReal); // TODO Consolidate this code with TezChild. runtimeWatch.start(); UserGroupInformation taskUgi = UserGroupInformation.createRemoteUser(request.getUser()); taskUgi.addCredentials(credentials); Map<String, ByteBuffer> serviceConsumerMetadata = new HashMap<>(); serviceConsumerMetadata.put( TezConstants.TEZ_SHUFFLE_HANDLER_SERVICE_ID, TezCommonUtils.convertJobTokenToBytes(jobToken)); Multimap<String, String> startedInputsMap = createStartedInputMap(request.getFragmentSpec()); UserGroupInformation taskOwner = UserGroupInformation.createRemoteUser(request.getTokenIdentifier()); final InetSocketAddress address = NetUtils.createSocketAddrForHost(request.getAmHost(), request.getAmPort()); SecurityUtil.setTokenService(jobToken, address); taskOwner.addToken(jobToken); umbilical = taskOwner.doAs( new PrivilegedExceptionAction<LlapTaskUmbilicalProtocol>() { @Override public LlapTaskUmbilicalProtocol run() throws Exception { return RPC.getProxy( LlapTaskUmbilicalProtocol.class, LlapTaskUmbilicalProtocol.versionID, address, conf); } }); taskReporter = new LlapTaskReporter( umbilical, confParams.amHeartbeatIntervalMsMax, confParams.amCounterHeartbeatInterval, confParams.amMaxEventsPerHeartbeat, new AtomicLong(0), request.getContainerIdString()); String attemptId = fragmentInfo.getFragmentIdentifierString(); IOContextMap.setThreadAttemptId(attemptId); try { synchronized (this) { if (shouldRunTask) { taskRunner = new TezTaskRunner2( conf, taskUgi, fragmentInfo.getLocalDirs(), taskSpec, request.getAppAttemptNumber(), serviceConsumerMetadata, envMap, startedInputsMap, taskReporter, executor, objectRegistry, pid, executionContext, memoryAvailable, false); } } if (taskRunner == null) { LOG.info("Not starting task {} since it was killed earlier", taskSpec.getTaskAttemptID()); return new TaskRunner2Result(EndReason.KILL_REQUESTED, null, false); } try { TaskRunner2Result result = taskRunner.run(); if (result.isContainerShutdownRequested()) { LOG.warn("Unexpected container shutdown requested while running task. Ignoring"); } isCompleted.set(true); return result; } finally { FileSystem.closeAllForUGI(taskUgi); LOG.info( "ExecutionTime for Container: " + request.getContainerIdString() + "=" + runtimeWatch.stop().elapsedMillis()); if (LOG.isDebugEnabled()) { LOG.debug( "canFinish post completion: " + taskSpec.getTaskAttemptID() + ": " + canFinish()); } } } finally { IOContextMap.clearThreadAttempt(attemptId); } }