Skip to content

Commit 8943e13

Browse files
HDDS-1969. Implement OM GetDelegationToken request to use Cache and DoubleBuffer. (#1296)
1 parent e356e4f commit 8943e13

File tree

9 files changed

+301
-1
lines changed

9 files changed

+301
-1
lines changed

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/security/OzoneDelegationTokenSecretManager.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient;
2525
import org.apache.hadoop.hdds.security.x509.exceptions.CertificateException;
2626
import org.apache.hadoop.io.Text;
27+
import org.apache.hadoop.ozone.om.OMConfigKeys;
2728
import org.apache.hadoop.ozone.om.S3SecretManager;
2829
import org.apache.hadoop.ozone.om.S3SecretManagerImpl;
2930
import org.apache.hadoop.ozone.om.exceptions.OMException;
@@ -71,6 +72,8 @@ public class OzoneDelegationTokenSecretManager
7172
*/
7273
private Object noInterruptsLock = new Object();
7374

75+
private boolean isRatisEnabled;
76+
7477
/**
7578
* Create a secret manager.
7679
*
@@ -93,6 +96,9 @@ public OzoneDelegationTokenSecretManager(OzoneConfiguration conf,
9396
this.s3SecretManager = (S3SecretManagerImpl) s3SecretManager;
9497
this.store = new OzoneSecretStore(conf,
9598
this.s3SecretManager.getOmMetadataManager());
99+
isRatisEnabled = conf.getBoolean(
100+
OMConfigKeys.OZONE_OM_RATIS_ENABLE_KEY,
101+
OMConfigKeys.OZONE_OM_RATIS_ENABLE_DEFAULT);
96102
loadTokenSecretState(store.loadState());
97103
}
98104

@@ -131,7 +137,13 @@ public Token<OzoneTokenIdentifier> createToken(Text owner, Text renewer,
131137
byte[] password = createPassword(identifier.getBytes(),
132138
getCurrentKey().getPrivateKey());
133139
long expiryTime = identifier.getIssueDate() + getTokenRenewInterval();
134-
addToTokenStore(identifier, password, expiryTime);
140+
141+
// For HA ratis will take care of updating.
142+
// This will be removed, when HA/Non-HA code is merged.
143+
if (!isRatisEnabled) {
144+
addToTokenStore(identifier, password, expiryTime);
145+
}
146+
135147
Token<OzoneTokenIdentifier> token = new Token<>(identifier.getBytes(),
136148
password, identifier.getKind(), getService());
137149
if (LOG.isDebugEnabled()) {
@@ -140,6 +152,22 @@ public Token<OzoneTokenIdentifier> createToken(Text owner, Text renewer,
140152
return token;
141153
}
142154

155+
/**
156+
* Add delegation token in to in-memory map of tokens.
157+
* @param token
158+
* @param ozoneTokenIdentifier
159+
* @return renewTime - If updated successfully, return renewTime.
160+
*/
161+
public long updateToken(Token<OzoneTokenIdentifier> token,
162+
OzoneTokenIdentifier ozoneTokenIdentifier) {
163+
long renewTime =
164+
ozoneTokenIdentifier.getIssueDate() + getTokenRenewInterval();
165+
TokenInfo tokenInfo = new TokenInfo(renewTime, token.getPassword(),
166+
ozoneTokenIdentifier.getTrackingId());
167+
currentTokens.put(ozoneTokenIdentifier, tokenInfo);
168+
return renewTime;
169+
}
170+
143171
/**
144172
* Stores given identifier in token store.
145173
*

hadoop-ozone/common/src/main/proto/OzoneManagerProtocol.proto

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ message OMRequest {
142142
optional hadoop.common.GetDelegationTokenRequestProto getDelegationTokenRequest = 61;
143143
optional hadoop.common.RenewDelegationTokenRequestProto renewDelegationTokenRequest= 62;
144144
optional hadoop.common.CancelDelegationTokenRequestProto cancelDelegationTokenRequest = 63;
145+
optional UpdateGetDelegationTokenRequest updateGetDelegationTokenRequest = 64;
145146

146147
optional GetFileStatusRequest getFileStatusRequest = 70;
147148
optional CreateDirectoryRequest createDirectoryRequest = 71;
@@ -307,6 +308,14 @@ message UserInfo {
307308
optional string remoteAddress = 3;
308309
}
309310

311+
/**
312+
This will be used during OM HA, once leader generates token sends this
313+
request via ratis to persist to OM DB. This request will be internally used
314+
by OM for replicating token across a quorum of OMs.
315+
*/
316+
message UpdateGetDelegationTokenRequest {
317+
required GetDelegationTokenResponseProto getDelegationTokenResponse = 1;
318+
}
310319

311320
/**
312321
Creates a volume

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3429,4 +3429,9 @@ public DBUpdatesWrapper getDBUpdates(
34293429
.getUpdatesSince(dbUpdatesRequest.getSequenceNumber());
34303430

34313431
}
3432+
3433+
public OzoneDelegationTokenSecretManager getDelegationTokenMgr() {
3434+
return delegationTokenMgr;
3435+
}
3436+
34323437
}

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.apache.hadoop.ozone.om.request.s3.multipart.S3MultipartUploadAbortRequest;
4444
import org.apache.hadoop.ozone.om.request.s3.multipart.S3MultipartUploadCommitPartRequest;
4545
import org.apache.hadoop.ozone.om.request.s3.multipart.S3MultipartUploadCompleteRequest;
46+
import org.apache.hadoop.ozone.om.request.security.OMGetDelegationTokenRequest;
4647
import org.apache.hadoop.ozone.om.request.volume.OMVolumeCreateRequest;
4748
import org.apache.hadoop.ozone.om.request.volume.OMVolumeDeleteRequest;
4849
import org.apache.hadoop.ozone.om.request.volume.OMVolumeSetOwnerRequest;
@@ -130,6 +131,8 @@ public static OMClientRequest createClientRequest(OMRequest omRequest) {
130131
case RemoveAcl:
131132
case SetAcl:
132133
return getOMAclRequest(omRequest);
134+
case GetDelegationToken:
135+
return new OMGetDelegationTokenRequest(omRequest);
133136
default:
134137
// TODO: will update once all request types are implemented.
135138
return null;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.ozone.om.request.security;
20+
21+
import com.google.common.base.Optional;
22+
import org.apache.hadoop.io.Text;
23+
import org.apache.hadoop.ozone.om.OMMetadataManager;
24+
import org.apache.hadoop.ozone.om.OzoneManager;
25+
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
26+
import org.apache.hadoop.ozone.om.request.OMClientRequest;
27+
import org.apache.hadoop.ozone.om.response.OMClientResponse;
28+
import org.apache.hadoop.ozone.om.response.security.OMDelegationTokenResponse;
29+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
30+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetDelegationTokenResponseProto;
31+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
32+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
33+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.UpdateGetDelegationTokenRequest;
34+
import org.apache.hadoop.ozone.protocolPB.OMPBHelper;
35+
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
36+
import org.apache.hadoop.security.proto.SecurityProtos;
37+
import org.apache.hadoop.security.proto.SecurityProtos.GetDelegationTokenRequestProto;
38+
import org.apache.hadoop.security.token.Token;
39+
import org.apache.hadoop.utils.db.cache.CacheKey;
40+
import org.apache.hadoop.utils.db.cache.CacheValue;
41+
import org.slf4j.Logger;
42+
import org.slf4j.LoggerFactory;
43+
44+
import java.io.IOException;
45+
46+
/**
47+
* Handle GetDelegationToken Request.
48+
*/
49+
public class OMGetDelegationTokenRequest extends OMClientRequest {
50+
51+
private static final Logger LOG =
52+
LoggerFactory.getLogger(OMGetDelegationTokenRequest.class);
53+
54+
public OMGetDelegationTokenRequest(OMRequest omRequest) {
55+
super(omRequest);
56+
}
57+
58+
@Override
59+
public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
60+
GetDelegationTokenRequestProto getDelegationTokenRequest =
61+
getOmRequest().getGetDelegationTokenRequest();
62+
63+
// Call OM to create token
64+
Token<OzoneTokenIdentifier> token = ozoneManager
65+
.getDelegationToken(new Text(getDelegationTokenRequest.getRenewer()));
66+
67+
68+
// Client issues GetDelegationToken request, when received by OM leader will
69+
// it generate Token. Original GetDelegationToken request is converted to
70+
// UpdateGetDelegationToken request with the generated token information.
71+
// This updated request will be submitted to Ratis. In this way delegation
72+
// token created by leader, will be replicated across all OMs.
73+
// And also original GetDelegationToken request from client does not need
74+
// any proto changes.
75+
76+
// Create UpdateGetDelegationTokenRequest with token response.
77+
OMRequest.Builder omRequest = OMRequest.newBuilder()
78+
.setUserInfo(getUserInfo())
79+
.setUpdateGetDelegationTokenRequest(
80+
UpdateGetDelegationTokenRequest.newBuilder()
81+
.setGetDelegationTokenResponse(
82+
GetDelegationTokenResponseProto.newBuilder()
83+
.setResponse(SecurityProtos.GetDelegationTokenResponseProto
84+
.newBuilder().setToken(OMPBHelper
85+
.convertToTokenProto(token)).build()).build()))
86+
.setCmdType(getOmRequest().getCmdType())
87+
.setClientId(getOmRequest().getClientId());
88+
89+
if (getOmRequest().hasTraceID()) {
90+
omRequest.setTraceID(getOmRequest().getTraceID());
91+
}
92+
93+
return omRequest.build();
94+
}
95+
96+
@Override
97+
public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
98+
long transactionLogIndex,
99+
OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) {
100+
101+
UpdateGetDelegationTokenRequest updateGetDelegationTokenRequest =
102+
getOmRequest().getUpdateGetDelegationTokenRequest();
103+
104+
SecurityProtos.TokenProto tokenProto = updateGetDelegationTokenRequest
105+
.getGetDelegationTokenResponse().getResponse().getToken();
106+
107+
Token<OzoneTokenIdentifier> ozoneTokenIdentifierToken =
108+
OMPBHelper.convertToDelegationToken(tokenProto);
109+
110+
OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
111+
112+
OMClientResponse omClientResponse = null;
113+
OMResponse.Builder omResponse =
114+
OMResponse.newBuilder()
115+
.setCmdType(OzoneManagerProtocolProtos.Type.GetDelegationToken)
116+
.setStatus(OzoneManagerProtocolProtos.Status.OK)
117+
.setSuccess(true);
118+
try {
119+
OzoneTokenIdentifier ozoneTokenIdentifier =
120+
ozoneTokenIdentifierToken.decodeIdentifier();
121+
122+
// Update in memory map of token.
123+
long renewTime = ozoneManager.getDelegationTokenMgr()
124+
.updateToken(ozoneTokenIdentifierToken, ozoneTokenIdentifier);
125+
126+
// Update Cache.
127+
omMetadataManager.getDelegationTokenTable().addCacheEntry(
128+
new CacheKey<>(ozoneTokenIdentifier),
129+
new CacheValue<>(Optional.of(renewTime), transactionLogIndex));
130+
131+
omClientResponse =
132+
new OMDelegationTokenResponse(ozoneTokenIdentifier, renewTime,
133+
omResponse.setGetDelegationTokenResponse(
134+
updateGetDelegationTokenRequest
135+
.getGetDelegationTokenResponse()).build());
136+
} catch (IOException ex) {
137+
LOG.error("Error in Updating DelegationToken {} to DB",
138+
ozoneTokenIdentifierToken, ex);
139+
omClientResponse = new OMDelegationTokenResponse(null, -1L,
140+
createErrorOMResponse(omResponse, ex));
141+
} finally {
142+
if (omClientResponse != null) {
143+
omClientResponse.setFlushFuture(
144+
ozoneManagerDoubleBufferHelper.add(omClientResponse,
145+
transactionLogIndex));
146+
}
147+
}
148+
149+
if (LOG.isDebugEnabled()) {
150+
LOG.debug("Updated delegation token to OM DB: {}",
151+
ozoneTokenIdentifierToken);
152+
}
153+
154+
return omClientResponse;
155+
}
156+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
/**
20+
* This package contains classes which handle security requests.
21+
*/
22+
package org.apache.hadoop.ozone.om.request.security;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.ozone.om.response.security;
20+
21+
import org.apache.hadoop.ozone.om.OMMetadataManager;
22+
import org.apache.hadoop.ozone.om.response.OMClientResponse;
23+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
24+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
25+
import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
26+
import org.apache.hadoop.utils.db.BatchOperation;
27+
28+
import java.io.IOException;
29+
30+
/**
31+
* Handle response for DelegationToken request.
32+
*/
33+
public class OMDelegationTokenResponse extends OMClientResponse {
34+
35+
private OzoneTokenIdentifier ozoneTokenIdentifier;
36+
private long renewTime;
37+
public OMDelegationTokenResponse(OzoneTokenIdentifier ozoneTokenIdentifier,
38+
long renewTime, OMResponse omResponse) {
39+
super(omResponse);
40+
this.ozoneTokenIdentifier = ozoneTokenIdentifier;
41+
this.renewTime = renewTime;
42+
}
43+
44+
@Override
45+
public void addToDBBatch(OMMetadataManager omMetadataManager,
46+
BatchOperation batchOperation) throws IOException {
47+
48+
if (getOMResponse().getStatus() == OzoneManagerProtocolProtos.Status.OK) {
49+
omMetadataManager.getDelegationTokenTable().putWithBatch(batchOperation,
50+
ozoneTokenIdentifier, renewTime);
51+
}
52+
}
53+
}
54+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
/**
20+
* This package contains classes which handle security request responses.
21+
*/
22+
package org.apache.hadoop.ozone.om.response.security;

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerHARequestHandlerImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public OMResponse handleApplyTransaction(OMRequest omRequest,
7474
case AddAcl:
7575
case RemoveAcl:
7676
case SetAcl:
77+
case GetDelegationToken:
7778
//TODO: We don't need to pass transactionID, this will be removed when
7879
// complete write requests is changed to new model. And also we can
7980
// return OMClientResponse, then adding to doubleBuffer can be taken

0 commit comments

Comments
 (0)