|
47 | 47 | public abstract class SecretManager<T extends TokenIdentifier> {
|
48 | 48 |
|
49 | 49 | public static final Logger LOG = LoggerFactory.getLogger(SecretManager.class);
|
| 50 | + |
| 51 | + private static String selectedAlgorithm; |
| 52 | + private static int selectedLength; |
| 53 | + |
| 54 | + /** |
| 55 | + * Key generator to use. |
| 56 | + */ |
| 57 | + private static boolean keygenInitialized; |
| 58 | + private final Object keyGenLock = new Object(); |
| 59 | + private volatile KeyGenerator keyGen; |
| 60 | + |
| 61 | + /** |
| 62 | + * A thread local store for the Macs. |
| 63 | + */ |
| 64 | + private static boolean macInitialized; |
| 65 | + private static final ThreadLocal<Mac> threadLocalMac = |
| 66 | + ThreadLocal.withInitial(SecretManager::createMac); |
| 67 | + |
| 68 | + private static boolean secretKeyInitialized; |
| 69 | + |
| 70 | + static { |
| 71 | + update(new Configuration()); |
| 72 | + } |
| 73 | + |
| 74 | + private static final String UPDATE_LOG_TEMPLATE = |
| 75 | + "{} was already initialized with older config, those will not be updated." + |
| 76 | + "Hint: If you turn on debug log you can see when it is happening. Thread: {}"; |
| 77 | + /** |
| 78 | + * Updates the selected cryptographic algorithm and key length using the provided |
| 79 | + * Hadoop {@link Configuration}. This method reads the values for |
| 80 | + * {@code HADOOP_SECURITY_SECRET_MANAGER_KEY_GENERATOR_ALGORITHM_KEY} and |
| 81 | + * {@code HADOOP_SECURITY_SECRET_MANAGER_KEY_LENGTH_KEY}, or uses default values if not set. |
| 82 | + * |
| 83 | + * @param conf the configuration object containing cryptographic settings |
| 84 | + */ |
| 85 | + public static synchronized void update(Configuration conf) { |
| 86 | + if (keygenInitialized) { |
| 87 | + LOG.warn(UPDATE_LOG_TEMPLATE, "KeyGenerator", Thread.currentThread()); |
| 88 | + } |
| 89 | + if (macInitialized) { |
| 90 | + LOG.warn(UPDATE_LOG_TEMPLATE, "Mac", Thread.currentThread()); |
| 91 | + } |
| 92 | + if (secretKeyInitialized) { |
| 93 | + LOG.warn(UPDATE_LOG_TEMPLATE, "SecretKey", Thread.currentThread()); |
| 94 | + } |
| 95 | + selectedAlgorithm = conf.get( |
| 96 | + CommonConfigurationKeysPublic.HADOOP_SECURITY_SECRET_MANAGER_KEY_GENERATOR_ALGORITHM_KEY, |
| 97 | + CommonConfigurationKeysPublic.HADOOP_SECURITY_SECRET_MANAGER_KEY_GENERATOR_ALGORITHM_DEFAULT); |
| 98 | + LOG.debug("Selected hash algorithm: {}", selectedAlgorithm); |
| 99 | + selectedLength = conf.getInt( |
| 100 | + CommonConfigurationKeysPublic.HADOOP_SECURITY_SECRET_MANAGER_KEY_LENGTH_KEY, |
| 101 | + CommonConfigurationKeysPublic.HADOOP_SECURITY_SECRET_MANAGER_KEY_LENGTH_DEFAULT); |
| 102 | + LOG.debug("Selected hash key length: {}", selectedLength); |
| 103 | + } |
| 104 | + |
50 | 105 | /**
|
51 | 106 | * The token was invalid and the message explains why.
|
52 | 107 | */
|
@@ -115,61 +170,17 @@ public void checkAvailableForRead() throws StandbyException {
|
115 | 170 | // Default to being available for read.
|
116 | 171 | }
|
117 | 172 |
|
118 |
| - private static final String SELECTED_ALGORITHM; |
119 |
| - private static final int SELECTED_LENGTH; |
120 |
| - |
121 |
| - static { |
122 |
| - Configuration conf = new Configuration(); |
123 |
| - String algorithm = conf.get( |
124 |
| - CommonConfigurationKeysPublic.HADOOP_SECURITY_SECRET_MANAGER_KEY_GENERATOR_ALGORITHM_KEY, |
125 |
| - CommonConfigurationKeysPublic.HADOOP_SECURITY_SECRET_MANAGER_KEY_GENERATOR_ALGORITHM_DEFAULT); |
126 |
| - LOG.debug("Selected hash algorithm: {}", algorithm); |
127 |
| - SELECTED_ALGORITHM = algorithm; |
128 |
| - int length = conf.getInt( |
129 |
| - CommonConfigurationKeysPublic.HADOOP_SECURITY_SECRET_MANAGER_KEY_LENGTH_KEY, |
130 |
| - CommonConfigurationKeysPublic.HADOOP_SECURITY_SECRET_MANAGER_KEY_LENGTH_DEFAULT); |
131 |
| - LOG.debug("Selected hash key length:{}", length); |
132 |
| - SELECTED_LENGTH = length; |
133 |
| - } |
134 |
| - |
135 |
| - /** |
136 |
| - * A thread local store for the Macs. |
137 |
| - */ |
138 |
| - private static final ThreadLocal<Mac> threadLocalMac = |
139 |
| - new ThreadLocal<Mac>(){ |
140 |
| - @Override |
141 |
| - protected Mac initialValue() { |
142 |
| - try { |
143 |
| - return Mac.getInstance(SELECTED_ALGORITHM); |
144 |
| - } catch (NoSuchAlgorithmException nsa) { |
145 |
| - throw new IllegalArgumentException("Can't find " + SELECTED_ALGORITHM, nsa); |
146 |
| - } |
147 |
| - } |
148 |
| - }; |
149 |
| - |
150 |
| - /** |
151 |
| - * Key generator to use. |
152 |
| - */ |
153 |
| - private final KeyGenerator keyGen; |
154 |
| - { |
155 |
| - try { |
156 |
| - keyGen = KeyGenerator.getInstance(SELECTED_ALGORITHM); |
157 |
| - keyGen.init(SELECTED_LENGTH); |
158 |
| - } catch (NoSuchAlgorithmException nsa) { |
159 |
| - throw new IllegalArgumentException("Can't find " + SELECTED_ALGORITHM, nsa); |
160 |
| - } |
161 |
| - } |
162 |
| - |
163 | 173 | /**
|
164 | 174 | * Generate a new random secret key.
|
165 | 175 | * @return the new key
|
166 | 176 | */
|
167 | 177 | protected SecretKey generateSecret() {
|
168 |
| - SecretKey key; |
169 |
| - synchronized (keyGen) { |
170 |
| - key = keyGen.generateKey(); |
| 178 | + synchronized (keyGenLock) { |
| 179 | + if (keyGen == null) { |
| 180 | + keyGen = createKeyGenerator(); |
| 181 | + } |
| 182 | + return keyGen.generateKey(); |
171 | 183 | }
|
172 |
| - return key; |
173 | 184 | }
|
174 | 185 |
|
175 | 186 | /**
|
@@ -197,6 +208,46 @@ public static byte[] createPassword(byte[] identifier,
|
197 | 208 | * @return the secret key
|
198 | 209 | */
|
199 | 210 | protected static SecretKey createSecretKey(byte[] key) {
|
200 |
| - return new SecretKeySpec(key, SELECTED_ALGORITHM); |
| 211 | + LOG.debug("Creating secretKey with algorithm {} with thread {}", |
| 212 | + selectedAlgorithm, Thread.currentThread()); |
| 213 | + secretKeyInitialized = true; |
| 214 | + return new SecretKeySpec(key, selectedAlgorithm); |
| 215 | + } |
| 216 | + |
| 217 | + /** |
| 218 | + * Creates a new {@link KeyGenerator} instance configured with the currently selected |
| 219 | + * algorithm and key length. |
| 220 | + * |
| 221 | + * @return a new {@code KeyGenerator} instance |
| 222 | + * @throws IllegalArgumentException if the specified algorithm is not available |
| 223 | + */ |
| 224 | + private static synchronized KeyGenerator createKeyGenerator() { |
| 225 | + LOG.debug("Creating key generator instance {} - {} bit with thread {}", |
| 226 | + selectedAlgorithm, selectedLength, Thread.currentThread()); |
| 227 | + try { |
| 228 | + KeyGenerator keyGen = KeyGenerator.getInstance(selectedAlgorithm); |
| 229 | + keyGen.init(selectedLength); |
| 230 | + keygenInitialized = true; |
| 231 | + return keyGen; |
| 232 | + } catch (NoSuchAlgorithmException nsa) { |
| 233 | + throw new IllegalArgumentException("Can't find " + selectedAlgorithm, nsa); |
| 234 | + } |
| 235 | + } |
| 236 | + |
| 237 | + /** |
| 238 | + * Creates a new {@link Mac} instance using the currently selected algorithm. |
| 239 | + * |
| 240 | + * @return a new {@code Mac} instance |
| 241 | + * @throws IllegalArgumentException if the specified algorithm is not available |
| 242 | + */ |
| 243 | + private static synchronized Mac createMac() { |
| 244 | + LOG.debug("Creating mac instance {} with thread {}", selectedAlgorithm, Thread.currentThread()); |
| 245 | + try { |
| 246 | + Mac mac = Mac.getInstance(selectedAlgorithm); |
| 247 | + macInitialized = true; |
| 248 | + return mac; |
| 249 | + } catch (NoSuchAlgorithmException nsa) { |
| 250 | + throw new IllegalArgumentException("Can't find " + selectedAlgorithm, nsa); |
| 251 | + } |
201 | 252 | }
|
202 | 253 | }
|
0 commit comments