This is an automated email from the ASF dual-hosted git repository.

smolnar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new d63507868 KNOX-2792 - Added a new Knox service to have auth related 
REST API endpoints (#625)
d63507868 is described below

commit d63507868b1ebef8b1337650a0346250647d47f6
Author: Sandor Molnar <[email protected]>
AuthorDate: Thu Aug 25 13:51:21 2022 +0200

    KNOX-2792 - Added a new Knox service to have auth related REST API 
endpoints (#625)
    
    A new REST API endpoint was developed that populates the response object 
with pre-calculated auth headers.
---
 gateway-release/pom.xml                            |   4 +
 gateway-service-auth/.gitignore                    |   1 +
 gateway-service-auth/pom.xml                       |  60 +++++++
 .../knox/gateway/service/auth/AuthMessages.java    |  30 ++++
 .../knox/gateway/service/auth/PreAuthResource.java | 128 +++++++++++++++
 .../deploy/AuthServiceDeploymentContributor.java   |  44 ++++++
 ...nox.gateway.deploy.ServiceDeploymentContributor |  19 +++
 .../gateway/service/auth/PreAuthResourceTest.java  | 176 +++++++++++++++++++++
 .../apache/knox/gateway/security/SubjectUtils.java |   5 +
 pom.xml                                            |   6 +
 10 files changed, 473 insertions(+)

diff --git a/gateway-release/pom.xml b/gateway-release/pom.xml
index e86449cc7..6529bc640 100644
--- a/gateway-release/pom.xml
+++ b/gateway-release/pom.xml
@@ -234,6 +234,10 @@
             <groupId>org.apache.knox</groupId>
             <artifactId>gateway-service-as</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-service-auth</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.knox</groupId>
             <artifactId>gateway-service-hbase</artifactId>
diff --git a/gateway-service-auth/.gitignore b/gateway-service-auth/.gitignore
new file mode 100644
index 000000000..ae3c17260
--- /dev/null
+++ b/gateway-service-auth/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/gateway-service-auth/pom.xml b/gateway-service-auth/pom.xml
new file mode 100644
index 000000000..0a4615d4d
--- /dev/null
+++ b/gateway-service-auth/pom.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.knox</groupId>
+        <artifactId>gateway</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>gateway-service-auth</artifactId>
+
+    <name>gateway-service-auth</name>
+    <description>Authentication and authorization related REST API 
endpoints.</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-spi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-i18n</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-provider-jersey</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/AuthMessages.java
 
b/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/AuthMessages.java
new file mode 100644
index 000000000..e744713f9
--- /dev/null
+++ 
b/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/AuthMessages.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.service.auth;
+
+import org.apache.knox.gateway.i18n.messages.Message;
+import org.apache.knox.gateway.i18n.messages.MessageLevel;
+import org.apache.knox.gateway.i18n.messages.Messages;
+
+@Messages(logger = "org.apache.knox.gateway.service.auth")
+public interface AuthMessages {
+
+  @Message(level = MessageLevel.ERROR, text = "There was a problem extracting 
authenticated principal from request.")
+  void noPrincipalFound();
+
+}
diff --git 
a/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/PreAuthResource.java
 
b/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/PreAuthResource.java
new file mode 100644
index 000000000..9aaab2a16
--- /dev/null
+++ 
b/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/PreAuthResource.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.service.auth;
+
+import static javax.ws.rs.core.Response.ok;
+import static javax.ws.rs.core.Response.status;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import javax.annotation.PostConstruct;
+import javax.security.auth.Subject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.security.SubjectUtils;
+
+@Path(PreAuthResource.RESOURCE_PATH)
+public class PreAuthResource {
+  static final String RESOURCE_PATH = "auth/api/v1/pre";
+  private static final AuthMessages LOG = 
MessagesFactory.get(AuthMessages.class);
+  static final String AUTH_ACTOR_ID_HEADER_NAME = 
"preauth.auth.header.actor.id.name";
+  static final String AUTH_ACTOR_GROUPS_HEADER_PREFIX = 
"preauth.auth.header.actor.groups.prefix";
+  static final String GROUP_FILTER_PATTERN = "preauth.group.filter.pattern";
+
+  static final String DEFAULT_AUTH_ACTOR_ID_HEADER_NAME = "X-Knox-Actor-ID";
+  static final String DEFAULT_AUTH_ACTOR_GROUPS_HEADER_PREFIX = 
"X-Knox-Actor-Groups";
+  private static final Pattern DEFAULT_GROUP_FILTER_PATTERN = 
Pattern.compile(".*");
+
+  private static final int MAX_HEADER_LENGTH = 1000;
+  private static final String ACTOR_GROUPS_HEADER_FORMAT = "%s-%d";
+
+  @Context
+  HttpServletResponse response;
+
+  @Context
+  ServletContext context;
+
+  private String authHeaderActorIDName;
+  private String authHeaderActorGroupsPrefix;
+  private Pattern groupFilterPattern;
+
+  @PostConstruct
+  public void init() {
+    authHeaderActorIDName = getInitParameter(AUTH_ACTOR_ID_HEADER_NAME, 
DEFAULT_AUTH_ACTOR_ID_HEADER_NAME);
+    authHeaderActorGroupsPrefix = 
getInitParameter(AUTH_ACTOR_GROUPS_HEADER_PREFIX, 
DEFAULT_AUTH_ACTOR_GROUPS_HEADER_PREFIX);
+    final String groupFilterPatternString = 
context.getInitParameter(GROUP_FILTER_PATTERN);
+    groupFilterPattern = groupFilterPatternString == null ? 
DEFAULT_GROUP_FILTER_PATTERN : Pattern.compile(groupFilterPatternString);
+  }
+
+  private String getInitParameter(String paramName, String defaultValue) {
+    final String initParam = context.getInitParameter(paramName);
+    return initParam == null ? defaultValue : initParam;
+  }
+
+  @GET
+  public Response doGet() {
+    final Subject subject = SubjectUtils.getCurrentSubject();
+
+    final String primaryPrincipalName = subject == null ? null : 
SubjectUtils.getPrimaryPrincipalName(subject);
+    if (primaryPrincipalName == null) {
+      LOG.noPrincipalFound();
+      return status(HttpServletResponse.SC_UNAUTHORIZED).build();
+    }
+    response.setHeader(authHeaderActorIDName, primaryPrincipalName);
+
+    // Populate actor groups headers
+    final Set<String> matchingGroupNames = subject == null ? 
Collections.emptySet()
+        : SubjectUtils.getGroupPrincipals(subject).stream().filter(group -> 
groupFilterPattern.matcher(group.getName()).matches()).map(group -> 
group.getName())
+            .collect(Collectors.toSet());
+    if (!matchingGroupNames.isEmpty()) {
+      final List<String> groupStrings = getGroupStrings(matchingGroupNames);
+      for (int i = 0; i < groupStrings.size(); i++) {
+        response.addHeader(String.format(Locale.ROOT, 
ACTOR_GROUPS_HEADER_FORMAT, authHeaderActorGroupsPrefix, i + 1), 
groupStrings.get(i));
+      }
+    }
+    return ok().build();
+  }
+
+  private List<String> getGroupStrings(Collection<String> groupNames) {
+    if (groupNames.isEmpty()) {
+      return Collections.emptyList();
+    }
+    List<String> groupStrings = new ArrayList<>();
+    StringBuilder sb = new StringBuilder();
+    for (String groupName : groupNames) {
+      if (sb.length() + groupName.length() > MAX_HEADER_LENGTH) {
+        groupStrings.add(sb.toString());
+        sb = new StringBuilder();
+      }
+      if (sb.length() > 0) {
+        sb.append(',');
+      }
+      sb.append(groupName);
+    }
+    if (sb.length() > 0) {
+      groupStrings.add(sb.toString());
+    }
+    return groupStrings;
+  }
+
+}
\ No newline at end of file
diff --git 
a/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/deploy/AuthServiceDeploymentContributor.java
 
b/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/deploy/AuthServiceDeploymentContributor.java
new file mode 100644
index 000000000..6bffa7ee6
--- /dev/null
+++ 
b/gateway-service-auth/src/main/java/org/apache/knox/gateway/service/auth/deploy/AuthServiceDeploymentContributor.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.service.auth.deploy;
+
+import org.apache.knox.gateway.jersey.JerseyServiceDeploymentContributorBase;
+
+public class AuthServiceDeploymentContributor extends 
JerseyServiceDeploymentContributorBase {
+
+  @Override
+  public String getRole() {
+    return "KNOX-AUTH-SERVICE";
+  }
+
+  @Override
+  public String getName() {
+    return "KnoxAuthService";
+  }
+
+  @Override
+  protected String[] getPackages() {
+    return new String[] { "org.apache.knox.gateway.service.auth" };
+  }
+
+  @Override
+  protected String[] getPatterns() {
+    return new String[] { "auth/api/**?**" };
+  }
+
+}
diff --git 
a/gateway-service-auth/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor
 
b/gateway-service-auth/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor
new file mode 100644
index 000000000..f7fcae8c9
--- /dev/null
+++ 
b/gateway-service-auth/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor
@@ -0,0 +1,19 @@
+##########################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##########################################################################
+
+org.apache.knox.gateway.service.auth.deploy.AuthServiceDeploymentContributor
\ No newline at end of file
diff --git 
a/gateway-service-auth/src/test/java/org/apache/knox/gateway/service/auth/PreAuthResourceTest.java
 
b/gateway-service-auth/src/test/java/org/apache/knox/gateway/service/auth/PreAuthResourceTest.java
new file mode 100644
index 000000000..4cb3b12e3
--- /dev/null
+++ 
b/gateway-service-auth/src/test/java/org/apache/knox/gateway/service/auth/PreAuthResourceTest.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.service.auth;
+
+import static org.junit.Assert.assertEquals;
+
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.security.auth.Subject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+
+import org.apache.knox.gateway.security.GroupPrincipal;
+import org.apache.knox.gateway.security.PrimaryPrincipal;
+import org.apache.knox.gateway.security.SubjectUtils;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PreAuthResourceTest {
+
+  private static final String USER_NAME = "test-username";
+  private ServletContext context;
+  private HttpServletRequest request;
+  private HttpServletResponse response;
+  private final Subject subject = new Subject();
+
+  @Before
+  public void setUp() {
+    subject.getPrincipals().add(new PrimaryPrincipal(USER_NAME));
+  }
+
+  private void configureCommonExpectations(String actorIdHeaderName, String 
groupsHeaderPrefix) {
+    configureCommonExpectations(actorIdHeaderName, groupsHeaderPrefix, 
Collections.emptySet());
+  }
+
+  private void configureCommonExpectations(String actorIdHeaderName, String 
groupsHeaderPrefix, Collection<String> groups) {
+    context = EasyMock.createNiceMock(ServletContext.class);
+    
EasyMock.expect(context.getInitParameter(PreAuthResource.AUTH_ACTOR_ID_HEADER_NAME)).andReturn(actorIdHeaderName).anyTimes();
+    
EasyMock.expect(context.getInitParameter(PreAuthResource.AUTH_ACTOR_GROUPS_HEADER_PREFIX)).andReturn(groupsHeaderPrefix).anyTimes();
+    request = EasyMock.createNiceMock(HttpServletRequest.class);
+    response = EasyMock.createNiceMock(HttpServletResponse.class);
+
+    if (SubjectUtils.getPrimaryPrincipalName(subject) != null) {
+      final String expectedActorIdHeader = actorIdHeaderName == null ? 
PreAuthResource.DEFAULT_AUTH_ACTOR_ID_HEADER_NAME : actorIdHeaderName;
+      response.setHeader(expectedActorIdHeader, USER_NAME);
+      EasyMock.expectLastCall();
+    }
+
+    if (!groups.isEmpty()) {
+      groups.forEach(group -> subject.getPrincipals().add(new 
GroupPrincipal(group)));
+      final int groupStringSize = calculateGroupStringSize(groups);
+      final int expectedGroupHeaderCount = groupStringSize / 1000 + 1;
+      final String expectedGroupsHeaderPrefix = (groupsHeaderPrefix == null ? 
PreAuthResource.DEFAULT_AUTH_ACTOR_GROUPS_HEADER_PREFIX : groupsHeaderPrefix)
+          + "-";
+      for (int i = 1; i <= expectedGroupHeaderCount; i++) {
+        response.addHeader(EasyMock.eq(expectedGroupsHeaderPrefix + i), 
EasyMock.anyString());
+        EasyMock.expectLastCall();
+      }
+    }
+    EasyMock.replay(context, request, response);
+  }
+
+  private int calculateGroupStringSize(Collection<String> groups) {
+    final AtomicInteger size = new AtomicInteger(0);
+    groups.forEach(group -> size.addAndGet(group.length()));
+    size.addAndGet(groups.size() - 1); // commas
+    return size.get();
+  }
+
+  @Test
+  public void testSubjectWithoutPrimaryPrincipalReturnsUnauthorized() throws 
Exception {
+    subject.getPrincipals().clear();
+    configureCommonExpectations(null, null);
+    final PreAuthResource preAuthResource = new PreAuthResource();
+    preAuthResource.context = context;
+    preAuthResource.response = response;
+    final Response response = executeResourceWithSubject(preAuthResource);
+    assertEquals(response.getStatus(), HttpServletResponse.SC_UNAUTHORIZED);
+  }
+
+  @Test
+  public void testPopulatingDefaultActorIdHeaderNoGroups() throws Exception {
+    configureCommonExpectations(null, null);
+    final PreAuthResource preAuthResource = new PreAuthResource();
+    preAuthResource.context = context;
+    preAuthResource.response = response;
+    executeResourceWithSubject(preAuthResource);
+    EasyMock.verify(response);
+  }
+
+  @Test
+  public void testPopulatingCustomActorIdHeaderNoGroups() throws Exception {
+    configureCommonExpectations("customActorId", null);
+    final PreAuthResource preAuthResource = new PreAuthResource();
+    preAuthResource.context = context;
+    preAuthResource.response = response;
+    executeResourceWithSubject(preAuthResource);
+    EasyMock.verify(response);
+  }
+
+  @Test
+  public void testPopulatingDefaultGroupsHeader() throws Exception {
+    configureCommonExpectations(null, null, Collections.singleton("group1"));
+    final PreAuthResource preAuthResource = new PreAuthResource();
+    preAuthResource.context = context;
+    preAuthResource.response = response;
+    executeResourceWithSubject(preAuthResource);
+    EasyMock.verify(response);
+  }
+
+  @Test
+  public void testPopulatingCustomGroupsHeader() throws Exception {
+    configureCommonExpectations(null, "customGroupHeader", 
Collections.singleton("group1"));
+    final PreAuthResource preAuthResource = new PreAuthResource();
+    preAuthResource.context = context;
+    preAuthResource.response = response;
+    executeResourceWithSubject(preAuthResource);
+    EasyMock.verify(response);
+  }
+
+  @Test
+  public void testPopulatingMultipleGroupsHeaderWithLargeGroupNames() throws 
Exception {
+    doTestPopulatingMultipleGroupsHeaderWithLargeGroupNames(100);
+    doTestPopulatingMultipleGroupsHeaderWithLargeGroupNames(500);
+  }
+
+  private void doTestPopulatingMultipleGroupsHeaderWithLargeGroupNames(int 
numberOfGroupsToAdd) throws Exception {
+    final Set<String> groups = new HashSet<>();
+    for (int i = 1; i <= numberOfGroupsToAdd; i++) {
+      groups.add("longGroupName" + i);
+    }
+    configureCommonExpectations(null, null, groups);
+    final PreAuthResource preAuthResource = new PreAuthResource();
+    preAuthResource.context = context;
+    preAuthResource.response = response;
+    executeResourceWithSubject(preAuthResource);
+    EasyMock.verify(response);
+  }
+
+  private Response executeResourceWithSubject(final PreAuthResource 
preAuthResource) throws PrivilegedActionException {
+    return (Response) Subject.doAs(subject, new 
PrivilegedExceptionAction<Object>() {
+
+      @Override
+      public Object run() throws Exception {
+        preAuthResource.init();
+        return preAuthResource.doGet();
+      }
+
+    });
+  }
+
+}
diff --git 
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java 
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
index d6ea15b10..3e8b41c72 100644
--- 
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
+++ 
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
@@ -18,6 +18,7 @@
 package org.apache.knox.gateway.security;
 
 import javax.security.auth.Subject;
+
 import java.security.AccessController;
 import java.security.Principal;
 import java.util.Optional;
@@ -86,4 +87,8 @@ public class SubjectUtils {
     return name;
   }
 
+  public static Set<GroupPrincipal> getGroupPrincipals(Subject subject) {
+    return subject.getPrincipals(GroupPrincipal.class);
+  }
+
 }
diff --git a/pom.xml b/pom.xml
index 8a859a8da..a8eaa4c57 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,6 +105,7 @@
         <module>gateway-provider-ha</module>
         <module>gateway-service-admin</module>
         <module>gateway-service-as</module>
+        <module>gateway-service-auth</module>
         <module>gateway-service-hbase</module>
         <module>gateway-service-hive</module>
         <module>gateway-service-impala</module>
@@ -1086,6 +1087,11 @@
                 <artifactId>gateway-service-as</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.knox</groupId>
+                <artifactId>gateway-service-auth</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.knox</groupId>
                 <artifactId>gateway-service-hbase</artifactId>

Reply via email to