blob: 1679fe14a3330e9c73c014ffd13c57660dcfa291 [file] [log] [blame]
Karl Pauls36407322008-03-07 00:37:30 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.framework.security.util;
20
Karl Pauls23287bd2010-01-10 22:11:27 +000021import java.security.Permission;
22import java.util.Dictionary;
Karl Pauls36407322008-03-07 00:37:30 +000023import java.util.HashMap;
24import java.util.HashSet;
25import java.util.Hashtable;
26import java.util.Iterator;
27import java.util.List;
28import java.util.Map;
Karl Pauls36407322008-03-07 00:37:30 +000029import java.util.WeakHashMap;
Karl Pauls36407322008-03-07 00:37:30 +000030
Karl Pauls23287bd2010-01-10 22:11:27 +000031import org.apache.felix.framework.security.condpermadmin.ConditionalPermissionInfoImpl;
Karl Pauls36407322008-03-07 00:37:30 +000032import org.apache.felix.framework.util.SecureAction;
Karl Pauls23287bd2010-01-10 22:11:27 +000033import org.apache.felix.moduleloader.IModule;
Karl Pauls36407322008-03-07 00:37:30 +000034import org.osgi.framework.Bundle;
Karl Pauls36407322008-03-07 00:37:30 +000035import org.osgi.service.condpermadmin.Condition;
36import org.osgi.service.condpermadmin.ConditionInfo;
37
38/**
39 * This class caches conditions instances by their infos. Furthermore, it allows
40 * to eval postponed condition permission tuples as per spec (see 9.45).
41 */
42// TODO: maybe use bundle events instead of soft/weak references.
43public final class Conditions
44{
45 private static final ThreadLocal m_conditionStack = new ThreadLocal();
Karl Pauls23287bd2010-01-10 22:11:27 +000046 private static final Map m_conditionCache = new WeakHashMap();
Karl Pauls36407322008-03-07 00:37:30 +000047
48 private final Map m_cache = new WeakHashMap();
Karl Pauls23287bd2010-01-10 22:11:27 +000049
50 private final IModule m_module;
Karl Pauls36407322008-03-07 00:37:30 +000051
52 private final ConditionInfo[] m_conditionInfos;
53 private final Condition[] m_conditions;
54 private final SecureAction m_action;
55
56 public Conditions(SecureAction action)
57 {
Karl Pauls23287bd2010-01-10 22:11:27 +000058 this(null, null, action);
Karl Pauls36407322008-03-07 00:37:30 +000059 }
Karl Pauls23287bd2010-01-10 22:11:27 +000060
61 private Conditions(IModule module, ConditionInfo[] conditionInfos,
62 SecureAction action)
Karl Pauls36407322008-03-07 00:37:30 +000063 {
Karl Pauls23287bd2010-01-10 22:11:27 +000064 m_module = module;
65 m_conditionInfos = conditionInfos;
66 if ((module != null) && (conditionInfos != null))
67 {
68 synchronized (m_conditionCache)
69 {
70 Map conditionMap = (Map) m_conditionCache.get(module);
71 if (conditionMap == null)
72 {
73 conditionMap = new HashMap();
74 conditionMap.put(m_conditionInfos,
75 new Condition[m_conditionInfos.length]);
76 m_conditionCache.put(module, conditionMap);
77 }
78 Condition[] conditions = (Condition[]) conditionMap
79 .get(m_conditionInfos);
80 if (conditions == null)
81 {
82 conditions = new Condition[m_conditionInfos.length];
83 conditionMap.put(m_conditionInfos, conditions);
84 }
85 m_conditions = conditions;
86 }
87 }
88 else
89 {
90 m_conditions = null;
91 }
Karl Pauls36407322008-03-07 00:37:30 +000092 m_action = action;
93 }
94
Karl Pauls23287bd2010-01-10 22:11:27 +000095 public Conditions getConditions(IModule key, ConditionInfo[] conditions)
Karl Pauls36407322008-03-07 00:37:30 +000096 {
97 Conditions result = null;
98 Map index = null;
99 synchronized (m_cache)
100 {
101 index = (Map) m_cache.get(conditions);
102 if (index == null)
103 {
104 index = new WeakHashMap();
105 m_cache.put(conditions, index);
106 }
107 }
108 synchronized (index)
109 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000110 if (key != null)
Karl Pauls36407322008-03-07 00:37:30 +0000111 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000112 result = (Conditions) index.get(key);
Karl Pauls36407322008-03-07 00:37:30 +0000113 }
114 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000115
Karl Pauls36407322008-03-07 00:37:30 +0000116 if (result == null)
117 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000118 result = new Conditions(key, conditions, m_action);
Karl Pauls36407322008-03-07 00:37:30 +0000119 synchronized (index)
120 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000121 index.put(key, result);
Karl Pauls36407322008-03-07 00:37:30 +0000122 }
123 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000124
Karl Pauls36407322008-03-07 00:37:30 +0000125 return result;
126 }
127
128 // See whether the given list is satisfied or not
Karl Pauls23287bd2010-01-10 22:11:27 +0000129 public boolean isSatisfied(List posts, Permissions permissions,
130 Permission permission)
Karl Pauls36407322008-03-07 00:37:30 +0000131 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000132 boolean check = true;
133 for (int i = 0; i < m_conditionInfos.length; i++)
Karl Pauls36407322008-03-07 00:37:30 +0000134 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000135 if (m_module == null)
Karl Pauls36407322008-03-07 00:37:30 +0000136 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000137 // TODO: check whether this is correct!
138 break;
Karl Pauls36407322008-03-07 00:37:30 +0000139 }
140 try
141 {
142 Condition condition = null;
143 boolean add = false;
144 Class clazz = Class.forName(m_conditionInfos[i].getType());
Karl Pauls23287bd2010-01-10 22:11:27 +0000145
146 synchronized (m_conditions)
Karl Pauls36407322008-03-07 00:37:30 +0000147 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000148 if (m_conditions[i] == null)
149 {
150 m_conditions[i] = createCondition(m_module.getBundle(),
151 clazz, m_conditionInfos[i]);
152 }
Karl Pauls36407322008-03-07 00:37:30 +0000153 condition = m_conditions[i];
Karl Pauls36407322008-03-07 00:37:30 +0000154 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000155
156 Object current = m_conditionStack.get();
157 if (current != null)
Karl Pauls36407322008-03-07 00:37:30 +0000158 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000159 if (current instanceof HashSet)
Karl Pauls36407322008-03-07 00:37:30 +0000160 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000161 if (((HashSet) current).contains(clazz))
Karl Pauls36407322008-03-07 00:37:30 +0000162 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000163 return false;
164 }
165 }
166 else
167 {
168 if (current == clazz)
169 {
170 return false;
Karl Pauls36407322008-03-07 00:37:30 +0000171 }
172 }
173 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000174
175 if (condition.isPostponed())
176 {
177 if (check && !permissions.implies(permission, null))
178 {
179 return false;
180 }
181 else
182 {
183 check = false;
184 }
185 posts.add(new Object[] { condition, new Integer(i) });
186 }
Karl Pauls36407322008-03-07 00:37:30 +0000187 else
188 {
Karl Pauls36407322008-03-07 00:37:30 +0000189
190 if (current == null)
191 {
192 m_conditionStack.set(clazz);
193 }
194 else
195 {
196 if (current instanceof HashSet)
197 {
198 if (((HashSet) current).contains(clazz))
199 {
200 return false;
201 }
202 ((HashSet) current).add(clazz);
203 }
204 else
205 {
206 if (current == clazz)
207 {
208 return false;
209 }
210 HashSet frame = new HashSet();
211 frame.add(current);
212 frame.add(clazz);
213 m_conditionStack.set(frame);
214 current = frame;
215 }
216 }
217 try
218 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000219 boolean mutable = condition.isMutable();
Karl Pauls36407322008-03-07 00:37:30 +0000220 boolean result = condition.isSatisfied();
221
Karl Pauls23287bd2010-01-10 22:11:27 +0000222 if (!mutable
223 && ((condition != Condition.TRUE) && (condition != Condition.FALSE)))
Karl Pauls36407322008-03-07 00:37:30 +0000224 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000225 synchronized (m_conditions)
Karl Pauls36407322008-03-07 00:37:30 +0000226 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000227 m_conditions[i] = result ? Condition.TRUE
228 : Condition.FALSE;
Karl Pauls36407322008-03-07 00:37:30 +0000229 }
230 }
231 if (!result)
232 {
233 return false;
234 }
235 }
236 finally
237 {
238 if (current == null)
239 {
240 m_conditionStack.set(null);
241 }
242 else
243 {
244 ((HashSet) current).remove(clazz);
245 if (((HashSet) current).isEmpty())
246 {
247 m_conditionStack.set(null);
248 }
249 }
250 }
251 }
252 }
253 catch (Exception e)
254 {
255 // TODO: log this as per spec
256 e.printStackTrace();
257 return false;
258 }
259 }
260 return true;
261 }
262
263 public boolean evalRecursive(List entries)
264 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000265 Map contexts = new HashMap();
266 outer: for (Iterator iter = entries.iterator(); iter.hasNext();)
Karl Pauls36407322008-03-07 00:37:30 +0000267 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000268 List tuples = (List) iter.next();
269 inner: for (Iterator inner = tuples.iterator(); inner.hasNext();)
Karl Pauls36407322008-03-07 00:37:30 +0000270 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000271 Object[] entry = (Object[]) inner.next();
272 List conditions = (List) entry[1];
273 if (conditions == null)
Karl Pauls36407322008-03-07 00:37:30 +0000274 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000275 if (!((ConditionalPermissionInfoImpl) entry[0]).isAllow())
Karl Pauls36407322008-03-07 00:37:30 +0000276 {
277 return false;
278 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000279 continue outer;
Karl Pauls36407322008-03-07 00:37:30 +0000280 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000281 for (Iterator iter2 = conditions.iterator(); iter2.hasNext();)
Karl Pauls36407322008-03-07 00:37:30 +0000282 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000283 Object[] condEntry = (Object[]) iter2.next();
284 Condition cond = (Condition) condEntry[0];
285 Dictionary context = (Dictionary) contexts.get(cond
286 .getClass());
287 if (context == null)
Karl Pauls36407322008-03-07 00:37:30 +0000288 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000289 context = new Hashtable();
290 contexts.put(cond.getClass(), context);
291 }
292 Object current = m_conditionStack.get();
293 if (current == null)
294 {
295 m_conditionStack.set(cond.getClass());
Karl Pauls36407322008-03-07 00:37:30 +0000296 }
297 else
298 {
Karl Pauls23287bd2010-01-10 22:11:27 +0000299 if (current instanceof HashSet)
300 {
301 ((HashSet) current).add(cond.getClass());
302 }
303 else
304 {
305 HashSet frame = new HashSet();
306 frame.add(current);
307 frame.add(cond.getClass());
308 m_conditionStack.set(frame);
309 current = frame;
310 }
311 }
312 boolean result;
313 boolean mutable = cond.isMutable();
314 try
315 {
316 result = cond.isSatisfied(new Condition[] { cond },
317 context);
318 }
319 finally
320 {
321 if (current == null)
Karl Pauls36407322008-03-07 00:37:30 +0000322 {
323 m_conditionStack.set(null);
324 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000325 else
326 {
327 ((HashSet) current).remove(cond.getClass());
328 if (((HashSet) current).isEmpty())
329 {
330 m_conditionStack.set(null);
331 }
332 }
333 }
334 if (!mutable && (cond != Condition.TRUE)
335 && (cond != Condition.FALSE))
336 {
337 synchronized (((Conditions) entry[2]).m_conditions)
338 {
339 ((Conditions) entry[2]).m_conditions[((Integer) condEntry[1])
340 .intValue()] = result ? Condition.TRUE
341 : Condition.FALSE;
342 }
343 }
344 if (!result)
345 {
346 continue inner;
Karl Pauls36407322008-03-07 00:37:30 +0000347 }
348 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000349 if (!((ConditionalPermissionInfoImpl) entry[0]).isAllow())
350 {
351 return false;
352 }
353 continue outer;
Karl Pauls36407322008-03-07 00:37:30 +0000354 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000355 return false;
Karl Pauls36407322008-03-07 00:37:30 +0000356 }
Karl Pauls23287bd2010-01-10 22:11:27 +0000357 return true;
Karl Pauls36407322008-03-07 00:37:30 +0000358 }
359
360 private Condition createCondition(final Bundle bundle, final Class clazz,
361 final ConditionInfo info) throws Exception
362 {
363 try
364 {
365 return (Condition) m_action.getMethod(clazz, "getCondition",
366 new Class[] { Bundle.class, ConditionInfo.class }).invoke(null,
367 new Object[] { bundle, info });
368 }
369 catch (Exception ex)
370 {
371 ex.printStackTrace();
372 return (Condition) m_action.getConstructor(clazz,
373 new Class[] { Bundle.class, ConditionInfo.class }).newInstance(
374 new Object[] { bundle, info });
375 }
376 }
377}