Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
Catalyst::Plugin::AuthUsercContributedsPerllDoin::Authentication::Internals(3)

NAME
       Catalyst::Plugin::Authentication::Internals - All about authentication
       Stores and Credentials

INTRODUCTION
       Catalyst::Plugin::Authentication	provides a standard authentication
       interface to application	developers using the Catalyst framework. It is
       designed	to allow application developers	to use various methods of user
       storage and credential verification. It is also designed	to provide for
       minimal change to the application when switching	between	different
       storage and credential verification methods.

       While Catalyst::Plugin::Authentication provides the interface to	the
       application developer, the actual work of verifying the credentials and
       retrieving users	is delegated to	separate modules. These	modules	are
       called Credentials and storage backends,	or Stores, respectively. For
       authentication to function there	must be	at least one credential	and
       one store. A pairing of a store and a credential	is referred to as a
       Realm. There may	be any number of realms	defined	for an application,
       though most applications	will not require more than one or two.

       The details of using this module	can be found in	the
       Catalyst::Plugin::Authentication	documentation.

       What follows is an explanation of how the module	functions internally
       and what	is required to implement a credential or a store.

OVERVIEW
       There are two main entry	points you need	to be aware of when writing a
       store or	credential module. The first is	initialization and the second
       is during the actual call to the	Catalyst application's authenticate
       method.

       A simplified description	of the authentication process follows:

       Initialization

	   Realm Setup - for each realm:

	       1) The Realm is instantiated using new()	method

	       2) The Store is instantiated using new()	method

	       3) The Credential Instantiated using new() method

	       4) Credential and Store objects tied to realm for use during
	       requests

       Authentication

	   "$c->authenticate( $userinfo, $realm	)" called

	       1) Credential object retrieved for realm	provided

	       2) Credential's authenticate() method called with authinfo and
	       realm object for	current	realm

		   The realm object and	the authinfo hash are provided to the
		   credential object's authenticate call. In most cases	the
		   credential object will attempt to retrieve a	user using the
		   realm's find_user() method, which by	default	relays the
		   call	directly to the	Store's	find_user() method. It will
		   then	usually	compare	the retrieved user's information with
		   the information provided in the $authinfo hash. This	is how
		   the default 'Password' credential functions.	If the
		   credentials match, the authenticate() method	should return
		   a user object.

	       3) User object stored in	session

		   If the user object supports session storage,	the
		   successfully	authenticated user will	be placed in session
		   storage. This is done by calling the	realm object's
		   persist_user() method. The persist_user() routine by
		   default calls the Store's for_session() method, which
		   should return serialized data (IE a scalar).	This
		   serialized data is passed back to the store via the
		   from_session() method, so the data should contain enough
		   information for the store to	recreate / reload the user.

       Sessions	- Per-Request operations

	   When	any user-related activity occurs, and $c->authenticate has not
	   yet been called, the	Catalyst::Plugin::Authentication module	will
	   attempt to restore the persisted user (normally from	the session if
	   one is available).  There is	only one step in this process:

	       1) Store	object's from_session()	is called

	   The serialized data previously returned by the store's
	   for_session() method	is provided to the from_session() method. The
	   from_session() method should	return a valid user object.

	   Note	that the for_session() is only called during the original
	   $c->authenticate() call, so if changes are made to the user that
	   need	to be reflected	in your	session	data, you will want to call
	   the $c->persist_user() method - which will perform the session
	   storage process again (complete with	call to	for_session()).

       More detailed information about these processes is below.

   INITIALIZATION
       When the	authentication module is loaded, it reads it's configuration
       to determine the	realms to set up for the application and which realm
       is to be	the default. For each realm defined in the application's
       config, Catalyst::Plugin::Authentication	instantiates both a new
       credential object and a new store object. See below for the details of
       how credentials and stores are instantiated.

       NOTE: The instances created will	remain active throughout the entire
       lifetime	of the application, and	so should be relatively	lightweight.
       Care should be taken to ensure that they	do not grow, or	retain
       information per request,	because	they will be involved in each
       authentication request and could	therefore substantially	hurt memory
       consumption over	time.

   AUTHENTICATION
       When "$c->authenticate()" is called from	within an application, the
       objects created in the initialization process come into play.
       "$c->authenticate()" takes two arguments. The first is a	hash reference
       containing all the information available	about the user.	This will be
       used to locate the user in the store and	verify the user's credentials.
       The second argument is the realm	to authenticate	against. If the	second
       argument	is omitted, the	default	realm is assumed.

       The main	authentication module then locates the credential and store
       objects for the realm specified and calls the credential	object's
       "authenticate()"	method.	It provides three arguments, first the
       application object, or $c, then a reference to the store	object,	and
       finally the hashref provided in the "$c->authenticate" call. The	main
       authentication module expects the return	value to be a reference	to a
       user object upon	successful authentication. If it receives anything
       aside from a reference, it is considered	to be an authentication
       failure.	Upon success, the returned user	is marked as authenticated and
       the application can act accordingly, using "$c->user" to	access the
       authenticated user, etc.

       Astute readers will note	that the main Catalyst::Plugin::Authentication
       module does not interact	with the store in any way, save	for passing a
       reference to it to the credential. This is correct. The credential
       object is responsible for obtaining the user from the provided store
       using information from the userinfo hashref and/or data obtained	during
       the credential verification process.

WRITING	A STORE
       There are two parts to an authentication	store, the store object	and
       the user	object.

   STORAGE BACKEND
       Writing a store is actually quite simple.  There	are only five methods
       that must be implemented. They are:

	   new()	   - instantiates the store object
	   find_user()	   - locates a user using data contained in the	hashref
	   for_session()   - prepares a	user to	be stored in the session
	   from_session()  - does any restoration required when	obtaining a user from the session
	   user_supports() - provides information about	what the user object supports

       STORE METHODS

       new( $config, $app, $realm )
	   The "new()" method is called	only once, during the setup process of
	   Catalyst::Plugin::Authentication. The first argument, $config, is a
	   hash	reference containing the configuration information for the
	   store module. The second argument is	a reference to the Catalyst
	   application.

	   Note	that when new()	is called, Catalyst has	not yet	loaded the
	   various controller and model	classes, nor is	it definite that other
	   plugins have	been loaded, so	your new() method must not rely	on any
	   of those being present.  If any of this is required for your	store
	   to function,	you should defer that part of initialization until the
	   first method	call.

	   The "new()" method should return a blessed reference	to your	store
	   object.

       find_user( $authinfo, $c	)
	   This	is the workhorse of any	authentication store. It's job is to
	   take	the information	provided to it via the $authinfo hashref and
	   locate the user that	matches	it. It should return a reference to a
	   user	object.	A return value of anything else	is considered to mean
	   no user was found that matched the information provided.

	   How "find_user()" accomplishes it's job is entirely up to you, the
	   author, as is what $authinfo	is required to contain.	 Many stores
	   will	simply use a username element in $authinfo to locate the user,
	   but more advanced functionality is possible and you may bend	the
	   $authinfo to	your needs.  Be	aware, however,	that both Credentials
	   and Stores usually work with	the same $authinfo hash, so take care
	   to avoid overlapping	element	names.

	   Please note that this routine may be	called numerous	times in
	   various circumstances, and that a successful	match for a user here
	   does	NOT necessarily	constitute successful authentication. Your
	   store class should never assume this	and in most cases $c should
	   not be modified by your store object.

       for_session( $c,	$user )
	   This	method is responsible for preparing a user object for storage
	   in the session.  It should return information that can be placed in
	   the session and later used to restore a user	object (using the
	   "from_session()" method).  It should	therefore ensure that whatever
	   information provided	can be used by the "from_session()" method to
	   locate the unique user being	saved.	Note that there	is no
	   guarantee that the same Catalyst instance will receive both the
	   "for_session()" and "from_session()"	calls.	You should take	care
	   to provide information that can be used to restore a	user,
	   regardless of the current state of the application.	A good rule of
	   thumb is that if "from_session()" can revive	the user with the
	   given information even if the Catalyst application has just started
	   up, you are in good shape.

       from_session( $c, $frozenuser )
	   This	method is called whenever a user is being restored from	the
	   session.  $frozenuser contains the information that was stored in
	   the session for the user.  This will	under normal circumstances be
	   the exact data your store returned from the previous	call to
	   "for_session()".  "from_session()" should return a valid user
	   object.

       user_supports( $feature,	...  )
	   This	method allows credentials and other objects to inquire as to
	   what	the underlying user object is capable of. This is pretty-well
	   free-form and the main purpose is to	allow graceful integration
	   with	credentials and	applications that may provide advanced
	   functionality based on whether the underlying user object can do
	   certain things. In most cases you will want to pass this directly
	   to the underlying user class' "supports" method. Note that this is
	   used	as a class method against the user class and therefore must be
	   able	to function without an instantiated user object.

       OPTIONAL	STORE METHODS

       If you want your	store to be able to auto- create users,	then you can
       implement these methods:

       auto_update_user( $authinfo, $c,	$res )

       This method is called if	the realm's auto_update_user setting is	true.

       auto_create_user( $authinfo, $c )

       This method is called if	the realm's auto_create_user setting is	true.

   USER	OBJECT
       The user	object is an important piece of	your store module. It will be
       the part	of the system that the application developer will interact
       with most. As such, the API for the user	object is very rigid. All user
       objects MUST inherit from Catalyst::Authentication::User.

       USER METHODS

       The routines required by	the Catalyst::Plugin::Authentication plugin
       are below. Note that of these, only get_object is strictly required, as
       the Catalyst::Authentication::User base class contains reasonable
       implementations of the rest. If you do choose to	implement only the
       "get_object()" routine, please read the base class code and
       documentation so	that you fully understand how the other	routines will
       be implemented for you.

       Also, your user object can implement whatever additional	methods	you
       require to provide the functionality you	need. So long as the below are
       implemented, and	you don't overlap the base class' methods with
       incompatible routines, you should experience no problems.

       id( )
	   The "id()" method should return a unique id (scalar)	that can be
	   used	to retreive this user from the store.  Often this will be
	   provided to the store's "find_user()" routine as "id	=> $user->id"
	   so you should ensure	that your store's "find_user()"	can cope with
	   that.

       supports( $feature, $subfeature ... )
	   This	method checks to see if	the user class supports	a particular
	   feature.  It	is implemented such that each argument provides	a
	   subfeature of the previous argument.	In other words,	passing	'foo',
	   'bar'  would	return true if the user	supported the 'foo' feature,
	   and the 'bar' feature of 'foo'.   This is implemented in
	   Catalyst::Authentication::User, so if your class inherits from
	   that, you do	not need to implement this and can instead implement
	   supported_features().

	   Note: If you	want the authentication	module to be able to save your
	   user	in the session you must	return true when presented with	the
	   feature 'session'.

       supported_features( )
	   This	method should return a hashref of features supported by	the
	   user	class.	This is	for more flexible integration with some
	   Credentials / applications. It is not required that you support
	   anything, and returning "undef" is perfectly	acceptable and in most
	   cases what you will do.

       get( $fieldname )
	   This	method should return the value of the field matching fieldname
	   provided, or	undef if there is no field matching that fieldname. In
	   most	cases this will	access the underlying storage mechanism	for
	   the user data and return the	information. This is used as a
	   standard method of accessing	an authenticated user's	data, and MUST
	   be implemented by all user objects.

	   Note: There is no equivalent	'set' method. Each user	class is
	   likely to vary greatly in how data must be saved and	it is
	   therefore impractical to try	to provide a standard way of
	   accomplishing it. When an application developer needs to save data,
	   they	should obtain the underlying object / data by calling
	   get_object, and work	with it	directly.

       get_object( )
	   This	method returns the underlying user object. If your user	object
	   is backed by	another	object class, this method should return	that
	   underlying object.  This allows the application developer to	obtain
	   an editable object. Generally speaking this will only be done by
	   developers who know what they are doing and require advanced
	   functionality which is either unforeseen or inconsistent across
	   user	classes. If your object	is not backed by another class,	or you
	   need	to provide additional intermediate functionality, it is
	   perfectly reasonable	to return $self.

WRITING	A CREDENTIAL
       Compared	to writing a store, writing a credential is very simple.
       There is	only one class to implement, and it consists of	only two
       required	routines. They are:

	   new()	   - instantiates the credential object
	   authenticate()  - performs the authentication and returns a user object

   CREDENTIAL METHODS
       new( $config, $app, $realm )
	   Like	the Store method of the	same name, the "new()" method is
	   called only once, during the	setup process of
	   Catalyst::Plugin::Authentication. The first argument, $config, is a
	   hash	reference containing the configuration information for the
	   credential module. The second argument is a reference to the
	   Catalyst application.  $realm is the	instantiated Realm object,
	   which you may use to	access realm routines -	such as	find_user.

	   Again, when the credential's	new() method is	called,	Catalyst has
	   not yet loaded the various controller and model classes.

	   The new method should perform any necessary setup required and
	   instantiate your credential object.	It should return your
	   instantiated	credential.

       authenticate( $c, $realm, $authinfo )
	   This	is the workhorse of your credential.  When $c->authenticate()
	   is called the Catalyst::Plugin::Authentication module retrieves the
	   realm object	and passes it, along with the $authinfo	hash to	your
	   credential's	authenticate method.  Your module should use the
	   $authinfo hash to obtain the	user from the realm passed, and	then
	   perform any credential verification steps necessary to authenticate
	   the user.  This method should return	the user object	returned by
	   the authentication store if credential verification succeeded.  It
	   should return undef on failure.

	   How your credential module performs the credential verification is
	   entirely up to you.	In most	cases, the credential will retrieve a
	   user	from the store first (using the	stores find_user() method),
	   and then validate the user's	information.  However, this does not
	   have	to be the case.

	   It is perfectly acceptable for your credential to perform other
	   tasks prior to attempting to	retrieve the user from the store. It
	   may also make sense for your	credential to perform activities which
	   help	to locate the user in question,	for example, finding a user id
	   based on an encrypted token.	 In these scenarios, the $authinfo
	   hash	passed to find_user() can be different than that which is
	   passed in to	$c->authenticate(). Once again this is perfectly
	   acceptable if it makes sense	for your credential, though you	are
	   strongly advised to note this behavior clearly in your credential's
	   documentation - as application authors are almost certainly
	   expecting the user to be found using	the information	provided to
	   $c->authenticate().

	   Look	at the Catalyst::Authentication::Credential::Password module
	   source to see this in action.  In order to avoid possible
	   mismatches between the encrypted and	unencrypted passwords, the
	   password credential actually	removes	the provided password from the
	   authinfo array.  It does this because, in many cases, the store's
	   password field will be encrypted in some way, and the password
	   passed to $c->authenticate is almost	certainly in plaintext.

	   NOTE: You should always assume that a store is going	to use all the
	   information passed to it to locate the user in question.  If	there
	   are fields in the $authinfo hash that you are sure are specific to
	   your	credential, you	may want to consider removing them before user
	   retrieval.  A better	solution is to place those arguments that are
	   specific to your credential within their own	subhash	named after
	   your	module.

	   The Catalyst::Authentication::Store::DBIx::Class module does	this
	   in order to encapsulate arguments intended specifically for that
	   module. See the Catalyst::Authentication::Store::DBIx::Class::User
	   source for details.

AUTHORS
       Jay Kuri, "jayk@cpan.org"

COPYRIGHT & LICENSE
       Copyright (c) 2005 the aforementioned authors. All rights reserved.
       This program is free software; you can redistribute it and/or modify it
       under the same terms as Perl itself.

perl v5.24.1			Catalyst::Plugin::Authentication::Internals(3)

NAME | INTRODUCTION | OVERVIEW | WRITING A STORE | WRITING A CREDENTIAL | AUTHORS | COPYRIGHT & LICENSE

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=Catalyst::Plugin::Authentication::Internals&sektion=3&manpath=FreeBSD+12.0-RELEASE+and+Ports>

home | help