|
@@ -18,6 +18,8 @@
|
|
|
|
|
|
package org.apache.hadoop.security;
|
|
package org.apache.hadoop.security;
|
|
|
|
|
|
|
|
+import com.google.protobuf.ByteString;
|
|
|
|
+
|
|
import java.io.BufferedInputStream;
|
|
import java.io.BufferedInputStream;
|
|
import java.io.DataInput;
|
|
import java.io.DataInput;
|
|
import java.io.DataInputStream;
|
|
import java.io.DataInputStream;
|
|
@@ -25,6 +27,7 @@ import java.io.DataOutput;
|
|
import java.io.DataOutputStream;
|
|
import java.io.DataOutputStream;
|
|
import java.io.File;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileInputStream;
|
|
|
|
+import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Collection;
|
|
@@ -47,9 +50,11 @@ import org.apache.hadoop.io.Writable;
|
|
import org.apache.hadoop.io.WritableUtils;
|
|
import org.apache.hadoop.io.WritableUtils;
|
|
import org.apache.hadoop.security.token.Token;
|
|
import org.apache.hadoop.security.token.Token;
|
|
import org.apache.hadoop.security.token.TokenIdentifier;
|
|
import org.apache.hadoop.security.token.TokenIdentifier;
|
|
|
|
+import org.apache.hadoop.security.proto.SecurityProtos.CredentialsKVProto;
|
|
|
|
+import org.apache.hadoop.security.proto.SecurityProtos.CredentialsProto;
|
|
|
|
|
|
/**
|
|
/**
|
|
- * A class that provides the facilities of reading and writing
|
|
|
|
|
|
+ * A class that provides the facilities of reading and writing
|
|
* secret keys and Tokens.
|
|
* secret keys and Tokens.
|
|
*/
|
|
*/
|
|
@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
|
|
@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
|
|
@@ -58,34 +63,34 @@ public class Credentials implements Writable {
|
|
private static final Log LOG = LogFactory.getLog(Credentials.class);
|
|
private static final Log LOG = LogFactory.getLog(Credentials.class);
|
|
|
|
|
|
private Map<Text, byte[]> secretKeysMap = new HashMap<Text, byte[]>();
|
|
private Map<Text, byte[]> secretKeysMap = new HashMap<Text, byte[]>();
|
|
- private Map<Text, Token<? extends TokenIdentifier>> tokenMap =
|
|
|
|
- new HashMap<Text, Token<? extends TokenIdentifier>>();
|
|
|
|
|
|
+ private Map<Text, Token<? extends TokenIdentifier>> tokenMap =
|
|
|
|
+ new HashMap<Text, Token<? extends TokenIdentifier>>();
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Create an empty credentials instance
|
|
|
|
|
|
+ * Create an empty credentials instance.
|
|
*/
|
|
*/
|
|
public Credentials() {
|
|
public Credentials() {
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Create a copy of the given credentials
|
|
|
|
|
|
+ * Create a copy of the given credentials.
|
|
* @param credentials to copy
|
|
* @param credentials to copy
|
|
*/
|
|
*/
|
|
public Credentials(Credentials credentials) {
|
|
public Credentials(Credentials credentials) {
|
|
this.addAll(credentials);
|
|
this.addAll(credentials);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Returns the Token object for the alias
|
|
|
|
|
|
+ * Returns the Token object for the alias.
|
|
* @param alias the alias for the Token
|
|
* @param alias the alias for the Token
|
|
* @return token for this alias
|
|
* @return token for this alias
|
|
*/
|
|
*/
|
|
public Token<? extends TokenIdentifier> getToken(Text alias) {
|
|
public Token<? extends TokenIdentifier> getToken(Text alias) {
|
|
return tokenMap.get(alias);
|
|
return tokenMap.get(alias);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Add a token in the storage (in memory)
|
|
|
|
|
|
+ * Add a token in the storage (in memory).
|
|
* @param alias the alias for the key
|
|
* @param alias the alias for the key
|
|
* @param t the token object
|
|
* @param t the token object
|
|
*/
|
|
*/
|
|
@@ -96,14 +101,14 @@ public class Credentials implements Writable {
|
|
LOG.warn("Null token ignored for " + alias);
|
|
LOG.warn("Null token ignored for " + alias);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Return all the tokens in the in-memory map
|
|
|
|
|
|
+ * Return all the tokens in the in-memory map.
|
|
*/
|
|
*/
|
|
public Collection<Token<? extends TokenIdentifier>> getAllTokens() {
|
|
public Collection<Token<? extends TokenIdentifier>> getAllTokens() {
|
|
return tokenMap.values();
|
|
return tokenMap.values();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* @return number of Tokens in the in-memory map
|
|
* @return number of Tokens in the in-memory map
|
|
*/
|
|
*/
|
|
@@ -112,23 +117,23 @@ public class Credentials implements Writable {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Returns the key bytes for the alias
|
|
|
|
|
|
+ * Returns the key bytes for the alias.
|
|
* @param alias the alias for the key
|
|
* @param alias the alias for the key
|
|
* @return key for this alias
|
|
* @return key for this alias
|
|
*/
|
|
*/
|
|
public byte[] getSecretKey(Text alias) {
|
|
public byte[] getSecretKey(Text alias) {
|
|
return secretKeysMap.get(alias);
|
|
return secretKeysMap.get(alias);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* @return number of keys in the in-memory map
|
|
* @return number of keys in the in-memory map
|
|
*/
|
|
*/
|
|
public int numberOfSecretKeys() {
|
|
public int numberOfSecretKeys() {
|
|
return secretKeysMap.size();
|
|
return secretKeysMap.size();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Set the key for an alias
|
|
|
|
|
|
+ * Set the key for an alias.
|
|
* @param alias the alias for the key
|
|
* @param alias the alias for the key
|
|
* @param key the key bytes
|
|
* @param key the key bytes
|
|
*/
|
|
*/
|
|
@@ -145,7 +150,7 @@ public class Credentials implements Writable {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Return all the secret key entries in the in-memory map
|
|
|
|
|
|
+ * Return all the secret key entries in the in-memory map.
|
|
*/
|
|
*/
|
|
public List<Text> getAllSecretKeys() {
|
|
public List<Text> getAllSecretKeys() {
|
|
List<Text> list = new java.util.ArrayList<Text>();
|
|
List<Text> list = new java.util.ArrayList<Text>();
|
|
@@ -155,13 +160,13 @@ public class Credentials implements Writable {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Convenience method for reading a token storage file, and loading the Tokens
|
|
|
|
- * therein in the passed UGI
|
|
|
|
|
|
+ * Convenience method for reading a token storage file and loading its Tokens.
|
|
* @param filename
|
|
* @param filename
|
|
* @param conf
|
|
* @param conf
|
|
* @throws IOException
|
|
* @throws IOException
|
|
*/
|
|
*/
|
|
- public static Credentials readTokenStorageFile(Path filename, Configuration conf)
|
|
|
|
|
|
+ public static Credentials readTokenStorageFile(Path filename,
|
|
|
|
+ Configuration conf)
|
|
throws IOException {
|
|
throws IOException {
|
|
FSDataInputStream in = null;
|
|
FSDataInputStream in = null;
|
|
Credentials credentials = new Credentials();
|
|
Credentials credentials = new Credentials();
|
|
@@ -178,13 +183,13 @@ public class Credentials implements Writable {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Convenience method for reading a token storage file, and loading the Tokens
|
|
|
|
- * therein in the passed UGI
|
|
|
|
|
|
+ * Convenience method for reading a token storage file and loading its Tokens.
|
|
* @param filename
|
|
* @param filename
|
|
* @param conf
|
|
* @param conf
|
|
* @throws IOException
|
|
* @throws IOException
|
|
*/
|
|
*/
|
|
- public static Credentials readTokenStorageFile(File filename, Configuration conf)
|
|
|
|
|
|
+ public static Credentials readTokenStorageFile(File filename,
|
|
|
|
+ Configuration conf)
|
|
throws IOException {
|
|
throws IOException {
|
|
DataInputStream in = null;
|
|
DataInputStream in = null;
|
|
Credentials credentials = new Credentials();
|
|
Credentials credentials = new Credentials();
|
|
@@ -199,10 +204,9 @@ public class Credentials implements Writable {
|
|
IOUtils.cleanup(LOG, in);
|
|
IOUtils.cleanup(LOG, in);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Convenience method for reading a token storage file directly from a
|
|
|
|
- * datainputstream
|
|
|
|
|
|
+ * Convenience method for reading a token from a DataInputStream.
|
|
*/
|
|
*/
|
|
public void readTokenStorageStream(DataInputStream in) throws IOException {
|
|
public void readTokenStorageStream(DataInputStream in) throws IOException {
|
|
byte[] magic = new byte[TOKEN_STORAGE_MAGIC.length];
|
|
byte[] magic = new byte[TOKEN_STORAGE_MAGIC.length];
|
|
@@ -211,25 +215,36 @@ public class Credentials implements Writable {
|
|
throw new IOException("Bad header found in token storage.");
|
|
throw new IOException("Bad header found in token storage.");
|
|
}
|
|
}
|
|
byte version = in.readByte();
|
|
byte version = in.readByte();
|
|
- if (version != TOKEN_STORAGE_VERSION) {
|
|
|
|
- throw new IOException("Unknown version " + version +
|
|
|
|
|
|
+ if (version != TOKEN_STORAGE_VERSION &&
|
|
|
|
+ version != OLD_TOKEN_STORAGE_VERSION) {
|
|
|
|
+ throw new IOException("Unknown version " + version +
|
|
" in token storage.");
|
|
" in token storage.");
|
|
}
|
|
}
|
|
- readFields(in);
|
|
|
|
|
|
+ if (version == OLD_TOKEN_STORAGE_VERSION) {
|
|
|
|
+ readFields(in);
|
|
|
|
+ } else if (version == TOKEN_STORAGE_VERSION) {
|
|
|
|
+ readProtos(in);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
private static final byte[] TOKEN_STORAGE_MAGIC =
|
|
private static final byte[] TOKEN_STORAGE_MAGIC =
|
|
"HDTS".getBytes(Charsets.UTF_8);
|
|
"HDTS".getBytes(Charsets.UTF_8);
|
|
- private static final byte TOKEN_STORAGE_VERSION = 0;
|
|
|
|
-
|
|
|
|
|
|
+ private static final byte TOKEN_STORAGE_VERSION = 1;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * For backward compatibility.
|
|
|
|
+ */
|
|
|
|
+ private static final byte OLD_TOKEN_STORAGE_VERSION = 0;
|
|
|
|
+
|
|
|
|
+
|
|
public void writeTokenStorageToStream(DataOutputStream os)
|
|
public void writeTokenStorageToStream(DataOutputStream os)
|
|
- throws IOException {
|
|
|
|
|
|
+ throws IOException {
|
|
os.write(TOKEN_STORAGE_MAGIC);
|
|
os.write(TOKEN_STORAGE_MAGIC);
|
|
os.write(TOKEN_STORAGE_VERSION);
|
|
os.write(TOKEN_STORAGE_VERSION);
|
|
- write(os);
|
|
|
|
|
|
+ writeProto(os);
|
|
}
|
|
}
|
|
|
|
|
|
- public void writeTokenStorageFile(Path filename,
|
|
|
|
|
|
+ public void writeTokenStorageFile(Path filename,
|
|
Configuration conf) throws IOException {
|
|
Configuration conf) throws IOException {
|
|
FSDataOutputStream os = filename.getFileSystem(conf).create(filename);
|
|
FSDataOutputStream os = filename.getFileSystem(conf).create(filename);
|
|
writeTokenStorageToStream(os);
|
|
writeTokenStorageToStream(os);
|
|
@@ -237,7 +252,29 @@ public class Credentials implements Writable {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Stores all the keys to DataOutput
|
|
|
|
|
|
+ * For backward compatibility.
|
|
|
|
+ */
|
|
|
|
+ public void writeLegacyTokenStorageLocalFile(File f) throws IOException {
|
|
|
|
+ writeLegacyOutputStream(new DataOutputStream(new FileOutputStream(f)));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * For backward compatibility.
|
|
|
|
+ */
|
|
|
|
+ public void writeLegacyTokenStorageFile(Path filename, Configuration conf)
|
|
|
|
+ throws IOException {
|
|
|
|
+ writeLegacyOutputStream(filename.getFileSystem(conf).create(filename));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void writeLegacyOutputStream(DataOutputStream os) throws IOException {
|
|
|
|
+ os.write(TOKEN_STORAGE_MAGIC);
|
|
|
|
+ os.write(OLD_TOKEN_STORAGE_VERSION);
|
|
|
|
+ write(os);
|
|
|
|
+ os.close();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Stores all the keys to DataOutput.
|
|
* @param out
|
|
* @param out
|
|
* @throws IOException
|
|
* @throws IOException
|
|
*/
|
|
*/
|
|
@@ -245,12 +282,12 @@ public class Credentials implements Writable {
|
|
public void write(DataOutput out) throws IOException {
|
|
public void write(DataOutput out) throws IOException {
|
|
// write out tokens first
|
|
// write out tokens first
|
|
WritableUtils.writeVInt(out, tokenMap.size());
|
|
WritableUtils.writeVInt(out, tokenMap.size());
|
|
- for(Map.Entry<Text,
|
|
|
|
- Token<? extends TokenIdentifier>> e: tokenMap.entrySet()) {
|
|
|
|
|
|
+ for(Map.Entry<Text,
|
|
|
|
+ Token<? extends TokenIdentifier>> e: tokenMap.entrySet()) {
|
|
e.getKey().write(out);
|
|
e.getKey().write(out);
|
|
e.getValue().write(out);
|
|
e.getValue().write(out);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
// now write out secret keys
|
|
// now write out secret keys
|
|
WritableUtils.writeVInt(out, secretKeysMap.size());
|
|
WritableUtils.writeVInt(out, secretKeysMap.size());
|
|
for(Map.Entry<Text, byte[]> e : secretKeysMap.entrySet()) {
|
|
for(Map.Entry<Text, byte[]> e : secretKeysMap.entrySet()) {
|
|
@@ -259,9 +296,51 @@ public class Credentials implements Writable {
|
|
out.write(e.getValue());
|
|
out.write(e.getValue());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Write contents of this instance as CredentialsProto message to DataOutput.
|
|
|
|
+ * @param out
|
|
|
|
+ * @throws IOException
|
|
|
|
+ */
|
|
|
|
+ public void writeProto(DataOutput out) throws IOException {
|
|
|
|
+ CredentialsProto.Builder storage = CredentialsProto.newBuilder();
|
|
|
|
+ for (Map.Entry<Text, Token<? extends TokenIdentifier>> e :
|
|
|
|
+ tokenMap.entrySet()) {
|
|
|
|
+ CredentialsKVProto.Builder kv = CredentialsKVProto.newBuilder().
|
|
|
|
+ setAliasBytes(ByteString.copyFrom(
|
|
|
|
+ e.getKey().getBytes(), 0, e.getKey().getLength())).
|
|
|
|
+ setToken(e.getValue().toTokenProto());
|
|
|
|
+ storage.addTokens(kv.build());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for(Map.Entry<Text, byte[]> e : secretKeysMap.entrySet()) {
|
|
|
|
+ CredentialsKVProto.Builder kv = CredentialsKVProto.newBuilder().
|
|
|
|
+ setAliasBytes(ByteString.copyFrom(
|
|
|
|
+ e.getKey().getBytes(), 0, e.getKey().getLength())).
|
|
|
|
+ setSecret(ByteString.copyFrom(e.getValue()));
|
|
|
|
+ storage.addSecrets(kv.build());
|
|
|
|
+ }
|
|
|
|
+ storage.build().writeTo((DataOutputStream)out);
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
- * Loads all the keys
|
|
|
|
|
|
+ * Populates keys/values from proto buffer storage.
|
|
|
|
+ * @param in - stream ready to read a serialized proto buffer message
|
|
|
|
+ */
|
|
|
|
+ public void readProtos(DataInput in) throws IOException {
|
|
|
|
+ CredentialsProto storage = CredentialsProto.parseFrom((DataInputStream)in);
|
|
|
|
+ for (CredentialsKVProto kv : storage.getTokensList()) {
|
|
|
|
+ addToken(new Text(kv.getAliasBytes().toByteArray()),
|
|
|
|
+ (Token<? extends TokenIdentifier>) new Token(kv.getToken()));
|
|
|
|
+ }
|
|
|
|
+ for (CredentialsKVProto kv : storage.getSecretsList()) {
|
|
|
|
+ addSecretKey(new Text(kv.getAliasBytes().toByteArray()),
|
|
|
|
+ kv.getSecret().toByteArray());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Loads all the keys.
|
|
* @param in
|
|
* @param in
|
|
* @throws IOException
|
|
* @throws IOException
|
|
*/
|
|
*/
|
|
@@ -269,7 +348,7 @@ public class Credentials implements Writable {
|
|
public void readFields(DataInput in) throws IOException {
|
|
public void readFields(DataInput in) throws IOException {
|
|
secretKeysMap.clear();
|
|
secretKeysMap.clear();
|
|
tokenMap.clear();
|
|
tokenMap.clear();
|
|
-
|
|
|
|
|
|
+
|
|
int size = WritableUtils.readVInt(in);
|
|
int size = WritableUtils.readVInt(in);
|
|
for(int i=0; i<size; i++) {
|
|
for(int i=0; i<size; i++) {
|
|
Text alias = new Text();
|
|
Text alias = new Text();
|
|
@@ -278,7 +357,7 @@ public class Credentials implements Writable {
|
|
t.readFields(in);
|
|
t.readFields(in);
|
|
tokenMap.put(alias, t);
|
|
tokenMap.put(alias, t);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
size = WritableUtils.readVInt(in);
|
|
size = WritableUtils.readVInt(in);
|
|
for(int i=0; i<size; i++) {
|
|
for(int i=0; i<size; i++) {
|
|
Text alias = new Text();
|
|
Text alias = new Text();
|
|
@@ -289,7 +368,7 @@ public class Credentials implements Writable {
|
|
secretKeysMap.put(alias, value);
|
|
secretKeysMap.put(alias, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Copy all of the credentials from one credential object into another.
|
|
* Copy all of the credentials from one credential object into another.
|
|
* Existing secrets and tokens are overwritten.
|
|
* Existing secrets and tokens are overwritten.
|