Package ch.tocco.nice2.security.api
package ch.tocco.nice2.security.api
The APIs for the security sub-system.
The Policy
The policy can be thought of as a table of security rules. Each row denotes one rule. An example:| Selector | Action | Permission | Subject | Condition | |---------------------------|--------------|-------------------------|---------------------------|--------------------------| | `entityManager(MyEntity)` | `grant` | `create` | `someGroup, anotherGroup` | | | `entityManager(MyEntity)` | `deny` | `create` | `group3` | | | `entity(MyEntity)` | `grant` | `access(read|write, *)` | | `principal.key == owner` | | `entity(MyEntity)` | `deny` | `access(write, *)` | `anonymous` | |For each secured action, this table will be processed top-down, resulting in a conclusion: deny or grant. It first assumes deny, then changes to the specified action for each rule where all conditions are met. A rule may be declared final, in which case processing stops if that rule applies, further rules will be ignored. The selector defines the general type of the object affected by the action. The permission the exact permission, that's asked for. The currently logged in user is the principal, and finally, there may be some generic condition.
Table Reduction
Because the full table for all possible principals and all possible objects may get very big for a full-scale application, this table will be reduced whenever possible. There are two points, where some important facts get known that allow to filter out rules that won't apply anyway:* After login, the exact principal is known. At this point, a new policy will be generated for that user that doesn't contain any rules anymore that don't affect that principal. * When a guard is needed, the exact object is known. At this point, all rules that don't affect this object will be filtered out using the selector.Therefore, in practice, the policy for a concrete object will finally be relatively compact.
The Access Control Language (ACL)
The define the policy, a language called "*ACL*" is introduced. The top-level structural element of this language is the section. A section defines the selector for the following rules, until a new section is started. The section header looks like this:entityManager(MyEntity): // the rulesSo, each rule starts with the keyword
grant
or deny
, optionally followed by a list
of permissions, optionally followed by the keyword to
and a list of subjects (role
name or '&'
+ principal name), optionally followed by the keyword if
and a condition
(or unless
and a condition, which is a shortcut for if not (...)
). It is finally
terminated by a semicolon.
Optionally, a rule may end with and stop
, which declares a rule final. If a final
rule applies, processing of rules stops at this point.
This is the table above written as ACL:
entityManager(myEntity): grant create to someGroup, anotherGroup; deny create to group3; entity(myEntity): grant access(read|write, *) if principal.key == owner; deny access(write, *) to anonymous;
Keywords
The following words are ACL keywords:grant
, deny
, include
, to
, if
, unless
,
principal
, null
, true
, false
, or
, and
, not
, role
. Also, the
keyword permission
is currently reserved, but unused.
Selectors and Permissions
Selectors and permissions are written very similarily:identifier [(arguments)]
.
The identifier is the one as contributed to the security system:
@Bean
public SecurityDomainContribution infoboxSecurityDomainContribution(MyDomain domain) {
SecurityDomainContribution contribution = new SecurityDomainContribution();
contribution.setName("myDomain");
contribution.setImplementation(domain);
return contribution;
}
@Bean
public PermissionContribution infoboxDisplayPermission() {
PermissionContribution contribution = new PermissionContribution();
contribution.setDomain("myDomain");
contribution.setName("myPermission");
contribution.setId("myPermission");
contribution.setPermissionClass(my.pkg.MyPermission.class);
return contribution;
}
This defines the domain myDomain
as provided by the service MyDomain, and assigns the
permission myPermission
imlemented by the class my.pkg.MyPermission
to this domain.
The argument list will be mapped to method signatures for domains and constructors for
permissions. See the documentation of
ch.tocco.nice2.security.spi.SecurityDomain#getSelectorFactory()
and
Permission
for more information.
Method and Constructor Matching
-------------------------------Primitive Types : Numeric types are matched straight-forward. All Java rules apply for Integers and Doubles. Supported primitive types are: Integer, Long, Short, Byte, Double and Boolean, all in their primitive and wrapped version. Strings : Strings may be written in three ways:myString
,'myString'
and"myString"
. The two quoted variants support all Java escapes, the unquoted variant must follow Java's rules for identifiers. If a string matches a keyword, it *must* be quoted. Enumerations : Enumeration types are written just like strings, however, these Strings are converted: All letters to upper case, '-' will be replaced by '_', i.e'my-enum-value'
refers to the enumeration valueMY_ENUM_VALUE
. Arrays of Enumerations : Arrays of enumerations can be written by separating the enum values with '|'. A typical example is read/write access:read|write
. Varargs : If the last argument of a method or constructor is an array, it will be interpreted as Varargs. If no varargs or the wildcard are passed, the method will be called withnull
for the array. Enumeration types are never treated as varargs. For all other types, arrays are only allowed as the last argument. Wildcards : Wildcards are written as '*' and result innull
being passed to the method. They're allowed both for arrays of enumerations or varargs.
Conditions
Conditions are simple boolean critera and logical operations (and, or, not, you know that stuff). Supported operators are`==`, `!=`, `<`, `<=`, `>`, `>=` and `~=`
.
Identifiers and paths thereof (a.b.c
is a path) will be resolved depending on the
object being checked. For example, in entities, relations and fields will be used.
The special identifier principal
may only occur as the first path element and
refers to the principal of the current security context. The second path element will
be resolved using the Principal's attributes, except name
(the Principal's username)
and key
(the Principal's primary key). All further path elements will be resolved
using the bean introspection.
Date Conditions
The keywordnow
specifies the current date/time. It's fields are actually operators
which operate on that object. These can be combined freely, e.g. now.yesterday.date
means yesterday at 0:00.
The following "path elements" (operators) are available:
date : Keep the date as-is, set the time to 0:00. time : Keep the time as-is, set the date to January 1st, 1970 tomorrow : Plus one day. yesterday : Minus one day.
Includes
ACL files may include other ACL files. The syntax for this is:
include 'another-resource.acl';Important: An
include
statement will end the current section! This is an error:
entity(*): grant access(*, *); include 'another-resource.acl'; deny access(write) to anonymous; // ERROR: No section header
-
ClassDescriptionThe
Guard
protects a single object.The result of a permission evaluation.Provides additional functionality for custom guard implementations, like access to the current principal and security context as well as the ability to evaluate conditions.A contribution which enables other modules to inject customGuard
implementations to enable custom security behaviour for certain objects.Provider for implied roles.Exception thrown by theSecurityManager
when the policy validation fails.Represents the permission to perform a certain operation.A set of rules.Result object of aPolicyValidator
.The principal represents a user.Interface to the principal store.A principal's role.Represents a single rule in the policy.Rule.Key<T>The security context of the current principal and factory forGuard
s.Factory forSecurityContext
s.Utility methods dealing withPrincipal
andSecurityManager
.Exception thrown when the permission for a certain operation is denied.