NAME

OpenInteract::Auth - Authenticate the user object and create its groups

SYNOPSIS

# Authenticate the user based on the session information
# or the login information

OpenInteract::Auth->user;

# Fetch the groups for the logged-in user

OpenInteract::Auth->group;

# See whether this user is an administrator

OpenInteract::Auth->is_admin;

# Run custom methods as defined in the server configuration

OpenInteract::Auth->custom_handler;

DESCRIPTION

This class/interface is responsible for authenticating users to the system and other authentication checks. If you have custom authentication needs you can specify your class in the server configuration and create your own or subclass this class and use pieces of it as needed.

This class tries to create a user in one of two ways:

  1. Find the user_id in their session information and create a user object from it.

  2. Find the $LOGIN_FIELD and $PASSWORD_FIELD arguments passed in via GET/POST and try to create a user with that login name and check the password.

If either of these is successful, then we create a user object and put it into:

$R->{auth}{user}

where it can be retrieved by all other handlers, modules, etc. Otherwise we create a 'transient' (not serialized) user object for every request via the create_nologin_user() method, which you can override by subclassing this class.

The class also creates an arrayref of groups the user belongs to as long as the user is a valid one.

METHODS

Neither of these methods returns a value that reflects what they did. Their success is judged by whether $R has entries for the user and groups.

user()

Creates a user object by whatever means possible and puts it into:

$R->{auth}{user}

Note that we also set:

$R->{auth}{logged_in}

which should be used to see whether the user is logged in or not. We will be changing the interface slightly so that you can no longer just check to see if $R->{auth}->{user} is defined. It will be defined with the 'not-logged-in' user to prevent some a nasty bug from happening.

In this method we check to see whether the user has typed in a new username and password. By default, the method will check in the variables 'login_login_name' for the username and 'login_password' for the password. (Both are stored as constants in this module.)

However, you can define your own variable names in your conf/server.perl file. Just set:

login => { login_name => 'xxx',
           password   => 'xxx', ... },

(If you modify the template for logging in to have new names under the 'INPUT' variables you will want to change these.)

You can also define custom behavior for a login by specifying in the server configuration:

login => { custom_handler => 'My::Handler::Login' },

The handler() method will then be called on 'My::Handler::Login' after the users and groups have been fetched when the method custom_handler() is called on this class or a subclass.

group()

If a user object has been created, this fetches the groups the user object belongs to and puts the arrayref of groups into:

$R->{auth}{group}

is_admin()

Looks at the user and groups and determines whether the user is an administrator. If the user is an administrator, then:

$R->{auth}{is_admin}

is set to a true value.

custom_handler()

Runs the handler defined in the server configuration key 'login.custom_handler' using the method 'login.custom_method' or 'handler', if that is not defined.

If the custom handler fails, we will call 'login.custom_fail_method' on the same class if the key is defined.

SUBCLASSING

As of OpenInteract 1.35, this module is now more amenable to subclassing. Both the user() and group() methods are broken down into more discrete actions which you can override as you need.

User Fetching Actions

fetch_user_id()

Retrieves the user ID for this request.

Default: get the 'user_id' key from the session.

Returns: user ID value.

fetch_user( $user_id )

Called only if a user ID is found using fetch_user_id(). This method retrieves the user object corresponding to $user_id.

Note that if you are using SPOPS for this (recommended), you almost certainly want to pass a true value for the 'skip_security' parameter, such as:

return $R->user->fetch( $uid, { skip_security => 1 } );

Because otherwise the superuser will never be able to login

Default: get the SPOPS user object matching $user_id.

Returns: user object on success, undef if user object not found, a die on failure.

fetch_user_failed( $user_id )

Called only if fetch_user() throws a die.

Default: Throws a code '311' error, blanks out the 'user_id' key of the session and returns undef.

Returns: not checked

check_first_login()

Called if fetch_user() succeeds. Many times you want to execute certain actions when the user logs in for the first time. This is a hook for you to do so.

Default: Make the user part of the 'public' group (this should probably done elsewhere)

Returns: not checked

login_user()

Called if fetch_user_id() does not find a user ID. This should look at the form values passed in and find at least a login name and password. If values for these are not found, the function returns undef.

If these values are found, the function should fetch the user and authenticate the user by whatever means are appropriate. If the user is properly authenticated, the function should set whatever values are necessary to ensure the user can be found by fetch_user_id() -- by default, this means setting 'user_id' in the session, but your application might use a different means to track the user.

Default: Look at the 'login_field' and 'password_field' as set in the server configuration under 'login' for the username and password.

Returns: A user object, along with setting the user object to {auth}{user} in the OpenInteract::Request object. If you cannot create one, just return undef.

remember_login()

Default is to make sessions (along with user identification) transient -- once the browser that created the session is closed, the cookie expires. The user can choose to have the system and their browser remember the session for a longer period of time (specified in the server config key 'session'->'expiration').

This method makes the session non-transient if either the user checks off the 'remember_field' checkbox (the fieldname is specified in the server config key 'login'->'remember_field') or if the server config setting for 'login'->'always_remember' is true.

custom_login_failed()

Executed if the execution of the custom login handler fails. (The custom login handler is specified by the class and method defined in the server configuration under 'login', 'custom_login_handler' and 'custom_login_method'.)

Default: Run create_nologin_user().

Returns: not checked

create_nologin_user()

If a user is not logged in, we create transient user object so that all OpenInteract handlers have something they can refer to. It is not a valid user and it gets created anew with every request where the user is not logged in.

If you want to rename the login_name, first/last name, etc, just subclass this class, create your own method, then specify your class in the server configuration under 'auth'.

This method should ensure that the system knows a user is not logged in by setting:

$R->{auth}{logged_in} = undef;

and by blanking out any tracking information your application sets in the session.

Finally, the method should set:

$R->{auth}{user}

To the transient user object you have created.

Group Fetching Actions

None! The group() method is so simple that we thought breaking it into pieces would make it overly complex. If you override it, your code should look something like:

if ( $R->{auth}{logged_in} ) {
   $R->{auth}{group} = $R->{auth}{user}->group;
}

Which is basically all this method does, with some error checking and debugging thrown in.

TO DO

Ticket handling

We should put checks in here to allow an application to check for expired authentication tickets, or to allow a module to add an authentication handler as a callback which implements its own logic for this.

BUGS

None known.

SEE ALSO

OpenInteract::User

OpenInteract::Group

COPYRIGHT

Copyright (c) 2001-2002 intes.net, inc.. All rights reserved.

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

AUTHORS

Chris Winters <chris@cwinters.com>