001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 *
020 */
021 package org.apache.qpid.server.security.access;
022
023 import java.util.Collection;
024 import java.util.HashMap;
025 import java.util.HashSet;
026 import java.util.Iterator;
027 import java.util.Map;
028 import java.util.Map.Entry;
029
030 import org.apache.commons.configuration.Configuration;
031 import org.apache.log4j.Logger;
032 import org.apache.qpid.framing.AMQShortString;
033 import org.apache.qpid.server.configuration.SecurityConfiguration;
034 import org.apache.qpid.server.configuration.ServerConfiguration;
035 import org.apache.qpid.server.configuration.VirtualHostConfiguration;
036 import org.apache.qpid.server.exchange.Exchange;
037 import org.apache.qpid.server.plugins.PluginManager;
038 import org.apache.qpid.server.protocol.AMQProtocolSession;
039 import org.apache.qpid.server.queue.AMQQueue;
040 import org.apache.qpid.server.security.access.ACLPlugin.AuthzResult;
041 import org.apache.qpid.server.security.access.plugins.SimpleXML;
042 import org.apache.qpid.server.virtualhost.VirtualHost;
043
044 public class ACLManager
045 {
046 private static final Logger _logger = Logger.getLogger(ACLManager.class);
047 private PluginManager _pluginManager;
048 private Map<String, ACLPluginFactory> _allSecurityPlugins = new HashMap<String, ACLPluginFactory>();
049 private Map<String, ACLPlugin> _globalPlugins = new HashMap<String, ACLPlugin>();
050 private Map<String, ACLPlugin> _hostPlugins = new HashMap<String, ACLPlugin>();
051
052 public ACLManager(SecurityConfiguration configuration, PluginManager manager)
053 {
054 this(configuration, manager, null);
055 }
056
057 public ACLManager(SecurityConfiguration configuration, PluginManager manager, ACLPluginFactory securityPlugin)
058 {
059 _pluginManager = manager;
060
061 if (manager == null) // No plugin manager, no plugins
062 {
063 return;
064 }
065
066 _allSecurityPlugins = _pluginManager.getSecurityPlugins();
067 if (securityPlugin != null)
068 {
069 _allSecurityPlugins.put(securityPlugin.getClass().getName(), securityPlugin);
070 }
071
072 _globalPlugins = configurePlugins(configuration);
073 }
074
075
076 public void configureHostPlugins(SecurityConfiguration hostConfig)
077 {
078 _hostPlugins = configurePlugins(hostConfig);
079 }
080
081 public Map<String, ACLPlugin> configurePlugins(SecurityConfiguration hostConfig)
082 {
083 Configuration securityConfig = hostConfig.getConfiguration();
084 Map<String, ACLPlugin> plugins = new HashMap<String, ACLPlugin>();
085 Iterator keys = securityConfig.getKeys();
086 Collection<String> handledTags = new HashSet();
087 while (keys.hasNext())
088 {
089 // Splitting the string is necessary here because of the way that getKeys() returns only
090 // bottom level children
091 String tag = ((String) keys.next()).split("\\.", 2)[0];
092 if (!handledTags.contains(tag))
093 {
094 for (ACLPluginFactory plugin : _allSecurityPlugins.values())
095 {
096 if (plugin.supportsTag(tag))
097 {
098 _logger.warn("Plugin handling security section "+tag+" is "+plugin.getClass().getSimpleName());
099 handledTags.add(tag);
100 plugins.put(plugin.getClass().getName(), plugin.newInstance(securityConfig));
101 }
102 }
103 }
104 if (!handledTags.contains(tag))
105 {
106 _logger.warn("No plugin handled security section "+tag);
107 }
108 }
109 return plugins;
110 }
111
112 public static Logger getLogger()
113 {
114 return _logger;
115 }
116
117 private abstract class AccessCheck
118 {
119 abstract AuthzResult allowed(ACLPlugin plugin);
120 }
121
122 private boolean checkAllPlugins(AccessCheck checker)
123 {
124 AuthzResult result = AuthzResult.ABSTAIN;
125 HashMap<String, ACLPlugin> remainingPlugins = new HashMap<String, ACLPlugin>();
126 remainingPlugins.putAll(_globalPlugins);
127 for (Entry<String, ACLPlugin> plugin : _hostPlugins.entrySet())
128 {
129 result = checker.allowed(plugin.getValue());
130 if (result == AuthzResult.DENIED)
131 {
132 // Something vetoed the access, we're done
133 return false;
134 }
135 else if (result == AuthzResult.ALLOWED)
136 {
137 // Remove plugin from global check list since
138 // host allow overrides global allow
139 remainingPlugins.remove(plugin.getKey());
140 }
141 }
142
143 for (ACLPlugin plugin : remainingPlugins.values())
144 {
145 result = checker.allowed(plugin);
146 if (result == AuthzResult.DENIED)
147 {
148 return false;
149 }
150 }
151 return true;
152 }
153
154 public boolean authoriseBind(final AMQProtocolSession session, final Exchange exch, final AMQQueue queue,
155 final AMQShortString routingKey)
156 {
157 return checkAllPlugins(new AccessCheck()
158 {
159
160 @Override
161 AuthzResult allowed(ACLPlugin plugin)
162 {
163 return plugin.authoriseBind(session, exch, queue, routingKey);
164 }
165
166 });
167 }
168
169 public boolean authoriseConnect(final AMQProtocolSession session, final VirtualHost virtualHost)
170 {
171 return checkAllPlugins(new AccessCheck()
172 {
173
174 @Override
175 AuthzResult allowed(ACLPlugin plugin)
176 {
177 return plugin.authoriseConnect(session, virtualHost);
178 }
179
180 });
181 }
182
183 public boolean authoriseConsume(final AMQProtocolSession session, final boolean noAck, final AMQQueue queue)
184 {
185 return checkAllPlugins(new AccessCheck()
186 {
187
188 @Override
189 AuthzResult allowed(ACLPlugin plugin)
190 {
191 return plugin.authoriseConsume(session, noAck, queue);
192 }
193
194 });
195 }
196
197 public boolean authoriseConsume(final AMQProtocolSession session, final boolean exclusive, final boolean noAck,
198 final boolean noLocal, final boolean nowait, final AMQQueue queue)
199 {
200 return checkAllPlugins(new AccessCheck()
201 {
202
203 @Override
204 AuthzResult allowed(ACLPlugin plugin)
205 {
206 return plugin.authoriseConsume(session, exclusive, noAck, noLocal, nowait, queue);
207 }
208
209 });
210 }
211
212 public boolean authoriseCreateExchange(final AMQProtocolSession session, final boolean autoDelete,
213 final boolean durable, final AMQShortString exchangeName, final boolean internal, final boolean nowait,
214 final boolean passive, final AMQShortString exchangeType)
215 {
216 return checkAllPlugins(new AccessCheck()
217 {
218
219 @Override
220 AuthzResult allowed(ACLPlugin plugin)
221 {
222 return plugin.authoriseCreateExchange(session, autoDelete, durable, exchangeName, internal, nowait,
223 passive, exchangeType);
224 }
225
226 });
227 }
228
229 public boolean authoriseCreateQueue(final AMQProtocolSession session, final boolean autoDelete,
230 final boolean durable, final boolean exclusive, final boolean nowait, final boolean passive,
231 final AMQShortString queue)
232 {
233 return checkAllPlugins(new AccessCheck()
234 {
235
236 @Override
237 AuthzResult allowed(ACLPlugin plugin)
238 {
239 return plugin.authoriseCreateQueue(session, autoDelete, durable, exclusive, nowait, passive, queue);
240 }
241
242 });
243 }
244
245 public boolean authoriseDelete(final AMQProtocolSession session, final AMQQueue queue)
246 {
247 return checkAllPlugins(new AccessCheck()
248 {
249
250 @Override
251 AuthzResult allowed(ACLPlugin plugin)
252 {
253 return plugin.authoriseDelete(session, queue);
254 }
255
256 });
257 }
258
259 public boolean authoriseDelete(final AMQProtocolSession session, final Exchange exchange)
260 {
261 return checkAllPlugins(new AccessCheck()
262 {
263
264 @Override
265 AuthzResult allowed(ACLPlugin plugin)
266 {
267 return plugin.authoriseDelete(session, exchange);
268 }
269
270 });
271 }
272
273 public boolean authorisePublish(final AMQProtocolSession session, final boolean immediate, final boolean mandatory,
274 final AMQShortString routingKey, final Exchange e)
275 {
276 return checkAllPlugins(new AccessCheck()
277 {
278
279 @Override
280 AuthzResult allowed(ACLPlugin plugin)
281 {
282 return plugin.authorisePublish(session, immediate, mandatory, routingKey, e);
283 }
284
285 });
286 }
287
288 public boolean authorisePurge(final AMQProtocolSession session, final AMQQueue queue)
289 {
290 return checkAllPlugins(new AccessCheck()
291 {
292
293 @Override
294 AuthzResult allowed(ACLPlugin plugin)
295 {
296 return plugin.authorisePurge(session, queue);
297 }
298
299 });
300 }
301
302 public boolean authoriseUnbind(final AMQProtocolSession session, final Exchange exch,
303 final AMQShortString routingKey, final AMQQueue queue)
304 {
305 return checkAllPlugins(new AccessCheck()
306 {
307
308 @Override
309 AuthzResult allowed(ACLPlugin plugin)
310 {
311 return plugin.authoriseUnbind(session, exch, routingKey, queue);
312 }
313
314 });
315 }
316
317 public void addHostPlugin(ACLPlugin aclPlugin)
318 {
319 _hostPlugins.put(aclPlugin.getClass().getName(), aclPlugin);
320 }
321 }
|