OMERO security system
=====================

The OMERO security system is intended to be as transparent as possible
while permitting users to configure the visibility of their data. For
the user, this means that with no special actions, data and metadata
created will be readable by both members of the same group and by other
users, but will be writable by no one, comparable to a umask of 755 on
Unix. For the developer, transparency means that there is little or no
code that must be written to prevent security violations, and simple
mechanisms for allowing restricted operations when the time comes.

Other links which may be of use:

-  :doc:`/developers/Modules/Api/AdminInterface`
-  :doc:`SecurityRoles`
-  :doc:`/sysadmins/server-permissions`
-  :doc:`Permissions`

Concepts
--------

Several concepts and/or components from our and other code bases play a role 
in OMERO security:

`Hibernate Listeners and Events <http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/events.html>`_
    listeners and events are the two extension points provided by
    Hibernate for responding to and influencing internal actions.
    Essentially any method on the ``org.hibernate.Session`` interface
    has a corresponding event, and almost the same is true for the
    interceptor. Additionally interceptors can change the state of the
    objects before INSERT and UPDATE, and after SELECT.

`Hibernate Filters <http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/filters.html>`_
    filters are a mechanism for injecting SQL clauses into the SELECT
    statements generated by Hibernate. Similar to listeners and events
    for write actions, filters allow us to extend Hibernate
    functionality with our own logic.

Handler/interceptor
    as outlined in :doc:`/developers/Server/Aop`, OMERO makes
    extensive use of method interceptors to relieve the developer of
    some coding burden. Transactions, session management, and,
    naturally, security are handled largely by our interceptors (or
    "handlers").

Events
    Every write action produces an Event in the database. This database 
    contains several ``EventLogs`` which specify exactly what was created or
    altered during that specific event.

Participants
------------

Now, with the concepts cleared up, we can take a look at all of the
concrete source artifacts ("participants") which are important for
security.

Top-level and build
~~~~~~~~~~~~~~~~~~~

:source:`omero.properties <etc/omero.properties>`
    contains login and connection information for the database and OMERO.

:source:`build.properties.example <etc/build.properties>`
    contains the default root password. This can be overridden with your
    own :file:`etc/local.properties` file.

:source:`hibernate.properties <etc/hibernate.properties>`
    contains default connection information for the database, this
    includes the user name and if necessary the user password. These
    values can be overridden in local.properties.

:source:`omero.properties <etc/omero.properties>`
    contains a default user group, event type, and connection
    information for logging in from the client side, if no Login or
    Server is specified to ServiceFactory.
    These values can be overridden in local.properties.

:source:`mapping.vm <components/dsl/resources/ome/dsl/object.vm>`
    specifies the default permissions that all objects will have after
    construction, as well as attaches the security filter to all classes
    and collections.

:source:`data.vm <components/dsl/resources/ome/dsl/psql-footer.vm>`
    used by DSLTask to generate psql-footer.sql which is used to   
    bootstrap the database security system (root et al).

:source:`common/build.xml <components/common/build.xml>`
    contains an ant target (adduser) which will create a user and empty
    password from the command line. This target can also be called from
    the top-level (java omero adduser).


Client and common
~~~~~~~~~~~~~~~~~

the server uses the information in /etc/local.properties to create a Login
    object. If no Login, Server, or Properties is provided to the
    ServiceFactory constructor, the empty
    properties defined in
    :source:`ome/config.xml <components/common/resources/ome/config.xml>`
    is used.

:source:`IAdmin.java <components/common/src/ome/api/IAdmin.java>`
    main interface for administering accounts and privileges. See
    :doc:`/developers/Modules/Api/AdminInterface` for more.

:source:`ITypes.java <components/common/src/ome/api/ITypes.java>`
    only related to security by necessity. The security system disallows
    the creation of certain "System-Types". Enumerations are one of
    these. ITypes, however, provides a createEnumeration method with
    general access.

:source:`GraphHolder.java <components/model/src/ome/model/internal/GraphHolder.java>`
    all model objects (implementations of IObject have a never-null
    GraphHolder instance available. This graph holder is responsible for
    various OMERO and Hibernate internal processes. One of these is the
    exchange of Tokens. For the server, the existence of a special token
    within the GraphHolder grants certain privileges to that IObject.
    This logic is encapsulated within the SecuritySystem.

:source:`Details.java <components/model/src/ome/model/internal/Details.java>`
    contains all the fields necessary to perform access control, such as owner, group,
    and permissions.

:source:`Permissions.java <components/model/src/ome/model/internal/Permissions.java>`
    representation of rights and roles. For more information, see
    :doc:`/sysadmins/server-permissions`.

:source:`Token.java <components/model/src/ome/model/internal/Token.java>`
    an extremely simple class ("public class Token {}") which is only
    significant when it is equivalent ("==") to a privileged Token
    stored within the SecuritySystem.

:source:`IEnum.java <components/model/src/ome/model/IEnum.java>`
    the only non-access control related types which are considered
    "System-Types" are enumerations. IEnum is a marker interface for all
    enumerations and creation of IEnum implementations can only be
    performed through ITypes.

:source:`SecurityViolation.java <components/model/src/ome/conditions/SecurityViolation.java>`
    the exception thrown by the
    :doc:`/developers/Server/SecuritySystem` at the first hint of
    misdoings.

:source:`Principal.java <components/common/src/ome/system/Principal.java>`
    an Omero-speciific implementation of the java.security.Principal
    interface. Carries in addition to the typical name field,
    information about the user group, the event type, and the session
    umasks.

:source:`meta.ome.xml <components/model/resources/mappings/meta.ome.xml>`

JBoss-only
^^^^^^^^^^

:source:`ServiceFactory.java <components/common/src/ome/system/ServiceFactory.java>`
:source:`Login.java <components/common/src/ome/system/Login.java>`
:source:`Server.java <components/common/src/ome/system/Server.java>`


Server side
~~~~~~~~~~~

:source:`AdminImpl.java <components/server/src/ome/logic/AdminImpl.java>`
:source:`CurrentDetails.java <components/server/src/ome/security/basic/CurrentDetails.java>`
:source:`SecureAction.java <components/server/src/ome/security/SecureAction.java>`
:source:`SecuritySystem.java <components/server/src/ome/security/SecuritySystem.java>`
:source:`BasicSecuritySystem.java <components/server/src/ome/security/basic/BasicSecuritySystem.java>`
:source:`ACLEventListener.java <components/server/src/ome/security/ACLEventListener.java>`
:source:`EventHandler.java <components/server/src/ome/security/basic/EventHandler.java>`
:source:`MergeEventListener.java <components/server/src/ome/security/basic/MergeEventListener.java>`
:source:`OmeroInterceptor.java <components/server/src/ome/security/basic/OmeroInterceptor.java>`
:source:`SessionHandler.java <components/server/src/ome/tools/hibernate/SessionHandler.java>`
:source:`SecurityFilter.java <components/server/src/ome/security/SecurityFilter.java>`
:source:`EventLogListener.java <components/server/src/ome/security/basic/EventLogListener.java>`
:source:`EventListenersFactoryBean.java <components/server/src/ome/security/basic/EventListenersFactoryBean.java>`
:source:`LocalAdmin.java <components/server/src/ome/api/local/LocalAdmin.java>`
:source:`hibernate.xml <components/server/resources/ome/services/hibernate.xml>`
:source:`sec-system.xml <components/server/resources/ome/services/sec-system.xml>`
:source:`services.xml <components/server/resources/ome/services/services.xml>`

End-to-end
----------

Build system
~~~~~~~~~~~~

Security starts with the build system and installation. During the
generation of the model (by the DSLTask), a sql script is created called
"data.sql". After ddl.sql creates the database, data.sql bootstraps the
security system by creating the initial (root) experimenter, and event,
and then creates the "system" group and the "user" group. It then
creates a password table and sets the root password to "ome". (It also
creates all of the enumeration values, but that is unimportant for
security).

.. note::

    The password table is not mapped into Hibernate, and is only
    accessible via the :doc:`/developers/Modules/Api/AdminInterface`.

Client-side
~~~~~~~~~~~

To begin the runtime security process, a user logs in by providing a
Login and/or a Server instance to ServiceFactory. These types are
immutable and their values remain constant for the lifetime of the
ServiceFactory. The user can also set the
umask property on ServiceFactory\_. This value is mutable and can be set
at anytime.

The values are converted to java.util.Properties which are merged with
the properties from the \*.properties files from /etc to create the
client :doc:`/developers/Server/Context` (also known as the "application context"). The
context contains a Principal and user credentials (password etc.) which
are associated with the thread before each method execution in a
specialized TargetSource. Finally, these objects are serialized to the
application server along with the method arguments.

Application server
~~~~~~~~~~~~~~~~~~

The application server first performs one query (most likely SQL) to
check that the credentials match those for the given user name. A second
query is executed to retrieve all roles/groups for the given user. If
the roles returned are allowed to invoke the desired method, invocation
continues with the queried user and roles stored in the
InvocationContext.

Server code
~~~~~~~~~~~

Execution then passes to OMERO code, specifically to the interceptors
and lifecycle methods defined on our session beans. This intercepting
code checks the passed Principal for OMERO-specific information. If this
information is available, it is passed into the SecuritySystem through
the login method. Finally, execution is returned to the actual bean
which can either delegate to OMERO services or perform logic themselves.

Interceptors
~~~~~~~~~~~~

All calls to the delegates (and in the future all calls on the session
beans) are also caught intercepted by Spring-configured interceptors.
These guarantee that the system is always in a valid and secure state.
In stack order they are:

-  the service handler, which handles logging and checks all arguments
   against ServiceInterface annotations;
-  the proxy handler, which after execution, removes all uninitialized
   Hibernate objects to prevent exceptions (special logic allows this to
   happen See unloaded objects);
-  the transaction handler, which binds a transaction to the thread,
-  the session handler, which uses the now prepared transaction to
   initialize either a new or a cached (in the case of stateful session
   beans) session and also bind it to the thread;
-  and finally, the event handler, which performs what one might
   actually consider login. It instatiates Experimenter,
   ExperimenterGroup, and Event objects from Hibernate and gives them a
   special Token so that they can authenticate themselves later to the
   SecuritySystem and turns session read security on for the entirety of
   execution below its frame.

Services
~~~~~~~~

Finally execution has reached the OMERO services and can begin to
perform logic. Because of these layers, almost no special logic (other
than eviction and not calling write methods from within read methods.
see :ticket:`223`) needs to be considered. There are,
however, a few special cases.

**IQuery** (within the application server), for example will always return a
graph of active Hibernate objects. Changes to them will be persisted to
the database on flush.

**IUpdate**, on the other hand, does contain some logic for easing
persistence, though this will eventually be ported to the Hibernate
event system. This includes pre-saving the newly created event and the
work of UpdateFilter like reloading objects unloaded by the proxy
handler (above).

Finally, **IAdmin** is special in that it and it alone access the
non-Hibernate password data store and even access application server
APIs (like JMX) in order to make authentication and authorization
function properly.

Hibernate
~~~~~~~~~

Once execution has left this service layer, it enters the world of
Hibernate ORM. Here we cannot actively change functionality but only
provide callbacks like the OmeroInterceptor and EventListeners. The
OmeroInterceptor instance registered with the Hibernate SessionFactory
(via Spring) is allowed for calling back to the often mentioned
SecuritySystem to determine what objects can be saved and which deleted.
It also properly sets the, for a user mostly unimportant, Details object.
The EventListeners are more comprehensive than the OmeroInterceptor and
can influence almost every phase of the Hibernate lifecycle,
specifically every method on the Session interface. 

The event listeners which implement AbstractSaveEventListener (i.e.
MergeEventListener, SaveOrUpdateEventListener, etc.) are responsible for
reloading unloaded objects (and will hopefully take this functionality
fully from IUpdate) and provide special handling for enums and other
system types. There are also event listeners which are the equivalent of
database triggers (pre-update, post-delete, etc.) and these are used for
generating our audit log.

So much for write activities. Select queries are, as mentioned above,
secured through the use of Hibernate filters which add join and where
clauses dynamically to queries. For example an HQL query of the form:

::

       select i from Image i

would be filtered so that the current user does not receive references to
any objects with reduced visibility:

::

       select i from Image i where ( current_user = :root OR i.permissions = :readable )

The actual clauses added are much more complex and are added for each
joined entity type (i.e. table) which apears in a query.

::

       select i from Image i join i.defaultPixels p

would contain the "( current\_user = :root …)" clause twice.

Currently, subqueries are an issue in that the clauses do not get added
to them. This may cause consternation for some particular queries.

Security system
~~~~~~~~~~~~~~~

All of this is supported by an implementation of the SecuritySystem
interface which encapsulates all logic regarding security. It also hides
as much as it can, and if not specifically needed should be ignored.
However, before you attempt to manually check security, by all means
use the security system, and for that, it may need to be acquired from
the server-side :doc:`/developers/Server/Context`. Currently,
there is no client-side security system. See :ticket:`234`.

The :doc:`/developers/Server/SecuritySystem` and its current only
implementation BasicSecuritySystem? are somewhat inert and expect
well-defined and trusted (see :ticket:`235`) methods
to invoke callbacks during the proper Hibernate phase.

Logging in (client-side)
------------------------

When using the client library and the
ServiceFactory, logging in is trivial. One
need only set several System properties or place them in an
omero.properties file somewhere on the classpath. 
Internally, Spring takes the System properties and creates an
:source:`ome.system.Principal <components/common/src/ome/system/Principal.java>`
instance. This is then passed to the server on each invocation of a
proxy obtained from JNDI.

Logging in (server-side)
------------------------

Much of this infrastructure is not available to server-side code (no
ome/client/spring.xml, no ServiceFactory,
etc.). As such, the Principal needs to be manually created and provided
to the server-side
:source:`SecuritySystem.java <components/server/src/ome/security/SecuritySystem.java>`.

Basically it amounts to this:

::

      Principal p = new Principal( omeroUserName, omeroGroupName, omeroEventTypeValue );
      securitySystem.login( p );

This must be run otherwise the
:source:`EventHandler <components/server/src/ome/security/basic/EventHandler.java>`
will throw a security exception. 

.. note::

    The code above is being run in a secure context (i.e. you are root).   
    Please be careful.