001: package org.tanukisoftware.wrapper.security;
002:
003: /*
004: * Copyright (c) 1999, 2006 Tanuki Software Inc.
005: *
006: * Permission is hereby granted, free of charge, to any person
007: * obtaining a copy of the Java Service Wrapper and associated
008: * documentation files (the "Software"), to deal in the Software
009: * without restriction, including without limitation the rights
010: * to use, copy, modify, merge, publish, distribute, sub-license,
011: * and/or sell copies of the Software, and to permit persons to
012: * whom the Software is furnished to do so, subject to the
013: * following conditions:
014: *
015: * The above copyright notice and this permission notice shall be
016: * included in all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
019: * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
020: * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
021: * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
022: * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
023: * WHETHER IN AN EVENT_TYPE OF CONTRACT, TORT OR OTHERWISE, ARISING
024: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
025: * OTHER DEALINGS IN THE SOFTWARE.
026: */
027:
028: import java.security.Permission;
029: import java.security.PermissionCollection;
030: import java.util.Enumeration;
031: import java.util.Vector;
032: import java.util.StringTokenizer;
033:
034: /**
035: * WrapperEventPermissions are used to grant the right to register to start
036: * receiving events from the Wrapper.
037: * <p>
038: * Some of these permissions can result in performance degredations if used
039: * impropperly.
040: * <p>
041: * The following are examples of how to specify the permission within a policy
042: * file.
043: * <pre>
044: * grant codeBase "file:../lib/-" {
045: * // Grant various permissions to a specific service.
046: * permission org.tanukisoftware.wrapper.security.WrapperEventPermission "service";
047: * permission org.tanukisoftware.wrapper.security.WrapperEventPermission "service, core";
048: * permission org.tanukisoftware.wrapper.security.WrapperEventPermission "*";
049: * };
050: * </pre>
051: * <p>
052: * Possible eventTypes include the following:
053: * <table border='1' cellpadding='2' cellspacing='0'>
054: * <tr>
055: * <th>Permission Event Type Name</th>
056: * <th>What the Permission Allows</th>
057: * <th>Risks of Allowing this Permission</th>
058: * </tr>
059: *
060: * <tr>
061: * <td>service</td>
062: * <td>Register to obtain events whenever the Wrapper service receives any service events.</td>
063: * <td>Malicious code could receive this event and never return and thus cause performance
064: * and timeout problems with the Wrapper. Normal use of these events are quite safe
065: * however.</td>
066: * </tr>
067: *
068: * <tr>
069: * <td>control</td>
070: * <td>Register to obtain events whenever the Wrapper receives any system control signals.</td>
071: * <td>Malicious code could trap and consome control events, thus preventing an application
072: * from being shut down cleanly.</td>
073: * </tr>
074: *
075: * <tr>
076: * <td>core</td>
077: * <td>Register to obtain events on the core workings of the Wrapper.</td>
078: * <td>Malicious code or even well meaning code can greatly affect the performance of
079: * the Wrapper simply by handling these methods slowly. Some of these events are
080: * fired from within the core timing code of the Wrapper. They are useful for
081: * testing and performance checks, but in general they should not be used by
082: * most applications.
083: * </td>
084: * </tr>
085: * </table>
086: *
087: * @author Leif Mortenson <leif@tanukisoftware.com>
088: */
089: public class WrapperEventPermission extends Permission {
090: public static String EVENT_TYPE_SERVICE = "service";
091: public static String EVENT_TYPE_CONTROL = "control";
092: public static String EVENT_TYPE_CORE = "core";
093:
094: private static int MASK_SERVICE = 1;
095: private static int MASK_CONTROL = 2;
096: private static int MASK_CORE = 65536;
097: private static int MASK_ALL = MASK_SERVICE | MASK_CONTROL
098: | MASK_CORE;
099:
100: private int m_eventTypeMask;
101:
102: /*---------------------------------------------------------------
103: * Constructors
104: *-------------------------------------------------------------*/
105: /**
106: * Creates a new WrapperEventPermission for the specified service.
107: *
108: * @param eventTypes The event type or event types to be registered.
109: */
110: public WrapperEventPermission(String eventTypes) {
111: super ("*");
112: m_eventTypeMask = buildEventTypeMask(eventTypes);
113: }
114:
115: /*---------------------------------------------------------------
116: * Permission Methods
117: *-------------------------------------------------------------*/
118: /**
119: * Checks two Permission objects for equality.
120: * <p>
121: * Do not use the equals method for making access control decisions; use
122: * the implies method.
123: *
124: * @param obj The object we are testing for equality with this object.
125: *
126: * @return True if both Permission objects are equivalent.
127: */
128: public boolean equals(Object obj) {
129: if (obj == this ) {
130: return true;
131: }
132:
133: if (!(obj instanceof WrapperEventPermission)) {
134: return false;
135: }
136:
137: WrapperEventPermission wsp = (WrapperEventPermission) obj;
138:
139: return (m_eventTypeMask == wsp.m_eventTypeMask)
140: && getName().equals(wsp.getName());
141: }
142:
143: /**
144: * Return the canonical string representation of the eventTypes.
145: * Always returns present eventTypes in the following order:
146: * start, stop, pause, continue, interrogate. userCode.
147: *
148: * @return the canonical string representation of the eventTypes.
149: */
150: public String getActions() {
151: StringBuffer sb = new StringBuffer();
152: boolean first = true;
153:
154: if ((m_eventTypeMask & MASK_SERVICE) != 0) {
155: if (first) {
156: sb.append(',');
157: } else {
158: first = false;
159: }
160: sb.append(EVENT_TYPE_SERVICE);
161: }
162: if ((m_eventTypeMask & MASK_CONTROL) != 0) {
163: if (first) {
164: sb.append(',');
165: } else {
166: first = false;
167: }
168: sb.append(EVENT_TYPE_CONTROL);
169: }
170: if ((m_eventTypeMask & MASK_CORE) != 0) {
171: if (first) {
172: sb.append(',');
173: } else {
174: first = false;
175: }
176: sb.append(EVENT_TYPE_CORE);
177: }
178:
179: return sb.toString();
180: }
181:
182: /**
183: * Checks if this WrapperEventPermission object "implies" the
184: * specified permission.
185: * <P>
186: * More specifically, this method returns true if:<p>
187: * <ul>
188: * <li><i>p2</i> is an instanceof FilePermission,<p>
189: * <li><i>p2</i>'s eventTypes are a proper subset of this object's eventTypes,
190: * and<p>
191: * <li><i>p2</i>'s service name is implied by this object's service name.
192: * For example, "MyApp*" implies "MyApp".
193: * </ul>
194: *
195: * @param p2 the permission to check against.
196: *
197: * @return true if the specified permission is implied by this object,
198: */
199: public boolean implies(Permission p2) {
200: if (!(p2 instanceof WrapperEventPermission)) {
201: return false;
202: }
203:
204: WrapperEventPermission wsp = (WrapperEventPermission) p2;
205:
206: // we get the effective mask. i.e., the "and" of this and that.
207: // They must be equal to that.mask for implies to return true.
208:
209: return ((m_eventTypeMask & wsp.m_eventTypeMask) == wsp.m_eventTypeMask)
210: && impliesIgnoreEventTypeMask(wsp);
211: }
212:
213: /**
214: * Returns an custom WECollection implementation of a PermissionCollection.
215: */
216: public PermissionCollection newPermissionCollection() {
217: return new WECollection();
218: }
219:
220: /**
221: * Returns the hash code value for this object.
222: *
223: * @return A hash code value for this object.
224: */
225: public int hashCode() {
226: return getName().hashCode();
227: }
228:
229: /*---------------------------------------------------------------
230: * Methods
231: *-------------------------------------------------------------*/
232: /**
233: * Returns the eventType mask of the Permission.
234: */
235: int getActionMask() {
236: return m_eventTypeMask;
237: }
238:
239: /**
240: * Tests whether this permissions implies another without taking the
241: * eventType mask into account.
242: */
243: boolean impliesIgnoreEventTypeMask(WrapperEventPermission p2) {
244: if (getName().equals(p2.getName())) {
245: return true;
246: }
247:
248: if (p2.getName().endsWith("*")) {
249: if (getName().startsWith(
250: p2.getName()
251: .substring(0, p2.getName().length() - 1))) {
252: return true;
253: }
254: }
255: return false;
256: }
257:
258: /**
259: * Builds an eventType mask given a comma separated list of eventTypes.
260: */
261: private int buildEventTypeMask(String eventTypes) {
262: // Check for the constants first as they are used internally.
263: if (eventTypes == EVENT_TYPE_SERVICE) {
264: return MASK_SERVICE;
265: } else if (eventTypes == EVENT_TYPE_CONTROL) {
266: return MASK_CONTROL;
267: } else if (eventTypes == EVENT_TYPE_CORE) {
268: return MASK_CORE;
269: } else if (eventTypes.equals("*")) {
270: return MASK_ALL;
271: }
272:
273: int mask = 0;
274: StringTokenizer st = new StringTokenizer(eventTypes, ",");
275: while (st.hasMoreTokens()) {
276: String eventType = st.nextToken();
277: if (eventType.equals(EVENT_TYPE_SERVICE)) {
278: mask |= MASK_SERVICE;
279: } else if (eventType.equals(EVENT_TYPE_CONTROL)) {
280: mask |= MASK_CONTROL;
281: } else if (eventType.equals(EVENT_TYPE_CORE)) {
282: mask |= MASK_CORE;
283: } else {
284: throw new IllegalArgumentException(
285: "Invalid permission eventType: \"" + eventType
286: + "\"");
287: }
288: }
289:
290: return mask;
291: }
292: }
293:
294: final class WECollection extends PermissionCollection {
295: private Vector m_permissions = new Vector();
296:
297: /*---------------------------------------------------------------
298: * Constructors
299: *-------------------------------------------------------------*/
300: /**
301: * Creates an empty WECollection.
302: */
303: public WECollection() {
304: }
305:
306: /*---------------------------------------------------------------
307: * Methods
308: *-------------------------------------------------------------*/
309: /**
310: * Adds a permission to the FilePermissions. The key for the hash is
311: * permission.path.
312: *
313: * @param permission the Permission object to add.
314: *
315: * @exception IllegalArgumentException - if the permission is not a
316: * FilePermission
317: *
318: * @exception SecurityException - if this FilePermissionCollection object
319: * has been marked readonly
320: */
321: public void add(Permission permission) {
322: if (!(permission instanceof WrapperEventPermission)) {
323: throw new IllegalArgumentException("invalid permission: "
324: + permission);
325: }
326:
327: if (isReadOnly()) {
328: throw new SecurityException("Collection is read-only.");
329: }
330:
331: m_permissions.add(permission);
332: }
333:
334: /**
335: * Check and see if this set of permissions implies the permissions
336: * expressed in "permission".
337: *
338: * @param permission the Permission object to compare
339: *
340: * @return true if "permission" is a proper subset of a permission in
341: * the set, false if not.
342: */
343: public boolean implies(Permission permission) {
344: if (!(permission instanceof WrapperEventPermission)) {
345: return false;
346: }
347:
348: WrapperEventPermission wsp = (WrapperEventPermission) permission;
349:
350: int desiredMask = wsp.getActionMask();
351: int pendingMask = desiredMask;
352: int foundMask = 0;
353:
354: for (Enumeration en = m_permissions.elements(); en
355: .hasMoreElements();) {
356: WrapperEventPermission p2 = (WrapperEventPermission) en
357: .nextElement();
358: if ((pendingMask & p2.getActionMask()) != 0) {
359: // This permission has one or more eventTypes that we need.
360: if (wsp.impliesIgnoreEventTypeMask(p2)) {
361: foundMask |= desiredMask & p2.getActionMask();
362: if (foundMask == desiredMask) {
363: return true;
364: }
365: pendingMask = desiredMask ^ foundMask;
366: }
367: }
368: }
369:
370: return false;
371: }
372:
373: /**
374: * Returns an enumeration of all the WrapperEventPermission
375: * objects in the container.
376: *
377: * @return An enumeration of all the WrapperEventPermission
378: * objects.
379: */
380: public Enumeration elements() {
381: return m_permissions.elements();
382: }
383: }
|