Introduction to SPOPS

Introduction

SPOPS -- or Simple Perl Object Persistence with Security -- allows you to easily define the structure of an object and to save, fetch or remove it any time thereafter. It is intended for SQL databases (using the DBI), but you can adapt it to use any storage mechanism for accomplishing these tasks. SPOPS also implements security on a per-object basis (authentication and authorization).

The goals of this module are:

Persistence

Classes

SPOPS (Simple Perl Object Persistence with Security) provides a framework to make your application objects persistent (meaning, you can store them somewhere, e.g., in a relational database), and to control access to them (the usual user/group access rights stuff).

You will configure SPOPS by means of configuration files, and SPOPS will create the necessary classes and objects for your application on the fly. You can of course have your own code implement additional object behavior -- extending the default SPOPS object behavior with your methods. However, if SPOPS shall know about your classes and objects, you will have to tell it -- by configuring it.

The typical class hierarchy for an SPOPS object looks like this:


     --------------------------
    |SPOPS                     |
     --------------------------
                ^
                |
     --------------------------
    |SPOPS::MyStorageTechnology|
     --------------------------
                ^
                |
     --------------------------
    |SPOPS::MyApplicationClass |
     --------------------------
SPOPS

Abstract base class, provides persistency and security framework (fetch, save, remove)

SPOPS::MyStorageTechnology

Concrete base class, provides technical implementation of framework for a particular storage technology (e.g., Filesystem, RDBMS, LDAP, ... )

Example: SPOPS::DBI, SPOPS::GDBM, SPOPS::Imperia ...

SPOPS::MyApplicationClass

User class, provides semantic implementation of framework (configuration of parent class, e.g., database connection strings, field mappings, ... )

Example: MyApplication::User, MyApplication::Document, ...

The individual objects in a package should not care how the objects are being stored, they should just know that when they call fetch() with a unique ID that the object magically appears. Similarly, all the object should know is that it calls save() on itself and can reappear at any later date with the proper invocation.

SPOPS Object States

Basically, each SPOPS object is always in one of two states:

In Runtime State, the object representation is based on a hash of attributes. The object gets notified about any changes to it through the tie(3) mechanism.

In Persistency State, the object exists in some persistent form, that is, it is stored in a database, or written out to a file.

You can control what happens to the object when it gets written to its persistent form, or when it is deleted, or fetched from its storage form, by implementing a simple API: fetch(), save(), remove().


     -------------         save, remove         -----------------
    |Runtime State|     ------------------->   |Persistency State|
     -------------      <------------------     -----------------
                              fetch

Security

Overview of security

By adding this module into the hierarchy for an SPOPS object class, you implement a transparent per-object security system. This security system relies on a few things being implemented:

Security is implemented with a number of methods that are called within the SPOPS implementation module. For instance, every time you call fetch() on an object, the system first determines whether you have rights to do so. Similar callbacks are located in save() and remove(). If you do not either define the method in your SPOPS implementation or use this module, the action will always be allowed.

We use a Unix-style permission scheme, separating the scope into: USER, GROUP and WORLD from most- to least-specific. (This is abbreviated as U/G/W.) When we check permissions, we check whether a security level is defined for the most-specific item first, then work our way up to the least specific.

Even though we use the U/G/W scheme from Unix, we are not constrained by its history. There is no strict 'ownership' assigned to an object as there is to a Unix file. Instead, an object can have assigned to it permissions from any number of users, and any number of groups.

There are three settings for any object combined with a specific scope:

 NONE:  The scope is barred from even seeing the object.
 READ:  The scope can read the object but not save it.
 WRITE: The scope can read, write and delete the object.

(To be explicit: WRITE permission implies READ permission as well; if a scope has WRITE permission for an object, it can do anything with it, including remove it.)

Security rules

With security, there are some important assumptions. These rules are laid out here.

For instance, look at an object that represents a news notice posted:

 Object Class: MyApp::News
 Object ID:    1625

 ------------------------------------------------
 | SCOPE | SCOPE_ID |  NONE  |  READ  |  WRITE  |
 ------------------------------------------------
 | USER  | 71827    |        |   X    |         |
 | USER  | 6351     |   X    |        |         |
 | USER  | 9182     |        |        |    X    |
 | GROUP | 762      |        |   X    |         |
 | GROUP | 938      |        |        |    X    |
 | WORLD |          |        |   X    |         |
 ------------------------------------------------

From this, we can say: