/* * ome.security.SecuritySystem * * Copyright 2006 University of Dundee. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.security; // Java imports // Third-party libraries // Application-internal dependencies import ome.conditions.ApiUsageException; import ome.conditions.SecurityViolation; import ome.model.IObject; import ome.model.internal.Details; import ome.model.internal.Permissions; import ome.model.internal.Token; import ome.model.meta.ExperimenterGroup; import ome.security.policy.Policy; import ome.system.EventContext; import ome.system.Principal; import ome.system.Roles; /** * central security interface. All queries and actions that deal with a secure * context should pass through an implementation of this interface. * * @author Josh Moore, josh.moore at gmx.de * @version $Revision$, $Date$ * @see Token * @see Details * @see Permissions * @see ACLEventListener * @since 3.0-M3 */ public interface SecuritySystem { // ~ Login/logout // ========================================================================= /** * stores this {@link Principal} instance in the current thread context for * authenticating and authorizing all actions. This method does <em>not</em> * make any queries and is only a conduit for login information from the * outermost levels. Session bean implementations and other in-JVM clients * can fill the {@link Principal}. Note, however, a call must first be made * to {@link #loadEventContext(boolean)} for some calls to be made to the * {@link SecuritySystem}. In general, this means that execution must pass * through the {@link ome.security.basic.EventHandler} * * @param principal the new current principal */ void login(Principal principal); /** * clears the top {@link Principal} instance from the current thread * context. * * @return the number of remaining instances. */ int logout(); /** * Calls {@link #getEventContext(boolean)} with a false as "refresh". * This is the previous, safer logic of the method since consumers * are not expecting a long method run. * * @return the event context */ EventContext getEventContext(); /** * Returns UID based on whether a share is active, etc. This is the UID * value that should be used for writing data. * * The return value <em>may be</em> null if the user is currently querying * across multiple contents. In this case another method for * choosing the UID must be chosen, for example by taking the UID of * another element under consideration. * * For example, * <pre> * Annotation toSave = ...; * if (toSave.getDetails().getOwner() == null) // No owner need to find one. * { * Long uid = sec.getEffectiveUID(); * if (uid != null) * { * toSave.getDetails().setOwner(new Experimenter(uid, false)); * } * else * { * toSave.getDetails().setOwner( * image.getDetails().getOwner()); // may be null. * } * } * image.linkAnnotation(toSave); * etc. * </pre> * * @return the effective user ID */ Long getEffectiveUID(); /** * If refresh is false, returns the current {@link EventContext} stored * in the session. Otherwise, reloads the context to have the most * up-to-date information. * @see <a href="http://trac.openmicroscopy.org/ome/ticket/4011">Trac ticket #4011</a> * * @param refresh if the event context should first be reloaded * @return the event context */ EventContext getEventContext(boolean refresh); /** * Prepares the current {@link EventContext} instance with the current * {@link Principal}. An exception is thrown if there is none. * * @param isReadOnly */ void loadEventContext(boolean isReadOnly); /** * Clears the content of the {@link EventContext}so that the * {@link SecuritySystem} will no longer return true for {@link #isReady()}. * The {@link Principal} set during {@link #login(Principal)} is retained. */ void invalidateEventContext(); // ~ Checks // ========================================================================= /** * checks if this {@link SecuritySystem} instance is in a valid state. This * includes that a user is properly logged in and that a connection is * available to all necessary resources, e.g. database handle and mapping * session. * * Not all methods require that the instance is ready. * * @return true if all methods on this interface are ready to be called. */ boolean isReady(); /** * checks if instances of the given type are "System-Types". Security logic * for all system types is significantly different. In general, system types * cannot be created, updated, or deleted by regular users, and are visible * to all users. * * @param klass * A class which extends from {@link IObject} * @return true if instances of the class argument can be considered system * types. */ boolean isSystemType(Class<? extends IObject> klass); /** * checks that the {@link IObject} argument has been granted a {@link Token} * by the {@link SecuritySystem}. */ boolean hasPrivilegedToken(IObject obj); /** * Checks whether or not a {@link Policy} instance of matching * name has been registered, considers itself active, <em>and</em> * considers the passed context object to be restricted. * * @param name A non-null unique name for a class of policies. * @param obj An instance which is to be checked against matching policies. * @throws {@link SecurityViolation} if the given {@link Policy} is * considered to be restricted. */ void checkRestriction(String name, IObject obj) throws SecurityViolation; // ~ Subsystem disabling // ========================================================================= /** * disables components of the backend for the current Thread. Further checks * to {@link #isDisabled(String)} will return false. It is the * responsibility of various security system components to then throw * exceptions. * * @param ids * Non-null, non-empty array of String ids to disable. */ void disable(String... ids); /** * enables components of the backend for the current Thread. Further checks * to {@link #isDisabled(String)} will return true. * * @param ids * possibly null array of String ids. A null array specifies that * all subsystems are to be enabled. Otherwise, only those * subsystems specified by the ids. */ void enable(String... ids); /** * checks if the listed id is disabled for the current Thread. * * @param id * non-null String representing a backend subsystem. * @return true if the backend subsystem has been previously disabled by * calls to {@link #disable(String[])} */ boolean isDisabled(String id); // ~ Details checking (prime responsibility) // ========================================================================= /** * Determines if the current security context has the possibility of * corrupting consistent graphs. Consistent graphs are enforced by the * security context to make sure that all READ actions work smoothly. If an * administrator or PI is logged into a private group, or otherwise may * create an object linked to an object with lower READ rights, then * corruption could occur. * * Starting with 4.4.2, a trusted details object should be passed in order * to handle the situation where the current group id is -1. Possibles * cases that can occur: * * <pre> * The current group is non-negative, then use the previous logic; * else the current group is negative, * and the object is in a non-"user" group: USE THAT GROUP; * else the object is in the "user" group: UNCLEAR * (for the moment we're throwing an exception) * </pre> * * If no {@link Details} instance is passed or a {@link Details} without * a {@link ExperimenterGroup} value, then throw as well. * * @see <a * href="http://trac.openmicroscopy.org.uk/ome/ticket/1434>1434</a> * @see <a * href="http://trac.openmicroscopy.org.uk/ome/ticket/1769>1769</a> * @see <a * href="http://trac.openmicroscopy.org.uk/ome/ticket/9474>9474</a> * @param details the details * @return if the graph is critical */ boolean isGraphCritical(Details details); /** * creates a new secure {@link IObject#getDetails() details} for transient * entities. Non-privileged users can only edit the * {@link Details#getPermissions() Permissions} field. Privileged users can * use the {@link Details} object as a single-step <code>chmod</code> and * <code>chgrp</code>. * * {@link #newTransientDetails(IObject) newTransientDetails} always returns * a non-null Details that is not equivalent (==) to the Details argument. * * This method can be used from anywhere in the codebase to obtain a valid * {@link Details}, but passing in an {@link IObject} instance with a null * {@link Details}. However, if the {@link Details} is non-null, there is * the possibility that this method will throw an exception. * * @throws ApiUsageException * if {@link SecuritySystem} is not {@link #isReady() ready} * @throws SecurityViolation * if {@link Details} instance contains illegal values. */ Details newTransientDetails(IObject iObject) throws ApiUsageException, SecurityViolation; /** * checks that a non-privileged user has not attempted to edit the entity's * {@link IObject#getDetails() security details}. Privileged users can set * fields on {@link Details} as a single-step <code>chmod</code> and * <code>chgrp</code>. * * {@link #checkManagedDetails(IObject, Details) managedDetails} may create * a new Details instance and return that if needed. If the returned Details * is not equivalent (==) to the argument Details, then values have been * changed. * * @param iObject * non-null {@link IObject} instance. {@link Details} for that * instance can be null. * @param trustedDetails * possibly null {@link Details} instance. These {@link Details} * are trusted in the sense that they have already once passed * through the {@link SecuritySystem}. * @throws ApiUsageException * if {@link SecuritySystem} is not {@link #isReady() ready} * @throws SecurityViolation * if {@link Details} instance contains illegal values. */ Details checkManagedDetails(IObject iObject, Details trustedDetails) throws ApiUsageException, SecurityViolation; // ~ Actions // ========================================================================= /** * Allows actions to be performed with the * {@link EventContext#isCurrentUserAdmin()} flag enabled but * <em>without</em> changing the value of * {@link EventContext#getCurrentUserId()}, so that ownerships are properly * handled. The merging of detached entity graphs should be disabled for the * extent of the execution. * * Due to the addition of the group permission system, we also permit * setting the group on the call so that the administrator can work within * all groups. A value of null will not change the current group. * * Note: the {@link ome.api.IUpdate} save methods should not be used, since * they also accept detached entities, which could pose security risks. * Instead load an entity from the database via {@link ome.api.IQuery}, * make changes, and save the changes with {@link ome.api.IUpdate}. * * @param group the group to run the action as * @param action the action to run */ void runAsAdmin(ExperimenterGroup group, AdminAction action); /** * Calls {@link #runAsAdmin(ExperimenterGroup, AdminAction)} with a * null group. * * @param action the action to run */ void runAsAdmin(AdminAction action); <T extends IObject> T doAction(SecureAction action, T... objs); // TODO do these need checks to isReady()? // ~ Configured Elements // ========================================================================= Roles getSecurityRoles(); }