OVERVIEW ABAC proves attributes about principals. libabac is comprised of three main types of objects: credentials, roles/osets, and contexts. A typical use of ABAC is: - create a context - load some certificates - add more certificates, possibly presented by another party - make a query 'does principal B have the role A.r1?' or a query 'is object B part of the oset A.o1?' CREDENTIAL An ABAC credential is the most basic unit of an ABAC proof. It is a signed assertion by a principal A that some other entity has a role r1. Abstractly, it is one of the following (A, B principals; r1, r2, r3 roles): A.r1 <- B A.r1 <- B.r2 A.r1 <- B.r2.r3 It is a signed assertion by a principal A that some other entity is an object of oset o1. (A, B principals; r1 role; o1, o2 osets; O object): A.o1 <- O A.o1 <- B.o2 A.o1 <- B.r1.o2 When interacting with libabac, a credential is represented by an X509 attribute certificates and the associated issuer X509 identity certificate. A principal is represented by the SHA1 hash of the public key of its identity certificate. Therefore when a credential is encoded in an attribute certificate, it will look something along the lines of: e65aace9237833ec775253cfde97f59a0af5bc3d.frobnicate <- e93547826455a80d9488825a1d083ef6ef264107 ROLE ABAC roles are the atomic units that form the head and tail of a credential. The head will always be a proper role, which is to say it takes form: A.r1 As seen in the CREDENTIAL section, the tail of a role can take one of three forms: principal: B role: B.r2 linking role: B.r2.r3 For more information about the different types of roles, refer to [Li03rt]. OSET ABAC osets are the atomic units that form the head and tail of a credential. See the RT2 description for how osets and roles differ. The head will always be a proper oset, which is to say it takes form: A.o1 As seen in the CREDENTIAL section, the tail of a oset can take one of three forms: object: O oset: B.o2 linking oset: B.r2.o3 CONTEXT An ABAC context object encapsulates a set of ABAC credentials and its associated YAP clause db. The context supports the following operations: - load X509 identity certificate - load X509 attribute certificate - list all the credentials (attribute identity certificate pairs) - query whether a principal has a given role - query whether an object belongs to a given o-set RT2 RT2 is a more expressive logic than the original RT0 logic that ABAC supported. The RT2 specification extends the existing RT0 notation in 5 ways: * More general principal specification to allow room for other identity providers * Explicit syntax for specifying RT2 objects * Explicit type information to differentiate roles and o-sets. * Explicit type information for RT1 and RT2 parameters * Syntax for constraints These additions make the syntax both much less terse and much less ambiguous. A few words about RT1 and RT2 before we describe syntax. RT1 parameterizes roles, that is, it attaches ordered, typed data to roles. It also adds matching requirements to role derivations, including constraints. The RT1 rule A.r(?x, ?y) <- A.s(1, ?y:[1..3]) & A.t(?y, ?x) requires that all instances of ?x and ?y on the right side have the same type and that the constraints on ?y in the first term are valid for that type. There's no explicit typing in the rule notation of the papers, which this specification addresses. The data types in the papers inlcude integers, floats, dates, closed enumerations, and open enumerations. Closed enumerations are things like C or C++ enums, with boolean being a specific example. Open enumerations include things like principals. For tractability we're going to want to define a specific set of data types, which we do below. RT2 allows principals to label data in the same way that they label principals. The ABAC authors helpfully use the exact same syntax for assigining a label to a data object as they do for assigning a role to a principal, but the semantics are slightly different. We add syntax that clarfies when data is being labelled and when principals are being labelled. These "data roles" are called o-sets. On with the specification, from the basic chunks up to rules. Principal Names We've been using self-signed X.509 identity certificates as identities, and that's been a useful way to get started, but it would be nice to be able to use other identities in the future. Now a principal name is not marked in the representation at all. New principal IDs will be of the form: [idtype:A]. The idtype will define what valid characters in A will be, but in any event "]" must be escaped with a backslash. The current id's will be of idtype 'keyid', so only applying the principal extensions, the role A.r would be written [keyid:A].r, where A is the sha1 hash of the public key. keyid principal names can include [0-9a-fA-F] (hex digits). I'm going to continue to use [keyid:A] here so not everything runs off the page. Data Objects The RT1 and RT2 parameters are loosely data objects. RT1 allows one to reason about them, RT2 adds the ability to have principals make statements about these data objects. Just as we need to represent principals including their type, we need to represent objects with their type. We support following types: int: 32-bit signed integers float: floats in the range of an IEEE float. time: a time expressed as yyyymmddThhmmss where the lower case letters are digits and the T is a T. Zulu time, everything after the T is optional boolean: true or false urn: a resource named by a URN string: a UTF-8 string. This is a free space for people to define local free-form attributes A particular object is specified by: [ type: name] Objects are always specified this way, because rules and assignments may come from many places and the typing information must mesh. Examples: [boolean: true] [int: 3454] [float: -323.0] also [ float: 1] [time: 20111109T122300] also [ time: 20101010T] [urn:"file:///usr/local/bin/ls"] [urn:"uuid://106c0cdd-0afb-11e1-90d8-14feb5e4012d"] [string:"a string"] Roles and O-Sets In the ABAC papers, roles and o-sets look exactly alike, and one may have trouble understanding that they are different. This spec explicitly types them for clarity. Roles are prefixed by "role:" and o-sets by "oset:". The rule that places principal P in role A.r is written in the paper as A.r <- P In our notation: [keyid:A].role:r <- [keyid:P] The rule that places file P in o-set A.r is written in the paper as A.r <- P In our notation: [keyid:A].oset:r <- [urn:"file://P"] Similarly derivation rules like: A.r <- B.r become [keyid:A].role:r <- [keyid:B].role:r or [keyid:A].oset:r <- [keyid:B].oset:r depending on their intent. It is an error to try (or probably to think): [keyid:A].oset:r <- [keyid:B].role:r Note also that [keyid:A].oset:os <- [keyid:B].role:r.oset:os Is the only valid linking credential for assigning o-sets. [keyid:B].role:r is a set of principals that may have defined an o-set (oset:os), but the members of an o-set could not have done so. Variables Both RT1 and RT2 allow rules defining roles or o-sets to match parameters using variable bindings. We illustrate with roles here, though all of this holds for o-sets. The variables may be named to specify connections between the role to be defined and the roles used to define it. For example the rule (in paper notation): A.evaluatorOf(?x) <- A.managerOf(?x) means that if A.managerOf(mikeryan) <- faber then A.evaluatorOf(mikeryan) <- faber is also true. The two ?x es bind to the same thing. For more complex rules, we have to make sure that the types are also consistent: A.example(?x) <- A.isInteger(?x) & A.isFloat(?x) ?x is not allowed to match an integer-typed data object in the first clause and a float-typed one in the second. The papers say this is an invalid rule, but without knowing the types of the parameters it cannot be checked. We adopt the same variable naming convention, but require them to be prefixed with the types above. Variable names start with a ?, followed by a capitalized character and can contain [_\-a-zA-Z0-9], that is, alphanumerics, underscore and the hyphens. ? is a valid anonymous variable name. Multiple instances of ? in the same rule can bind to different types. This is OK: [keyid:A].role:weird([urn:?X]) <- [keyid:B].role:a([urn:?X], [int:?]) & [keyid:C].role:b([urn:?X], [boolean:?]) Other examples: [keyid:A].role:example([int:?X]) <- [keyid:A].role:isInteger([int:?X]) & [keyid:A].role:isFloat([int:?X]) is valid [keyid:A].role:example([int:?X]) <- [keyid:A].role:isInteger([int:?X]) & [keyid:A].role:isFloat([float:?X]) is not, because the types of ?X are different. In addition to the data object types, the "principal" type is allowed as well, indicating that the variable must match an ABAC principal. The first example in this section is written: [keyid:A].role:evaluatorOf([principal:?X]) <- [keyid:A].role:managerOf([principal:?X]) A special keyword "this" for principal type can be used as a data term. It is translated into an implicit principal variable and all appearances of "this" data term refer to the same binding within the credential. Constraints A constraint is a static (RT1) or dynamic (RT2) set of valid choices for a parameter. There are two kinds of constraint sets, static and dynamic. A dynamic constraint set is an o-set or role. Static constraint sets are a list of valid values. Constraints are separated from a variable name by a colon (:). We specify a static set by enclosing the values in [] separated by commas. Because the set is bound to a typed variable, the values in the set can omit the [type:], so we write: [keyid:A].role:r([int:?X:[1,3,5]) not [keyid:A].role:r([int:?X:[[int:1],[int:3],[int:5]]]) For ordered sets like integers, floats and dates, the .. sequence specifies a range: [keyid:A].role:r(int:?X:[1..5]) in static constraint sets, commas, elipses (..), and the bracket characters [, ] must be escaped using a backslash (\) prefix. The constraint can also be an o-set (for objects) or a role (for a principal). Variable name is not syntactically separated from o-set/role constraint with a colon. [keyid:A].role:r([principal:?X[[keyid:A].role:r1]) [keyid:A].role:r([urn:?X[[keyid:A].oset:o1]) A Complex Example The example on p. 10 of "Design of a Role-Based Trust Management Framework" starts with the rule Alpha.fileAc(read, ?F:Alpha.documents(?proj)) <- Alpha.team(?proj) and says that given Alpha.documents(proj1) <- fileA Alpha.team(proj1) <- Bob one can conclude Alpha.fileAc(read, fileA) <- Bob In our notation the initial rule is encoded (note the mingling of o-sets and roles) [keyid:Alpha].role:fileAc([string:"read"], [string:?F:[keyid:Alpha].oset:documents([string:?proj])]) <- [keyid:Alpha].role:team([string:?proj]) and given [keyid:Alpha].oset:documents([string:"proj1"]) <- [string:"fileA"] [keyid:Alpha].role:team([string:"proj1"]) <- [keyid:Bob] one can conclude [keyid:Alpha].role:fileAc([string:"read"], [string:"fileA"]) <- [keyid:Bob] It is more verbose, but draws out the different roles and o-sets in play. REFERENCES [Li03rt] Li, N. and Mitchell, J. C. RT: A role-based trust-management framework. In Proceedings of the Third DARPA Information Survivability Conference and Exposition. IEEE Computer Society Press, 201­212. http://groups.geni.net/geni/wiki/TIEDABACModel http://groups.geni.net/geni/wiki/TIEDABACDemo