Skip to content

Commit 4f719c6

Browse files
committed
HADOOP-6581. Add authenticated TokenIdentifiers to UGI so that they can be used for authorization. Kan Zhang and Jitendra Pandey via jghoman.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@948573 13f79535-47bb-0310-9956-ffa450edef68
1 parent 74405dc commit 4f719c6

File tree

9 files changed

+98
-25
lines changed

9 files changed

+98
-25
lines changed

CHANGES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ Hadoop Change Log
22

33
Trunk (unreleased changes)
44

5+
NEW FEATURES
6+
HADOOP-6581. Add authenticated TokenIdentifiers to UGI so that
7+
they can be used for authorization (Kan Zhang and Jitendra Pandey
8+
via jghoman)
9+
510
IMPROVEMENTS
611
HADOOP-6644. util.Shell getGROUPS_FOR_USER_COMMAND method name
712
- should use common naming convention (boryas)

ivy/libraries.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
apacheant.version=1.7.1
1818
ant-task.version=2.0.10
1919

20-
avro.version=1.3.0
20+
avro.version=1.3.2
2121

2222
checkstyle.version=4.2
2323

src/java/org/apache/hadoop/ipc/Server.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,13 @@ private UserGroupInformation getAuthorizedUgi(String authorizedId)
923923
if (authMethod == SaslRpcServer.AuthMethod.DIGEST) {
924924
TokenIdentifier tokenId = SaslRpcServer.getIdentifier(authorizedId,
925925
secretManager);
926-
return tokenId.getUser();
926+
UserGroupInformation ugi = tokenId.getUser();
927+
if (ugi == null) {
928+
throw new AccessControlException(
929+
"Can't retrieve username from tokenIdentifier.");
930+
}
931+
ugi.addTokenIdentifier(tokenId);
932+
return ugi;
927933
} else {
928934
return UserGroupInformation.createRemoteUser(authorizedId);
929935
}
@@ -1531,7 +1537,7 @@ void enableSecurity() {
15311537
public void setSocketSendBufSize(int size) { this.socketSendBufferSize = size; }
15321538

15331539
/** Starts the service. Must be called before any calls will be handled. */
1534-
public synchronized void start() throws IOException {
1540+
public synchronized void start() {
15351541
responder.start();
15361542
listener.start();
15371543
handlers = new Handler[handlerCount];

src/java/org/apache/hadoop/security/SaslRpcServer.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ static byte[] decodeIdentifier(String identifier) {
6868
return Base64.decodeBase64(identifier.getBytes());
6969
}
7070

71-
public static TokenIdentifier getIdentifier(String id,
72-
SecretManager<TokenIdentifier> secretManager) throws InvalidToken {
71+
public static <T extends TokenIdentifier> T getIdentifier(String id,
72+
SecretManager<T> secretManager) throws InvalidToken {
7373
byte[] tokenId = decodeIdentifier(id);
74-
TokenIdentifier tokenIdentifier = secretManager.createIdentifier();
74+
T tokenIdentifier = secretManager.createIdentifier();
7575
try {
7676
tokenIdentifier.readFields(new DataInputStream(new ByteArrayInputStream(
7777
tokenId)));
@@ -202,11 +202,12 @@ public void handle(Callback[] callbacks) throws InvalidToken,
202202
ac.setAuthorized(false);
203203
}
204204
if (ac.isAuthorized()) {
205-
String username = getIdentifier(authzid, secretManager).getUser()
206-
.getUserName().toString();
207-
if (LOG.isDebugEnabled())
205+
if (LOG.isDebugEnabled()) {
206+
String username = getIdentifier(authzid, secretManager).getUser()
207+
.getUserName().toString();
208208
LOG.debug("SASL server DIGEST-MD5 callback: setting "
209209
+ "canonicalized client ID: " + username);
210+
}
210211
ac.setAuthorizedID(authzid);
211212
}
212213
}

src/java/org/apache/hadoop/security/UserGroupInformation.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,28 @@ public String getUserName() {
610610
return null;
611611
}
612612

613+
/**
614+
* Add a TokenIdentifier to this UGI. The TokenIdentifier has typically been
615+
* authenticated by the RPC layer as belonging to the user represented by this
616+
* UGI.
617+
*
618+
* @param tokenId
619+
* tokenIdentifier to be added
620+
* @return true on successful add of new tokenIdentifier
621+
*/
622+
public synchronized boolean addTokenIdentifier(TokenIdentifier tokenId) {
623+
return subject.getPublicCredentials().add(tokenId);
624+
}
625+
626+
/**
627+
* Get the set of TokenIdentifiers belonging to this UGI
628+
*
629+
* @return the set of TokenIdentifiers belonging to this UGI
630+
*/
631+
public synchronized Set<TokenIdentifier> getTokenIdentifiers() {
632+
return subject.getPublicCredentials(TokenIdentifier.class);
633+
}
634+
613635
/**
614636
* Add a token to this UGI
615637
*

src/java/org/apache/hadoop/security/token/delegation/DelegationKey.java

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import org.apache.hadoop.io.Writable;
2929
import org.apache.hadoop.io.WritableUtils;
30+
import org.apache.avro.reflect.Nullable;
3031

3132
/**
3233
* Key used for generating and verifying delegation tokens
@@ -35,7 +36,8 @@
3536
public class DelegationKey implements Writable {
3637
private int keyId;
3738
private long expiryDate;
38-
private SecretKey key;
39+
@Nullable
40+
private byte[] keyBytes = null;
3941

4042
public DelegationKey() {
4143
this(0, 0L, null);
@@ -44,7 +46,9 @@ public DelegationKey() {
4446
public DelegationKey(int keyId, long expiryDate, SecretKey key) {
4547
this.keyId = keyId;
4648
this.expiryDate = expiryDate;
47-
this.key = key;
49+
if (key!=null) {
50+
this.keyBytes = key.getEncoded();
51+
}
4852
}
4953

5054
public int getKeyId() {
@@ -56,7 +60,12 @@ public long getExpiryDate() {
5660
}
5761

5862
public SecretKey getKey() {
59-
return key;
63+
if (keyBytes == null || keyBytes.length == 0) {
64+
return null;
65+
} else {
66+
SecretKey key = AbstractDelegationTokenSecretManager.createSecretKey(keyBytes);
67+
return key;
68+
}
6069
}
6170

6271
public void setExpiryDate(long expiryDate) {
@@ -68,9 +77,12 @@ public void setExpiryDate(long expiryDate) {
6877
public void write(DataOutput out) throws IOException {
6978
WritableUtils.writeVInt(out, keyId);
7079
WritableUtils.writeVLong(out, expiryDate);
71-
byte[] keyBytes = key.getEncoded();
72-
WritableUtils.writeVInt(out, keyBytes.length);
73-
out.write(keyBytes);
80+
if (keyBytes == null) {
81+
WritableUtils.writeVInt(out, -1);
82+
} else {
83+
WritableUtils.writeVInt(out, keyBytes.length);
84+
out.write(keyBytes);
85+
}
7486
}
7587

7688
/**
@@ -79,8 +91,11 @@ public void readFields(DataInput in) throws IOException {
7991
keyId = WritableUtils.readVInt(in);
8092
expiryDate = WritableUtils.readVLong(in);
8193
int len = WritableUtils.readVInt(in);
82-
byte[] keyBytes = new byte[len];
83-
in.readFully(keyBytes);
84-
key = AbstractDelegationTokenSecretManager.createSecretKey(keyBytes);
94+
if (len == -1) {
95+
keyBytes = null;
96+
} else {
97+
keyBytes = new byte[len];
98+
in.readFully(keyBytes);
99+
}
85100
}
86101
}

src/test/core/org/apache/hadoop/ipc/AvroTestProtocol.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@
1919
package org.apache.hadoop.ipc;
2020

2121
import org.apache.avro.ipc.AvroRemoteException;
22-
import org.apache.avro.util.Utf8;
2322

2423
@SuppressWarnings("serial")
2524
public interface AvroTestProtocol {
2625
public static class Problem extends AvroRemoteException {
2726
public Problem() {}
2827
}
2928
void ping();
30-
Utf8 echo(Utf8 value);
29+
String echo(String value);
3130
int add(int v1, int v2);
3231
int error() throws Problem;
3332
}

src/test/core/org/apache/hadoop/ipc/TestAvroRpc.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.apache.hadoop.net.NetUtils;
3131

3232
import org.apache.avro.ipc.AvroRemoteException;
33-
import org.apache.avro.util.Utf8;
3433

3534
/** Unit tests for AvroRpc. */
3635
public class TestAvroRpc extends TestCase {
@@ -50,7 +49,7 @@ public static class TestImpl implements AvroTestProtocol {
5049

5150
public void ping() {}
5251

53-
public Utf8 echo(Utf8 value) { return value; }
52+
public String echo(String value) { return value; }
5453

5554
public int add(int v1, int v2) { return v1 + v2; }
5655

@@ -74,8 +73,8 @@ public void testCalls() throws Exception {
7473

7574
proxy.ping();
7675

77-
Utf8 utf8Result = proxy.echo(new Utf8("hello world"));
78-
assertEquals(new Utf8("hello world"), utf8Result);
76+
String echo = proxy.echo("hello world");
77+
assertEquals("hello world", echo);
7978

8079
int intResult = proxy.add(1, 2);
8180
assertEquals(3, intResult);

src/test/core/org/apache/hadoop/security/TestUserGroupInformation.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434

3535
import junit.framework.Assert;
3636

37-
import org.apache.hadoop.security.SaslRpcServer.AuthMethod;
3837
import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod;
3938
import org.apache.hadoop.security.token.Token;
4039
import org.apache.hadoop.security.token.TokenIdentifier;
@@ -215,6 +214,33 @@ public Collection<Token<?>> run() throws IOException {
215214
assertTrue(otherSet.contains(t2));
216215
}
217216

217+
@Test
218+
public void testTokenIdentifiers() throws Exception {
219+
UserGroupInformation ugi = UserGroupInformation.createUserForTesting(
220+
"TheDoctor", new String[] { "TheTARDIS" });
221+
TokenIdentifier t1 = mock(TokenIdentifier.class);
222+
TokenIdentifier t2 = mock(TokenIdentifier.class);
223+
224+
ugi.addTokenIdentifier(t1);
225+
ugi.addTokenIdentifier(t2);
226+
227+
Collection<TokenIdentifier> z = ugi.getTokenIdentifiers();
228+
assertTrue(z.contains(t1));
229+
assertTrue(z.contains(t2));
230+
assertEquals(2, z.size());
231+
232+
// ensure that the token identifiers are passed through doAs
233+
Collection<TokenIdentifier> otherSet = ugi
234+
.doAs(new PrivilegedExceptionAction<Collection<TokenIdentifier>>() {
235+
public Collection<TokenIdentifier> run() throws IOException {
236+
return UserGroupInformation.getCurrentUser().getTokenIdentifiers();
237+
}
238+
});
239+
assertTrue(otherSet.contains(t1));
240+
assertTrue(otherSet.contains(t2));
241+
assertEquals(2, otherSet.size());
242+
}
243+
218244
@Test
219245
public void testUGIAuthMethod() throws Exception {
220246
final UserGroupInformation ugi = UserGroupInformation.getCurrentUser();

0 commit comments

Comments
 (0)