Skip navigation links

Package com.goldencode.p2j.security

Implements a set of classes  that control application access to abstract resources and manage security credentials.

See: Description

Package com.goldencode.p2j.security Description

Implements a set of classes  that control application access to abstract resources and manage security credentials.

Author
Nick Saxon
Greg Shah
Date
October 14, 2011
Access Control
CONFIDENTIAL

Contents

Introduction
Participants
Definitions
Requirements
Security Context
Process Context
User Context
Group Context
Using Security Context
Creating and Switching Contexts
Maintaining State Information
Authentication
User Authentication
User Authentication Hook
Process Authentication
Programmatic Authentication
Special Case: Router/Server Authentication
Special Case: Remote User Authentication
Resources
Abstract Resource
Resource Plugin
Resource Type Name
Resource Instance Name
Resource Access Rights
Primitive Directory Service Data Types
Rights Field Description
Field Object
Security Database
Subject Identification
Access Control Lists
Shared Access Control Lists
Server-specific Access Control Lists
Arbitrary Account Extensions
Access Rights Check
Application Calls
Security Manager and Resource Plugin Interaction
Using Expressions in Access Rights
Hierarchical Resources
Builtin Resource Type "system"
Auditing
Configuration
Directory Service Interface
Security Manager Directory Hierarchy
Bootstrap Configuration
Client/Application
Server
Manageability
Editing Security Database
Thread Synchronization
Debugging
API Summary
Interfaces
Classes
Security Manager Variables
Variables
Functions
Appendix A. Security Utilities

Introduction

This package provides application level security for the P2J environment.  It is important to understand that this kind of security solution is not, and cannot be, make up for poor operating system level security.  Application level security is a means of protecting application data and logic from unauthorized access or modification in a multiuser environment.  This protection is the result of the cooperative efforts of all trusted components of the P2J environment.   Although in theory there should be no truly untrusted components, not all components of an application can be equally trustworthy.  Even though it is impossible to insulate them from each other, some layering of the code and internal checks are made to minimize the consequences of a potentially malfunctioning component.

Participants

A P2J code typically runs as one or more multi threaded servers, listening on predefined ports for incoming TLS connections from remote processes.  The components of P2J concerned with security run on the server side.  They are the Security Manager, resource plugins and transactions.  A directory service is a separate component of the server which provides the Security Manager with access to security relevant data storage.

Remote processes may be either P2J utilities (called P2J applications or simply applications), which do not represent any particular user or clients that the users may use to authenticate themselves and then perform some transactions.   Remote processes may make TLS connections to the P2J servers using a known certificate or anonymously.

A server may have permanent daemon threads, transient threads, one or more listening threads and a pool of worker threads.  The worker threads serve incoming requests on behalf of connected and authenticated users.

Definitions

The security model is based on these concepts:
Security subjects are either applications or users.  Authentication is a process of verifying that subjects are whom they claim to be.  Authentication is not always required. In some cases a subject may remain anonymous.   Anonymous subjects are also associated with a security context and may have ACLs permitting some actions on some resources.

It is application or client code that decides whether or not to authenticate a subject with the server.  The authentication process is not hard coded to some algorithm.  A generic authentication hook can be created and installed with the server to perform some form of authentication.

Users can be grouped for the purpose of easy access rights management.  A group is a collection of users sharing a set of ACLs.  Users may participate in multiple groups.  The security context for such users has references to all relevant groups.

The Security Manager is a code layer that manages security contexts and ACLs and cooperates with the resource hooks when they produce access decisions.

Each resource hook is a pluggable module that encapsulates all the knowledge about a category of application resources.   This knowledge includes:

Requirements

The security model should allow:

Security Context

A security context is a set of objects created and maintained by the Security Manager that are associated with server threads and that identify each thread's rights with regards to application resources.  A security context is accessible through a ThreadLocal object and is not visible outside the Security Manager.  The security context is made of a process context, a user context and group contexts.  This fact is reflected with this notation: {process, user, group}.

When a new thread is created, there is no security context associated with it.  The thread may do other work, but it cannot request services from the Security Manager unless a security context gets created and assigned for it as the result of a special API call.  Once created, the security context remains associated with the thread for its lifetime, if no special action is taken to change that.

Process Context

Process security context represents the client process as a subject to the Security Manager.  The only method of authentication of the client processes is through the use of TLS certificates.  There are three possible states of the process security context:
If there is no process security context, this component cannot pass access right checks.  This is the common starting point for all server threads.

Anonymous TLS connections create an anonymous process security context.  Certified TLS connections create named process security contexts.  The rights these contexts define are the function of appropriate ACLs.  Once created, the process security context is associated with a numeric ID and never changes.

User Context

User security context represents the user of the client process as a subject to the Security Manager.  The user has to be authenticated with whatever method the authentication hook provides for the user security context to be created.   Similarly, as soon as the user signs off, his or her user context gets deleted.

Group Context

Group security context is just a convenience.  If the user is assigned to one or more groups, the creation of the user security context triggers the creation of the group security context for every group the user is assigned to.  So, in general, the group context is a set of zero or more objects, one per group.  For convenience, this document always refers to an existing group context as long as there is a user context.

Using Security Context

All server threads start with no security contexts.  Any security related API call, besides the call that creates the context, fails immediately if called from a thread without a security context.

As any access to the controllable application resources is done only after access rights check, the application should call one of the available check methods that the resource type plugin provides, passing the resource name and (optionally) access mode.  The resource type plugin in turn calls the Security Manager and asks the first ACL to be read.

The Security Manager obtains the security context for the calling thread from the ThreadLocal object.  Besides the case where no security context exists and the Security Manager returns a failure immediately, the following cases are possible:
  1. process context, no user context, no group context: {process};
  2. no process context, user context, group context {, user, group};
  3. process context, user context, group context {process, user, group}.
In the case 1, process context is the only context that can be checked.  In the cases 2 and 3, the user context is checked and the process context is not.  In other words, the system adjusts to the user rights for the user logon session, and to the process rights otherwise.

Group contexts make sense only if the user context is present.  In such a case, multiple contexts are chained for the access checks.  It is the resource type plugin that makes the decision.  If the returned ACL allows or explicitly denies access, no further checks are made.  Otherwise, the plugin should request the next ACL in the chain.  'No more ACLs' condition is treated as 'access denied'.  This means that all resource plugins must be written such that they deny access by default.

Creating and Switching Contexts

The server threads concerned with servicing of incoming requests are either listeners or workers.  When they start, they create an initial security context indirectly when they call some com.goldencode.p2j.net package method depending on the nature of the thread.  Ultimately, this resolves into a call to the setInitialSecurityContext() method.  Only a known method in the com.goldencode.p2j.net package is allowed to call a Security Manager API that creates the initial security contexts.

The initial security context is made of a process security context only: {process}.  This is the security context the server threads use when listening for incoming connections or waiting in the thread pool.

When a request comes that opens a new P2J session, a thread in the com.goldencode.p2j.net package is spawned to accept the connection.  This thread calls the Security Manager API pushAndSwitchSecurityContext(Object) to push its initial security context on stack and create a new one, which corresponds to the client's end of the connection.  The client's security context is determined by the nature of the TLS connection as follows.  This thread then initializes the networking components of the com.goldencode.p2j.net package and starts those components.  From there, all incoming requests on that active connection are read by the com.goldencode.p2j.net.Dispatcher which implements a thread pool that services incoming requests.

If the TLS connection is anonymous or certified with an application certificate, the client's security context is {process}.  If the TLS connection is certified with an user certificate, the client's security context is {, user, group}.

A session established under {process} security context, may authenticate a user later and become {process, user, group} by calling a Security Manager API.  However, this feature is not planned for implementation this time.  Neither session established under {, user, group} security context nor session having {process, user, group} security context after having authenticated a user, can change individual components of the context.

These rules limit possible security context transitions to improve security.  Briefly, they can be summarized as follows (client security context only):
When com.goldencode.p2j.net.Dispatcher threads are done with servicing a request, they return to the pool and have to reset their security contexts back to the initial state.  They do it by calling a Security Manager API that pops the client's security context off the stack and restores the initial server security context.

This is the summary of the server <--> client security context transitions:
There are no valid transitions between two server security contexts.  In other words, threads cannot change their process contexts at will.

When a request comes that continues an existing P2J session, a thread from the pool should assume the security context of the client associated with the session.  This is the same action in the thread, although the Security Manager does not create a new security context in this case.

There is a tight connection between the P2J protocol (com.goldencode.p2j.net package) managing client sessions and the Security Manager mapping those sessions into security contexts.

Maintaining State Information

The P2J runtime environment and applications may need to maintain some state information for the lifetime of the session. The old proven method of keeping that state information on a per thread basis would fail in P2J environment, as the Dispatcher assigns arbitrary threads from its pool to perform elementary requests.  The right place to keep state information is the security context, because it is preserved for the lifetime of the session.

Security Manager provides convenient methods to query, add, get and remove pieces of state information associated with the current security context. The state information is organized into named tokens. A token is any kind of object. Names are arbitrary. The only requirement is not to use names starting with "system" in applications. Names starting with "system" are reserved for the runtime components and are protected from the accidental use in applications.

Authentication

User Authentication

All methods of user authentication are categorized as follows:
User TLS certificate based authentication means clients use user certificates to establish TLS connections to the server instead of no certificate or an application certificate.  There potentially is some client side code and definitely server side code to manage this type of authentication.

The client side code is optional in the sense the server can function with or without it.  The client side prepares the user certificate before it can be used for making the TLS connection.  As the user certificates are normally kept in the same keystore where the private keys of their respective owners are, they constitute pieces of important security information that must be protected.  A typical form of protection for user certificates is either using portable storage, symmetric password encryption or a combination of both.  The client side is responsible for finding the proper certificate file, prompting the user for the password and for decryption of the certificate.  Then the TLS connection is made and the server authenticates the user based on the user certificate.

The P2J directory should contain a valid user account, which is identified using the certificate as follows:

Password based server side authentication means clients merely send passwords over an already established TLS connection, which provides a secured transport.  There are both client and server sides  to manage this type of authentication.  The client side code prompts the user for the password and sends the user ID and password over the link.  The server side receives them, calculates a hash and compares the result with the security data from its database.

Combined certificate and password authentication is just the combination of the previous two.  The user's entry in the keystore (private key and certificate) has to be decrypted with a password first.  Then, the password is sent over the link along with the user ID for the server side verification.

Distributed authentication means anything more sophisticated than password based authentication.  It definitely includes both the client and server sides, which may exchange some information over the secured TLS link before authentication completes.  This type of authentication normally involves some kind of biometric device or physical security token like magnetic card reader, smart card reader etc.

In all cases, some startup code on the client drives the process and some listener thread on the server responds to it.   The flow of control is described below.

Client
Server

As part of initialization, the server calls getServerTransportSecurity(AuthUIHelper) method, which returns an instance of the TransportSecurity class, embedding KeyManager and TrustManager objects.  The KeyManager manages the server's certificate and private key.  The TrustManager manages the certificates of the root authorities and, possibly, individual certificates of clients and other servers.   All this information comes from the P2J directory.

The Listener creates a secured socket based on the TransportSecurity class and waits for incoming connections.
The Startup code wants to create a new session and calls the Security Manager's getClientTransportSecurity(AuthUIHelper) method.
The getClientTransportSecurity method returns an instance of the TransportSecurity class, embedding KeyManager and TrustManager objects.  The KeyManager manages the client's certificate and private key.  The TrustManager manages the certificates of the root authorities and the known server(s).  This information comes from the bootstrap configuration.
The Startup code establishes a secured TLS connection with the server, using the bootstrap configuration and the TransportSecurity class.

The Listener accepts the connection, gets the server side socket for it and calls the Security Manager's authenticateLocal(SSLSocket) method.
The Startup code calls the Security Manager's authenticateClient(SSLSocket, AuthUIHelper) method.   Security Manager verifies the server's certificate and terminates the connection if verification fails.  The verification procedure is identical to what is described in RFC2830, section 3.6.

Both ends of the connection are temporarily under control of the Security Manager.
Security Manager waits for a message from the server.
Security Manager queries the database service and finds out the general authentication mode.  The general authentication mode tells what type of client authentication is acceptable and, optionally, includes some additional configuration data like class name.  Security Manager transmits the requested authentication mode and parameters down the link and waits for the authentication input.
Security Manager receives the requested authentication mode and, depending on the authentication mode, either performs requested action directly or calls the authentication hook.  The authentication message is sent to the server.  The client waits for the authentication result.


Security Manager verifies the authentication input, produces and sends the authentication result.
Security Manager receives the result.

Security Manager relinquishes control of the link on both ends.  If authentication has failed, the connection is terminated.

authenticateLocal(SSLSocket) method returns a unique context ID (which is a reference to a JVM object) that may be used as a key to security context switches later.

Notes
  1. TransportSecurity class is a singleton.  Multiple TLS connections are allowed.
  2. The AuthUIHelper is an interface that hides all user interface related actions from the Security Manager.  Such actions are asking the end user for used ID and password, if requested by the server.  This interface provides methods that return needed pieces of input to the Security Manager.
  3. The security database has a global authentication mode configuration parameter, as well as optional per user ID overrides. The global authentication mode parameter is used for all connections where no client certificate is presented. Otherwise if the override exists for the client it is used instead.
  4. Briefly, the authentication related exchanges between the peers are:
    Client
    Link
    Server

    <--
     authentication request
    authentication message
    -->


    <--
    authentication result
A shorter form is allowed in special cases. This shorter form is:
          Client          
Link
Server

<--
 authentication result

Sometimes, the server can produce a decision based on the peer certificate.  If this is the case, the authentication result is sent immediately.  There are known cases when it happens:
  • the server successfully authenticates another server by its certificate;
  • the server rejects a connection due to a bad certificate presented by the peer;
  • the server rejects an anonymous connection if they are not allowed by configuration.
In some cases, it is desirable to be able to retry the authentication without terminating the connection. This makes sense for the authentication types that involve typing passwords. This feature is fully controllable by the server. In case the server allows retries, the authentication result indicates "retriable failure". The client has a choice of reзуфештп the authentication messages exchange as indicated above, using the existing conneciton or terminating the connection.

User Authentication Hook

As can be seen from the previous sections, the user authentication is in general managed by two communicating pieces of code.  The security module is designed to provide user authentication as a configurable feature.  The user TLS based and the password based authentication modes are implemented as built-in features.

Whether the built-in authentication feature is used or not is defined in the authentication mode.  If it is not one of the first three choices discussed in the previous section, then it has to be a name of a class that implements authentication.  This class is known as an authentication hook.

An authentication hook is a class that implements the Authenticator interface.  The built-in authentication modes implement this interface.  The basis for custom logic in the authentication hook is that the both sides of the connection are given a chance to run the specified class and use the secured connection to communicate with each other.

Authentication hooks can be dynamically downloaded from the server. The server first reads the class data for the specified hook class. If no such class exists, the server tries the original name concatenated with "Client" and "Server". This is done to support single class hooks (e.g., CustomHook.java) and separate hooks (e.g., CustomHookClient.java and CustomHookServer.java).  Separate hooks are useful when the client side has little to nothing in common with the server side. This is anticipated to be typically the case, since the client side is responsible for the UI.

Process Authentication

Process authentication occurs when a remote process creates a TLS connection to the server.  If the TLS connection is established with the remote process' certificate verification, the identity of the application is confirmed on the server.  If there was no certificate presented, the application remains anonymous.  The server can be configured to reject anonymous connections or to accept them and associate special rights with the process context.

The listener thread on the server is always prepared to get an application's certificate, but from the TLS (industry standard) perspective it is optional.

The overall procedure for process authentication is the same as for a user, with the following remarks:
Process authentication is based on X.509 certificates and PKCS#8 private key information. Both are normally kept in a keystore or separate keystores which are encrypted.  Thus, to be able to get to those entries, the program has to present keystore password(s).  There are normally two levels of passwords. The keystore level decrypts the whole keystore. After that, a specific entry may require its own password.

Embedding a password into a Java program is almost as weak as listing it in a text file.  This is something to avoid if possible.  The class file format is easily read by javap or many other tools.  However, providing password based encryption for process keystores is just an additional optional feature of process authentication that can be handled by the generic idea of the AuthUIHelper.  This approach concentrates the decision making about how to get passwords in one well defined place. This class is free to implement any policy that seems appropriate - ask the user, for instance. However, there may be cases, where ANY user interaction is impossible (for example, in a process authentication).  Note that given a server's access to some secure storage without embedding credentials in the program, the AuthUIHelper could be programmed to handle such a case.

Programmatic Authentication

Programmatic authentication is intended for use with special client applications, that require custom user interface for getting the user ID and password. One such application is the Admin Client.

Essentially, the programmatic authentication is the user ID + password type. However, since it is a weeker authentication compared to the certificate based ones, the server only allows it for specially configured user accounts.

To authenticate the session programamtically, the client application should prepare a bootstrap configuration object and set the following keys:

      setConfigItem("security", "authentication", "type", "program");
      setConfigItem("access", "subject", "id", id);
      setConfigItem("access", "password", "user", pw);

The server side requirements for the account associated with the given user ID are:
When all these requirements are met, the programmatic authentication succeeds. The application may use any suitable method to get the user ID and password from the end user.

Special Case: Router/Server Authentication

In a routed network case, one server, performing a routing function, needs to connect to another server.  In this configuration, the originating router establishes a TLS connection with the target server as a certified process.  The TransportSecurity class on the server can be used to create outgoing TLS connections as well.  This technique authenticates this server as a certified process on the remote server.

Special Case: Remote User Authentication

As the addition to the previous section, the local router as a certified server process, may ask a remote target server to create a security context on behalf of a local client.  This cannot be based on the procedure described above.  A different procedure exists for this case:
This description is accurate only as far as the Security Manager is concerned.  Refer to the P2J protocol (com.goldencode.p2j.net package) description for details about routing.

Resources

As noted earlier, the notion of resource is an abstraction the Security Manager has very little to do with.  It is up to application code and to the resource related plugin code to agree on the rules of the resource naming and access rights.

Abstract Resource

Every time the application reaches an important point in the execution where it is required by application logic or security policy to check the user's rights before the application may proceed, we say the application is about to check the user's access right to some resource.  Resources exist only because applications name them and want the Security Manager to check if the user has enough rights to continue.

This abstract and, consequently, very generic nature of application resources dictates the need for a pluggable resource architecture.  These are the main architectural concepts of the abstract resources:
The listed concepts allow for a flexible and effective implementation of resources that can be easily extended to include new types.

Resource Plugin

A resource plugin is an implementation of an abstract resource.  Methods of the plugin class can be called from the Security Manager and from the application.

The com.goldencode.p2j.security.AbstractResource class is a partial implementation of the abstract resource.  This class implements  the Resource interface.  The methods from this interface are called by the Security Manager.  They are:
passes the instance of the SecurityManager class to the plugin
returns unique type name of this category of resources
reports the assigned resource type ID back to the plugin
returns an instance of a library class for the plugin's own symbol resolution if the plugin exports any variables or functions for use in expressions, otherwise null.
returns an array of Description objects which report the details about every field of the access rights specific to the plugin
returns an instance of the Rights interface constructed using the given array of Field objects
verifies if a given string is a syntactically valid resource instance name for this category of resources
verifies if the given parameters make a valid access rights set for this category of resources

A concrete implementation of a resource plugin has to be an extension of the AbstractResource class.  This guarantees that anything that has to be programmatically enforced, can be coded as a final method in the base class.

At server startup, the Security Manager reads the resource plugins configuration, instantiates the plugins in turn, and calls getTypeName(), getLibrary(), registeredAs(int) and describeRights() methods to create a registry of resource types.  This is how the plugins become known components of the security model.  Other methods are discussed later.

The application calls those methods of the resource plugin, which are made specifically for the access rights check.  As both the plugin and the application know what they mean, the application can call them directly.  They are all methods of the plugin class.  The application typically passes the resource instance name and the method itself knows what to check.  Sometimes a more generic method is implemented and both the instance name and the requested access rights are passed as parameters.  The interface between the plugin and the application is up to the plugin implementors.

This is an example.  A plugin called DatabaseResource has a method static boolean canSeeTable(String tableName) which the application calls somewhere as DatabaseResource.canSeeTable("customers").

Resource Type Name

The resource type name is a string that uniquely identifies this type of resources.  When the Security Manager calls the getTypeName() method, it checks the registry for duplication.  If no duplication found, the Security Manager assigns a numeric resource type ID to this plugin and calls its registeredAs(int) method.  The latter lets the plugin know the Security Manager's assigned resource type ID.  During application calls for access rights checks, the plugin uses the resource type ID as a parameter for all Security Manager method calls.

Resource Instance Name

The application uses a resource instance name as a convention with the resource plugin.  This name is used during an access rights check procedure to associate an ACL with the request.  It is up to the plugin implementors to introduce instances of the resources and name them.

Resource Access Rights

Resource plugins encapsulate all knowledge about what subjects can do with the resources (actions).  The exposed part of this knowledge is a set of methods that the application can call.  The hidden part of this knowledge is the encoded access rights.  The rules of this encoding are shared between all instances of the resource.  In other words, the data structure of access rights is associated with a resource type rather than with a specific instance.

For the external world, the access rights are visible as a sequence of fields in an ACL.  Neither the number nor the interpretation of the contents of those fields are known to the Security Manager upfront.  To deal with it, the Security Manager expects the resource plugin to provide:
The Security Manager gets a reference to the Rights interface no matter what plugin it calls, so it can handle the access rights uniformly.

The Rights interface does not contain any methods.  The implementing class, however, is something specific to the resource plugin, and may implement methods as it seems appropriate to the plugin implementors.
Primitive Directory Service Data Types
As it is the Directory Service that manages storage of security relevant configuration information, the rest of P2J relies upon the set of primitive data types which the Directory Service can process.  The following is a full list of primitive data types used in the Security Manager:
Rights Field Description
Plugins have to provide enough information about the fields of their access rights so that:
The way of describing the fields of access rights is through the use of the Description objects. A Description object contains information about:
Field labels must be unique within the plugin as they are used to map fields into the P2J directory.
Field Object
Field objects are used by the Security Manager as an intermediate step in creating instances of Rights. Rights are used in access rights checks and in P2J directory administration.

To instantiate a Rights object, the Security Manager uses the array of Description objects.  For every Description in the array, the corresponding instance of a field object is created.  A field object is a ready to use copy of an access rights field from the P2J directory.  The type of a field object depends on the implementation of the primitive data type.

Fields marked as optional may have no associated value.  The null reference is used in such cases.

Security Database

The security database is a collection of records that identify the subjects (applications, users and groups) and define what actions on abstract resources are available for what subjects.

Subject Identification

All clients and servers are collectively known as application subjects.  Users, user groups and application subjects are collectively known as security subjects, or just subjects.

Subjects have identification in form of accounts.  For simplicity, all accounts are required to have unique names.  If this becomes too much a limitation, the internal account names may be constructed with prefixes like 'app', 'user', 'group' followed by the external names.  These names are externally visible subject IDs.  Accounts associate subject names and other pieces of information like certificates and keys.

When the server starts up, the Security Manager initialization code scans the security database for all defined subject IDs and assigns unique temporary numeric IDs.  This scan also reveals any possible subject name duplication.  The numeric IDs are valid only for the lifespan of one server run.  There is no need to preserve numeric IDs between server runs.

Numeric IDs are positive integers.  One of the assigned IDs represents the unidentified application subjects on the other ends of anonymous TLS connections.  This one is also called the guest ID.  There must be an associated guest account defined in order to allow anonymous connections.

Access Control Lists

The remaining part of the security database is dedicated to the access control.  The rules that define the relationship between subjects, resources and allowed actions are formed into Access Control Lists, or ACLs.

Because there are more than two entities involved, the ACLs may be represented in many different ways.  The representation introduced below does not claim to be the best ever.  There cannot be just one best representation.  It is believed, though, to be a very good fit for the class of applications where P2J belongs.

Although technically it is stored as a tree of keys in the P2j directory, logically it can be represented as one "file" that defines all ACLs.  The top level structure of the file is made of sections with every section describing one abstract resource type:
 Type "system"
ACLs for the resource type "system"

Type "database"
ACLs for the resource type "database"

...
For every configured abstract resource type, there may be zero or one section.

Resource type sections are divided into access rights subsections.  There must be at least one subsection, otherwise the whole abstract resource type section should be omitted.  The rights statement encodes the specific rights as a sequence of fields, as described in Resource Access Rights.
 Type "database"
Rights 4096, 1024, "true", 1
ACLs that share the rights above
Rights 4096, 1024, "false"
ACLs that share the rights above
...
Further, following the access rights is one or more groups of two statements: subjects and resources.  The subjects statement lists the subject names that have the rights defined above with respect to the resources defined here.  There must be one or more subject names. 

The last subjects statement for the subsection is allowed this special form: all_others.  This means that all subjects not mentioned in the previous statements of this subsection fall into this category.

The resources statements name instances of the resource exactly, or specify regular expressions for a set of matching instance names.  Due to this matching capability, the order of definitions is very important.  The lookup happens in the order the instances appear in the ACL.  The first matching entry wins.

Here is a sample section:
 Type "database"

Rights 4096, 1024, "true", 1

subjects u1, u2, g1
resources instance "abc"

 subjects u3, g2
resources instance "xyz" match "ab[0-9]"

Rights 4096, 1024, "false"

subjects all_others
resources match "ab."

Rights 2048

subjects all_others
resources instance "xyz"
As externally defined in the P2J directory, the ACLs are not suitable for quick access.  The Security Manager needs to do some translation.  This is done at startup.   The whole ACL definition is read and parsed.  During this process:
This internal representation of the ACLs is optimized for the frequent access rights checks.  The lazy approach shortens the startup time but defers problem discovery, whereas the up front approach takes more time at startup but guarantees validity once it is done.

The following illustrates the translation done by the Security Manager using the sample ACL.  The first step is to create triplets {rights, subjects, resource} keeping the order of definitions.
    Rights 4096, 1024, "true", 1
subjects u1, u2, g1
instance "abc"

Rights 4096, 1024, "true", 1
 subjects u3, g2
instance "xyz"

Rights 4096, 1024, "true", 1
 subjects u3, g2
match "ab[0-9]"

Rights 4096, 1024, "false"
subjects all_others
match "ab."

Rights 2048
subjects all_others
instance "xyz"
The second step is to regroup the triplets under the resource instance/match.
   Instance "abc"       
subjects u1, u2, g1
rights 4096, 1024, "true", 1

Instance "xyz"
 subjects u3, g2
rights 4096, 1024, "true", 1

Match "ab[0-9]"
 subjects u3, g2
rights 4096, 1024, "true", 1

Match "ab."
subjects all_others
rights 4096, 1024, "false"

Instance "xyz"
subjects all_others
rights 2048
The third step is to merge triplets displaying the same instance/match ("xyz" in the ACL shown).
Shared Access Control Lists
The shared ACLs are defined in the P2J directory under a well known path, /security/acl. At startup, the servers search this path first and load all ACLs defined there, unconditionally.
Server-specific Access Control Lists
The server-specific ACLs are defined in the P2J directory under a different well known path, /security/acls/server-ID where the server-ID portion is variable. At startup, the servers search this path for a node with the server-ID name matching the server's ID. If such a node exists in the directory, all ACLs defined under it are loaded, too.

Arbitrary Account Extensions

The subject account structure is predefined and cannot change easily. However, there may be a need to associate some extra piece of information with the subject account, which is application-specific. The Arbitrary account extension feature covers this need.

An application may attach a named instance of a typed variable to an account. The supported types are:
These types correspond to the standard directory object classes. Applications are allowed to set and get the extension data by its name and by subject ID, within the extent of rights granted by the directory resource ACLs.

To use this facility, please see the setExt<type>() and getExt<type>() methods in SecurityManager (for example, SecurityManager.setExtInteger()).  These methods read/write the backing values in the /security/<server_id>/users/<userid> container in the directory (which is the same container used to store the standard P2J account-specific security configuration).

Access Rights Check

The access rights are checked when and where the application wants them to be.  So, everything starts with an application call.

Application Calls

Application calls directly into a resource plugin to check access rights.  It does not have to specify the subject, because the Security Manager figures out the subjects involved from the security context of the calling thread, but that happens later.  It only specifies:
It is important to note, that the security model does not provide an access rights check for third parties.  That would be the case if a security subject X wanted to check if a security subject Y could do some action on some resource.  It does not mean, however, that this support cannot be implemented, if required.

This is an example.  A resource plugin called DatabaseResource provides a method static boolean canSeeTable(String tableName).  The application calls it from somewhere as DatabaseResource.canSeeTable("customers").  The reference to DatabaseResource implicitly specifies the resource type.  The resource name is given explicitly as "customers".  The action is specified implicitly through the method name canSeeTable.  The same hypothetical plugin could have provided another method like checkTableAccess(String tableName, int accessMode) where the requested rights would have been explicitly coded as a method parameter.

The plugin implementation decides about the interfaces.  Typically, a single call to static getInstance() method is used to get a reference to the plugin instance, which is a singleton, and then call instance methods using that reference.

Security Manager and Resource Plugin Interaction

The first link in the chain is the called method in the resource plugin.  It should normally collect all the needed pieces of information and further call a shared private worker method to do the rest.  These pieces of information are:
The worker method calls some methods of the Security Manager to do its job in a predefined order.  Those calls throw a security exception if the calling thread has no security context.

First of all, it checks to see if the Security Manager has a cached decision for the case, by calling the getCachedDecision(int resourceId, string instanceName, int mode) method of the Security Manager.  The mode parameter is a value that should consistently map all possible requested rights into integers.  This call returns either null or a Boolean.  The null simply means there is no cached decision, otherwise the Boolean conveys what has to be returned immediately.

The cached decision can be safely ignored should the plugin decide so.  If it is honored, the check is done and the boolean result is returned to the application.

The next step is to initiate the ACL search by calling the openRightsSearch(int resourceId, string instanceName, int mode) method.  This call makes the Security Manager discard any existing cache entry for the case, look up the security database and create a temporary list of references to Rights objects and insert the list into the list of open searches together with the search parameters {resourceId, instanceName, mode}.  This call returns an integer which can be considered the search handle.  The Rights objects selected to the list are the result of applying the security context check policy to the ACLs.  The number of the objects and their order complies with the policy, as described in Using Security Context.

The next step is a loop, where the plugin gets the next Rights object from the list, interacts with it and then either breaks out of the loop or continues until the list is empty.  The plugin has to be prepared to receive no Rights objects at all as a valid case.

To get the next Rights object from the list, the plugin calls the getNextRights(int handle) method which returns either Rights or null.  Once an instance of the Rights object is obtained, the plugin is free to utilize any custom interface that may exist to get the rights evaluation done.  It is up to the plugin to decide where, when and if to break out of the loop or continue checks.  One particular case is worth mentioning.  If the plugin decides to provide a so called negative permission or veto, this is how it can be implemented.  A negative permission means the access is explicitly denied and no other checks are to be made.  The plugin simply breaks out of the loop to implement it.

Once done with the loop (no matter how), the plugin is required to close the ACL search.  This action has two effects.  By calling the closeRightsSearch(int handle, boolean decision, boolean cache) method, the plugin  tells the Security Manager to do the necessary cleanup and, at the same time it posts the final decision and whether the Security Manager should cache the result or not.  The Security Manager destroys the temporary list of the Rights object and removes the associated item from the open searches list.  If caching is requested, it turns this item into a cache entry.

The decision whether to cache or not is left to the plugin.  Some resources may implement rights checks that depend on external parameters which the Security Manager has no clue about.  A typical case is the time of day dependency.   Caching makes perfect sense in case of no external dependencies.  In general, if the result of the check depends only on the security subject, resource instance name and requested rights - it is a good candidate for caching.  If such a check is made frequently, then caching is almost a must.

Please note that it is a valid situation to have some initial access rights check initiate another check internally.  In other words, nested security access checks are completely valid.  The Security Manager is prepared to handle such situations.  A good example is a hierarchical resource, where an original check from the application may cause the plugin to issue other checks for parent resources in a hierarchy.

Using Expressions in Access Rights

Using expressions in access rights is a way of having a highly customizable access rights check procedure.  The power of expressions comes from their ability to refer to various pieces of information, referred to as variables, and even custom logic, referred to as functions.  There are two major category of variables: those provided by the Security Manager and those that come from the plugin.  Functions are provided by Security Manager and may also be provided by resource plugins.

The names for variables and functions are scoped to avoid clashes.  These are the rules:
The Security Manager provides variables that refer to:
The Security Manager provides functions that:
Both lists may grow in the future.

The Security Manager offers the use of expressions through an API.  It is up to the plugins to decide whether they implement expressions or not.

Expressions may be used in access rights in one of the following ways:
The Security Manager architecture allows all these cases.  The use of an expression is a two step process.  The first step is the expression compilation, which is relatively expensive work but which is only done once per unique expression.  The second step is expression evaluation, given instances of the variables.  Due to the expression engine implementation logic, there is no penalty in recompiling an expression as long as the string representation of the expression and the associated symbol resolver class do not change.

With this in mind, the three expression use patterns listed above translate into the following coding patterns:
The plugin implementors should strive to design the access rights check procedures to use static expressions (if any) for resources with a high frequency of checks.

Although the expression engine classes are public and can be used directly from the plugin code, it is not recommended as the Security Manager's pool of variables will not be available.  This is the implementation plan for the expressions in a resource plugin:
  1. The plugin's class implements an inner class which is the symbol library. Only one instance of this class will be required. It can be created either from the plugin constructor or in the getLibrary() method.
  2. The exported variables may be of the type long, boolean or String. Every variable is implemented as a method named getVariableName or isVariableName without parameters, where VariableName matches the variable name and is case-insensitive. The type of the returned value of the method determines the type of the variable.
  3. The exported functions may be of the type long, boolean or String. Every function is implemented as a method named getFunctionName or isFunctionName with parameters, where FunctionName matches the function name and is case-insensitive. The type of the returned value of the method determines the type of the function.
  4. The access rights check code calls one of the compute() or evaluate() method of the Security Manager passing it an instance of Rights that supplies the backing data.
  5. Security Manager calls associate(Rights) method of the plugin to make a temporary association of the Rights with the library. The plugin stores the reference into a thread local object to avoid multithreading problems. The final implementation of this method is provided in the AbstractResource base class.
  6. Expression engine calls library methods whenever necessary and those use the associated Rights object to produce values for variables and functions. Methods can use getRights() call to get to the Rights object.
  7. Security Manager calls disassociate() method of the plugin to break the temporary association of the Rights with the library. The plugin nullifies the reference to help let that instance go. The  final implementation of this method is provided in the AbstractResource base class.
  8. The result of the expression evaluation is used in decision making.

Hierarchical Resources

Some resources naturally group into hierarchies like trees.  A well known example is the UNIX-like filesystem.  With regards to access rights checking, this natural hierarchy may help simplify the rights definition by utilizing the concept of inheritance, also called propagation.  Although there may be various interpretations of the concept, the regular convention is to say that a node or a leaf in the tree inherits an attribute (the access rights in this case) from its parent node if no attribute is attached to this node or leaf explicitly.  It does not matter whether the parent node has an explicitly attached attribute or inherits it in turn.

This concept simplifies the ACLs definition because the vast majority of nodes and leaves in the tree can be described with just a few generic inheritable rules and exceptions described individually.

The Security Manager design makes it possible.  Again, it is up to a resource plugin to introduce a hierarchical relationship between instances of the resource type.  There are no changes needed to the ACLs nor to the access rights design. The only thing that is different for a hierarchical resource, is the logic of the access rights check.

Let's assume there is an instance named "/a/b/c" with no ACL defined, and another instance "/a/b" with the rights defined as X.  The application issues a check like canUpdate("/a/b/c").  The Security Manager returns an empty list of ACLs as the result of a call to the openRightsSearch.  Now the resource plugin can issue an internal check for the parent resource: "/a/b".  This check returns the rights X, so the only thing that is left to do is to use X as if it was returned for "/a/b/c".

Builtin Resource Type "system"

This abstract resource allows applications to provide controllable access to the P2J system.  As of time of this writing, here are the following well known instances of this resource type:
The logon instance represents the abstract ability to log onto the P2J system.  Authentication procedure checks the subject's access rights on the logon instance and only allows logon if the check succeeds.  This resource instance allows for a very flexible control over the logon availability. 

The context instance helps in auditing of the context switch category of the security relevant events. See Auditing for details.

The change instance controls the access to the P2J directory editing. Only those subjects having access to this instance, can successfully open an editing batch.

The shutdown instance controls application access to the programmatic server shutdown feature.

The debug instance controls application access to the current debug level variable. The higher the variable value, the more verbose debug output is produced. See Debugging for details.

Other instances of the system resource type may be added later.

The system resource comes with a simple structure of access rights, made of just one field. Here comes the description.

Field's primitive data type string
Is it optional or mandatory? mandatory
Is it variable or fixed size? variable
Field's size unlimited
Field's displayable label "check"
Field's descriptive text an arbitrary logical expression that, if evaluated to "true", allows access
Bitfield's array of bit names n/a
Bitfield's BitSet of unused bits n/a

Auditing

Auditing is a feature that allows retrospective analysis of the security relevant events.  Such events are:
Auditing is implemented as a simple log of formatted records of several types.  Due to a potentially high volume of records, a filtering mechanism exists that only logs records based on the following criteria:
A special instance of the system resource named context is introduced to allow security context related events to be selectively audited like any other resource.

Multiple filters of the same type are always combined using logical OR operation, like in {subject1, subject2} or in {resource type1, {resource type2, instance name2}} creating log records for all listed events.

Multiple filter types may be combined either using OR or AND operation.  Sometimes it is useful to log only records for subject1 about all rejected accesses (AND operation).  Other times, it is desirable to log accesses to a specific resource instance and, at the same time, all rejected accesses to any resource (OR operation).  It may be possible to extend filtering in the future by applying the expression engine.  In order to avoid performance degradation due to auditing, regular expressions are not allowed in the resource instance names.

The audit log files are defined in the P2J directory as a collection of these attributes:
The entire audit subsystem is off by default. To enable auditing, the /security/audit/enabled value should be set to true.

Configuration

Directory Service Interface

Directory Service is the way P2J applications implement persistent storage for the majority of configuration information.  Only some minor portion of the configuration information is kept separately.  Generally, this is the information needed to figure out how to get in touch with a server (client side) or how to initialize the Directory Service (server side), frequently called the bootstrap configuration.

Directory Service is a package that runs on P2J servers.  It exposes a set of APIs as public methods through its front end.  The front end is how the rest of P2J perceives the P2J directory.  The implementation is encapsulated inside the Directory Service package and is of no interest to the rest of P2J environment.

Security Manager Directory Hierarchy

The following depicts all  P2J directory objects maintained by the Security Manager.  Every node has attribute specification suitable for identifying the object and the object class in parenthesis.

/security (container) single object
config (container)
single object
        resource-plugins (strings)
single object
auth-mode (authmode)
single object
accounts (container)
single object
users (container)
single object
userID (user)
one object per user name
account extensions
one or more user account extension objects
groups (container)
single object
groupID (group)
one object per group name
processes (container)
single object
processID (process)
one object per server or application name
account extensions
one or more process account extension objects
certificates (container)
single object
peers (container)
single object
alias (bytes)
one object per certificate owner name (alias)
CAs (container)
single object
alias (bytes)
one object per CA certificate owner name (alias)
audit (container)
single object
enabled (boolean)
single object; the value set to true enables audit
logfile (string)
single object; pattern for log file names
logsize (integer)
single object; size of log file in K
logcount (integer)
singleobject; number of log files
filterMode (booleanOption)
single object
subjects (strings)
single object
resources (container)
single object
(auditResource)
one object per auditable resource instance
decisions (auditDecision)
single object
acl (container)
single object
resource type (container)
one object per resource type name
seqno (resourceRights)
one object per Rights line in ACL, ordered by seq
seqno (strings)
one object per list of subjects, ordered by seq
seqno (binding)
one object per resource instance, ordered by seq
acls (container)
single object
server-ID (container)
optional; one object per server needing specific ACLs
resource type (container)
one object per Rights line in ACL, ordered by seq
seqno (resourceRights)
one object per list of subjects, ordered by seq
seqno (binding)
one object per resource instance, ordered by seq
holidays (dates)
single object with one value per holiday


Notes
  1. Well known object names are in bold.
  2. Names in italics mean an arbitrary name or, most likely, multiple names.
  3. Aliases are short unique names attached to certificates.
  4. The server's private key is not kept in the directory. It is provided through the bootstrap configuration. The server's certificate, on the other hand, should be made available through both the bootstrap configuration (to be able to connect to a LDAP server using secure TLS connection) and the directory (see the next note).
  5. All client, process and server certificates are kept under "/security/certificates/peers" branch. They cannot be self-signed.
  6. All certification authorities' certificates are kept under "/security/certificates/CAs" branch. If some of them are not self-signed, the whole certification chains should be made available there, including the final self-signed root CA certificates, or else the the certificate validity check fails.
  7. All servers in a multi server configuration share a single P2J directory.  Every server has to be identified through its bootstrap configuration, so that a matching "/security/accounts/processes/..." object can be found.  Servers with a master attribute having a value of true, are allowed to edit the directory.
  8. Storing certificates separate from their user/process objects allowes for a better security control.
  9. All known groups to which users belong, are enumerated in the user object.  Non-existing groups are deleted from the user definitions at startup of the master server.
  10. User accounts are kept under "/security/accounts/users". One of the accounts is selected for the session according to the rules described in User Authentication. If that account has no password attribute value, the access is allowed without presenting a password.
  11. "/security/audit/logfile" specifies path and naming pattern for the audit log files. The pattern definition may include some variables that are substituted with their values at runtime. See the full description in java.util.logging package, FileHandler class. Briefly, these are:
    • "/" the local pathname separator
    • "%t" the system temporary directory
    • "%h" the value of the "user.home" system property
    • "%g" the generation number to distinguish rotated logs
    • "%u" a unique number to resolve conflicts
    • "%%" translates to a single percent sign "%"
  12. "/security/audit/filterMode" object specifies OR or AND operation if multiple filters are defined.
  13. "/security/audit/subjects" object lists subject IDs to audit.  An empty (omitted) set means no filtering by subject.
  14. "/security/audit/resources" is a container.  If it's empty, no filtering by resource instance is in effect.  Otherwise, objects of the auditResource class put there determine audit filtering by resource instance. 
  15. An instance of auditResource creates a filter that filters by resource type, then, optionally, by one or more instance names, and then, optionally, by one or more requested rights.
  16. resourceRights is a pseudo-dynamic directory object class.  resource portion is a variable portion of the class name, taken from the resource type name.  Unlike for the other classes, the directory class definition of resourceRights is generated internally by the Security Manager at startup using the Definitions objects.  See Directory Service document for samples (systemRights and directoryRights).
  17. seqno specifies an integer attribute which helps maintain the ordering of definitions, which is important for correct interpretation of assigned rights.
  18. binding directory object class is predefined.  See the Directory Service document for details.
  19. "/security/holidays" is a list of dates which have to be considered holidays. The "holiday" variable when used in expressions is evaluated based on this object. As holidays vary significantly between countries, states and even organizations, this is the only feasible way of specifying them accurately.
  20. Currently, the account extension objects are kept either under "/security/accounts/users" or under "/security/accounts/processes", but the location is not guaranteed. They are of one of the mandatory named value classes.
  21. Authentication retries are controlled by the "retries" attribute of the "/security/config/authMode" object. A positive number indicates the maximum number of retries. Zero indicates no retries allowed. -1 indicates unlimited retries.

Bootstrap Configuration

The P2J directory contains most of the configuration information for servers.  However, there is a need to specify some minimal configuration information that would allow a server to get to the P2J directory.  This information is what is called the bootstrap configuration.

Note that clients/applications do not have access to the P2J directory at all.  For them, any piece of information they need to connect to the server is part of the bootstrap configuration.

This document does not discuss how the bootstrap configuration is organized or where it can be found.  Also, only the security model related portion of it is considered here.
Client/Application
The following security related configuration information is required on clients/applications:
Passwords and user alias that are required to access proper X.590 certificates and PKCS#8 private key are obtainable using the AuthUIHelper interface.
Server
The following security related configuration information is required on servers:

Manageability

A P2J system must be able to run in 24x7 mode.  That means restarts cannot be used as a way of refreshing the security database.  The P2J directory must be editable as applications run.  This poses some challenges:
These challenges have to be addressed by devising a methodology of directory updates.

Editing Security Database

The visibility of partial updates is a more serious problem to crack than caching.  For this reason, the Security Manager implements a cache, which is also a performance booster, and a batch update strategy, which works as follows:
The procedure can be enhanced to make a backup of the batch as well.  Note, that an empty batch works like a refresh signal and the Security Manager simply reloads the cache with the data from the directory.

Thread Synchronization

As multiple threads will be accessing the security database cache simultaneously, including the transient refresh thread, care should be taken to synchronize accesses and to minimize performance impact.

There is a simple method of doing this.  All accesses to the cache are made through a synchronized method that returns a reference to the key cache object.  Using that reference does not require further synchronization because all accesses are read only.  Only the transient refresh thread needs to be synchronized to make the reference substitution an atomic operation.

Debugging

Support for debugging is implemented through the multiple points in the code where controllable messages can be produced on output. Every debug message has a numeric level code assigned to it. The meanings of the level codes are:
The list may grow in the future.

Error messages are internally implemented using the same approach with the level value of -1.

Messages are printed to the System.err stream. The current debug level, an internal variable, determines what appears on output. A level value X allows all messages having debug level Y to appear on output if Y <= X.

Setting the current debug level is a controllable action. A special instance of the system resource named debug is used for access rights check.  Some messages may appear before any user can get a chance to log on, like those related to the P2J directory reading and interpretation. In this case, the default debug level is set soon after the server starts up, based on the server's own account permissions.

API Summary

Interfaces

AuthUIHelper

This interface defines methods that hide the end user interaction from the Security Manager code in a flexible way.  An instance of this interface should be created before a code may call the getClientTransportSecurity(AuthUIHelper) or getServerTransportSecurity(AuthUIHelper) methods.  The methods of the interface should provide pieces of information like user ID and various passwords.

Method Signature
Description
public char[] getKeyStorePassword(); Returns the password that unlocks the key store.
public char[] getTrustStorePassword(); Returns the password that unlocks the trust store.
public char[] getAliasPassword(String alias);
Returns the password that unlocks a specific key entry identified by alias.
public String getUserId(); Returns a string that represents the identification of the user.
public char[] getUserPassword(); Returns the user's password.

Authenticator

This interface is implemented by the built in authorization modes and authentication hooks.

Method Signature
Description
public byte[] clientAuthHook(AuthUIHelper auth, String parameters); Implements client side custom authorization logic.   Returns a byte array to be transmitted to the server as authorization input.  May use the given instance of AuthUIHelper to get passwords, and custom parameters.
public String serverAuthHook(byte[] auth, String parameters);
Implements server side custom authorization logic.   Accepts the byte array produced by the client side authorization hook as the authentication input, and custom parameters.  Returns a user ID (positive authentication) or null (failed to authenticate).
public void clientFinalize(); Finalizes any resources allocated during authentication by the client.


Rights


This interface has no methods.  It must be implemented by a class from a resource plugin package.

Resource

This interface defines the resource plugin registration procedure.

Method Signature
Description
public void attach(SecurityManager); Notifies the plugin about the instance of the Security Manager to communicate with.
public String getTypeName(); Returns the plugin resource type as a string.
public Object getLibrary(); Returns an instance of a library class for the plugin's own symbol resolution if the plugin exports any variables or functions for use in expressions, otherwise null.
public void registeredAs(int); Notifies the plugin that the resource type has been assigned a numeric value.
public Description[] describeRights(); Returns an array of descriptions, one object per the plugin's access rights item.
public Rights getRightsInstance(Object[]); Instantiates a plugin's class that implements the Rights interface, using the array of objects representing a set of access rights fields.  Returns the reference to the interface.
public boolean isInstanceNameValid(String); Checks whether a given string is a syntactically valid resource name for this resource type.
public boolean isRightsSetValid(Object[]); Checks whether a given array of objects representing a set of access rights fields is acceptable.

Classes

AbstractResource

This class is an abstract class that provides a partial implementation of the Resource interface.  The resource plugins should extend this base class instead of implementing the Resource interface directly.

TransportSecurity

This class provides the functionality of JSSE's KeyManager and TrustManager classes without exposing those to the outside world.

Method Signature
Description
public void attach(SSLContext); Initializes the given SSLContext object so that the latter uses the key manager and the trust manager embedded into this TransportSecurity class.


SecurityManager


This class is the core of the Security Manager implementation.  For convenience, methods of this class are grouped by function category.
Initialization Control Methods
Method Signature
Description
public static SecurityManager createInstance(BootstrapConfig); Creates and returns an instance of SecurityManager class based on a given BootstrapConfig object
public static SecurityManager getInstance(); Returns an instance of SecurityManager class.
public TransportSecurity getClientTransportSecurity(AuthUIHelper); Creates an initialized instance of the TransportSecurity class by request from the client startup code.
public TransportSecurity getServerTransportSecurity(AuthUIHelper); Creates an initialized instance of the TransportSecurity class by request from the server startup code.

Authentication and Session Control Methods
Method Signature
Description
 public boolean authenticateClient(SSLSocket, AuthUIHelper); Restricted.  Access is limited to a specific calling class/method only.
Triggers the user authentication on the client. Returns the authentication result.
 public Object authenticateLocal(SSLSocket); Restricted.  Access is limited to a specific calling class/method only.
Triggers the user authentication on the server.  Returns the authentication result as an object reference (positive) or null (negative).  The returned object is a key to security context switching.
 public String getUserId(); Returns the effective subject ID from the current security context. It is the user ID if a user is logged on, otherwise the process ID.
This method is in support of the PROGRESS' USERID() builtin function.
 public String getIdentity(Object); Restricted.  Access is limited to a specific calling class/method only.
Returns the subject identification using the result of authentication as the key.
 public Object authenticateRemote(String); Restricted.  Access is limited to a specific calling class/method only.
Registers the given user as authenticated.  Returns the authentication result as an object reference.  The returned object is a key to security context switching.
 public void terminateSession(Object); Restricted.  Access is limited to a specific calling class/method only.
Signals the TLS connection termination.  If the session's security context has the use count of 0, the security context is deleted immediately.  Otherwise, it's marked as "Pending Termination".

Security Context Control Methods
Method Signature
Description
 public void setInitialSecurityContext(); Restricted.  Access is limited to a specific calling class/method only.
Server threads call this method at startup.  The calling thread has to have no security context.
 public void pushAndSwitchSecurityContext(Object); Server threads call this method to temporarily switch to a user context to serve the associated request.  The calling thread has to have the initial security context. 
If the target security context is marked as "Pending Termination", an exception is thrown as a result.   Otherwise, the use count for the target security context is incremented by 1.
 public void popAndRestoreSecurityContext(); Server threads call this method to restore their initial security context when they are done with the user request.  The calling thread has to have its security context switched to a user context prior to this call. 
The use count for the current security context is decremented by 1.  If it becomes 0 and the security context is marked as "Pending Termination", it is deleted immediately.

State Information Control Methods
Method Signature
Description
 public boolean addToken(String name, Object token); Restricted.  Token names starting with "system" are of  restricted use.
Token is saved in a storage associated with the current security context under the given name.
 public boolean removeToken(String name); Restricted.  Token names starting with "system" are of  restricted use.
The named token is peranently removed from the current security context.
 public boolean hasToken(String name); Restricted.  Token names starting with "system" are of  restricted use.
Checks whether the named token is in the current security context.
 public Object getToken(String name);
Restricted.  Token names starting with "system" are of  restricted use.
Gets the named token from the current security context.

Resource Plugin Support Methods
Method Signature
Description
public AbstractResource getPluginInstance(String resourceTypeName);
Searches abstract resource registry for a plugin that is responsible for the resources of the specified type and returns its instance. Application calls this method to get the instance of a plugin.
public Boolean getCachedDecision(int resourceId, String instanceName, int mode);
Returns a Boolean with the decision or null if not available. 
Plugins call this method to check whether a cached access check decision is available.  Cached access check decisions are identified by triplets of {resourceId, instanceName, mode} exactly as they were specified when the decision was taken.
public int openRightsSearch(int resourceId, String instanceName, int mode); Returns a search handle.  Plugins call this method to initiate the access rights search for the specified resource instance and requested rights.
public Rights getNextRights(int handle); Returns an instance of Rights interface to be used next in the access rights check loop.  Plugins cast Rights to their own classes and use their custom methods to perform the check.
public void closeRightsSearch(int handle, boolean decision, boolean cache); Plugins call this method to trigger cleanup of all temporary objects related to the search and notify the Security manager about the decision just made and whether it has to be cached or not.
public synchronized Double compute(int resourceId, Rights rights, String expr); Computes an arithmetic expression using the backing data from the specified instance of Rights.
public synchronized Boolean evaluate(int resourceId, Rights rights, String expr); Evaluates a logical expression using the backing data from the specified instance of Rights.
Batch Editing Methods
These APIs is a means of controlling the editing session from the Directory Service.  They are listed in the table below.

Method Signature
Description
public boolean openBatch();
Restricted.  Access is limited to a specific calling class/method only.
Returns true if an editing batch has been opened.  Fails if another batch is open for the calling thread.
public boolean isEditing(); Restricted.  Access is limited to a specific calling class/method only.
Returns true if an editing batch is currently open.
public boolean closeBatch(boolean disposition); Restricted.  Access is limited to a specific calling class/method only.
Closes the currently open editing batch.  The disposition parameter tells what to do with the closed batch:
  • true means apply changes to the directory;
  • false means discard the batch.
Returns true if the requested disposition has been successfully applied.

Account Extension Access Methods
Method Signature
Description
public Integer getExtInteger(String extName);
Finds the specified integer account extension for the current user and returns the value or null.
public Boolean getExtBoolean(String extName);
Finds the specified boolean account extension for the current user and returns the value or null.
public String getExtString(String extName); Finds the specified string account extension for the current user and returns the value or null.
public byte[] getExtBytes(String extName); Finds the specified bytearray account extension for the current user and returns the value or null.
public Integer getExtInteger(String extName, String subjectId); Finds the specified integer account extension for the specified user and returns the value or null.
public Boolean getExtBoolean(String extName, String subjectId); Finds the specified boolean account extension for the specified user and returns the value or null.
public String getExtString(String extName, String subjectId); Finds the specified string account extension for the specified user and returns the value or null.
public byte[] getExtBytes(String extName, String subjectId); Finds the specified bytearray account extension for the specified user and returns the value or null.
public boolean setExtInteger(String extName, int value);
Sets the specified integer account extension for the current user.
public boolean setExtBoolean(String extName, boolean value);
Sets the specified boolean account extension for the current user.
public boolean setExtString(String extName, String value); Sets the specified string account extension for the current user.
public boolean setExtBytes(String extName, byte[] value); Sets the specified bytearray account extension for the current user.
public boolean setExtInteger(String extName, String subjectId, int value); Sets the specified integer account extension for the specified user.
public boolean setExtBoolean(String extName, String subjectId, boolean value); Sets the specified boolean account extension for the specified user.
public boolean setExtString(String extName, String subjectId, String value); Sets the specified string account extension for the specified user.
public boolean setExtBytes(String extName, String subjectId, byte[] value); Sets the specified bytearray account extension for the specified user.

Security Manager Variables and Functions

Variables
The Security Manager creates a pool of special variables that helps in creating flexible and powerful expressions as a way of specifying access rights.  The following table lists all Security Manager's variables.

Category
Variable
Description
Session
Various values taken from the current session environment.

String userid
User identity

String groupid
First or only group identity or empty string

String appid
Application identity

String groups
Number of groups this user account has been assigned to

int peerip
Peer's IP Address

int serverip
Server's IP Address

String peername
Peer's hostname

String servername
Server's hostname

boolean secureConnection true if the socket is SSL/TLS based, false if an insecure socket is in use for this session.

int peernode
Peer's P2J node address

int servernode
Server's P2J node address
Calendar/Date
Various forms of the current date

String date
Current date as in "YYYY/MM/DD", suitable for comparisons

int year
Current year like 2005

int month
Current month 1-12

int dayofmonth
Current day of the month 1-31

int dayofyear
Current day of the year 1-365

int dayofepoch
Current day of the epoch, 0 = Jan 1, 1970

int weekday
Current day of the week, sun=0, mon=1 etc.

int weeknum
Current week number 1-52

boolean holiday
Today is a holiday (true) or a workday (false). The implementation relies upon the P2J directory object /security/holidays which lists all holidays
Time of day
Various forms of the time of day

String time
Current time of day as in "HH:MM:SS" from "00:00:00" to "23:59:59"

int hourampm
Current hour 1-12

int hour
Current hour 0-23

int minute
Current minute 0-59

int second
Current second 0-59

boolean AM
Current time is AM (true)

boolean PM
Current time is PM (true)

int minSinceMidnight Current minute since midnight 0-1439

int secSinceMidnight Current second since midnight 0-86399
Miscellaneous

int debuglevel
requested debug level or -1; useful in expressions controlling access to the debugging feature (debug instance of the system resource)

Functions
All said about variables is true for the user defined functions.  The Security Manager currently exports the following functions:
Category
Function
Description
Miscellaneous


String group(int n) Returns the name of the nth group the user has been assigned to
Directory Access
Functions querying various directory keys.  The returned type is the type of the directory key.

String dirs(String oid, String attr)
Queries the first value of a P2J attribute which specifies a string

String dirs(String oid, String attr, int i) Queries the specified value of a P2J attribute which specifies a string

long dirl(String oid, String attr) Queries the first value of a P2J key which specifies a long integer

long dirl(String oid, String attr, int i) Queries the specified value of a P2J attribute which specifies a long integer

boolean dirb(String oid, String attr)
Queries the first value of a P2J key which specifies a boolean

boolean dirb(String oid, String attr, int i) Queries the specified value of a P2J attribute which specifies a boolean
 

Appendix A. Security Utilities

The security package offers a few command line utilities:

WARNING!
All these utilities change the specified directory file. Please make it a rule to create a backup copy of the file before applying any of the utilities.

Using subjects

Use subjects to scan the specified ACLs in a directory file, select ACLs by an account and apply deletions and/or additions to the subjects list. A typical use of this utility may sound like this: provide access rights that a subject X owns, to the subject Y.
How to run subjects
java com.goldencode.p2j.security.SecurityAdmin subjects
Parameters
dir-file dir-path quoted-selector quoted-deletions quoted-additions

The dir-file gets scanned started from the dir-path node, which should specify an ACL section.  All encountered ACL containers are then inspected.  If quoted-selector is given, it has to be a subject ID. The ACLs are selected if this subject ID makes part of the subjects list. Selection can be bypassed if the quoted-selector is specified as an empty string in double quotes.

The selected ACLs (or all if no selector given) are edited next. The quoted-deletions parameter specifies zero, one or more subject IDs that have to be removed from the ACLs. An empty double quoted string instructs the utility not to delete. Multiple space separated subject IDs can be specified in the double quotes.

The  quoted-additions parameter works in a similar way. It specifes zero, one or more subject IDs that are to be added to the ACLs.
Examples
The following command will list all existing ACLs for the system resource in the test-directory.xml file:

java com.goldencode.p2j.security.SecurityAdmin subjects test-directory.xml /security/acl/system "" "" ""

The following command will list all existing ACLs for the system resource and account admins in the test-directory.xml file:

java com.goldencode.p2j.security.SecurityAdmin subjects test-directory.xml /security/acl/system admins "" ""

The following command will add admin2 subject ID to all ACLs for the system resource where the admin1 account is used in the test-directory.xml file:

java com.goldencode.p2j.security.SecurityAdmin subjects test-directory.xml /security/acl/system admin1 "" admin2

The following command will replace admin2 subject ID with admin1 and admin3 in all ACLs for the system resource in the test-directory.xml file:

java com.goldencode.p2j.security.SecurityAdmin subjects test-directory.xml /security/acl/system admin2 admin2 "admin1 admin3"

Using migrate

Use migrate to change the ACL coding style to the new style. It may be required for the offline use of an older directory.
How to run migrate
java com.goldencode.p2j.security.SecurityAdmin migrate
Parameters
dir-file dir-path resource-plugin
The dir-path should specify an ACL section of the directory file dir-file.  The resource-plugin parameter gives the class name of the resource plugin that manages this type of the resources.
Example
To migrate the net resource ACLs  in a section of the test-directory.xml:

java com.goldencode.p2j.security.SecurityAdmin migrate test-directory.xml /security/acls/second/net com.goldencode.p2j.net.NetResource

Using johndoe

Use johndoe to analyze and validate the subjects lists for the whole ACL section of the directory file. Validation means a subject ID refers to a defined user, group or process account.
How to run johndoe
java com.goldencode.p2j.security.SecurityAdmin johndoe
Parameters
dir-file dir-path resource-plugin

The resource-plugin parameter gives the class name of the resource plugin that manages this type of the resources.

Using resource

Use resource to analyze and validate the resource instance names for the whole ACL section of the directory file. Validation means resource instance names are verified by the resource plugin.
How to run resource
java com.goldencode.p2j.security.SecurityAdmin resurce
Parameters
dir-file dir-path resource-plugin

The resource-plugin parameter gives the class name of the resource plugin that manages this type of the resources.

Using encode

Use encode to convert the plain text passwords stored in the user account's some other attributes and add password attribute with the hashes.
How to run encode
java com.goldencode.p2j.security.SecurityAdmin encode
Parameters
dir-file input-attr

The input-attr parameter specifies where to get the plain text password from. It has to be some string attribute of the user directory class. The encoded password will be placed in the password attribute.






  
Copyright (c) 2004-2011, Golden Code Development Corporation.
ALL RIGHTS RESERVED. Use is subject to license terms.
Skip navigation links
Copyright (c) 2004-2017, Golden Code Development Corporation.
ALL RIGHTS RESERVED. Use is subject to license terms.