Repository: ambari
Updated Branches:
  refs/heads/branch-2.0.0 7d7468904 -> c7e8cbaa7


AMBARI-9007. Identity references fail to deference for service-level references 
in Kerberos descriptor parser (rlevas)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/c7e8cbaa
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/c7e8cbaa
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/c7e8cbaa

Branch: refs/heads/branch-2.0.0
Commit: c7e8cbaa73563c600c0bd6e8b3a0d57cfc2dd28d
Parents: 7d74689
Author: Robert Levas <rle...@hortonworks.com>
Authored: Wed Mar 11 21:14:17 2015 -0400
Committer: Robert Levas <rle...@hortonworks.com>
Committed: Wed Mar 11 21:14:17 2015 -0400

----------------------------------------------------------------------
 .../AbstractKerberosDescriptorContainer.java    | 127 +++++++++++++------
 .../state/kerberos/KerberosDescriptor.java      |  20 +++
 .../HIVE/0.12.0.2.0/kerberos.json               |  54 ++++----
 .../state/kerberos/KerberosDescriptorTest.java  |  89 +++++++++++++
 ...test_get_referenced_identity_descriptor.json | 127 +++++++++++++++++++
 5 files changed, 350 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/c7e8cbaa/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java
index 2ec2cb5..874e331 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptorContainer.java
@@ -527,10 +527,38 @@ public abstract class AbstractKerberosDescriptorContainer 
extends AbstractKerber
    * <p/>
    * The path value is expected to be an "absolute" path through the Kerberos 
Descriptor hierarchy
    * to some specific KerberosIdentityDescriptor.  The path must be in one of 
the following forms:
+   * <ul>
+   * <li>/identity</li>
+   * <li>/service/identity</li>
+   * <li>/service/component/identity</li>
+   * </ul>
    * <p/>
-   * /identity
-   * /service/identity
-   * /service/component/identity
+   * If the path starts with "../", the ".." will be translated to the path of 
the parent item.
+   * In the following example, <code>../service_identity</code> will resolve to
+   * <code>/SERVICE/service_identity</code>:
+   * <pre>
+   * {
+   *  "name": "SERVICE",
+   *  "identities": [
+   *    {
+   *      "name": "service_identity",
+   *      ...
+   *    }
+   *  ],
+   *  "components" : [
+   *    {
+   *      "name": "COMPONENT",
+   *      "identities": [
+   *        {
+   *          "name": "./service_identity",
+   *          ...
+   *        },
+   *        ...
+   *      ]
+   *    }
+   *  ]
+   * }
+   * </pre>
    *
    * @param path a String declaring the path to a KerberosIdentityDescriptor
    * @return a KerberosIdentityDescriptor identified by the path or null if 
not found
@@ -539,50 +567,72 @@ public abstract class AbstractKerberosDescriptorContainer 
extends AbstractKerber
       throws AmbariException {
     KerberosIdentityDescriptor identityDescriptor = null;
 
-    if ((path != null) && path.startsWith("/")) {
-      // The name indicates it is referencing an identity somewhere in the 
hierarchy... try to find it.
-      // /[<service name>/[<component name>/]]<identity name>
-      String[] pathParts = path.split("/");
+    if (path != null) {
+      if(path.startsWith("../")) {
+        // Resolve parent path
+        AbstractKerberosDescriptor parent = getParent();
 
-      String serviceName = null;
-      String componentName = null;
-      String identityName;
+        path = path.substring(2);
 
-      switch (pathParts.length) {
-        case 3:
-          serviceName = pathParts[0];
-          componentName = pathParts[1];
-          identityName = pathParts[2];
-          break;
-        case 2:
-          serviceName = pathParts[0];
-          identityName = pathParts[1];
-          break;
-        case 1:
-          identityName = pathParts[0];
-          break;
-        default:
-          throw new AmbariException(String.format("Unexpected path length in 
%s", path));
+        while(parent != null) {
+          String name = parent.getName();
+
+          if (name != null) {
+            path = String.format("/%s", name) + path;
+          }
+
+          parent = parent.getParent();
+        }
       }
 
-      if (identityName != null) {
-        // Start at the top of the hierarchy
-        AbstractKerberosDescriptor descriptor = getRoot();
+      if (path.startsWith("/")) {
+        // The name indicates it is referencing an identity somewhere in the 
hierarchy... try to find it.
+        // /[<service name>/[<component name>/]]<identity name>
+        String[] pathParts = path.split("/");
+
+        String serviceName = null;
+        String componentName = null;
+        String identityName;
+
+        switch (pathParts.length) {
+          case 4:
+            serviceName = pathParts[1];
+            componentName = pathParts[2];
+            identityName = pathParts[3];
+            break;
+          case 3:
+            serviceName = pathParts[1];
+            identityName = pathParts[2];
+            break;
+          case 2:
+            identityName = pathParts[1];
+            break;
+          case 1:
+            identityName = pathParts[0];
+            break;
+          default:
+            throw new AmbariException(String.format("Unexpected path length in 
%s", path));
+        }
+
+        if (identityName != null) {
+          // Start at the top of the hierarchy
+          AbstractKerberosDescriptor descriptor = getRoot();
 
-        if (descriptor != null) {
-          if ((serviceName != null) && !serviceName.isEmpty()) {
-            descriptor = 
descriptor.getDescriptor(KerberosDescriptorType.SERVICE, serviceName);
+          if (descriptor != null) {
+            if ((serviceName != null) && !serviceName.isEmpty()) {
+              descriptor = 
descriptor.getDescriptor(KerberosDescriptorType.SERVICE, serviceName);
 
-            if ((descriptor != null) && (componentName != null) && 
!componentName.isEmpty()) {
-              descriptor = 
descriptor.getDescriptor(KerberosDescriptorType.COMPONENT, componentName);
+              if ((descriptor != null) && (componentName != null) && 
!componentName.isEmpty()) {
+                descriptor = 
descriptor.getDescriptor(KerberosDescriptorType.COMPONENT, componentName);
+              }
             }
-          }
 
-          if (descriptor != null) {
-            descriptor = 
descriptor.getDescriptor(KerberosDescriptorType.IDENTITY, identityName);
+            if (descriptor != null) {
+              descriptor = 
descriptor.getDescriptor(KerberosDescriptorType.IDENTITY, identityName);
 
-            if (descriptor instanceof KerberosIdentityDescriptor) {
-              identityDescriptor = (KerberosIdentityDescriptor) descriptor;
+              if (descriptor instanceof KerberosIdentityDescriptor) {
+                identityDescriptor = (KerberosIdentityDescriptor) descriptor;
+              }
             }
           }
         }
@@ -590,7 +640,6 @@ public abstract class AbstractKerberosDescriptorContainer 
extends AbstractKerber
     }
 
     return identityDescriptor;
-
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7e8cbaa/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
index 791b0e6..8cd9718 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
@@ -256,6 +256,26 @@ public class KerberosDescriptor extends 
AbstractKerberosDescriptorContainer {
   }
 
   /**
+   * Gets the requested AbstractKerberosDescriptor implementation using a type 
name and a relevant
+   * descriptor name.
+   * <p/>
+   * This implementation handles service descriptors and delegates to the 
AbstractKerberosDescriptor
+   * implementation to handle component and identity types.
+   *
+   * @param type a String indicating the type of the requested descriptor
+   * @param name a String indicating the name of the requested descriptor
+   * @return a AbstractKerberosDescriptor representing the requested 
descriptor or null if not found
+   */
+  @Override
+  protected AbstractKerberosDescriptor getDescriptor(KerberosDescriptorType 
type, String name) {
+    if (KerberosDescriptorType.SERVICE == type) {
+      return getService(name);
+    } else {
+      return super.getDescriptor(type, name);
+    }
+  }
+
+  /**
    * Creates a Map of values that can be used to create a copy of this 
KerberosDescriptor
    * or generate the JSON structure described in
    * {@link org.apache.ambari.server.state.kerberos.KerberosDescriptor}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7e8cbaa/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/kerberos.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/kerberos.json
 
b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/kerberos.json
index ad5ee3e..e154c02 100644
--- 
a/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/kerberos.json
+++ 
b/ambari-server/src/main/resources/common-services/HIVE/0.12.0.2.0/kerberos.json
@@ -8,6 +8,25 @@
         },
         {
           "name": "/smokeuser"
+        },
+        {
+          "name": "hive",
+          "principal": {
+            "value": "hive/_HOST@${realm}",
+            "type": "service",
+            "local_username": "${hive-env/hive_user}"
+          },
+          "keytab": {
+            "file": "${keytab_dir}/hive.service.keytab",
+            "owner": {
+              "name": "${hive-env/hive_user}",
+              "access": "r"
+            },
+            "group": {
+              "name": "${cluster-env/user_group}",
+              "access": ""
+            }
+          }
         }
       ],
       "configurations": [
@@ -35,23 +54,11 @@
           "name": "HIVE_METASTORE",
           "identities": [
             {
-              "name": "hive_metastore_hive",
+              "name": "../hive",
               "principal": {
-                "value": "hive/_HOST@${realm}",
-                "type" : "service",
-                "configuration": "hive-site/hive.metastore.kerberos.principal",
-                "local_username": "${hive-env/hive_user}"
+                "configuration": "hive-site/hive.metastore.kerberos.principal"
               },
               "keytab": {
-                "file": "${keytab_dir}/hive.service.keytab",
-                "owner": {
-                  "name": "${hive-env/hive_user}",
-                  "access": "r"
-                },
-                "group": {
-                  "name": "${cluster-env/user_group}",
-                  "access": ""
-                },
                 "configuration": 
"hive-site/hive.metastore.kerberos.keytab.file"
               }
             }
@@ -61,23 +68,11 @@
           "name": "HIVE_SERVER",
           "identities": [
             {
-              "name": "hive_server_hive",
+              "name": "../hive",
               "principal": {
-                "value": "hive/_HOST@${realm}",
-                "type" : "service",
-                "configuration": 
"hive-site/hive.server2.authentication.kerberos.principal",
-                "local_username": "${hive-env/hive_user}"
+                "configuration": 
"hive-site/hive.server2.authentication.kerberos.principal"
               },
               "keytab": {
-                "file": "${keytab_dir}/hive.service.keytab",
-                "owner": {
-                  "name": "${hive-env/hive_user}",
-                  "access": "r"
-                },
-                "group": {
-                  "name": "${cluster-env/user_group}",
-                  "access": ""
-                },
                 "configuration": 
"hive-site/hive.server2.authentication.kerberos.keytab"
               }
             },
@@ -105,6 +100,9 @@
               }
             }
           ]
+        },
+        {
+          "name": "HIVE_CLIENT"
         }
       ]
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7e8cbaa/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
index 97f8008..637facc 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/state/kerberos/KerberosDescriptorTest.java
@@ -22,6 +22,9 @@ import junit.framework.Assert;
 import org.apache.ambari.server.AmbariException;
 import org.junit.Test;
 
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -435,4 +438,90 @@ public class KerberosDescriptorTest {
     Assert.assertEquals("$c6401.ambari.apache.org",
         KerberosDescriptor.replaceVariables("$${host}", configurations));
   }
+
+  @Test
+  public void testGetReferencedIdentityDescriptor() throws IOException {
+    URL systemResourceURL = 
ClassLoader.getSystemResource("kerberos/test_get_referenced_identity_descriptor.json");
+    Assert.assertNotNull(systemResourceURL);
+    KerberosDescriptor descriptor = 
KERBEROS_DESCRIPTOR_FACTORY.createInstance(new 
File(systemResourceURL.getFile()));
+
+    KerberosIdentityDescriptor identity;
+
+    // Stack-level identity
+    identity = descriptor.getReferencedIdentityDescriptor("/stack_identity");
+    Assert.assertNotNull(identity);
+    Assert.assertEquals("stack_identity", identity.getName());
+
+    // Service-level identity
+    identity = 
descriptor.getReferencedIdentityDescriptor("/SERVICE1/service1_identity");
+    Assert.assertNotNull(identity);
+    Assert.assertEquals("service1_identity", identity.getName());
+    Assert.assertNotNull(identity.getParent());
+    Assert.assertEquals("SERVICE1", identity.getParent().getName());
+
+    // Component-level identity
+    identity = 
descriptor.getReferencedIdentityDescriptor("/SERVICE2/SERVICE2_COMPONENT1/service2_component1_identity");
+    Assert.assertNotNull(identity);
+    Assert.assertEquals("service2_component1_identity", identity.getName());
+    Assert.assertNotNull(identity.getParent());
+    Assert.assertEquals("SERVICE2_COMPONENT1", identity.getParent().getName());
+    Assert.assertNotNull(identity.getParent().getParent());
+    Assert.assertEquals("SERVICE2", 
identity.getParent().getParent().getName());
+  }
+
+  @Test
+  public void testGetReferencedIdentityDescriptor_NameCollisions() throws 
IOException {
+    URL systemResourceURL = 
ClassLoader.getSystemResource("kerberos/test_get_referenced_identity_descriptor.json");
+    Assert.assertNotNull(systemResourceURL);
+    KerberosDescriptor descriptor = 
KERBEROS_DESCRIPTOR_FACTORY.createInstance(new 
File(systemResourceURL.getFile()));
+
+    KerberosIdentityDescriptor identity;
+
+    // Stack-level identity
+    identity = descriptor.getReferencedIdentityDescriptor("/collision");
+    Assert.assertNotNull(identity);
+    Assert.assertEquals("collision", identity.getName());
+    Assert.assertNotNull(identity.getParent());
+    Assert.assertEquals(null, identity.getParent().getName());
+
+    // Service-level identity
+    identity = 
descriptor.getReferencedIdentityDescriptor("/SERVICE1/collision");
+    Assert.assertNotNull(identity);
+    Assert.assertEquals("collision", identity.getName());
+    Assert.assertNotNull(identity.getParent());
+    Assert.assertEquals("SERVICE1", identity.getParent().getName());
+
+    // Component-level identity
+    identity = 
descriptor.getReferencedIdentityDescriptor("/SERVICE2/SERVICE2_COMPONENT1/collision");
+    Assert.assertNotNull(identity);
+    Assert.assertEquals("collision", identity.getName());
+    Assert.assertNotNull(identity.getParent());
+    Assert.assertEquals("SERVICE2_COMPONENT1", identity.getParent().getName());
+    Assert.assertNotNull(identity.getParent().getParent());
+    Assert.assertEquals("SERVICE2", 
identity.getParent().getParent().getName());
+  }
+
+  @Test
+  public void testGetReferencedIdentityDescriptor_RelativePath() throws 
IOException {
+    URL systemResourceURL = 
ClassLoader.getSystemResource("kerberos/test_get_referenced_identity_descriptor.json");
+    Assert.assertNotNull(systemResourceURL);
+
+    KerberosDescriptor descriptor = 
KERBEROS_DESCRIPTOR_FACTORY.createInstance(new 
File(systemResourceURL.getFile()));
+    Assert.assertNotNull(descriptor);
+
+    KerberosServiceDescriptor serviceDescriptor = 
descriptor.getService("SERVICE2");
+    Assert.assertNotNull(serviceDescriptor);
+
+    KerberosComponentDescriptor componentDescriptor =  
serviceDescriptor.getComponent("SERVICE2_COMPONENT1");
+    Assert.assertNotNull(componentDescriptor);
+
+    KerberosIdentityDescriptor identity;
+    identity = 
componentDescriptor.getReferencedIdentityDescriptor("../service2_identity");
+    Assert.assertNotNull(identity);
+    Assert.assertEquals("service2_identity", identity.getName());
+    Assert.assertEquals(serviceDescriptor, identity.getParent());
+
+    identity = 
serviceDescriptor.getReferencedIdentityDescriptor("../service2_identity");
+    Assert.assertNull(identity);
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/c7e8cbaa/ambari-server/src/test/resources/kerberos/test_get_referenced_identity_descriptor.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/resources/kerberos/test_get_referenced_identity_descriptor.json
 
b/ambari-server/src/test/resources/kerberos/test_get_referenced_identity_descriptor.json
new file mode 100644
index 0000000..307a1e1
--- /dev/null
+++ 
b/ambari-server/src/test/resources/kerberos/test_get_referenced_identity_descriptor.json
@@ -0,0 +1,127 @@
+{
+  "properties": {
+    "realm": "${kerberos-env/realm}",
+    "keytab_dir": "/etc/security/keytabs"
+  },
+  "identities": [
+    {
+      "name": "stack_identity",
+      "principal": {
+        "value": "stack@${realm}",
+        "type": "user"
+      },
+      "keytab": {
+        "file": "${keytab_dir}/stack.keytab",
+        "owner": {
+          "name": "root",
+          "access": "r"
+        },
+        "group": {
+          "name": "${cluster-env/user_group}",
+          "access": "r"
+        }
+      }
+    },
+    {
+      "name": "collision",
+      "principal": {
+        "value": "stack_collision@${realm}",
+        "type": "user"
+      }
+    }
+  ],
+  "services" : [
+    {
+      "name": "SERVICE1",
+      "identities": [
+        {
+          "name": "service1_identity",
+          "principal": {
+            "value": "service1@${realm}",
+            "type": "user"
+          },
+          "keytab": {
+            "file": "${keytab_dir}/service1.keytab",
+            "owner": {
+              "name": "root",
+              "access": "r"
+            },
+            "group": {
+              "name": "${cluster-env/user_group}",
+              "access": "r"
+            }
+          }
+        },
+        {
+          "name": "collision",
+          "principal": {
+            "value": "service1_collision@${realm}",
+            "type": "user"
+          }
+        }
+      ]
+    },
+    {
+      "name": "SERVICE2",
+      "identities": [
+        {
+          "name": "service2_identity",
+          "principal": {
+            "value": "service2@${realm}",
+            "type": "user"
+          },
+          "keytab": {
+            "file": "${keytab_dir}/service2.keytab",
+            "owner": {
+              "name": "root",
+              "access": "r"
+            },
+            "group": {
+              "name": "${cluster-env/user_group}",
+              "access": "r"
+            }
+          }
+        },
+        {
+          "name": "collision",
+          "principal": {
+            "value": "service2_collision@${realm}",
+            "type": "user"
+          }
+        }
+      ],
+      "components" : [
+        {
+          "name": "SERVICE2_COMPONENT1",
+          "identities": [
+            {
+              "name": "service2_component1_identity",
+              "principal": {
+                "value": "service2_component1@${realm}",
+                "type": "user"
+              },
+              "keytab": {
+                "file": "${keytab_dir}/service2_component1.keytab",
+                "owner": {
+                  "name": "root",
+                  "access": "r"
+                },
+                "group": {
+                  "name": "${cluster-env/user_group}",
+                  "access": "r"
+                }
+              }
+            },
+            {
+              "name": "collision",
+              "principal": {
+                "value": "service2_component1_collision@${realm}",
+                "type": "user"
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

Reply via email to