.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 .\" .\" Standard preamble: .\" ======================================================================== .de Sh \" Subsection heading .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. | will give a .\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to .\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' .\" expand to `' in nroff, nothing in troff, for use with C<>. .tr \(*W-|\(bv\*(Tr .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .\" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .hy 0 .if n .na .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Tree::Authz 3" .TH Tree::Authz 3 "2008-01-13" "perl v5.8.8" "User Contributed Perl Documentation" .SH "NAME" Tree::Authz \- inheritance\-based authorization scheme .SH "VERSION" .IX Header "VERSION" 0.02_1 .SH "DEVELOPER RELEASE" .IX Header "DEVELOPER RELEASE" Re-organised to return objects (blessed into the new class \f(CW\*(C`Tree::Authz::Role\*(C'\fR), instead of strings, which are now referred to as \f(CW\*(C`roles\*(C'\fR rather than \f(CW\*(C`groups\*(C'\fR in the documentation. Some method names changed to reflect the terminology. .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& use Tree::Authz; .Ve .PP .Vb 8 \& my $roles = { superuser => [ qw( spymasters politicians ) ], \& spymasters => [ qw( spies moles ) ], \& spies => [ 'informants' ], \& informants => [ 'base' ], \& moles => [ 'base' ], \& politicians => [ 'citizens' ], \& citizens => [ 'base' ], \& }; .Ve .PP .Vb 1 \& my $authz = Tree::Authz->setup_hierarchy( $roles, 'SpyLand' ); .Ve .PP .Vb 4 \& my $superuser = $authz->role( 'superuser' ); \& my $spies = $authz->role( 'spies' ); \& my $citizens = $authz->role( 'citizens' ); \& my $base = $authz->role( 'base' ); .Ve .PP .Vb 3 \& $spies ->setup_permissions( [ qw( read_secrets wear_disguise ) ] ); \& $citizens->setup_permissions( 'vote' ); \& $base ->setup_permissions( 'breathe' ); .Ve .PP .Vb 9 \& foreach my $role ( $superuser, $spies, $citizens, $base ) { \& foreach my $ability ( qw( unspecified_ability \& spy \& spies \& read_secrets \& wear_disguise \& vote \& breathe \& can ) ) { .Ve .PP .Vb 8 \& if ( $role->can( $ability ) ) { \& print "$role can '$ability'\en"; \& } \& else { \& print "$role cannot '$ability'\en"; \& } \& } \& } .Ve .PP .Vb 1 \& # prints: .Ve .PP .Vb 32 \& superuser can 'unspecified_ability' # superpowers! \& superuser can 'spy' \& superuser can 'spies' \& superuser can 'read_secrets' \& superuser can 'wear_disguise' \& superuser can 'vote' \& superuser can 'breathe' \& superuser can 'can' \& spies cannot 'unspecified_ability' \& spies can 'spy' \& spies can 'spies' \& spies can 'read_secrets' \& spies can 'wear_disguise' \& spies can 'vote' \& spies can 'breathe' \& spies can 'can' \& citizens cannot 'unspecified_ability' \& citizens cannot 'spy' \& citizens cannot 'spies' \& citizens cannot 'read_secrets' \& citizens cannot 'wear_disguise' \& citizens can 'vote' \& citizens can 'breathe' \& citizens can 'can' \& base cannot 'unspecified_ability' \& base cannot 'spy' \& base cannot 'spies' \& base cannot 'read_secrets' \& base cannot 'wear_disguise' \& base cannot 'vote' \& base cannot 'breathe' # ! \& base cannot 'can' # !! .Ve .PP .Vb 2 \& # storing code on the nodes (roles) of the tree \& $spies->setup_abilities( read_secret => $coderef ); .Ve .PP .Vb 1 \& print $spies->read_secret( '/path/to/secret/file' ); .Ve .PP .Vb 1 \& $spies->setup_plugins( 'My::Spies::Skills' ); .Ve .PP .Vb 1 \& $spies->fly( $jet ); # My::Spies::Skills::fly .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" Class for inheritable, role-based permissions system (Role Based Access Control \- \s-1RBAC\s0). .PP Custom methods can be placed on role objects. Authorization can be performed either by checking whether the role name matches the required name, or by testing (via \f(CW\*(C`can\*(C'\fR) whether the role can perform the method required. .PP Two role are specified by default. At the top, \fIsuperuser\fRs can do anything (\f(CW\*(C`$superuser\->can( $action )\*(C'\fR always returns a coderef). At the bottom, the \&\fIbase\fR role can do nothing (\f(CW\*(C`$base\->can( $action )\*(C'\fR always returns undef). .PP All roles are automatically capable of authorizing actions named for the singular and plural of the role name. .Sh "\s-1ROADMAP\s0" .IX Subsection "ROADMAP" I'm planning to implement some of the main features and terminology described in this document, which describes a standard for Role Based Access Control: .PP .Vb 1 \& http://csrc.nist.gov/rbac/rbacSTD-ACM.pdf .Ve .PP Thanks to Kingsley Kerce for providing the link. .SH "METHODS" .IX Header "METHODS" This class is a static class \- all methods are class methods. .PP Some methods return Tree::Authz::Role subclass objects. .Sh "Namespaces and class methods" .IX Subsection "Namespaces and class methods" This class is designed to work in environments where multiple applications run within the same process (i.e. websites under \f(CW\*(C`mod_perl\*(C'\fR). If the optional namespace parameter is supplied to \f(CW\*(C`setup_hierarchy\*(C'\fR, the roles are isolated to the specified namespace. All methods should be called through the class name returned from \f(CW\*(C`setup_hierarchy\*(C'\fR. .PP If your program is not operating in such an environment (e.g. \s-1CGI\s0 scripts), then you can completely ignore this parameter, and call class methods either through \f(CW\*(C`Tree::Authz\*(C'\fR, or through the string returned from \f(CW\*(C`setup_hierarchy\*(C'\fR (which, funnily enough, will be 'Tree::Authz'). .ie n .IP "role( $role_name )" 4 .el .IP "role( \f(CW$role_name\fR )" 4 .IX Item "role( $role_name )" Factory method, returns a Tree::Authz::Role subclass object. .Sp Sets up two permitted actions on the group \- the singular and plural of the group name. \fBThis might be too cute, and could change to just the group name in a near future release\fR. Opinions welcome. .ie n .IP "new( $role_name )" 4 .el .IP "new( \f(CW$role_name\fR )" 4 .IX Item "new( $role_name )" \&\s-1DEPRECATED\s0. .Sp Use \f(CW\*(C`role\*(C'\fR instead. .ie n .IP "get_group( $group_name )" 4 .el .IP "get_group( \f(CW$group_name\fR )" 4 .IX Item "get_group( $group_name )" \&\s-1DEPRECATED\s0. .Sp Use \f(CW\*(C`role\*(C'\fR instead. .ie n .IP "role_exists( $role_name )" 4 .el .IP "role_exists( \f(CW$role_name\fR )" 4 .IX Item "role_exists( $role_name )" Returns true if the specified group exists \fBanywhere\fR within the hierarchy. .ie n .IP "group_exists( $group_name )" 4 .el .IP "group_exists( \f(CW$group_name\fR )" 4 .IX Item "group_exists( $group_name )" \&\s-1DEPRECATED\s0. .Sp Use \f(CW\*(C`role_exists\*(C'\fR instead. .ie n .IP "subrole_exists( $subrole_name\fR, [ \f(CW$role_name ] )" 4 .el .IP "subrole_exists( \f(CW$subrole_name\fR, [ \f(CW$role_name\fR ] )" 4 .IX Item "subrole_exists( $subrole_name, [ $role_name ] )" \&\fBMethod not implemented yet\fR. .Sp Give me a nudge if this would be useful. .Sp Returns true if the specified role exists anywhere in the hierarchy underneath the current or specified role. .IP "\fIlist_roles()\fR" 4 .IX Item "list_roles()" Returns an array or arrayref of all the role names in the hierarchy, sorted by name. .IP "\fIlist_groups()\fR" 4 .IX Item "list_groups()" \&\s-1DEPRECATED\s0. .Sp Use \f(CW\*(C`list_roles\*(C'\fR instead. .ie n .IP "dump_hierarchy( [ $namespace ] )" 4 .el .IP "dump_hierarchy( [ \f(CW$namespace\fR ] )" 4 .IX Item "dump_hierarchy( [ $namespace ] )" Get a simple printout of the structure of your hierarchy. .Sp This method \f(CW\*(C`require\*(C'\fRs Devel::Symdump. .Sp If you find yourself parsing the output and using it somehow in your code, let me know, and I'll find a Better Way to provide the data. This method is just intended for quick and dirty printouts and could \fBchange at any time\fR. .ie n .IP "setup_hierarchy( $groups\fR, [ \f(CW$namespace ] )" 4 .el .IP "setup_hierarchy( \f(CW$groups\fR, [ \f(CW$namespace\fR ] )" 4 .IX Item "setup_hierarchy( $groups, [ $namespace ] )" Class method. .Sp \&\fI$groups\fR has: .Sp .Vb 2 \& keys - group names \& values - arrayrefs of subgroup name(s) .Ve .Sp Sets up a hierarchy of Perl classes representing the group structure. .Sp The hierarchy will be contained within the \fI$namespace\fR top level if supplied. This makes it easy to set up several independent hierarchies to use within the same process, e.g. for different websites under \f(CW\*(C`mod_perl\*(C'\fR. .Sp Returns a class name through which group objects can be retrieved and other class methods called. This will be 'Tree::Authz' if no namespace is specified. .Sp If called with a \fI$namespace\fR argument, then all loaded packages within the \&\f(CW$namespace::Tree::Authz\fR symbol table hierarchy are removed (using Symbol::delete_package from the symbol table. This is experimental and may lead to bugs, the jury is still out. The purpose of this is to allow re-initialisation of the setup within a long-running process such as \f(CW\*(C`mod_perl\*(C'\fR. It could also allow dynamic updates to the hierarchy. .Sh "Persistence" .IX Subsection "Persistence" Tree::Authz can be used independently of a persistence mechanism \&\fIvia\fR \f(CW\*(C`setup_hierarchy\*(C'\fR. However, if you want to manipulate the hierarchy at runtime, a persistence mechanism is required. The implementation is left up to you, but the \s-1API\s0 is defined. The persistence \s-1API\s0 should be implemented by the object passed to \f(CW\*(C`setup_from_database\*(C'\fR. .ie n .IP "setup_from_database( $database\fR, [ \f(CW$namespace ] )" 4 .el .IP "setup_from_database( \f(CW$database\fR, [ \f(CW$namespace\fR ] )" 4 .IX Item "setup_from_database( $database, [ $namespace ] )" \&\fI$database\fR should be an object that responds to the persistence \s-1API\s0 defined below. The object is stored as class data and is available via the \f(CW\*(C`_database\*(C'\fR method. .PP \fIPass-through methods\fR .IX Subsection "Pass-through methods" .PP The following methods are passed on to the database object, after checking whether any changes would result in a recursive inheritance pattern, in which case they return false. The database methods should return true on success. .IP "\fIget_roles_data()\fR" 4 .IX Item "get_roles_data()" Returns a hashref. Keys are role names, values are arrayrefs of subroles. .Sp \&\f(CW\*(C`setup_from_database\*(C'\fR calls this method on the database object, then passes the data on to \f(CW\*(C`setup_hierarchy\*(C'\fR. .ie n .IP "add_role( $new_role\fR, \f(CW$parent\fR, [ \f(CW$children ] )" 4 .el .IP "add_role( \f(CW$new_role\fR, \f(CW$parent\fR, [ \f(CW$children\fR ] )" 4 .IX Item "add_role( $new_role, $parent, [ $children ] )" Adds a new role to the scheme. .Sp \&\fI$parent\fR is required, so no new top-level roles can be inserted. It's up to you to decide whether to raise an error or just return if \fI$parent\fR is omitted. .Sp \&\fI$children\fR can be a role name or an arrayref of role names. Defaults to \&\f(CW'base'\fR if omitted. It might be worth checking if these roles already exist. .Sp At the moment I am assuming no multiple inheritance, but things are shaping up to look like there's no great difficulty about allowing it. If allowed, this method should check if \fI$new_role\fR already exists. If it does, ignore any \&\fI$children\fR (probably raise a warning), add <$new_role> to the sub-roles list of \fI$parent\fR, and return without trying to insert \fI$new_role\fR into the database (because it already exists). .ie n .IP "remove_role( $role )" 4 .el .IP "remove_role( \f(CW$role\fR )" 4 .IX Item "remove_role( $role )" Removes the role from the database, including finding and removing any occurrences of \fI$role\fR in the sub-role lists of other roles. .Sp Returns the list of subroles for the role that was removed, in case you want to put them somewhere else. .ie n .IP "move_role( $role\fR, \f(CW$to )" 4 .el .IP "move_role( \f(CW$role\fR, \f(CW$to\fR )" 4 .IX Item "move_role( $role, $to )" Makes \fI$role\fR a sub-role of \fI$to\fR, and deletes it from the sub-roles list of its current parent. .ie n .IP "add_subrole( $role\fR, \f(CW$subrole )" 4 .el .IP "add_subrole( \f(CW$role\fR, \f(CW$subrole\fR )" 4 .IX Item "add_subrole( $role, $subrole )" Adds a subrole to a role. Must remove \f(CW'base'\fR from the subroles list if present. .ie n .IP "remove_subrole( $role\fR, \f(CW$subrole )" 4 .el .IP "remove_subrole( \f(CW$role\fR, \f(CW$subrole\fR )" 4 .IX Item "remove_subrole( $role, $subrole )" Removes a subrole from a role. If the resulting list of subroles would be empty, must insert \f(CW'base'\fR. .Sh "Adding authorizations" .IX Subsection "Adding authorizations" .ie n .IP "setup_permissions_on_role( $role_name\fR, \f(CW$cando )" 4 .el .IP "setup_permissions_on_role( \f(CW$role_name\fR, \f(CW$cando\fR )" 4 .IX Item "setup_permissions_on_role( $role_name, $cando )" Class method version of \f(CW\*(C`Tree::Authz::Role::setup_permissions\*(C'\fR. .ie n .IP "setup_permissions_on_group( $group_name\fR, \f(CW$cando )" 4 .el .IP "setup_permissions_on_group( \f(CW$group_name\fR, \f(CW$cando\fR )" 4 .IX Item "setup_permissions_on_group( $group_name, $cando )" \&\s-1DEPRECATED\s0. .Sp Use \f(CW\*(C`setup_permissions_on_role\*(C'\fR instead. .ie n .IP "setup_abilities_on_role( $role_name\fR, \f(CW%code )" 4 .el .IP "setup_abilities_on_role( \f(CW$role_name\fR, \f(CW%code\fR )" 4 .IX Item "setup_abilities_on_role( $role_name, %code )" Class method version of \f(CW\*(C`Tree::Authz::Role::setup_abilities\*(C'\fR. .ie n .IP "setup_abilities_on_group( $group_name\fR, \f(CW%code )" 4 .el .IP "setup_abilities_on_group( \f(CW$group_name\fR, \f(CW%code\fR )" 4 .IX Item "setup_abilities_on_group( $group_name, %code )" \&\s-1DEPRECATED\s0. .Sp Use \f(CW\*(C`setup_abilities_on_role\*(C'\fR instead. .ie n .IP "setup_plugins_on_role( $role_name\fR, \f(CW$plugins )" 4 .el .IP "setup_plugins_on_role( \f(CW$role_name\fR, \f(CW$plugins\fR )" 4 .IX Item "setup_plugins_on_role( $role_name, $plugins )" Class method version of \f(CW\*(C`Tree::Authz::Role::setup_plugins\*(C'\fR. .ie n .IP "setup_plugins_on_group( $group_name\fR, \f(CW$plugins )" 4 .el .IP "setup_plugins_on_group( \f(CW$group_name\fR, \f(CW$plugins\fR )" 4 .IX Item "setup_plugins_on_group( $group_name, $plugins )" Deprecated version of \f(CW\*(C`setup_plugins_on_role\*(C'\fR. .SH "CHANGES" .IX Header "CHANGES" The deprecation policy is: .PP 1) \s-1DEPRECATED\s0 methods issue a warning (via \f(CW\*(C`carp\*(C'\fR) and then call the new method. They will be documented next to the replacement method. .PP 2) \s-1OBSOLETE\s0 methods will croak. These will be documented in a separate section. .PP 3) Removed methods will be documented in a separate section, in the first version they no longer exist in. .PP Main changes in 0.02 .PP .Vb 7 \& - changed terminology to refer to I instead of I. Deprecated \& all methods with I in their name. These methods now issue a \& warning via C, and will be removed in a future release. \& - added a new class to represent a role - L. \& L is now a static class (all its methods are \& class methods). The objects it returns from some methods are subclasses \& of L. .Ve .SH "TODO" .IX Header "TODO" Roles are now represented by their own class. This should make it easier to add constraints and other \s-1RBAC\s0 features. .PP More methods for returning meta information, e.g. immediate subroles of a role, all subroles of a role, list available actions of a role and its subroles. .PP Might be nice to register users with roles. .PP Make role objects be singletons \- not necessary if the only data they carry is their own name. .PP Under \f(CW\*(C`mod_perl\*(C'\fR, all setup of hierarchies and permissions must be completed during server startup, before the startup process forks off Apache children. It would be nice to have some way of communicating updates to other processes. Alternatively, you could run the full startup sequence every time you need to access a Tree::Authz role, but that seems sub\-optimal. .SH "DEPENDENCIES" .IX Header "DEPENDENCIES" Lingua::EN::Inflect::Number, Class::Data::Inheritable. .PP Optional \- Devel::Symdump. .PP Sub::Override for the test suite. .SH "BUGS" .IX Header "BUGS" Please report all bugs via the \s-1CPAN\s0 Request Tracker at . .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" Copyright 2004 by David Baird. .PP This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. .SH "AUTHOR" .IX Header "AUTHOR" David Baird, \f(CW\*(C`cpan@riverside\-cms.co.uk\*(C'\fR .SH "SEE ALSO" .IX Header "SEE ALSO" DBIx::UserDB, Data::ACL.