Skip to content

Commit 84bcfcf

Browse files
committed
RANGER-5393: updated RangerOzoneAuthorizer to support AssumeRole (#766)
(cherry picked from commit 3c8e532)
1 parent c4a21da commit 84bcfcf

File tree

8 files changed

+506
-20
lines changed

8 files changed

+506
-20
lines changed

agents-common/src/main/resources/service-defs/ranger-servicedef-ozone.json

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"uiHint":"",
2626
"label": "Ozone Volume",
2727
"description": "Ozone Volume",
28+
"accessTypeRestrictions": [ "read", "write", "create", "list", "delete", "read_acl", "write_acl", "all" ],
2829
"isValidLeaf": true
2930
},
3031
{
@@ -44,9 +45,9 @@
4445
"uiHint":"",
4546
"label": "Ozone Bucket",
4647
"description": "Ozone Bucket",
48+
"accessTypeRestrictions": [ "read", "write", "create", "list", "delete", "read_acl", "write_acl", "all" ],
4749
"isValidLeaf": true
4850
},
49-
5051
{
5152
"itemId": 3,
5253
"name": "key",
@@ -64,7 +65,25 @@
6465
"uiHint":"",
6566
"label": "Ozone Key",
6667
"description": "Ozone Key",
68+
"accessTypeRestrictions": [ "read", "write", "create", "list", "delete", "read_acl", "write_acl", "all" ],
6769
"isValidLeaf": true
70+
},
71+
{
72+
"itemId": 4,
73+
"name": "role",
74+
"type": "string",
75+
"level": 10,
76+
"parent": "",
77+
"mandatory": true,
78+
"lookupSupported": true,
79+
"recursiveSupported": false,
80+
"excludesSupported": false,
81+
"matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
82+
"matcherOptions": { "wildCard":true, "ignoreCase":false },
83+
"label": "Role",
84+
"description": "Role",
85+
"accessTypeRestrictions": [ "assume_role" ],
86+
"isValidLeaf": true
6887
}
6988
],
7089

@@ -130,6 +149,12 @@
130149
"name": "write_acl",
131150
"label": "Write_ACL",
132151
"category": "UPDATE"
152+
},
153+
{
154+
"itemId": 8,
155+
"name": "assume_role",
156+
"label": "Assume_Role",
157+
"category": "MANAGE"
133158
}
134159
],
135160

plugin-ozone/pom.xml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,21 @@ limitations under the License.
145145
<version>${org.bouncycastle.bcpkix-jdk18on}</version>
146146
</dependency>
147147
<dependency>
148-
<groupId>org.slf4j</groupId>
149-
<artifactId>log4j-over-slf4j</artifactId>
150-
<version>${slf4j.version}</version>
148+
<groupId>org.junit.jupiter</groupId>
149+
<artifactId>junit-jupiter-api</artifactId>
150+
<version>${junit.jupiter.version}</version>
151+
<scope>test</scope>
152+
</dependency>
153+
<dependency>
154+
<groupId>org.mockito</groupId>
155+
<artifactId>mockito-inline</artifactId>
156+
<version>${mockito.version}</version>
157+
<scope>test</scope>
158+
</dependency>
159+
<dependency>
160+
<groupId>org.mockito</groupId>
161+
<artifactId>mockito-junit-jupiter</artifactId>
162+
<version>${mockito.version}</version>
151163
<scope>test</scope>
152164
</dependency>
153165
</dependencies>

plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java

Lines changed: 172 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,56 @@
2020

2121
package org.apache.ranger.authorization.ozone.authorizer;
2222

23+
import org.apache.commons.lang3.StringUtils;
24+
import org.apache.hadoop.ozone.om.exceptions.OMException;
25+
import org.apache.hadoop.ozone.security.acl.AssumeRoleRequest;
26+
import org.apache.hadoop.ozone.security.acl.AssumeRoleRequest.OzoneGrant;
2327
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
2428
import org.apache.hadoop.ozone.security.acl.IOzoneObj;
2529
import org.apache.hadoop.ozone.security.acl.OzoneObj;
2630
import org.apache.hadoop.ozone.security.acl.RequestContext;
2731
import org.apache.hadoop.security.UserGroupInformation;
2832
import org.apache.hadoop.thirdparty.com.google.common.collect.Sets;
2933
import org.apache.ranger.audit.provider.MiscUtil;
34+
import org.apache.ranger.authz.util.RangerResourceNameParser;
3035
import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
36+
import org.apache.ranger.plugin.model.RangerInlinePolicy;
37+
import org.apache.ranger.plugin.model.RangerPrincipal;
3138
import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
3239
import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
3340
import org.apache.ranger.plugin.policyengine.RangerAccessResult;
3441
import org.apache.ranger.plugin.service.RangerBasePlugin;
42+
import org.apache.ranger.plugin.util.JsonUtilsV2;
3543
import org.apache.ranger.plugin.util.RangerPerfTracer;
3644
import org.slf4j.Logger;
3745
import org.slf4j.LoggerFactory;
3846

47+
import java.util.Collections;
3948
import java.util.Date;
49+
import java.util.HashMap;
50+
import java.util.List;
51+
import java.util.Map;
52+
import java.util.Objects;
53+
import java.util.Set;
54+
import java.util.stream.Collectors;
4055

4156
public class RangerOzoneAuthorizer implements IAccessAuthorizer {
42-
public static final String ACCESS_TYPE_READ = "read";
43-
public static final String ACCESS_TYPE_WRITE = "write";
44-
public static final String ACCESS_TYPE_CREATE = "create";
45-
public static final String ACCESS_TYPE_LIST = "list";
46-
public static final String ACCESS_TYPE_DELETE = "delete";
47-
public static final String ACCESS_TYPE_READ_ACL = "read_acl";
48-
public static final String ACCESS_TYPE_WRITE_ACL = "write_acl";
57+
public static final String ACCESS_TYPE_READ = "read";
58+
public static final String ACCESS_TYPE_WRITE = "write";
59+
public static final String ACCESS_TYPE_CREATE = "create";
60+
public static final String ACCESS_TYPE_LIST = "list";
61+
public static final String ACCESS_TYPE_DELETE = "delete";
62+
public static final String ACCESS_TYPE_READ_ACL = "read_acl";
63+
public static final String ACCESS_TYPE_WRITE_ACL = "write_acl";
64+
public static final String ACCESS_TYPE_ASSUME_ROLE = "assume_role";
65+
public static final String ACCESS_TYPE_ALL = "all";
4966

50-
51-
public static final String KEY_RESOURCE_VOLUME = "volume";
67+
public static final String KEY_RESOURCE_VOLUME = "volume";
5268
public static final String KEY_RESOURCE_BUCKET = "bucket";
53-
public static final String KEY_RESOURCE_KEY = "key";
69+
public static final String KEY_RESOURCE_KEY = "key";
70+
public static final String KEY_RESOURCE_ROLE = "role";
71+
72+
private static final String S3_VOLUME_NAME = "s3Vol";
5473

5574
private static final Logger PERF_OZONEAUTH_REQUEST_LOG = RangerPerfTracer.getPerfLogger("ozoneauth.request");
5675

@@ -78,6 +97,10 @@ public RangerOzoneAuthorizer() {
7897
}
7998
}
8099

100+
RangerOzoneAuthorizer(RangerBasePlugin plugin) {
101+
rangerPlugin = plugin;
102+
}
103+
81104
@Override
82105
public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) {
83106
boolean returnValue = false;
@@ -149,11 +172,7 @@ public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) {
149172
if (ozoneObj.getResourceType() == OzoneObj.ResourceType.VOLUME) {
150173
rangerResource.setValue(KEY_RESOURCE_VOLUME, ozoneObj.getVolumeName());
151174
} else if (ozoneObj.getResourceType() == OzoneObj.ResourceType.BUCKET || ozoneObj.getResourceType() == OzoneObj.ResourceType.KEY) {
152-
if (ozoneObj.getStoreType() == OzoneObj.StoreType.S3) {
153-
rangerResource.setValue(KEY_RESOURCE_VOLUME, "s3Vol");
154-
} else {
155-
rangerResource.setValue(KEY_RESOURCE_VOLUME, ozoneObj.getVolumeName());
156-
}
175+
rangerResource.setValue(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? S3_VOLUME_NAME : ozoneObj.getVolumeName());
157176
rangerResource.setValue(KEY_RESOURCE_BUCKET, ozoneObj.getBucketName());
158177
if (ozoneObj.getResourceType() == OzoneObj.ResourceType.KEY) {
159178
rangerResource.setValue(KEY_RESOURCE_KEY, ozoneObj.getKeyName());
@@ -166,6 +185,10 @@ public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) {
166185
}
167186

168187
try {
188+
if (StringUtils.isNotBlank(context.getSessionPolicy())) {
189+
rangerRequest.setInlinePolicy(JsonUtilsV2.jsonToObj(context.getSessionPolicy(), RangerInlinePolicy.class));
190+
}
191+
169192
RangerAccessResult result = plugin
170193
.isAccessAllowed(rangerRequest);
171194
if (result == null) {
@@ -186,6 +209,61 @@ public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) {
186209
return returnValue;
187210
}
188211

212+
@Override
213+
public String generateAssumeRoleSessionPolicy(AssumeRoleRequest assumeRoleRequest) throws OMException {
214+
LOG.debug("==> RangerOzoneAuthorizer.generateAssumeRoleSessionPolicy(assumeRoleRequest={})", assumeRoleRequest);
215+
216+
if (assumeRoleRequest == null) {
217+
throw new OMException("invalid request: null", OMException.ResultCodes.INVALID_REQUEST);
218+
} else if (assumeRoleRequest.getClientUgi() == null) {
219+
throw new OMException("invalid request: request.clientUgi null", OMException.ResultCodes.INVALID_REQUEST);
220+
} else if (assumeRoleRequest.getTargetRoleName() == null) {
221+
throw new OMException("invalid request: request.targetRoleName null", OMException.ResultCodes.INVALID_REQUEST);
222+
}
223+
224+
RangerBasePlugin plugin = rangerPlugin;
225+
226+
if (plugin == null) {
227+
throw new OMException("Ranger authorizer not initialized", OMException.ResultCodes.INTERNAL_ERROR);
228+
}
229+
230+
UserGroupInformation ugi = assumeRoleRequest.getClientUgi();
231+
RangerAccessResourceImpl resource = new RangerAccessResourceImpl(Collections.singletonMap(KEY_RESOURCE_ROLE, assumeRoleRequest.getTargetRoleName()));
232+
RangerAccessRequestImpl request = new RangerAccessRequestImpl(resource, ACCESS_TYPE_ASSUME_ROLE, ugi.getShortUserName(), Sets.newHashSet(ugi.getGroupNames()), null);
233+
234+
try {
235+
RangerAccessResult result = plugin.isAccessAllowed(request);
236+
237+
if (result != null && result.getIsAccessDetermined() && result.getIsAllowed()) {
238+
final Set<OzoneGrant> ozoneGrants = assumeRoleRequest.getGrants();
239+
final List<RangerInlinePolicy.Grant> inlineGrants;
240+
241+
if (ozoneGrants == null) { // allow all permissions
242+
inlineGrants = null;
243+
} else if (ozoneGrants.isEmpty()) { // don't allow any permission
244+
inlineGrants = Collections.singletonList(new RangerInlinePolicy.Grant());
245+
} else { // allow explicitly specified permissions
246+
inlineGrants = ozoneGrants.stream().map(g -> toRangerGrant(g, plugin)).collect(Collectors.toList());
247+
}
248+
249+
RangerInlinePolicy inlinePolicy = new RangerInlinePolicy(RangerPrincipal.PREFIX_ROLE + assumeRoleRequest.getTargetRoleName(), RangerInlinePolicy.Mode.INLINE, inlineGrants, ugi.getShortUserName());
250+
String ret = JsonUtilsV2.objToJson(inlinePolicy);
251+
252+
LOG.debug("<== RangerOzoneAuthorizer.generateAssumeRoleSessionPolicy(assumeRoleRequest={}): ret={}", assumeRoleRequest, ret);
253+
254+
return ret;
255+
} else {
256+
throw new OMException("Permission denied", OMException.ResultCodes.ACCESS_DENIED);
257+
}
258+
} catch (OMException excp) {
259+
throw excp;
260+
} catch (Throwable t) {
261+
LOG.error("isAccessAllowed() failed. request = {}", request, t);
262+
263+
throw new OMException("Ranger authorizer failed", t, OMException.ResultCodes.INTERNAL_ERROR);
264+
}
265+
}
266+
189267
private String mapToRangerAccessType(ACLType operation) {
190268
String rangerAccessType = null;
191269
switch (operation) {
@@ -213,5 +291,84 @@ private String mapToRangerAccessType(ACLType operation) {
213291
}
214292
return rangerAccessType;
215293
}
294+
295+
private static RangerInlinePolicy.Grant toRangerGrant(OzoneGrant ozoneGrant, RangerBasePlugin plugin) {
296+
RangerInlinePolicy.Grant ret = new RangerInlinePolicy.Grant();
297+
298+
if (ozoneGrant.getObjects() != null) {
299+
ret.setResources(ozoneGrant.getObjects().stream().map(o -> toRrn(o, plugin)).filter(Objects::nonNull).collect(Collectors.toSet()));
300+
}
301+
302+
if (ozoneGrant.getPermissions() != null) {
303+
ret.setPermissions(ozoneGrant.getPermissions().stream().map(RangerOzoneAuthorizer::toRangerPermission).filter(Objects::nonNull).collect(Collectors.toSet()));
304+
}
305+
306+
LOG.debug("toRangerGrant(ozoneGrant={}): ret={}", ozoneGrant, ret);
307+
308+
return ret;
309+
}
310+
311+
private static String toRrn(IOzoneObj obj, RangerBasePlugin plugin) {
312+
OzoneObj ozoneObj = (OzoneObj) obj;
313+
Map<String, String> resource = new HashMap<>();
314+
String resType = null;
315+
316+
switch (ozoneObj.getResourceType()) {
317+
case VOLUME:
318+
resType = KEY_RESOURCE_VOLUME;
319+
320+
resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getVolumeName());
321+
break;
322+
323+
case BUCKET:
324+
resType = KEY_RESOURCE_BUCKET;
325+
326+
resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? S3_VOLUME_NAME : ozoneObj.getVolumeName());
327+
resource.put(KEY_RESOURCE_BUCKET, ozoneObj.getBucketName());
328+
break;
329+
330+
case KEY:
331+
resType = KEY_RESOURCE_KEY;
332+
333+
resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? S3_VOLUME_NAME : ozoneObj.getVolumeName());
334+
resource.put(KEY_RESOURCE_BUCKET, ozoneObj.getBucketName());
335+
resource.put(KEY_RESOURCE_KEY, ozoneObj.getKeyName());
336+
break;
337+
}
338+
339+
RangerResourceNameParser rrnParser = resType != null ? plugin.getServiceDefHelper().getRrnParser(resType) : null;
340+
String ret = rrnParser != null ? (resType + RangerResourceNameParser.RRN_RESOURCE_TYPE_SEP + rrnParser.toResourceName(resource)) : null;
341+
342+
LOG.debug("toRrn(ozoneObj={}): ret={}", ozoneObj, ret);
343+
344+
return ret;
345+
}
346+
347+
348+
private static String toRangerPermission(ACLType acl) {
349+
switch (acl) {
350+
case READ:
351+
return ACCESS_TYPE_READ;
352+
case WRITE:
353+
return ACCESS_TYPE_WRITE;
354+
case CREATE:
355+
return ACCESS_TYPE_CREATE;
356+
case LIST:
357+
return ACCESS_TYPE_LIST;
358+
case DELETE:
359+
return ACCESS_TYPE_DELETE;
360+
case READ_ACL:
361+
return ACCESS_TYPE_READ_ACL;
362+
case WRITE_ACL:
363+
return ACCESS_TYPE_WRITE_ACL;
364+
case ALL:
365+
return ACCESS_TYPE_ALL;
366+
case NONE:
367+
case ASSUME_ROLE: // ASSUME_ROLE is not supported in session policy
368+
return null;
369+
}
370+
371+
return null;
372+
}
216373
}
217374

0 commit comments

Comments
 (0)