mirror of https://github.com/apache/druid.git
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
This commit is contained in:
parent
553f5c8570
commit
0ecc90142e
|
@ -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>
|
||||
|
|
|
@ -119,4 +119,13 @@ public class BasicAuthorizerPermission
|
|||
: 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "BasicAuthorizerPermission{" +
|
||||
"resourceAction=" + resourceAction +
|
||||
", resourceNamePattern=" + resourceNamePattern +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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-view", "type", "VIEW"),
|
||||
"action", "READ"
|
||||
),
|
||||
"resourceNamePattern", "some-view"
|
||||
),
|
||||
ImmutableMap.of(
|
||||
"resourceAction",
|
||||
ImmutableMap.of(
|
||||
"resource",
|
||||
ImmutableMap.of("name", "foo", "type", "DATASOURCE"),
|
||||
"action", "UNKNOWN"
|
||||
),
|
||||
"resourceNamePattern", "some-view"
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
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-view", ResourceType.VIEW), Action.READ))
|
||||
),
|
||||
roleMap.get(thirdRoleName).getPermissions()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue