NAME
    Authorize::Rule - Rule-based authorization mechanism

VERSION
    version 0.001

SYNOPSIS
    A simple example:

        my $auth = Authorize::Rule->new(
            rules => {
                # Marge can do everything
                Marge => [ allow => '*' ],

                # Homer can do everything except go to the kitchen
                Homer => [
                    deny  => ['oven'],
                    allow => '*',
                ],

                # kids can clean and eat at the kitchen
                # but nothing else
                # and they can do whatever they want in their bedroom
                kids => [
                    allow => {
                        kitchen => {
                            action => ['eat', 'clean'],
                        },

                        bedroom => '*',
                    },

                    deny => ['kitchen'],
                ],
            },
        );

        $auth->check( Marge => 'kitchen' ); # 1
        $auth->check( Marge => 'garage'  ); # 1
        $auth->check( Marge => 'bedroom' ); # 1
        $auth->check( Homer => 'oven'    ); # 0
        $auth->check( Homer => 'kitchen' ); # 1

        $auth->check( kids => 'kitchen', { action => 'eat'     } ); # 1
        $auth->check( kids => 'kitchen', { action => 'destroy' } ); # 0

DESCRIPTION
    Authorize::Rule allows you to provide a set of rules for authorizing
    access of entities to resources. This does not cover authentication.
    While authentication asks "who are you?", authorization asks "what are
    you allowed to do?"

    The system is based on decisions per resources and their parameters.

    The following two authorization decisions are available:

    *   allow

        Allow an action. If something is allowed, 1 (indicating *true*) is
        returned.

    *   deny

        Deny an action. If something is denied, 0 (indicating *false*) is
        returned.

    The following levels of authorization are available:

    *   For all resources

        Cats think they can do everything.

            my $rules = {
                cats => [ allow => '*' ]
            };

            my $auth = Authorize::Rule->new( rules => $rules );
            $auth->check( cats => 'kitchen' ); # 1, success
            $auth->check( cats => 'bedroom' ); # 1, success

        The star (*) character means 'allow/deny all resources to this
        entity'. By setting the "cats" entity to "allow", we basically allow
        cats on all resources. The resources can be anything such as couch,
        counter, tables, etc.

        If you don't like the example of cats (what's wrong with you?), try
        to think of a department (or person) given all access to all
        resources in your company:

            $rules = {
                syadmins => [ allow => '*' ],
                CEO      => [ allow => '*' ],
            }

    *   Per resource

        Dogs, however, provide less of a problem. Mostly if you tell them
        they aren't allowed somewhere, they will comply. Dogs can't get on
        the table. Except the table, we do want them to have access
        everywhere.

            $rules = {
                cats => [ allow => '*' ],
                dogs => [
                    deny  => ['table'], # they can't go on the table
                    allow => '*',       # otherwise, allow everything
                ],
            }

        To provide access (allow/deny) to resources, you have specify them
        as an array. This helps differ between the star character for 'all'.

        Rules are read consecutively and as soon as a rule matches the
        matching stops.

        You can provide multiple resources in a single rule. That way we can
        ask dogs to also keep away from the laundry room:

            $rules = {
                cats => [ allow => '*' ],
                dogs => [
                    deny  => [ 'table', 'laundry room' ], # they can't go on the table
                    allow => '*',                         # otherwise, allow everything
                ],
            }

        Suppose we adopted kitties and we want to keep them safe until they
        grow older, we keep them in our room and keep others out:

            $rules = {
                cats => [ deny => ['bedroom'], allow => '*' ],
                dogs => [
                    deny  => [ 'table', 'laundry room', 'bedroom' ],
                    allow => '*',
                ],

                kitties => [
                    allow => ['bedroom'],
                    deny  => '*',
                ],
            }

        A corporate example might refer to some departments (or persons)
        having access to some resources while denied everything else, or a
        certain resource not available to some while all others are.

            $rules = {
                CEO => [
                    deny  => ['Payroll'],
                    allow => '*',
                ],

                support => [
                    allow => [ 'UserPreferences', 'UserComplaintHistory' ],
                    deny  => '*',
                ],
            }

        You might ask 'what if there is no last catch-all rule at the end?'
        - the answer is that the "default" clause will be used. You can find
        an explanation of it under *ATTRIBUTES*.

    *   Per resource and per conditions

        This is the most extensive control you can have. This allows you to
        set permissions based on conditions, such as specific parameters per
        resource.

        The conditions are sent to the "check" method as additional
        parameters and checked against it.

        Suppose we have no problem for the dogs to walk on that one table we
        don't like?

            my $rules => {
                dogs => [
                    allow => {
                        table => { owner => ['someone-else'] }
                    },

                    deny  => ['table'],
                    allow => '*',
                ]
            };

            my $auth = Authorize::Rule->new( rules => $rules );
            $auth->check( dogs => 'table', { owner => 'me' } ); # 0, fails

        Of course you can use a star ("*") as the value which means 'all'.

        Since you specify values as an array, you can specify multiple
        values. They will each be checked against the value of each hash
        key. We assume the hash value for each key is a single string.

        Here we specify a list of people whose things we don't mind the dog
        ruining:

            my $rules => {
                dogs => [
                    allow => {
                        table => { owner => ['jim', 'john'] }
                    },

                    deny  => ['table'],
                    allow => '*',
                ]
            };

            my $auth = Authorize::Rule->new( rules => $rules );
            $auth->check( dogs => 'table', { owner => 'me'   } ); # 0, fails
            $auth->check( dogs => 'table', { owner => 'jim'  } ); # 1, succeeds
            $auth->check( dogs => 'table', { owner => 'john' } ); # 1, succeeds

    More complicated structures (other than hashref of keys to string
    values) are currently not supported, though there are plans to add
    callbacks in order to allow the user to specify their own checks of
    conditions.

ALPHA CODE
    I can't promise some of this won't change in the next few versions.

    Stay tuned.

ATTRIBUTES
  default
    In case there is no matching rule for the entity/resource/conditions,
    what would you like to do. The default is to deny (0), but you can
    change it to allow by default if there is no match.

        Authorize::Rule->new(
            default => 1, # allow by default
            rules   => {...},
        );

  rules
    A hash reference of your permissions.

    Top level keys are the entities. This can be groups, users, whichever
    way you choose to view it.

        {
            ENTITY => RULES,
        }

    For each entity you provide an arrayref of the rules. The will be read
    and matched in sequential order. It's good practice to have an explicit
    last one as the catch-all for that entity. However, take into account
    that there is also the "default". By default it will deny unless you
    change the default to allow.

        {
            ENTITY => [
                RULE1,
                RULE2,
            ],
        }

    Each rule contains a key of the action, either to "allow" or "deny",
    followed by a resource definition.

        {
            ENTITY => [
                ACTION => RESOURCE
            ]
        }

    You can provide a value of star ("*") to say 'this entity can do
    everything' or 'this entity cannot do anyting'. You can provide an
    arrayref of the resources you want to allow/deny.

        {
            Bender => [
                deny  => [ 'fly ship', 'command team' ],
                allow => '*', # allow everything else
            ],

            Leila => [
                deny  => ['goof off'],
                allow => [ 'fly ship', 'command team' ],
                # if none are matched, it will take the default
            ]
        }

    You can also provide conditions as a hashref for each resource. The
    value should be either a star ("*") to match key existence, or an
    arrayref to try and match the value.

        {
            Bender => [
                allow => {
                    # must have booze to function
                    functioning => { booze => '*' }
                },

                # allow friendship to these people
                allow => {
                    friendship => { person => [ 'Leila', 'Fry', 'Amy' ]
                },

                # deny friendship to everyone else
                deny => ['friendship'],
            ]
        }

METHODS
  check
        $auth->check( ENTITY, RESOURCE );
        $auth->check( ENTITY, RESOURCE, { CONDITIONS } );

    You decide what entities and resources you have according to how you
    define the rules.

    You can think of resources as possible actions on an interface:

        my $auth = Authorize::Rule->new(
            rules => {
                Sawyer => [ allow => [ 'view', 'edit' ] ]
            }
        );

        $auth->check( Sawyer => 'edit' )
            or die 'Sawyer is not allowed to edit';

    However, if you have multiple interfaces (which you usually do in more
    complicated environments), your resources are those interfaces:

        my $auth = Authorize::Rule->new(
            rules => {
                Sawyer => [ allow => [ 'Dashboard', 'Forum' ] ],
            }
        );

        # can I access the dashboard?
        $auth->check( Sawyer => 'Dashboard' );

    That's better. However, it doesn't describe what Sawyer can do in each
    resource. This is why you have conditions.

        my $auth = Authorize::Rule->new(
            rules => {
                Sawyer => [
                    allow => {
                        Dashboard => { action => ['edit', 'view'] }
                    }
                ]
            }
        );

        $auth->check( Sawyer => 'Dashboard', { action => 'delete' } )
            or die 'Stop trying to delete the Dashboard, Sawyer!';

AUTHOR
    Sawyer X <xsawyerx@cpan.org>

COPYRIGHT AND LICENSE
    This software is copyright (c) 2013 by Sawyer X.

    This is free software; you can redistribute it and/or modify it under
    the same terms as the Perl 5 programming language system itself.

