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 }