/** * 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.mapreduce.security.token; import java.util.Map; import java.util.TreeMap; import javax.crypto.SecretKey; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.security.token.SecretManager; import org.apache.hadoop.security.token.Token; /** * SecretManager for job token. It can be used to cache generated job tokens. */ @InterfaceAudience.Private @InterfaceStability.Unstable public class JobTokenSecretManager extends SecretManager<JobTokenIdentifier> { private final SecretKey masterKey; private final Map<String, SecretKey> currentJobTokens; /** * Convert the byte[] to a secret key * @param key the byte[] to create the secret key from * @return the secret key */ public static SecretKey createSecretKey(byte[] key) { return SecretManager.createSecretKey(key); } /** * Compute the HMAC hash of the message using the key * @param msg the message to hash * @param key the key to use * @return the computed hash */ public static byte[] computeHash(byte[] msg, SecretKey key) { return createPassword(msg, key); } /** * Default constructor */ public JobTokenSecretManager() { this.masterKey = generateSecret(); this.currentJobTokens = new TreeMap<String, SecretKey>(); } /** * Create a new password/secret for the given job token identifier. * @param identifier the job token identifier * @return token password/secret */ @Override public byte[] createPassword(JobTokenIdentifier identifier) { byte[] result = createPassword(identifier.getBytes(), masterKey); return result; } /** * Add the job token of a job to cache * @param jobId the job that owns the token * @param token the job token */ public void addTokenForJob(String jobId, Token<JobTokenIdentifier> token) { SecretKey tokenSecret = createSecretKey(token.getPassword()); synchronized (currentJobTokens) { currentJobTokens.put(jobId, tokenSecret); } } /** * Remove the cached job token of a job from cache * @param jobId the job whose token is to be removed */ public void removeTokenForJob(String jobId) { synchronized (currentJobTokens) { currentJobTokens.remove(jobId); } } /** * Look up the token password/secret for the given jobId. * @param jobId the jobId to look up * @return token password/secret as SecretKey * @throws InvalidToken */ public SecretKey retrieveTokenSecret(String jobId) throws InvalidToken { SecretKey tokenSecret = null; synchronized (currentJobTokens) { tokenSecret = currentJobTokens.get(jobId); } if (tokenSecret == null) { throw new InvalidToken("Can't find job token for job " + jobId + " !!"); } return tokenSecret; } /** * Look up the token password/secret for the given job token identifier. * @param identifier the job token identifier to look up * @return token password/secret as byte[] * @throws InvalidToken */ @Override public byte[] retrievePassword(JobTokenIdentifier identifier) throws InvalidToken { return retrieveTokenSecret(identifier.getJobId().toString()).getEncoded(); } /** * Create an empty job token identifier * @return a newly created empty job token identifier */ @Override public JobTokenIdentifier createIdentifier() { return new JobTokenIdentifier(); } }