KNOX-3036 - Add Primary Group Virtual Group (#905)

* KNOX-3036 - Add Primary Group Virtual Group
diff --git a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/VirtualGroupMapper.java b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/VirtualGroupMapper.java
index 9ab3920..783835f 100644
--- a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/VirtualGroupMapper.java
+++ b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/VirtualGroupMapper.java
@@ -32,6 +32,7 @@
 import org.apache.knox.gateway.plang.Interpreter;
 
 public class VirtualGroupMapper {
+    public static final String PRIMARY_GROUP = "$PRIMARY_GROUP";
     private final IdentityAsserterMessages LOG = MessagesFactory.get(IdentityAsserterMessages.class);
     private final Map<String, AbstractSyntaxTree> virtualGroupToPredicateMap;
 
@@ -46,6 +47,9 @@
         Set<String> virtualGroups = new HashSet<>();
         for (Map.Entry<String, AbstractSyntaxTree> each : virtualGroupToPredicateMap.entrySet()) {
             String virtualGroupName = each.getKey();
+            // check for logical virtual groups - names to be dynamically created
+            virtualGroupName = resolveLogicalGroupName(username, virtualGroupName);
+
             AbstractSyntaxTree predicate = each.getValue();
             if (evalPredicate(virtualGroupName, username, groups, predicate, request)) {
                 virtualGroups.add(virtualGroupName);
@@ -56,6 +60,13 @@
         return virtualGroups;
     }
 
+    private String resolveLogicalGroupName(String username, String virtualGroupName) {
+        if (PRIMARY_GROUP.equalsIgnoreCase(virtualGroupName)) {
+            virtualGroupName = username;
+        }
+        return virtualGroupName;
+    }
+
     /**
      * @return true if the user should be added to the virtual group based on the given predicate
      */
diff --git a/gateway-util-common/src/test/java/org/apache/knox/gateway/plang/InterpreterTest.java b/gateway-util-common/src/test/java/org/apache/knox/gateway/plang/InterpreterTest.java
index 8e7880d..aea7ef9 100644
--- a/gateway-util-common/src/test/java/org/apache/knox/gateway/plang/InterpreterTest.java
+++ b/gateway-util-common/src/test/java/org/apache/knox/gateway/plang/InterpreterTest.java
@@ -268,6 +268,17 @@
         assertFalse((boolean)eval("(empty groups)"));
     }
 
+    /**
+     * Adding the ability to create a primary group
+     * (group with same name as username) when it is missing
+     */
+    @Test
+    public void testPrimaryGroup() {
+        interpreter.addConstant("username", "user1");
+        interpreter.addConstant("groups", singletonList("grp1"));
+        assertTrue((boolean)eval("(not (member username))"));
+    }
+
     @Test
     public void testLowerUpper() {
         assertEquals("apple", eval("(lowercase 'APPLE')"));