RBAC and Object Technology
Implementing Role Based Access Control
using
Object Technology
John Barkley
NIST
B266 Tech
Gaithersburg MD 20899
(301) 975-3346
jbarkley@nist.gov
Tue Nov 28 08:31:40 EST 1995
With Role Based Access Control (RBAC), each role is associated with a
set of operations which a user in
that role may perform. The power of RBAC as an access control mechanism is
the concept that an operation may theoretically be anything. This is
contrasted to other access control mechanisms where bits or labels are
associated with information blocks. These bits or labels indicate
relatively simple operations, such as, read or write, which can be performed
on an information block.
Operations in RBAC may be arbitrarily complex, e.g., ``a
night surgical nurse can only append surgical information to a patient record
from a workstation in the operating theater while
on duty in that operating theater from midnight to 8 AM.''
A goal for implementing RBAC is to allow operations associated with roles
to be as general as possible while not adversely impacting the administrative
flexibility or the behavior of applications.
Consider the possible activities associated with defining and modifying
roles:
- Add a role and its associated
operations.
- Remove a role and its associated operations.
- Modify an existing role:
- Add an operation.
- Remove an operation.
- Modify an existing operation.
Information is usually accessed by applications
based on a fixed set of operations defined by
the mechanism or processor which is used to access the information.
Applications are built based on a
fixed set of operations which they routinely perform.
For example, Unix files are accessed by the operations defined by the
procedures: open(), close(), read(), write(), fseek(), etc.;
tables in a relational data base are accessed by the operations defined
by SQL.
Modifying the operations available to an application can have a
great impact on an existing application.
Removing an operation or modifying the semantics of an operation
seriously affects an application's functioning and can produce
very unpredictable results.
Figure 1: Implementing RBAC with layered objects
One approach which can be used to maintain flexible administration,
minimize impact on applications, and
maintain a significant capability for defining complex role operations is
to use Object Technology in the following manner (see fig. 1).
A complete set of operations based on access methods
associated with the information storage mechanism is defined
and held fixed.
These are the operations that are made available to an application.
These operations become the methods in a basic access methods class.
Access control for the basic access methods class is
provided by role classes, one for each defined role.
The methods of the role classes have the same names, types and parameters
as the methods of the basic access methods class.
Access control to the information accessed by the basic access
methods class is located exclusively in the role classes and not
in any other part of the application.
The bodies of the methods in the role classes are restricted to:
- conditionals
which determine access for the role associated with that role class; and/or
- filters which constrict the flow of information between the application
interface and the basic access methods.
If access is permitted for a role, the methods of the role class then
invoke the corresponding methods of the
basic access methods class.
If not all information obtained by the basic access methods is permitted to
a role, then the parts of the information not permitted can be
filtered out. Filtering may be more desirable in a application rather
than generating an access violation for the entire information block.
The methods of the application interface class
also have the same names, types and parameters as the methods of
the basic access methods
class. The methods of the application interface class invoke the
corresponding methods of the role classes.
It is the methods of an
application interface object which the application invokes.
Given the current role associated with the application, the methods
of the application interface object select the appropriate role object.
This approach has the following advantages:
- Applications need not change when access conditions for roles are
changed.
Applications use the methods of the application interface class
whose methods have the same names, types, and parameters
as the methods in the basic access methods
class. The methods of the application interface class and the methods of
the basic access methods class are fixed and remain
constant over time. When access conditions for
roles change, applications fail only because of access violations.
This type of failure is comparable to the failures that typically occur
when information protection bits or labels are changed. Applications
are normally implemented to be able to handle access violations.
- Access conditions for roles are easily changed.
Access conditions for roles are located exclusively within the role classes.
Consequently, role policy
changes do not require modifications to the applications themselves.
One can conceive of a simple language, suitable for use by data and
security administrators, for expressing access conditions restricted
to conditionals and filters. A
processor for such a language could generate the role objects and
place them in the libraries used by applications. Most environments
today support dynamically linked libraries which link when an application
is loaded into memory for execution. Thus, applications do not need
to be relinked when role classes are changed.
This ability to easily change access conditions associated with roles
permits rapid response to policy changes.
Figure 2: Example basic access methods class for accessing patient
information
The C++ example in the appendix illustrates the approach.
The appendix provides a complete C++ example which may be compiled and run.
In actual practice, RBAC roles, operations, and policy can be numerous and
complex. In order to simplify this example, only a small subset of the
roles, operations, and policy that would normally be required are illustrated.
This example has the following operations which can be performed by applications
on a patient record database:
- Get patient ID list
- This operation obtains a complete list of patient
names and their IDs.
- Get patient record
- This operation obtains the patient record given the
patient ID.
Figure 2 shows C++ code for a basic access methods class
(Access_PRDBO) which has methods (GetIDinfo(), and GetPR())
for performing these operations.
Figure 3: Example role classes for accessing patient
information
Figure 3 shows C++ code for role classes associated
with a patient (Pat_PRDBO)
and doctor role (Doc_PRDBO). These role classes inherit from a base
class (Role_PRDBO) which defines the names, types, and parameters
for the methods which
correspond to the methods in the basic access methods class.
The patient and doctor role classes together implement the following
RBAC policy:
- Only Doctors are permitted to read the list of patient names and IDs.
- Doctors are permitted to read the records for all patients.
- Patients are only permitted to read their own record.
In order to ensure that patients only access their own records,
the patient role object (Pat_PRDBO) calls a system
procedure which returns the patient ID for the user.
Figure 4: Example application interface class for accessing patient
information
Figure 5: Example procedure to locate the proper role object
Figure 4 shows the application interface class
(PRDBO) used by
applications. When an object of this class is instantiated and a method
of that object is called,
that method first calls a system procedure
(get_role()) which
returns the user's current role.
The method then
calls another system procedure (get_role_obj()) which returns a
pointer to the role object for that role.
This procedure is shown in Figure 5.
Finally, the method calls
its corresponding method in the role object passing its input
arguments to the role object method.
... Footnote:Some operations may
be available to more than one role, e.g., a credit account may be
read by both a bank teller and a bank supervisor.
Presented at the First ACM Workshop on Role Based Access Control, November 1995
Author's email address:
John Barkley - jbarkley@nist.gov, (301) 975-3346
This document was generated using the LaTeX2HTML translator Version 0.6.4 (Tues Aug 30 1994) Copyright © 1993, 1994, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
The command line arguments were:
latex2html -split 0 -t RBAC and Object Technology titlewkshp.tex.
The translation was initiated by John Barkley on Tue Nov 28 08:31:29 EST 1995
John Barkley
Tue Nov 28 08:31:29 EST 1995
Appendix
Updated C++ example:
(the original version follows the updated version)
-------------------------- applint_update.cc ---------------------------------
//
// C++ Example of Role Based Access Control
// Implementation Using Object Technology
//
// John Barkley
// (jbarkley@nist.gov)
//
// This C++ program illustrates the implementation of RBAC using Object
// Technology. In this example, there are two methods which provide
// a healthcare application with access to patient records:
// GetIdinfo() - provides a list of patient names and their IDs
// GetPR(pid) - given a patient ID, returns the patient record
// These two methods are associated with several classes:
// Access_PRDBO - this class provides the basic access methods
// to patient information
// Role_PRDBO - the abstract role class
// Pat_PRDBO - the patient role class
// Doc_PRDBO - the doctor role class
// PRDBO - the application programming interface class
//
// For each role, there is a role class for that role derived from the
// abstract role class. The methods in each role class contain the
// conditions under which a user in that role may perform the
// corresponding methods in a basic access methods class (Access_PRDBO in
// this example). The methods in the basic access methods class perform
// actions on the information. The methods in each role class are invoked
// by corresponding methods in the application programming interface
// class (PRDBO in this example).
//
// This approach permits much of the generality of the RBAC concept of
// "action" to be realized, i.e., once the basic actions on information
// have been established, any conditions permitting actions on information
// specified in an RBAC policy may be implemented. In addition,
// this approach permits roles to be created, removed, and modified
// without having to recompile either the application or the basic access
// methods class. When a role is added, removed, or modified in the
// policy, a role class is added, removed, or modified.
//
// This example is an update of:
// http://www.itl.nist.gov/div897/staff/barkley/rbacot/applint_cc.txt
// It was compiled using GNU gcc version 3.4.4:
// gcc applint_update.cc -lstdc++
//
#include
#include
#include
const int ROLE_NAME_LENGTH = 50;
const int NUMBER_OF_ROLES = 2;
typedef char *Idlist;
typedef char *Patrec;
typedef int Patid;
extern char * get_role();
extern int get_user_pid();
extern "C" void exit(int);
// basic access methods class
class Access_PRDBO{
public:
Idlist GetIdinfo(){
return("Here's the list of patients and their IDs\n");
};
Patrec GetPR(Patid pid){
const int BUFLEN = 128;
static char buf[BUFLEN];
static std::ostrstream oss(buf, BUFLEN, std::ios::out);
oss.seekp(std::ios::beg);
oss << "Here's the patient record for patient ID: "
<< pid << std::endl << std::ends;
return(buf);
};
};
Access_PRDBO access_prdbo;
// role classes:
// one for each role derived from the abstract class Role_PRDBO
class Role_PRDBO{
public:
virtual Idlist GetIdinfo()=0;
virtual Patrec GetPR(Patid patid)=0;
};
class Pat_PRDBO:public Role_PRDBO{
public:
// the policy does not permit patients to access
// the list of patient names and their IDs
virtual Idlist GetIdinfo(){
return("ERROR: patient cannot access patient id list\n");
};
// the policy only permits a patient to have access
// to his own patient information
virtual Patrec GetPR(Patid pid){
if (pid == get_user_pid())
return(access_prdbo.GetPR(pid));
else
return("ERROR: patients cannot get other's records\n");
};
};
static Pat_PRDBO pat_prdbo;
class Doc_PRDBO:public Role_PRDBO{
public:
// the policy permits doctors to have access
// to all information on any patient
virtual Idlist GetIdinfo(){
return(access_prdbo.GetIdinfo());
};
virtual Patrec GetPR(Patid pid){
return(access_prdbo.GetPR(pid));
};
};
static Doc_PRDBO doc_prdbo;
// this procedure, which must be changed when roles are added or deleted,
// would be a system call which finds the the role object given the
// user's role
Role_PRDBO *get_role_obj(char *role_name){
struct{
char role_name[ROLE_NAME_LENGTH];
Role_PRDBO *role_object;
} role_tab[NUMBER_OF_ROLES] =
{
{"patient", &pat_prdbo},
{"doctor", &doc_prdbo}
};
for(int i=0; iGetIdinfo());
};
Patrec GetPR(Patid patid){
char * role_name;
Role_PRDBO *roleobj;
role_name = get_role();
roleobj = get_role_obj(role_name);
if (roleobj == (Role_PRDBO *)NULL)
return("ERROR: no such role\n");
return(roleobj->GetPR(patid));
};
};
PRDBO prdbo;
// this procedure would be a system call to return the user's current role
char * get_role(){
static char role_name[ROLE_NAME_LENGTH];
std::cout << "Enter role name: ";
std::cin >> role_name;
return(role_name);
};
// this procedure would be a system call to return the user's patient ID
int get_user_pid(){
int pid;
std::cout << "Enter user's patient id: ";
std::cin >> pid;
return(pid);
};
main(){
char opt;
Patid pid;
while(1){
std::cout << "Enter i-GetIdlist, r-GetPR: " ;
std::cin >> opt;
if ( !std::cin ) {std::cout << std::endl; exit(0); };
switch (opt) {
case 'i' : std::cout << prdbo.GetIdinfo() << std::endl;
break;
case 'r' : std::cout << "Enter patient id: ";
std::cin >> pid;
std::cout << prdbo.GetPR(pid) << std::endl;
break;
};
};
};
-------------------------- end of applint_update.cc ------------------------
Original version:
------------------------------- applint.cc ---------------------------------
//
// C++ Example of Role Based Access Control
// Implementation Using Object Technology
//
// John Barkley
// (barkley@sst.ncsl.nist.gov)
//
// This C++ program illustrates the implementation of RBAC using Object
// Technology. In this example, there are two methods which provide
// a healthcare application with access to patient records:
// GetIdinfo() - provides a list of patient names and their IDs
// GetPR(pid) - given a patient ID, returns the patient record
// These two methods are associated with several classes:
// Access_PRDBO - this class provides the basic access methods
// to patient information
// Role_PRDBO - the abstract role class
// Pat_PRDBO - the patient role class
// Doc_PRDBO - the doctor role class
// PRDBO - the application programming interface class
//
// For each role, there is a role class for that role derived from the
// abstract role class. The methods in each role class contain the
// conditions under which a user in that role may perform the
// corresponding methods in a basic access methods class (Access_PRDBO in
// this example). The methods in the basic access methods class perform
// actions on the information. The methods in each role class are invoked
// by corresponding methods in the application programming interface
// class (PRDBO in this example).
//
// This approach permits much of the generality of the RBAC concept of
// "action" to be realized, i.e., once the basic actions on information
// have been established, any conditions permitting actions on information
// specified in an RBAC policy may be implemented. In addition,
// this approach permits roles to be created, removed, and modified
// without having to recompile either the application or the basic access
// methods class. When a role is added, removed, or modified in the
// policy, a role class is added, removed, or modified.
//
// This example was compiled using the GNU C++ compiler.
//
#include
#include
#include
const int ROLE_NAME_LENGTH = 50;
const int NUMBER_OF_ROLES = 2;
typedef char *Idlist;
typedef char *Patrec;
typedef int Patid;
extern char * get_role();
extern int get_user_pid();
extern "C" void exit(int);
// basic access methods class
class Access_PRDBO{
public:
Idlist GetIdinfo(){
return("Here's the list of patients and their IDs\n");
};
Patrec GetPR(Patid pid){
const int BUFLEN = 128;
static char buf[BUFLEN];
static ostrstream oss(buf, BUFLEN, ios::out);
oss.seekp(ios::beg);
oss << "Here's the patient record for patient ID: "
<< pid << endl << ends;
return(buf);
};
};
Access_PRDBO access_prdbo;
// role classes:
// one for each role derived from the abstract class Role_PRDBO
class Role_PRDBO{
public:
virtual Idlist GetIdinfo()=0;
virtual Patrec GetPR(Patid patid)=0;
};
class Pat_PRDBO:public Role_PRDBO{
public:
// the policy does not permit patients to access
// the list of patient names and their IDs
virtual Idlist GetIdinfo(){
return("ERROR: patient cannot access patient id list\n");
};
// the policy only permits a patient to have access
// to his own patient information
virtual Patrec GetPR(Patid pid){
if (pid == get_user_pid())
return(access_prdbo.GetPR(pid));
else
return("ERROR: patients cannot get other's records\n");
};
};
static Pat_PRDBO pat_prdbo;
class Doc_PRDBO:public Role_PRDBO{
public:
// the policy permits doctors to have access
// to all information on any patient
virtual Idlist GetIdinfo(){
return(access_prdbo.GetIdinfo());
};
virtual Patrec GetPR(Patid pid){
return(access_prdbo.GetPR(pid));
};
};
static Doc_PRDBO doc_prdbo;
// this procedure, which must be changed when roles are added or deleted,
// would be a system call which finds the the role object given the
// user's role
Role_PRDBO *get_role_obj(char *role_name){
struct{
char role_name[ROLE_NAME_LENGTH];
Role_PRDBO *role_object;
} role_tab[NUMBER_OF_ROLES] =
{
{"patient", &pat_prdbo},
{"doctor", &doc_prdbo}
};
for(int i=0; iGetIdinfo());
};
Patrec GetPR(Patid patid){
char * role_name;
Role_PRDBO *roleobj;
role_name = get_role();
roleobj = get_role_obj(role_name);
if (roleobj == (Role_PRDBO *)NULL)
return("ERROR: no such role\n");
return(roleobj->GetPR(patid));
};
};
PRDBO prdbo;
// this procedure would be a system call to return the user's current role
char * get_role(){
static char role_name[ROLE_NAME_LENGTH];
cout << "Enter role name: ";
cin >> role_name;
return(role_name);
};
// this procedure would be a system call to return the user's patient ID
int get_user_pid(){
int pid;
cout << "Enter user's patient id: ";
cin >> pid;
return(pid);
};
main(){
char opt;
Patid pid;
while(1){
cout << "Enter i-GetIdlist, r-GetPR: " ;
cin >> opt;
if ( !cin ) {cout << endl; exit(0); };
switch (opt) {
case 'i' : cout << prdbo.GetIdinfo() << endl;
break;
case 'r' : cout << "Enter patient id: ";
cin >> pid;
cout << prdbo.GetPR(pid) << endl;
break;
};
};
};