55import com .fasterxml .jackson .databind .ObjectMapper ;
66import org .apache .hadoop .conf .Configuration ;
77import org .apache .hadoop .security .GroupMappingServiceProvider ;
8+ import org .apache .hadoop .util .Lists ;
89import org .slf4j .Logger ;
910import org .slf4j .LoggerFactory ;
1011
1314import java .net .http .HttpClient ;
1415import java .net .http .HttpRequest ;
1516import java .net .http .HttpResponse ;
17+ import java .util .HashMap ;
1618import java .util .List ;
19+ import java .util .Map ;
1720import java .util .Objects ;
21+ import java .util .function .UnaryOperator ;
1822
1923public 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 */
0 commit comments