/* * Javolution - Java(TM) Solution for Real-Time and Embedded Systems * Copyright (C) 2007 - Javolution (http://javolution.org/) * All rights reserved. * * Permission to use, copy, modify, and distribute this software is * freely granted, provided that this notice is preserved. */ package javolution.context; import javolution.lang.Configurable; /** * <p> This class represents a high-level security context (low level * security being addressed by the system security manager).</p> * * <p> Applications may extend this base class to address specific security * requirements. For example:[code] * // This class defines custom policy with regards to database access. * public abstract class DatabaseAccess extends SecurityContext { * public static boolean isReadAllowed(Table table) { * SecurityContext policy = SecurityContext.current(); * return (policy instanceof DatabaseAccess.Permission) ? * ((DatabaseAccess.Permission)policy).isReadable(table) : false; * } * public interface Permission { * boolean isReadable(Table table); * boolean isWritable(Table table); * } * }[/code]</p> * * <p> The use of interfaces (such as <code>Permission</code> above) makes * it easy for custom policies to support any security actions. * For example:[code] * class Policy extends SecurityContext implements DatabaseAccess.Permission, FileAccess.Permission { * public boolean isReadable(Table table) { * return !table.isPrivate(); * } * public boolean isWritable(Table table) { * return Session.getSession().getUser().isAdministrator(); * } * public boolean isReadable(File file) { * return true; * } * public boolean isWritable(File file) { * return false; * } * } * ... * Policy localPolicy = new Policy(); * SecurityContext.enter(localPolicy); // Current thread overrides default policy (configurable) * try { // (if allowed, ref. SecurityContext.isReplaceable()) * ... * DatabaseAccess.isReadAllowed(table); * ... * FileAccess.isWriteAllowed(file); * ... * } finally { * SecurityContext.exit(); * }[/code]</p> * * <p> The default permissions managed by the {@link #DEFAULT} implementation * are the permission to {@link #isReplaceable replace} the current security * context by default) and the permission to {@link #isConfigurable configure} * the application.</p> * * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> * @version 5.2, August 5, 2007 */ public abstract class SecurityContext extends Context { /** * Holds the default security context. */ private static volatile SecurityContext _Default = new Default(); /** * Holds the default security context implementation (configurable). */ public static final Configurable/*<Class<? extends SecurityContext>>*/ DEFAULT = new Configurable(Default.class) { protected void notifyChange(Object oldValue, Object newValue) { _Default = (SecurityContext) ObjectFactory.getInstance((Class) newValue).object(); } }; /** * Default constructor. */ protected SecurityContext() { } /** * Returns the current security context. If the current thread has not * entered any security context then {@link #getDefault()} is returned. * * @return the current security context. */ public static SecurityContext getCurrentSecurityContext() { for (Context ctx = Context.getCurrentContext(); ctx != null; ctx = ctx.getOuter()) { if (ctx instanceof SecurityContext) return (SecurityContext) ctx; } return SecurityContext._Default; } /** * Returns the default instance ({@link #DEFAULT} implementation). * * @return the default instance. */ public static SecurityContext getDefault() { return SecurityContext._Default; } // Implements Context abstract method. protected final void enterAction() { // Checks if the previous security context is replaceable. SecurityContext previousPolicy = SecurityContext._Default; for (Context ctx = this.getOuter(); ctx != null; ctx = ctx.getOuter()) { if (ctx instanceof SecurityContext) { previousPolicy = (SecurityContext) ctx; break; } } if (!previousPolicy.isReplaceable()) throw new SecurityException("Current Security Context not Replaceable"); } // Implements Context abstract method. protected final void exitAction() { // Do nothing. } /** * Indicates if a new security context can be entered (default * <code>true</code>). Applications may return <code>false</code> and * prevent untrusted code to increase their privileges. Usually, * such security setting should also prevent reconfiguring of the * {@link #DEFAULT default} security context by making * {@link #DEFAULT} not replaceable. * * @return <code>true</code> if a new security context can be entered; * <code>false</code> otherwise. */ public boolean isReplaceable() { return true; } /** * Indicates if this security context allows changes in the specified * {@link javolution.lang.Configurable Configurable} * (default <code>true</code>). Applications may override this method * to return <code>false</code> and prevent untrusted code to update the * some or all configuration parameters. * * @param cfg the configurable to check if changes are allowed. * @return <code>true</code> if the specified configurable can be modified; * <code>false</code> otherwise. */ public boolean isConfigurable(Configurable cfg) { return true; } /** * Default implementation. */ private static class Default extends SecurityContext { } // Allows instances of private classes to be factory produced. static { ObjectFactory.setInstance(new ObjectFactory() { protected Object create() { return new Default(); } }, Default.class); } }