blob: ab436531226fefc8bb972e268d4c51f1e51df82b [file] [log] [blame]
/*
* 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.qpid.server.security.access.plugins;
import static org.apache.qpid.server.security.access.ObjectProperties.Property.*;
import java.security.Principal;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.log4j.Logger;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
import org.apache.qpid.server.security.AbstractPlugin;
import org.apache.qpid.server.security.Result;
import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.SecurityPluginFactory;
import org.apache.qpid.server.security.access.ObjectProperties;
import org.apache.qpid.server.security.access.ObjectType;
import org.apache.qpid.server.security.access.Operation;
import org.apache.qpid.server.security.access.config.PrincipalPermissions;
import org.apache.qpid.server.security.access.config.PrincipalPermissions.Permission;
/**
* This uses the default
*/
public class SimpleXML extends AbstractPlugin
{
public static final Logger _logger = Logger.getLogger(SimpleXML.class);
private Map<String, PrincipalPermissions> _users;
public static final SecurityPluginFactory<SimpleXML> FACTORY = new SecurityPluginFactory<SimpleXML>()
{
public SimpleXML newInstance(ConfigurationPlugin config) throws ConfigurationException
{
SimpleXMLConfiguration configuration = config.getConfiguration(SimpleXMLConfiguration.class.getName());
// If there is no configuration for this plugin then don't load it.
if (configuration == null)
{
return null;
}
SimpleXML plugin = new SimpleXML();
plugin.configure(configuration);
return plugin;
}
public String getPluginName()
{
return SimpleXML.class.getName();
}
public Class<SimpleXML> getPluginClass()
{
return SimpleXML.class;
}
};
public void configure(ConfigurationPlugin config)
{
super.configure(config);
SimpleXMLConfiguration configuration = (SimpleXMLConfiguration) _config;
_users = new ConcurrentHashMap<String, PrincipalPermissions>();
processConfig(configuration.getConfiguration());
}
private void processConfig(Configuration config)
{
processPublish(config);
processConsume(config);
processCreate(config);
processAccess(config);
}
/**
* @param config XML Configuration
*/
private void processAccess(Configuration config)
{
Configuration accessConfig = config.subset("access");
if (accessConfig.isEmpty())
{
//there is no access configuration to process
return;
}
// Process users that have full access permission
String[] users = accessConfig.getStringArray("users.user");
for (String user : users)
{
grant(Permission.ACCESS, user);
}
}
/**
* Publish format takes Exchange + Routing Key Pairs
*
* @param config XML Configuration
*/
private void processPublish(Configuration config)
{
Configuration publishConfig = config.subset("publish");
// Process users that have full publish permission
String[] users = publishConfig.getStringArray("users.user");
for (String user : users)
{
grant(Permission.PUBLISH, user);
}
// Process exchange limited users
int exchangeCount = 0;
Configuration exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")");
while (!exchangeConfig.isEmpty())
{
// Get Exchange Name
AMQShortString exchangeName = new AMQShortString(exchangeConfig.getString("name"));
// Get Routing Keys
int keyCount = 0;
Configuration routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")");
while (!routingkeyConfig.isEmpty())
{
// Get RoutingKey Value
AMQShortString routingKeyValue = new AMQShortString(routingkeyConfig.getString("value"));
// Apply Exchange + RoutingKey permissions to Users
users = routingkeyConfig.getStringArray("users.user");
for (String user : users)
{
grant(Permission.PUBLISH, user, exchangeName, routingKeyValue);
}
// Apply permissions to Groups
// Check for more configs
keyCount++;
routingkeyConfig = exchangeConfig.subset("routing_keys.routing_key(" + keyCount + ")");
}
// Apply Exchange wide permissions to Users
users = exchangeConfig.getStringArray("exchange(" + exchangeCount + ").users.user");
for (String user : users)
{
grant(Permission.PUBLISH, user, exchangeName);
}
// Apply permissions to Groups
exchangeCount++;
exchangeConfig = publishConfig.subset("exchanges.exchange(" + exchangeCount + ")");
}
}
private void grant(Permission permission, String user, Object... parameters)
{
PrincipalPermissions permissions = _users.get(user);
if (permissions == null)
{
permissions = new PrincipalPermissions(user);
}
_users.put(user, permissions);
permissions.grant(permission, parameters);
}
/**
* @param config XML Configuration
*/
private void processConsume(Configuration config)
{
boolean temporary = false;
Configuration tempConfig = null;
Configuration consumeConfig = config.subset("consume");
tempConfig = consumeConfig.subset("queues.temporary(0)");
if (tempConfig != null)
{
temporary = true;
}
//Permission all users who have rights to temp queues and topics
if (tempConfig != null && !tempConfig.isEmpty())
{
String[] tempUsers = tempConfig.getStringArray("users.user");
for (String user : tempUsers)
{
grant(Permission.CONSUME, user, temporary);
}
}
// Process queue limited users
int queueCount = 0;
Configuration queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")");
while (!queueConfig.isEmpty())
{
// Get queue Name
AMQShortString queueName = new AMQShortString(queueConfig.getString("name"));
// if there is no name then there may be a temporary element
boolean ownQueues = queueConfig.containsKey("own_queues");
// Process permissions for this queue
String[] users = queueConfig.getStringArray("users.user");
for (String user : users)
{
grant(Permission.CONSUME, user, queueName, ownQueues);
}
// See if we have another config
queueCount++;
queueConfig = consumeConfig.subset("queues.queue(" + queueCount + ")");
}
// Process users that have full consume permission
String[] users = consumeConfig.getStringArray("users.user");
for (String user : users)
{
//NOTE: this call does not appear to do anything inside the grant section for consume
grant(Permission.CONSUME, user);
}
}
/**
* @param config XML Configuration
*/
private void processCreate(Configuration config)
{
boolean temporary = false;
Configuration tempConfig = null;
Configuration createConfig = config.subset("create");
tempConfig = createConfig.subset("queues.temporary(0)");
if (tempConfig != null)
{
temporary = true;
}
//Permission all users who have rights to temp queues and topics
if (tempConfig != null && !tempConfig.isEmpty())
{
String[] tempUsers = tempConfig.getStringArray("users.user");
for (String user : tempUsers)
{
grant(Permission.CREATEQUEUE, user, temporary);
}
}
// Process create permissions for queue creation
int queueCount = 0;
Configuration queueConfig = createConfig.subset("queues.queue(" + queueCount + ")");
while (!queueConfig.isEmpty())
{
// Get queue Name
AMQShortString queueName = new AMQShortString(queueConfig.getString("name"));
int exchangeCount = 0;
Configuration exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")");
while (!exchangeConfig.isEmpty())
{
AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name"));
AMQShortString routingKey = new AMQShortString(exchangeConfig.getString("routing_key"));
// Process permissions for this queue
String[] users = exchangeConfig.getStringArray("users.user");
for (String user : users)
{
//This is broken as the user name is not stored
grant(Permission.CREATEEXCHANGE, user, exchange);
//This call could be cleaned up as temporary is now being set earlier (above)
grant(Permission.CREATEQUEUE, user, temporary, (queueName.equals("") ? null : queueName), (exchange
.equals("") ? null : exchange), (routingKey.equals("") ? null : routingKey));
}
// See if we have another config
exchangeCount++;
exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")");
}
// Process users that are not bound to an exchange
String[] users = queueConfig.getStringArray("users.user");
for (String user : users)
{
grant(Permission.CREATEQUEUE, user, temporary, queueName);
}
// See if we have another config
queueCount++;
queueConfig = createConfig.subset("queues.queue(" + queueCount + ")");
}
// Process create permissions for exchange creation
int exchangeCount = 0;
Configuration exchangeConfig = createConfig.subset("exchanges.exchange(" + exchangeCount + ")");
while (!exchangeConfig.isEmpty())
{
AMQShortString exchange = new AMQShortString(exchangeConfig.getString("name"));
AMQShortString clazz = new AMQShortString(exchangeConfig.getString("class"));
// Process permissions for this queue
String[] users = exchangeConfig.getStringArray("users.user");
for (String user : users)
{
//And this is broken too
grant(Permission.CREATEEXCHANGE, user, exchange, clazz);
}
// See if we have another config
exchangeCount++;
exchangeConfig = queueConfig.subset("exchanges.exchange(" + exchangeCount + ")");
}
// Process users that have full create permission
String[] users = createConfig.getStringArray("users.user");
for (String user : users)
{
grant(Permission.CREATEEXCHANGE, user);
grant(Permission.CREATEQUEUE, user);
}
}
public Result access(ObjectType objectType, Object instance)
{
Principal principal = SecurityManager.getThreadPrincipal();
if (principal == null)
{
return getDefault(); // Default if there is no user associated with the thread
}
PrincipalPermissions principalPermissions = _users.get(principal.getName());
if (principalPermissions == null)
{
return Result.DENIED;
}
// Authorise object access
if (objectType == ObjectType.VIRTUALHOST)
{
return principalPermissions.authorise(Permission.ACCESS);
}
// Default
return getDefault();
}
public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties)
{
Principal principal = SecurityManager.getThreadPrincipal();
if (principal == null)
{
return getDefault(); // Default if there is no user associated with the thread
}
PrincipalPermissions principalPermissions = _users.get(principal.getName());
if (principalPermissions == null)
{
return Result.DENIED;
}
// Authorise operation
switch (operation)
{
case CONSUME:
return principalPermissions.authorise(Permission.CONSUME, properties.get(NAME), properties.get(AUTO_DELETE), properties.get(OWNER));
case PUBLISH:
return principalPermissions.authorise(Permission.PUBLISH, properties.get(NAME), properties.get(ROUTING_KEY));
case CREATE:
if (objectType == ObjectType.EXCHANGE)
{
return principalPermissions.authorise(Permission.CREATEEXCHANGE, properties.get(NAME));
}
else if (objectType == ObjectType.QUEUE)
{
return principalPermissions.authorise(Permission.CREATEQUEUE, properties.get(AUTO_DELETE), properties.get(NAME));
}
case ACCESS:
return principalPermissions.authorise(Permission.ACCESS);
case BIND:
return principalPermissions.authorise(Permission.BIND, null, properties.get(NAME), properties.get(QUEUE_NAME), properties.get(ROUTING_KEY));
case UNBIND:
return principalPermissions.authorise(Permission.UNBIND);
case DELETE:
return principalPermissions.authorise(Permission.DELETE);
case PURGE:
return principalPermissions.authorise(Permission.PURGE);
}
// Default
return getDefault();
}
}