You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by cw...@apache.org on 2021/03/30 03:22:52 UTC

[druid] branch 0.21.0 updated: [Backport] basic security extension ignore permissions that use unknown ResourceType or Action (#10919)

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

cwylie pushed a commit to branch 0.21.0
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/0.21.0 by this push:
     new dec53c9  [Backport] basic security extension ignore permissions that use unknown ResourceType or Action (#10919)
dec53c9 is described below

commit dec53c9a9cb4b4d901ba32f7ea680e5c4266e92b
Author: Clint Wylie <cw...@apache.org>
AuthorDate: Mon Mar 29 20:22:21 2021 -0700

    [Backport] basic security extension ignore permissions that use unknown ResourceType or Action (#10919)
    
    * basic security extension ignore permissions that use unknown ResourceType or Action (#10896)
    
    * suppress unknown ResourceType and Action for basic-security authorizer stuff
    
    * fix pom
    
    * print failed role, test logs
    
    * fix test for backport
---
 extensions-core/druid-basic-security/pom.xml       |   7 ++
 .../entity/BasicAuthorizerPermission.java          |   9 ++
 .../authorization/entity/BasicAuthorizerRole.java  |  45 +++++++-
 .../apache/druid/security/BasicAuthUtilsTest.java  | 123 +++++++++++++++++++++
 .../src/test/resources/log4j2.xml                  |  35 ++++++
 5 files changed, 218 insertions(+), 1 deletion(-)

diff --git a/extensions-core/druid-basic-security/pom.xml b/extensions-core/druid-basic-security/pom.xml
index 3db5f4c..514bc43 100644
--- a/extensions-core/druid-basic-security/pom.xml
+++ b/extensions-core/druid-basic-security/pom.xml
@@ -147,5 +147,12 @@
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.druid</groupId>
+      <artifactId>druid-processing</artifactId>
+      <version>${project.parent.version}</version>
+      <scope>test</scope>
+      <type>test-jar</type>
+    </dependency>
   </dependencies>
 </project>
diff --git a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/entity/BasicAuthorizerPermission.java b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/entity/BasicAuthorizerPermission.java
index 8efddac..6316976 100644
--- a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/entity/BasicAuthorizerPermission.java
+++ b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/entity/BasicAuthorizerPermission.java
@@ -119,4 +119,13 @@ public class BasicAuthorizerPermission
                             : 0);
     return result;
   }
+
+  @Override
+  public String toString()
+  {
+    return "BasicAuthorizerPermission{" +
+           "resourceAction=" + resourceAction +
+           ", resourceNamePattern=" + resourceNamePattern +
+           '}';
+  }
 }
diff --git a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/entity/BasicAuthorizerRole.java b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/entity/BasicAuthorizerRole.java
index 83b2d55..f04f088 100644
--- a/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/entity/BasicAuthorizerRole.java
+++ b/extensions-core/druid-basic-security/src/main/java/org/apache/druid/security/basic/authorization/entity/BasicAuthorizerRole.java
@@ -21,19 +21,31 @@ package org.apache.druid.security.basic.authorization.entity;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.apache.druid.java.util.common.RE;
+import org.apache.druid.java.util.common.logger.Logger;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
 public class BasicAuthorizerRole
 {
+  private static final Logger log = new Logger(BasicAuthorizerRole.class);
+
   private final String name;
   private final List<BasicAuthorizerPermission> permissions;
 
   @JsonCreator
   public BasicAuthorizerRole(
       @JsonProperty("name") String name,
-      @JsonProperty("permissions") List<BasicAuthorizerPermission> permissions
+      @JsonProperty("permissions") @JsonDeserialize(using = PermissionsDeserializer.class) List<BasicAuthorizerPermission> permissions
   )
   {
     this.name = name;
@@ -78,4 +90,35 @@ public class BasicAuthorizerRole
     result = 31 * result + (getPermissions() != null ? getPermissions().hashCode() : 0);
     return result;
   }
+
+
+  static class PermissionsDeserializer extends JsonDeserializer<List<BasicAuthorizerPermission>>
+  {
+    @Override
+    public List<BasicAuthorizerPermission> deserialize(
+        JsonParser jsonParser,
+        DeserializationContext deserializationContext
+    ) throws IOException
+    {
+      List<BasicAuthorizerPermission> permissions = new ArrayList<>();
+      // sanity check
+      ObjectCodec codec = jsonParser.getCodec();
+      JsonNode hopefullyAnArray = codec.readTree(jsonParser);
+      if (!hopefullyAnArray.isArray()) {
+        throw new RE("Failed to deserialize authorizer role list");
+      }
+
+      for (JsonNode node : hopefullyAnArray) {
+        try {
+          permissions.add(codec.treeToValue(node, BasicAuthorizerPermission.class));
+        }
+        catch (JsonProcessingException e) {
+          // ignore unparseable, it might be resource types we don't know about
+          log.warn(e, "Failed to deserialize authorizer role, ignoring: %s", node.toPrettyString());
+        }
+      }
+
+      return permissions;
+    }
+  }
 }
diff --git a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java
index 142e44a..dfbb183 100644
--- a/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java
+++ b/extensions-core/druid-basic-security/src/test/java/org/apache/druid/security/BasicAuthUtilsTest.java
@@ -19,10 +19,25 @@
 
 package org.apache.druid.security;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import org.apache.druid.security.basic.BasicAuthUtils;
+import org.apache.druid.security.basic.BasicSecurityDruidModule;
+import org.apache.druid.security.basic.authorization.entity.BasicAuthorizerPermission;
+import org.apache.druid.security.basic.authorization.entity.BasicAuthorizerRole;
+import org.apache.druid.segment.TestHelper;
+import org.apache.druid.server.security.Action;
+import org.apache.druid.server.security.Resource;
+import org.apache.druid.server.security.ResourceAction;
+import org.apache.druid.server.security.ResourceType;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class BasicAuthUtilsTest
 {
   @Test
@@ -36,4 +51,112 @@ public class BasicAuthUtilsTest
     Assert.assertEquals(BasicAuthUtils.SALT_LENGTH, salt.length);
     Assert.assertEquals(BasicAuthUtils.KEY_LENGTH / 8, hash.length);
   }
+
+  @Test
+  public void testPermissionSerdeIsChillAboutUnknownEnumStuffs() throws JsonProcessingException
+  {
+    final String someRoleName = "some-role";
+    final String otherRoleName = "other-role";
+    final String thirdRoleName = "third-role";
+    final ResourceAction fooRead = new ResourceAction(new Resource("foo", ResourceType.DATASOURCE), Action.READ);
+    final ResourceAction barRead = new ResourceAction(new Resource("bar", ResourceType.DATASOURCE), Action.READ);
+
+    final ObjectMapper mapper = TestHelper.makeJsonMapper();
+    mapper.registerModules(new BasicSecurityDruidModule().getJacksonModules());
+    Map<String, Object> rawMap = new HashMap<>();
+    rawMap.put(
+        someRoleName,
+        new BasicAuthorizerRole(
+          someRoleName,
+          BasicAuthorizerPermission.makePermissionList(
+              ImmutableList.of(
+                  fooRead,
+                  barRead
+              )
+          )
+      )
+    );
+    // bad ResourceType
+    rawMap.put(
+        otherRoleName,
+        ImmutableMap.of(
+            "name",
+            otherRoleName,
+            "permissions",
+            ImmutableList.of(
+                ImmutableMap.of(
+                    "resourceAction", fooRead,
+                    "resourceNamePattern", "foo"
+                ),
+                ImmutableMap.of(
+                    "resourceAction",
+                    ImmutableMap.of(
+                        "resource",
+                        ImmutableMap.of("name", "bar", "type", "UNKNOWN"),
+                        "action", "READ"
+                    ),
+                    "resourceNamePattern", "bar"
+                )
+            )
+        )
+    );
+    // bad Action
+    rawMap.put(
+        thirdRoleName,
+        ImmutableMap.of(
+            "name",
+            thirdRoleName,
+            "permissions",
+            ImmutableList.of(
+                ImmutableMap.of(
+                    "resourceAction",
+                    ImmutableMap.of(
+                        "resource",
+                        ImmutableMap.of("name", "some-table", "type", "DATASOURCE"),
+                        "action", "READ"
+                    ),
+                    "resourceNamePattern", "some-table"
+                ),
+                ImmutableMap.of(
+                    "resourceAction",
+                    ImmutableMap.of(
+                        "resource",
+                        ImmutableMap.of("name", "foo", "type", "DATASOURCE"),
+                        "action", "UNKNOWN"
+                    ),
+                    "resourceNamePattern", "foo"
+                )
+            )
+        )
+    );
+    byte[] mapBytes = mapper.writeValueAsBytes(rawMap);
+    Map<String, BasicAuthorizerRole> roleMap = BasicAuthUtils.deserializeAuthorizerRoleMap(mapper, mapBytes);
+    Assert.assertNotNull(roleMap);
+    Assert.assertEquals(3, roleMap.size());
+
+    Assert.assertTrue(roleMap.containsKey(someRoleName));
+    Assert.assertEquals(2, roleMap.get(someRoleName).getPermissions().size());
+    Assert.assertEquals(
+        BasicAuthorizerPermission.makePermissionList(ImmutableList.of(fooRead, barRead)),
+        roleMap.get(someRoleName).getPermissions()
+    );
+
+    // this one has an unknown ResourceType, expect only 1 permission to deserialize correctly and failure ignored
+    Assert.assertTrue(roleMap.containsKey(otherRoleName));
+    Assert.assertEquals(1, roleMap.get(otherRoleName).getPermissions().size());
+    Assert.assertEquals(
+        BasicAuthorizerPermission.makePermissionList(ImmutableList.of(fooRead)),
+        roleMap.get(otherRoleName).getPermissions()
+    );
+
+    // this one has an unknown Action, expect only 1 permission to deserialize correctly and failure ignored
+    Assert.assertTrue(roleMap.containsKey(thirdRoleName));
+    Assert.assertEquals(1, roleMap.get(thirdRoleName).getPermissions().size());
+    Assert.assertEquals(
+        BasicAuthorizerPermission.makePermissionList(
+            ImmutableList.of(new ResourceAction(new Resource("some-table", ResourceType.DATASOURCE), Action.READ))
+        ),
+        roleMap.get(thirdRoleName).getPermissions()
+    );
+  }
 }
diff --git a/extensions-core/druid-basic-security/src/test/resources/log4j2.xml b/extensions-core/druid-basic-security/src/test/resources/log4j2.xml
new file mode 100644
index 0000000..bca6c69
--- /dev/null
+++ b/extensions-core/druid-basic-security/src/test/resources/log4j2.xml
@@ -0,0 +1,35 @@
+<?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.
+  -->
+
+<Configuration status="WARN">
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="%d{ISO8601} %p [%t] %c - %m%n"/>
+    </Console>
+  </Appenders>
+  <Loggers>
+    <Root level="info">
+      <AppenderRef ref="Console"/>
+    </Root>
+    <Logger level="debug" name="org.apache.druid" additivity="false">
+      <AppenderRef ref="Console"/>
+    </Logger>
+  </Loggers>
+</Configuration>

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org