ARTEMIS-3863 - allow Role configuration via properties
This commit is contained in:
parent
56e9d9525d
commit
6d926719f4
|
@ -28,32 +28,36 @@ public class Role implements Serializable {
|
|||
|
||||
private static final long serialVersionUID = 3560097227776448872L;
|
||||
|
||||
private final String name;
|
||||
private String name;
|
||||
|
||||
private final boolean send;
|
||||
private boolean send;
|
||||
|
||||
private final boolean consume;
|
||||
private boolean consume;
|
||||
|
||||
private final boolean createAddress;
|
||||
private boolean createAddress;
|
||||
|
||||
private final boolean deleteAddress;
|
||||
private boolean deleteAddress;
|
||||
|
||||
private final boolean createDurableQueue;
|
||||
private boolean createDurableQueue;
|
||||
|
||||
private final boolean deleteDurableQueue;
|
||||
private boolean deleteDurableQueue;
|
||||
|
||||
private final boolean createNonDurableQueue;
|
||||
private boolean createNonDurableQueue;
|
||||
|
||||
private final boolean deleteNonDurableQueue;
|
||||
private boolean deleteNonDurableQueue;
|
||||
|
||||
private final boolean manage;
|
||||
private boolean manage;
|
||||
|
||||
private final boolean browse;
|
||||
private boolean browse;
|
||||
|
||||
public JsonObject toJson() {
|
||||
return JsonLoader.createObjectBuilder().add("name", name).add("send", send).add("consume", consume).add("createDurableQueue", createDurableQueue).add("deleteDurableQueue", deleteDurableQueue).add("createNonDurableQueue", createNonDurableQueue).add("deleteNonDurableQueue", deleteNonDurableQueue).add("manage", manage).add("browse", browse).add("createAddress", createAddress).add("deleteAddress", deleteAddress).build();
|
||||
}
|
||||
|
||||
public Role() {
|
||||
// for properties config
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* @param send
|
||||
|
@ -165,6 +169,50 @@ public class Role implements Serializable {
|
|||
return browse;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setSend(boolean send) {
|
||||
this.send = send;
|
||||
}
|
||||
|
||||
public void setConsume(boolean consume) {
|
||||
this.consume = consume;
|
||||
}
|
||||
|
||||
public void setCreateAddress(boolean createAddress) {
|
||||
this.createAddress = createAddress;
|
||||
}
|
||||
|
||||
public void setDeleteAddress(boolean deleteAddress) {
|
||||
this.deleteAddress = deleteAddress;
|
||||
}
|
||||
|
||||
public void setCreateDurableQueue(boolean createDurableQueue) {
|
||||
this.createDurableQueue = createDurableQueue;
|
||||
}
|
||||
|
||||
public void setDeleteDurableQueue(boolean deleteDurableQueue) {
|
||||
this.deleteDurableQueue = deleteDurableQueue;
|
||||
}
|
||||
|
||||
public void setCreateNonDurableQueue(boolean createNonDurableQueue) {
|
||||
this.createNonDurableQueue = createNonDurableQueue;
|
||||
}
|
||||
|
||||
public void setDeleteNonDurableQueue(boolean deleteNonDurableQueue) {
|
||||
this.deleteNonDurableQueue = deleteNonDurableQueue;
|
||||
}
|
||||
|
||||
public void setManage(boolean manage) {
|
||||
this.manage = manage;
|
||||
}
|
||||
|
||||
public void setBrowse(boolean browse) {
|
||||
this.browse = browse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer stringReturn = new StringBuffer("Role {name=" + name + "; allows=[");
|
||||
|
|
|
@ -1726,6 +1726,12 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
|
||||
@Override
|
||||
public ConfigurationImpl putSecurityRoles(String match, Set<Role> roles) {
|
||||
securitySettings.put(match, new RoleSet(match, roles));
|
||||
return this;
|
||||
}
|
||||
|
||||
// to provide type information to creation from properties
|
||||
public ConfigurationImpl addSecurityRole(String match, RoleSet roles) {
|
||||
securitySettings.put(match, roles);
|
||||
return this;
|
||||
}
|
||||
|
@ -2813,7 +2819,8 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
if (!map.containsKey(key)) {
|
||||
map.put(key, newNamedInstanceForCollection(collectionInfo.getA(), collectionInfo.getB(), key));
|
||||
}
|
||||
return map.get(key);
|
||||
Object value = map.get(key);
|
||||
return trackCollectionOrMap(null, value, value);
|
||||
} else { // collection
|
||||
Object value = findByNameProperty(key, (Collection)bean);
|
||||
if (value == null) {
|
||||
|
@ -2821,12 +2828,16 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
value = newNamedInstanceForCollection(collectionInfo.getA(), collectionInfo.getB(), key);
|
||||
((Collection) bean).add(value);
|
||||
}
|
||||
return value;
|
||||
return trackCollectionOrMap(null, value, value);
|
||||
}
|
||||
}
|
||||
|
||||
Object resolved = getNestedProperty(bean, name);
|
||||
|
||||
return trackCollectionOrMap(name, resolved, bean);
|
||||
}
|
||||
|
||||
private Object trackCollectionOrMap(String name, Object resolved, Object bean) {
|
||||
if (resolved instanceof Collection || resolved instanceof Map) {
|
||||
collections.push(new Pair<String, Object>(name, bean));
|
||||
}
|
||||
|
@ -2907,8 +2918,11 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
private Object newNamedInstanceForCollection(String collectionPropertyName, Object hostingBean, String name) {
|
||||
// find the add X and init an instance of the type with name=name
|
||||
|
||||
// expect an add... without the plural
|
||||
String addPropertyName = "add" + Character.toUpperCase(collectionPropertyName.charAt(0)) + collectionPropertyName.substring(1, collectionPropertyName.length() - 1);
|
||||
String addPropertyName = "add";
|
||||
// expect an add... without the plural for named accessors
|
||||
if (collectionPropertyName != null && collectionPropertyName.length() > 0) {
|
||||
addPropertyName += Character.toUpperCase(collectionPropertyName.charAt(0)) + collectionPropertyName.substring(1, collectionPropertyName.length() - 1);
|
||||
}
|
||||
|
||||
// we don't know the type, infer from add method add(X x) or add(String key, X x)
|
||||
final Method[] methods = hostingBean.getClass().getMethods();
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.activemq.artemis.core.config.impl;
|
||||
|
||||
import org.apache.activemq.artemis.core.security.Role;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class RoleSet extends HashSet<Role> {
|
||||
|
||||
private String name;
|
||||
|
||||
public RoleSet() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RoleSet(String key, Set<Role> value) {
|
||||
setName(key);
|
||||
if (value != null) {
|
||||
addAll(value);
|
||||
}
|
||||
}
|
||||
|
||||
// provide a helper add method with the type
|
||||
public void add(String name, Role value) {
|
||||
super.add(value);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -16,9 +16,11 @@
|
|||
*/
|
||||
package org.apache.activemq.artemis.core.config.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
|
@ -28,6 +30,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.activemq.artemis.ArtemisConstants;
|
||||
|
@ -39,6 +42,8 @@ import org.apache.activemq.artemis.core.config.amqpBrokerConnectivity.AMQPBroker
|
|||
import org.apache.activemq.artemis.core.config.amqpBrokerConnectivity.AMQPBrokerConnectionAddressType;
|
||||
import org.apache.activemq.artemis.core.config.amqpBrokerConnectivity.AMQPMirrorBrokerConnectionElement;
|
||||
import org.apache.activemq.artemis.core.config.ha.LiveOnlyPolicyConfiguration;
|
||||
import org.apache.activemq.artemis.core.deployers.impl.FileConfigurationParser;
|
||||
import org.apache.activemq.artemis.core.security.Role;
|
||||
import org.apache.activemq.artemis.core.server.JournalType;
|
||||
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
|
||||
import org.apache.activemq.artemis.core.server.plugin.impl.LoggingActiveMQServerPlugin;
|
||||
|
@ -759,6 +764,79 @@ public class ConfigurationImplTest extends ActiveMQTestBase {
|
|||
Assert.assertEquals(SimpleString.toSimpleString("moreImportant"), configuration.getAddressSettings().get("Name.With.Dots").getExpiryAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoleSettingsViaProperties() throws Exception {
|
||||
ConfigurationImpl configuration = new ConfigurationImpl();
|
||||
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.put("securityRoles.TEST.users.send", "true");
|
||||
properties.put("securityRoles.TEST.users.consume", "true");
|
||||
|
||||
configuration.parsePrefixedProperties(properties, null);
|
||||
|
||||
Assert.assertEquals(1, configuration.getSecurityRoles().size());
|
||||
Assert.assertEquals(1, configuration.getSecurityRoles().get("TEST").size());
|
||||
Assert.assertTrue(configuration.getSecurityRoles().get("TEST").stream().findFirst().orElse(null).isConsume());
|
||||
Assert.assertTrue(configuration.getSecurityRoles().get("TEST").stream().findFirst().orElse(null).isSend());
|
||||
Assert.assertFalse(configuration.getSecurityRoles().get("TEST").stream().findFirst().orElse(null).isCreateAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoleAugmentViaProperties() throws Exception {
|
||||
|
||||
final String xmlConfig = "<configuration xmlns=\"urn:activemq\"\n" +
|
||||
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
|
||||
"xsi:schemaLocation=\"urn:activemq /schema/artemis-configuration.xsd\">\n" +
|
||||
"<security-settings>" + "\n" +
|
||||
"<security-setting match=\"#\">" + "\n" +
|
||||
"<permission type=\"consume\" roles=\"guest\"/>" + "\n" +
|
||||
"<permission type=\"send\" roles=\"guest\"/>" + "\n" +
|
||||
"</security-setting>" + "\n" +
|
||||
"</security-settings>" + "\n" +
|
||||
"</configuration>";
|
||||
|
||||
FileConfigurationParser parser = new FileConfigurationParser();
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(xmlConfig.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
ConfigurationImpl configuration = (ConfigurationImpl) parser.parseMainConfig(input);
|
||||
Properties properties = new Properties();
|
||||
|
||||
// new entry
|
||||
properties.put("securityRoles.TEST.users.send", "true");
|
||||
properties.put("securityRoles.TEST.users.consume", "false");
|
||||
|
||||
// modify existing role
|
||||
properties.put("securityRoles.#.guest.consume", "false");
|
||||
|
||||
// modify with new role
|
||||
properties.put("securityRoles.#.users.send", "true");
|
||||
|
||||
configuration.parsePrefixedProperties(properties, null);
|
||||
|
||||
// verify new addition
|
||||
Assert.assertEquals(2, configuration.getSecurityRoles().size());
|
||||
Assert.assertEquals(1, configuration.getSecurityRoles().get("TEST").size());
|
||||
Assert.assertFalse(configuration.getSecurityRoles().get("TEST").stream().findFirst().orElse(null).isConsume());
|
||||
Assert.assertTrue(configuration.getSecurityRoles().get("TEST").stream().findFirst().orElse(null).isSend());
|
||||
|
||||
// verify augmentation
|
||||
Assert.assertEquals(2, configuration.getSecurityRoles().get("#").size());
|
||||
Set roles = configuration.getSecurityRoles().get("#");
|
||||
class RolePredicate implements Predicate<Role> {
|
||||
final String roleName;
|
||||
RolePredicate(String name) {
|
||||
this.roleName = name;
|
||||
}
|
||||
@Override
|
||||
public boolean test(Role role) {
|
||||
return roleName.equals(role.getName()) && !role.isConsume() && role.isSend() && !role.isCreateAddress();
|
||||
}
|
||||
}
|
||||
Assert.assertEquals(1L, roles.stream().filter(new RolePredicate("guest")).count());
|
||||
Assert.assertEquals(1L, roles.stream().filter(new RolePredicate("users")).count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValuePostFixModifier() throws Throwable {
|
||||
ConfigurationImpl configuration = new ConfigurationImpl();
|
||||
|
|
Loading…
Reference in New Issue