in reply to CGI::Application with access control on certain functions/run modes

One approach is to nest CGI::Applications within each other. Then put authorization on the individual C::As. See Re: Why CGI::Application? for an outline of this approach.

In general I'd suggest that scattering authorization logic around is somewhat fragile, and will make it hard to determine who can do what, and that someone who shouldn't be able to X really has no way to get that privilege. A missed authorization step is very easy to overlook both while coding and testing. So try to make that step very rarely.

Note that I'm drawing a critical but subtle distinction between authentication and authorization. When you authenticate someone you are determining that they are who they say they are. There are multiple ways that you can do that (cookies, Basic, Digest, etc). This is orthogonal to how you authorize that person to have permission to do critical things.

In your design, assume that there is a standard way of knowing who someone claims to be. In your authorization logic you don't have to care what that is, just that it must be available in some specified and convenient way. When you set up authentication, make sure that that is satisfied. (This can be as simple as turning on Digest authentication and having the webserver put the user name in an environment variable for you.)

  • Comment on Re: CGI::Application with access control on certain functions/run modes

Replies are listed 'Best First'.
Re: Re: CGI::Application with access control on certain functions/run modes
by Golo (Friar) on Mar 28, 2004 at 14:19 UTC
    "One approach is to nest CGI::Applications within each other. Then put authorization on the individual C::As"
    I see that this would be the prefered way when your individual C::As implement a functionality which requires new run-modes anyways or you don't mind overwritting/rewriting some runmode with altered functionality. But that's exactly where my problem is:

    In my guestbook example I want to come around having to overwrite or rewrite the view method, just to add that extra piece of information (showing the IP of the poster, and maybe adding a link to the "delete" run-mode). I don't see a way of accomplishing that with creating an additional C::A (but maybe I shouldn't be that lazy?)

    Besides from that other C::A part my strategy in regards to authentification and authorization goes a very similar way as described in Re: Why CGI::Application?.
    Instead of having the intance script calling another C::A, my instance script enables the accessible run-modes via the enable_rm_set('X', 'Y', 'Z') method. If a user tries to call one of the restricted run modes (rm=delete in this example), he run's into the same error as when calling it from a different C::A. In both cases, the C::A does not know the called run mode.
    "In general I'd suggest that scattering authorization logic around is somewhat fragile"
    Agreed, but in a case like this the only required steps is to check if a privileged "run-mode set" has been loaded and if authentification has been performed.

    The first is set in the enable_rm_set() by setting $self->param("run-mode set" => '1').

    The second is done only in the "delete" run-mode (out of laziness, to spare me copying the admin.pl to a secured and unsecured area on the webserver, and having to type the different links). It really should be placed into the setup() like this:
    if ($self->param('RESTRICTED')) { return _no_auth() unless defined($ENV{UserName}); }
    This should catch configuration mistakes in regards to authorization, e.g. if one forgot to enable access control to the admin.pl. This is following the logic of "if there was no authentification there can't be authorization, as we know it should be restricted in someway (not caring about the specific groups/users to be allowed)".

    The only "scattering of authorization logic" happens in the view run mode when adding those extra bits of information for the admin mode:
    if ($self->param('RESTRICTED')) { # add the infos for admins only }

    But that's the goal I am going for in this case.

    In the end it seems to come down to:

    Is there a way of achieving this (not having to overwrite/rewrite the view for that extra bit) without that bit of "authorization logic scattering"?

    If not, is this prize to pay a fair one or shall I better forget about the first point at all?
      I have a User object, which has all the authorization logic built into it. (It also has the authentication logic as well, but that's a separate concern.)

      Basically, setup() creates a User object and passes in the value of a cookie. This value can be anything from a userid (insecure) to a session id (secure). The User object knows how to authenticate that cookie value. At that point, I can then look that authenticated user up in some datastore and determine what privileges (or authorities) that user has. Then, a User object is returned. setup() then stores it as a param() of the C::A object.

      Then, when you need to determine if a given User has an authority, you ask the User object. It's that simple.

      This design principle is called "Separation of Concerns". Basically, it boils down to "Only those who care should know", or "Who cares?"

      ------
      We are the carpenters and bricklayers of the Information Age.

      Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose