001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2007 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.context;
010:
011: import javolution.lang.Configurable;
012:
013: /**
014: * <p> This class represents a high-level security context (low level
015: * security being addressed by the system security manager).</p>
016: *
017: * <p> Applications may extend this base class to address specific security
018: * requirements. For example:[code]
019: * // This class defines custom policy with regards to database access.
020: * public abstract class DatabaseAccess extends SecurityContext {
021: * public static boolean isReadAllowed(Table table) {
022: * SecurityContext policy = SecurityContext.current();
023: * return (policy instanceof DatabaseAccess.Permission) ?
024: * ((DatabaseAccess.Permission)policy).isReadable(table) : false;
025: * }
026: * public interface Permission {
027: * boolean isReadable(Table table);
028: * boolean isWritable(Table table);
029: * }
030: * }[/code]</p>
031: *
032: * <p> The use of interfaces (such as <code>Permission</code> above) makes
033: * it easy for custom policies to support any security actions.
034: * For example:[code]
035: * class Policy extends SecurityContext implements DatabaseAccess.Permission, FileAccess.Permission {
036: * public boolean isReadable(Table table) {
037: * return !table.isPrivate();
038: * }
039: * public boolean isWritable(Table table) {
040: * return Session.getSession().getUser().isAdministrator();
041: * }
042: * public boolean isReadable(File file) {
043: * return true;
044: * }
045: * public boolean isWritable(File file) {
046: * return false;
047: * }
048: * }
049: * ...
050: * Policy localPolicy = new Policy();
051: * SecurityContext.enter(localPolicy); // Current thread overrides default policy (configurable)
052: * try { // (if allowed, ref. SecurityContext.isReplaceable())
053: * ...
054: * DatabaseAccess.isReadAllowed(table);
055: * ...
056: * FileAccess.isWriteAllowed(file);
057: * ...
058: * } finally {
059: * SecurityContext.exit();
060: * }[/code]</p>
061: *
062: * <p> The default permissions managed by the {@link #DEFAULT} implementation
063: * are the permission to {@link #isReplaceable replace} the current security
064: * context by default) and the permission to {@link #isModifiable modify}
065: * all the application {@link javolution.lang.Configurable.Logic
066: * configuration} settings.</p>
067: *
068: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
069: * @version 5.2, August 5, 2007
070: */
071: public abstract class SecurityContext extends Context {
072:
073: /**
074: * Holds the default security context.
075: */
076: private static volatile SecurityContext _Default = new Default();
077:
078: /**
079: * Holds the default security context implementation (configurable).
080: */
081: public static final Configurable/*<Class<? extends SecurityContext>>*/DEFAULT = new Configurable(
082: _Default.getClass()) {
083: protected void notifyChange() {
084: _Default = (SecurityContext) ObjectFactory.getInstance(
085: (Class) get()).object();
086: }
087: };
088:
089: /**
090: * Default constructor.
091: */
092: protected SecurityContext() {
093: }
094:
095: /**
096: * Returns the current security context. If the current thread has not
097: * entered any security context then {@link #getDefault()} is returned.
098: *
099: * @return the current security context.
100: */
101: public static/*SecurityContext*/Context getCurrent() {
102: for (Context ctx = Context.getCurrent(); ctx != null; ctx = ctx
103: .getOuter()) {
104: if (ctx instanceof SecurityContext)
105: return (SecurityContext) ctx;
106: }
107: return SecurityContext._Default;
108: }
109:
110: /**
111: * Returns the default instance ({@link #DEFAULT} implementation).
112: *
113: * @return the default instance.
114: */
115: public static SecurityContext getDefault() {
116: return SecurityContext._Default;
117: }
118:
119: // Implements Context abstract method.
120: protected final void enterAction() {
121: // Checks if the previous security context is replaceable.
122: SecurityContext previousPolicy = SecurityContext._Default;
123: for (Context ctx = this .getOuter(); ctx != null; ctx = ctx
124: .getOuter()) {
125: if (ctx instanceof SecurityContext) {
126: previousPolicy = (SecurityContext) ctx;
127: break;
128: }
129: }
130: if (!previousPolicy.isReplaceable())
131: throw new SecurityException(
132: "Current Security Context not Replaceable");
133: }
134:
135: // Implements Context abstract method.
136: protected final void exitAction() {
137: // Do nothing.
138: }
139:
140: /**
141: * Indicates if a new security context can be entered (default
142: * <code>true</code>). Applications may return <code>false</code> and
143: * prevent untrusted code to increase their privileges. Usually,
144: * such security setting should also prevent reconfiguring of the
145: * {@link #DEFAULT default} context by making {@link #DEFAULT} not
146: * {@link #isModifiable modifiable}.
147: *
148: * @return <code>true</code> if a new security context can be entered;
149: * <code>false</code> otherwise.
150: */
151: public boolean isReplaceable() {
152: return true;
153: }
154:
155: /**
156: * Indicates if this security context allows modification of the
157: * {@link javolution.lang.Configurable.Logic configuration} settings
158: * (default <code>true</code>). Applications may override this method
159: * to return <code>false</code> and prevent untrusted code to update the
160: * some/all configuration parameters.
161: *
162: * @param cfg the configurable to check if modifiable.
163: * @return <code>true</code> if the specified configurable can be modified;
164: * <code>false</code> otherwise.
165: */
166: public boolean isModifiable(Configurable cfg) {
167: return true;
168: }
169:
170: /**
171: * Default implementation.
172: */
173: private static class Default extends SecurityContext {
174: }
175:
176: // Allows instances of private classes to be factory produced.
177: static {
178: ObjectFactory.setInstance(new ObjectFactory() {
179: protected Object create() {
180: return new Default();
181: }
182: }, _Default.getClass());
183: }
184: }
|