Skip to content

Commit 9e7942a

Browse files
committed
make response field configurable
1 parent 4c857f2 commit 9e7942a

File tree

5 files changed

+56
-54
lines changed

5 files changed

+56
-54
lines changed

src/main/java/tech/stackable/hadoop/OpaQueryResult.java

Lines changed: 0 additions & 35 deletions
This file was deleted.

src/main/java/tech/stackable/hadoop/StackableGroupMapper.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.fasterxml.jackson.databind.ObjectMapper;
66
import org.apache.hadoop.conf.Configuration;
77
import org.apache.hadoop.security.GroupMappingServiceProvider;
8+
import org.apache.hadoop.util.Lists;
89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
1011

@@ -13,11 +14,18 @@
1314
import java.net.http.HttpClient;
1415
import java.net.http.HttpRequest;
1516
import java.net.http.HttpResponse;
17+
import java.util.HashMap;
1618
import java.util.List;
19+
import java.util.Map;
1720
import java.util.Objects;
21+
import java.util.function.UnaryOperator;
1822

1923
public class StackableGroupMapper implements GroupMappingServiceProvider {
2024
public static final String OPA_MAPPING_URL_PROP = "hadoop.security.group.mapping.opa.url";
25+
public static final String OPA_MAPPING_GROUP_NAME_PROP = "hadoop.security.group.mapping.opa.list.name";
26+
// response base field: see https://www.openpolicyagent.org/docs/latest/rest-api/#response-message
27+
public static final String OPA_RESULT_FIELD = "result";
28+
public final String mappingGroupName;
2129
private final Logger LOG = LoggerFactory.getLogger(StackableGroupMapper.class);
2230
private final HttpClient httpClient = HttpClient.newHttpClient();
2331
private final ObjectMapper json;
@@ -37,6 +45,11 @@ public StackableGroupMapper() {
3745
throw new OpaException.UriInvalid(opaUri, e);
3846
}
3947

48+
this.mappingGroupName = configuration.get(OPA_MAPPING_GROUP_NAME_PROP);
49+
if (mappingGroupName == null) {
50+
throw new RuntimeException("Config \"" + OPA_MAPPING_GROUP_NAME_PROP + "\" missing");
51+
}
52+
4053
this.json = new ObjectMapper()
4154
// https://github.com/stackabletech/trino-opa-authorizer/issues/24
4255
// OPA server can send other fields, such as `decision_id`` when enabling decision logs
@@ -82,13 +95,31 @@ public List<String> getGroups(String user) throws IOException {
8295

8396
String responseBody = response.body();
8497
LOG.debug("Response body [{}]", responseBody);
98+
List<String> groups = Lists.newArrayList();
99+
100+
@SuppressWarnings("unchecked")
101+
Map<String, Object> result = (Map<String, Object>) json.readValue(responseBody, HashMap.class).get(OPA_RESULT_FIELD);
102+
List<String> rawGroups = (List<String>) result.get(this.mappingGroupName);
103+
104+
for (String rawGroup : rawGroups) {
105+
groups.add(removeSlashes.apply(rawGroup));
106+
}
85107

86-
OpaQueryResult result = json.readValue(responseBody, OpaQueryResult.class);
87-
LOG.info("Groups for [{}]: [{}]", user, result.groups);
108+
LOG.info("Groups for [{}]: [{}]", user, groups);
88109

89-
return result.groups;
110+
return groups;
90111
}
91112

113+
private final static UnaryOperator<String> removeSlashes = s -> {
114+
if (s.startsWith("/")) {
115+
s = s.substring(1);
116+
}
117+
if (s.endsWith("/")) {
118+
s = s.substring(0, s.length() - 1);
119+
}
120+
return s;
121+
};
122+
92123
/**
93124
* Caches groups, no need to do that for this provider
94125
*/

src/test/java/tech/stackable/hadoop/StackableGroupMapperTest.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@
77
import org.junit.Assert;
88
import org.junit.Test;
99

10+
import java.util.HashMap;
11+
import java.util.List;
12+
import java.util.Map;
13+
1014
public class StackableGroupMapperTest {
1115

16+
@SuppressWarnings("unchecked")
1217
@Test
1318
public void testJsonMapper() throws JsonProcessingException {
1419
String input = "{\n" +
1520
" \"result\": {\n" +
16-
" \"groups\": {\n" +
17-
" \"groups\": [\n" +
18-
" \"/admin\",\n" +
19-
" \"/superuser\"\n" +
20-
" ]\n" +
21-
" },\n" +
21+
" \"groups\": [\n" +
22+
" \"/admin\",\n" +
23+
" \"/superuser\"\n" +
24+
" ]\n" +
25+
" ,\n" +
2226
" \"users_by_name\": {\n" +
2327
" \"alice\": {\n" +
2428
" \"customAttributes\": {},\n" +
@@ -52,8 +56,10 @@ public void testJsonMapper() throws JsonProcessingException {
5256
ObjectMapper json = new ObjectMapper()
5357
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
5458
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
55-
OpaQueryResult result = json.readValue(input, OpaQueryResult.class);
56-
Assert.assertEquals("admin", result.groups.get(0));
57-
Assert.assertEquals("superuser", result.groups.get(1));
59+
60+
Map<String, List<String>> result = (Map<String, List<String>>) json.readValue(input, HashMap.class).get("result");
61+
List<String> groups = result.get("groups");
62+
Assert.assertEquals("/admin", groups.get(0));
63+
Assert.assertEquals("/superuser", groups.get(1));
5864
}
5965
}

test/stack/05-opa.yaml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@ data:
1111
1212
# this will return the group data in this form:
1313
# "result": {
14-
# "groups":
15-
# "groups": [
16-
# "/admin",
17-
# "/superuser"
18-
# ]
19-
# },...
20-
groups := json.filter(users_by_name[input.username], ["groups"])
14+
# "groups": [
15+
# "/admin",
16+
# "/superuser"
17+
# ]
18+
# ...
19+
groups := users_by_name[input.username].groups
2120
2221
# returning data in the form presented by the UIF
2322
users_by_name := {

test/stack/10-hdfs.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ spec:
4444
# the mapper is only handled on the namenode so no need to apply this config to all roles
4545
hadoop.security.group.mapping: "tech.stackable.hadoop.StackableGroupMapper"
4646
hadoop.security.group.mapping.opa.url: "http://test-opa.default.svc.cluster.local:8081/v1/data/hdfs"
47+
hadoop.security.group.mapping.opa.list.name: "groups"
4748
# The operator adds a default static mapping when kerberos is activated, see:
4849
# https://github.com/stackabletech/hdfs-operator/blob/main/rust/operator-binary/src/kerberos.rs#L97-L101
4950
# This should be removed so that the mapping implementation can provide this information instead:

0 commit comments

Comments
 (0)