/**
*
* Copyright 2004 Hiram Chirino
*
* Licensed 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.codehaus.activemq.security.jassjacc;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.Iterator;
import javax.jms.JMSException;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.jacc.PolicyConfiguration;
import javax.security.jacc.PolicyConfigurationFactory;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.broker.BrokerClient;
import org.codehaus.activemq.message.ActiveMQDestination;
import org.codehaus.activemq.message.ActiveMQMessage;
import org.codehaus.activemq.message.ConnectionInfo;
import org.codehaus.activemq.message.ConsumerInfo;
import org.codehaus.activemq.message.ProducerInfo;
import org.codehaus.activemq.security.SecurityAdapter;
/**
* Implements SecurityAdapter that uses JASS to authenticate and
* JACC to authorize the user operations.
*
* @version $Revision: 1.2 $
*/
public class JassJaccSecurityAdapter implements SecurityAdapter {
static final private Log log = LogFactory.getLog(JassJaccSecurityAdapter.class);
private String jassConfiguration;
/**
* @param jassConfiguration
*/
public JassJaccSecurityAdapter(String jassConfiguration) {
this.jassConfiguration = jassConfiguration;
}
protected AccessControlContext getAccessControlContext(BrokerClient client) {
Subject subject = client.getSubject();
if (subject == null) throw new IllegalArgumentException("Subject must not be null");
AccessControlContext acc = (AccessControlContext) Subject.doAsPrivileged(subject, new PrivilegedAction() {
public Object run() {
return AccessController.getContext();
}
}, null);
return acc;
}
static protected String getBrokerName(BrokerClient client) {
return client.getBrokerConnector().getBrokerInfo().getBrokerName();
}
public void authorizeConnection(BrokerClient client, ConnectionInfo info) throws JMSException {
// Set the TCCL since it seems JAAS needs it to find the login module classes.
Thread.currentThread().setContextClassLoader(JassJaccSecurityAdapter.class.getClassLoader());
// Do the login.
Subject subject = doJassLogin(info);
client.setSubject(subject);
// Can the user really use the broker?
PolicyContext.setContextID(getBrokerPoicyContextId(client));
AccessControlContext accessContext = getAccessControlContext(client);
if (accessContext != null) {
Permission permission = new JMSBrokerPermission(getBrokerName(client),JMSBrokerPermission.CONNECT_ACTION);
accessContext.checkPermission(permission);
}
}
/**
* @param client
* @return
*/
static private String getBrokerPoicyContextId(BrokerClient client) {
return getBrokerPolicyContextId(getBrokerName(client));
}
/**
* @param client
* @return
*/
static private String getBrokerPolicyContextId(String brokerName) {
return "org.codehaus.activemq.broker:"+brokerName;
}
/**
* @param info
* @param subject
* @return
*/
private Subject doJassLogin(ConnectionInfo info) throws JMSException {
try {
LoginContext lc = new LoginContext(jassConfiguration,
new UsernamePasswordCallback(info.getUserName(), info
.getPassword()));
lc.login();
return lc.getSubject();
} catch (Exception e) {
throw (JMSException)new JMSException("Login failed: "+e.getMessage()).initCause(e);
}
}
public void authorizeConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
PolicyContext.setContextID(getDestinationPoicyContextId(client, info.getDestination()));
AccessControlContext accessContext = getAccessControlContext(client);
if (accessContext != null) {
Permission permission = new JMSDestinationPermission(info.getDestination().getPhysicalName(),JMSDestinationPermission.CONSUME_ACTION);
accessContext.checkPermission(permission);
}
}
/**
* @param client
* @param destination
* @return
*/
static private String getDestinationPoicyContextId(BrokerClient client, ActiveMQDestination destination) {
return getDestinationPoicyContextId(getBrokerName(client), destination);
}
static private String getDestinationPoicyContextId(String brokerName, ActiveMQDestination destination) {
ActiveMQDestination activeMQDestination = ((ActiveMQDestination)destination);
return (activeMQDestination.isTopic()?"org.codehaus.activemq.topic:":"org.codehaus.activemq.queue:")+brokerName+":"+activeMQDestination.getPhysicalName();
}
public void authorizeProducer(BrokerClient client, ProducerInfo info) throws JMSException {
PolicyContext.setContextID(getDestinationPoicyContextId(client, info.getDestination()));
AccessControlContext accessContext = getAccessControlContext(client);
if (accessContext != null) {
Permission permission = new JMSDestinationPermission(info.getDestination().getPhysicalName(),JMSDestinationPermission.PRODUCE_ACTION);
accessContext.checkPermission(permission);
}
}
public void authorizeSendMessage(BrokerClient client, ActiveMQMessage message) throws JMSException {
PolicyContext.setContextID(getDestinationPoicyContextId(client, message.getJMSActiveMQDestination()));
AccessControlContext accessContext = getAccessControlContext(client);
if (accessContext != null) {
String physicalName = ((ActiveMQDestination)message.getJMSDestination()).getPhysicalName();
Permission permission = new JMSDestinationPermission(message.getJMSActiveMQDestination().getPhysicalName(),JMSDestinationPermission.SEND_ACTION);
accessContext.checkPermission(permission);
}
}
/**
* Creates a JACC PolicyConfiguration for the broker security.
*
* @param brokerSecurity
*/
static public void secure(BrokerSecurityConfig brokerSecurity) {
try {
PolicyConfigurationFactory factory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
PolicyConfiguration policyConfiguration = factory.getPolicyConfiguration(
getBrokerPolicyContextId(brokerSecurity.getBrokerName()), true);
for (Iterator iter = brokerSecurity.getConnectRoles().iterator(); iter.hasNext();) {
String role = (String) iter.next();
policyConfiguration.addToRole(role, new JMSBrokerPermission(
brokerSecurity.getBrokerName(), JMSBrokerPermission.CONNECT_ACTION));
}
policyConfiguration.commit();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (PolicyContextException e) {
e.printStackTrace();
}
}
/**
* Creates a JACC PolicyConfiguration for the broker security.
*
* @param brokerSecurity
*/
static public void secure(DestinationSecurityConfig destinationSecurity) {
try {
String policyId = getDestinationPoicyContextId(destinationSecurity.getBrokerName(), destinationSecurity.getDestination());
PolicyConfigurationFactory factory = PolicyConfigurationFactory.getPolicyConfigurationFactory();
PolicyConfiguration policyConfiguration = factory.getPolicyConfiguration(policyId, true);
for (Iterator iter = destinationSecurity.getConsumeRoles().iterator(); iter.hasNext();) {
String role = (String) iter.next();
policyConfiguration.addToRole(role, new JMSDestinationPermission(
destinationSecurity.getDestination().getPhysicalName(), JMSDestinationPermission.CONSUME_ACTION));
}
for (Iterator iter = destinationSecurity.getProduceRoles().iterator(); iter.hasNext();) {
String role = (String) iter.next();
policyConfiguration.addToRole(role, new JMSDestinationPermission(
destinationSecurity.getDestination().getPhysicalName(), JMSDestinationPermission.PRODUCE_ACTION));
}
for (Iterator iter = destinationSecurity.getSendRoles().iterator(); iter.hasNext();) {
String role = (String) iter.next();
policyConfiguration.addToRole(role, new JMSDestinationPermission(
destinationSecurity.getDestination().getPhysicalName(), JMSDestinationPermission.SEND_ACTION));
}
policyConfiguration.commit();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (PolicyContextException e) {
e.printStackTrace();
}
}
}