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:

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:

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:

  
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:

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.

About this document ...

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 <stdio.h> #include <iostream> #include <strstream> 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; i<NUMBER_OF_ROLES; i++) if (strcmp(role_name, role_tab[i].role_name) == 0) return(role_tab[i].role_object); return((Role_PRDBO *) NULL); }; // application interface class class PRDBO{ public: Idlist GetIdinfo(){ 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->GetIdinfo()); }; 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 <stdio.h> #include <iostream.h> #include <strstream.h> 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; i<NUMBER_OF_ROLES; i++) if (strcmp(role_name, role_tab[i].role_name) == 0) return(role_tab[i].role_object); return((Role_PRDBO *) NULL); }; // application interface class class PRDBO{ public: Idlist GetIdinfo(){ 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->GetIdinfo()); }; 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; }; }; };