001 /** 002 * 003 * Copyright 2004 Hiram Chirino 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 **/ 018 package org.activemq.security.jassjacc; 019 020 import java.security.AccessControlContext; 021 import java.security.AccessControlException; 022 import java.security.AccessController; 023 import java.security.Permission; 024 import java.security.PrivilegedAction; 025 import java.util.Iterator; 026 027 import javax.jms.JMSException; 028 import javax.security.auth.Subject; 029 import javax.security.auth.login.LoginContext; 030 import javax.security.jacc.PolicyConfiguration; 031 import javax.security.jacc.PolicyConfigurationFactory; 032 import javax.security.jacc.PolicyContext; 033 import javax.security.jacc.PolicyContextException; 034 035 import org.activemq.broker.BrokerClient; 036 import org.activemq.message.ActiveMQDestination; 037 import org.activemq.message.ActiveMQMessage; 038 import org.activemq.message.ConnectionInfo; 039 import org.activemq.message.ConsumerInfo; 040 import org.activemq.message.ProducerInfo; 041 import org.activemq.security.SecurityAdapter; 042 043 /** 044 * Implements SecurityAdapter that uses JASS to authenticate and 045 * JACC to authorize the user operations. 046 * 047 * @version $Revision: 1.1.1.1 $ 048 */ 049 public class JassJaccSecurityAdapter implements SecurityAdapter { 050 051 private String jassConfiguration; 052 053 /** 054 * @param jassConfiguration 055 */ 056 public JassJaccSecurityAdapter(String jassConfiguration) { 057 this.jassConfiguration = jassConfiguration; 058 } 059 060 061 protected AccessControlContext getAccessControlContext(BrokerClient client) { 062 063 Subject subject = client.getSubject(); 064 if (subject == null) throw new IllegalArgumentException("Subject must not be null"); 065 066 AccessControlContext acc = (AccessControlContext) Subject.doAsPrivileged(subject, new PrivilegedAction() { 067 public Object run() { 068 return AccessController.getContext(); 069 } 070 }, null); 071 072 return acc; 073 } 074 075 static protected String getBrokerName(BrokerClient client) { 076 return client.getBrokerConnector().getBrokerInfo().getBrokerName(); 077 } 078 079 public void authorizeConnection(BrokerClient client, ConnectionInfo info) throws JMSException { 080 081 // Set the TCCL since it seems JAAS needs it to find the login module classes. 082 Thread.currentThread().setContextClassLoader(JassJaccSecurityAdapter.class.getClassLoader()); 083 084 // Do the login. 085 Subject subject = doJassLogin(info); 086 client.setSubject(subject); 087 088 // Can the user really use the broker? 089 PolicyContext.setContextID(getBrokerPoicyContextId(client)); 090 AccessControlContext accessContext = getAccessControlContext(client); 091 if (accessContext != null) { 092 Permission permission = new JMSBrokerPermission(getBrokerName(client),JMSBrokerPermission.CONNECT_ACTION); 093 accessContext.checkPermission(permission); 094 } 095 } 096 097 /** 098 * @param client 099 * @return 100 */ 101 static private String getBrokerPoicyContextId(BrokerClient client) { 102 return getBrokerPolicyContextId(getBrokerName(client)); 103 } 104 105 /** 106 * @param client 107 * @return 108 */ 109 static private String getBrokerPolicyContextId(String brokerName) { 110 return "org.activemq.broker:"+brokerName; 111 } 112 113 /** 114 * @param info 115 * @param subject 116 * @return 117 */ 118 private Subject doJassLogin(ConnectionInfo info) throws JMSException { 119 try { 120 LoginContext lc = new LoginContext(jassConfiguration, 121 new UsernamePasswordCallback(info.getUserName(), info 122 .getPassword())); 123 lc.login(); 124 return lc.getSubject(); 125 } catch (Exception e) { 126 throw (JMSException)new JMSException("Login failed: "+e.getMessage()).initCause(e); 127 } 128 } 129 130 public void authorizeConsumer(BrokerClient client, ConsumerInfo info) throws JMSException { 131 PolicyContext.setContextID(getDestinationPoicyContextId(client, info.getDestination())); 132 AccessControlContext accessContext = getAccessControlContext(client); 133 if (accessContext != null) { 134 Permission permission = new JMSDestinationPermission(info.getDestination().getPhysicalName(),JMSDestinationPermission.CONSUME_ACTION); 135 accessContext.checkPermission(permission); 136 } 137 } 138 139 public boolean authorizeReceive(BrokerClient client, ActiveMQMessage message) { 140 try { 141 PolicyContext.setContextID(getDestinationPoicyContextId(client, message.getJMSActiveMQDestination())); 142 AccessControlContext accessContext = getAccessControlContext(client); 143 if (accessContext != null) { 144 Permission permission = new JMSDestinationPermission(message.getJMSActiveMQDestination().getPhysicalName(),JMSDestinationPermission.CONSUME_ACTION); 145 accessContext.checkPermission(permission); 146 } 147 } 148 catch (AccessControlException e) { 149 return false; 150 } 151 return true; 152 } 153 154 155 /** 156 * @param client 157 * @param destination 158 * @return 159 */ 160 static private String getDestinationPoicyContextId(BrokerClient client, ActiveMQDestination destination) { 161 return getDestinationPoicyContextId(getBrokerName(client), destination); 162 } 163 164 static private String getDestinationPoicyContextId(String brokerName, ActiveMQDestination destination) { 165 ActiveMQDestination activeMQDestination = ((ActiveMQDestination)destination); 166 return (activeMQDestination.isTopic()?"org.activemq.topic:":"org.activemq.queue:")+brokerName+":"+activeMQDestination.getPhysicalName(); 167 } 168 169 public void authorizeProducer(BrokerClient client, ProducerInfo info) throws JMSException { 170 PolicyContext.setContextID(getDestinationPoicyContextId(client, info.getDestination())); 171 AccessControlContext accessContext = getAccessControlContext(client); 172 if (accessContext != null) { 173 Permission permission = new JMSDestinationPermission(info.getDestination().getPhysicalName(),JMSDestinationPermission.PRODUCE_ACTION); 174 accessContext.checkPermission(permission); 175 } 176 } 177 178 public void authorizeSendMessage(BrokerClient client, ActiveMQMessage message) throws JMSException { 179 PolicyContext.setContextID(getDestinationPoicyContextId(client, message.getJMSActiveMQDestination())); 180 AccessControlContext accessContext = getAccessControlContext(client); 181 if (accessContext != null) { 182 String physicalName = ((ActiveMQDestination)message.getJMSDestination()).getPhysicalName(); 183 Permission permission = new JMSDestinationPermission(message.getJMSActiveMQDestination().getPhysicalName(),JMSDestinationPermission.SEND_ACTION); 184 accessContext.checkPermission(permission); 185 } 186 } 187 188 /** 189 * Creates a JACC PolicyConfiguration for the broker security. 190 * 191 * @param brokerSecurity 192 */ 193 static public void secure(BrokerSecurityConfig brokerSecurity) { 194 195 try { 196 197 PolicyConfigurationFactory factory = PolicyConfigurationFactory.getPolicyConfigurationFactory(); 198 PolicyConfiguration policyConfiguration = factory.getPolicyConfiguration( 199 getBrokerPolicyContextId(brokerSecurity.getBrokerName()), true); 200 201 for (Iterator iter = brokerSecurity.getConnectRoles().iterator(); iter.hasNext();) { 202 String role = (String) iter.next(); 203 policyConfiguration.addToRole(role, new JMSBrokerPermission( 204 brokerSecurity.getBrokerName(), JMSBrokerPermission.CONNECT_ACTION)); 205 } 206 207 policyConfiguration.commit(); 208 209 } catch (ClassNotFoundException e) { 210 e.printStackTrace(); 211 } catch (PolicyContextException e) { 212 e.printStackTrace(); 213 } 214 215 } 216 217 /** 218 * Creates a JACC PolicyConfiguration for the broker security. 219 * 220 * @param brokerSecurity 221 */ 222 static public void secure(DestinationSecurityConfig destinationSecurity) { 223 224 try { 225 226 String policyId = getDestinationPoicyContextId(destinationSecurity.getBrokerName(), destinationSecurity.getDestination()); 227 PolicyConfigurationFactory factory = PolicyConfigurationFactory.getPolicyConfigurationFactory(); 228 PolicyConfiguration policyConfiguration = factory.getPolicyConfiguration(policyId, true); 229 230 for (Iterator iter = destinationSecurity.getConsumeRoles().iterator(); iter.hasNext();) { 231 String role = (String) iter.next(); 232 policyConfiguration.addToRole(role, new JMSDestinationPermission( 233 destinationSecurity.getDestination().getPhysicalName(), JMSDestinationPermission.CONSUME_ACTION)); 234 } 235 for (Iterator iter = destinationSecurity.getProduceRoles().iterator(); iter.hasNext();) { 236 String role = (String) iter.next(); 237 policyConfiguration.addToRole(role, new JMSDestinationPermission( 238 destinationSecurity.getDestination().getPhysicalName(), JMSDestinationPermission.PRODUCE_ACTION)); 239 } 240 for (Iterator iter = destinationSecurity.getSendRoles().iterator(); iter.hasNext();) { 241 String role = (String) iter.next(); 242 policyConfiguration.addToRole(role, new JMSDestinationPermission( 243 destinationSecurity.getDestination().getPhysicalName(), JMSDestinationPermission.SEND_ACTION)); 244 } 245 246 policyConfiguration.commit(); 247 248 } catch (ClassNotFoundException e) { 249 e.printStackTrace(); 250 } catch (PolicyContextException e) { 251 e.printStackTrace(); 252 } 253 254 } 255 256 }