Summary: AuthUser account self-registration and management
Version: 2011-04-11
Prerequisites: PmWiki 2.2.17 or newer,
AuthUser
Status: alpha
Maintainer:
Eemeli Aro (UserAdmin-Profiles) and
Peter Bowers (UserAdmin-Core & UserAdmin-AuthUser)
Description
This recipe is under development & needs more testing before full-scale use. Use at your own risk.
This recipe combines a proposed framework and an implementation for handling AuthUser user authentication and administration. Its functionality (and documentation!) is not yet complete and its behaviour may yet change drastically. For more context, please see the pages linked to below.
The previous version of this recipe was named AuthUserProfiles; I've renamed it as UserAdmin since it now supports different kinds of back-end storage solutions, as well as having a slightly larger scope.
To install:
UserAdmin currently has 2 storage solutions to store users. One method stores the user information in their Profiles page while the other stores user information in the SiteAdmin.AuthUser page (with a slightly extended syntax). Functionality and user interface is identical between the 2 solutions -- the only thing that gets changed is where and how the information is stored.
To install with user & authentication information in SiteAdmin.AuthUser page:
include_once("$FarmD/cookbook/useradmin-authuser.php");
To install with user & authentication information in the Profiles page:
Note: Due to ongoing development in useradmin-core and useradmin-authuser without corresponding adjustments in useradmin-profiles this version no longer works. If someone wants to work on bringing it up to date, feel free. Until then, please do not try to use it.
include_once("$FarmD/cookbook/useradmin-profiles.php");
- add the following line to your
SiteAdmin.AuthUser page:
userprofilegroup: Profiles
Configuration options
Configuring the main menu for UserAdmin options
The main menu can be over-ridden by a #ua-mainmenu template -- see Custom Forms below for more details.
If it is not over-ridden by a template then the main menu is constructed from the global variable $UserAdminActions. Its default initialization follows:
SDVA($UserAdminActions, array(
'onlyadmin' => array('group'),
'onlyauth' => array('edit'),
'anonymous' => array('resetpasswd', 'new', 'unlock', 'login2edit', 'login'),
'onlyanonymous' => array('login2edit', 'login'),
'unlock' => array('login'),
'extra' => array('login2edit', 'login')
));
The concept is that we begin with a set of all possible actions.
- Any elements in the array element
extra are added.
- If the current user is not an administrator then actions in the array element
onlyadmin will be removed from the menu.
- If the current user is not logged in then actions in the array element
onlyauth will be removed from the menu and (as an additional measure of security) the possible actions will be intersected with the array element anonymous.
- If a user is logged in then actions in the array element
onlyanonymous will be removed from the menu.
- If the current action (new, edit, unlock, resetpasswd, etc.) has a corresponding array element in
$UserAdminActions then it will be intersected with the set of all possible actions, reducing the possible actions.
For each action there are either 1 or 2 XL strings which should exist (in each case action is substituted by the actual action name from above):
- UAaction_link -- this value is a URL which executes the action
- If this XL string is not available then it defaults to
$ScriptUrl/Cookbook/UserAdmin?action=user/action
- UAaction_title -- this value will be displayed to the user as the actual menu item text
Thus the main menu can be configured very flexibly by altering the various elements of the $UserAdminActions array within the config.php or by altering the XL strings for the various links and titles. For instance, to eliminate the "Login to edit your user profile" option, change the wording and destination on the "Login to continue" option, and add a new "logout" option you would have something like this:
XLSDV('en', array(
'UAlogin_link' => 'Profiles.{$AuthId}',
'UAlogin_title' => 'Login and view your profile',
'UAlogout_link' => '{$FullName}?action=logout',
'UAlogout_title' => 'Logout',
));
include_once("$FarmD/cookbook/useradmin-authuser");
$UserAdminActions['extra'] = array('login', 'logout'); // added 'logout', removed 'login2edit'
$UserAdminActions['onlyauth'] = array('edit', 'logout'); // added 'logout'
Custom forms
By default, UserAdmin will generate the forms used by the recipe directly. However, you may also define these forms using wiki markup. For a sample implementation, copy the page Cookbook.UserAdminTemplates to your site with the name Site.UserAdminTemplates. These templates may later become a part of the default UserAdmin installation.
Currently the following section names will be honored (each of these can also have a -admin suffix):
- #ua-new
- #ua-edit
- #ua-resetpasswd
- #ua-unlock
- #ua-mainmenu
Note that #ua-group is not configurable in this way.
The naming of the section is significant. It begins with #ua- followed by the action name followed by an option -admin if the form is specific for administrators.
Usage
So far the recipe has the following functional parts. To get a menu of available actions, add ?action=user to any page where the recipe is enabled. Note that you should be logged out to see the full list of actions.
Self-registering a new user, with optional email address confirmation: ?action=user/new
To use, add ?action=user/new to any page where the recipe is enabled. You'll be presented with a form asking for a username, password and email address. These will be verified, and the data added to a profile page along with a randomly generated key. An activation link (including said key) will be mailed to the given address, and when said link is followed, the account activated.
PROFILE-METHOD NOTE: Using a profile page for a new user is allowed even if the page already exists, provided that it doesn't have a user account previously associated with it.
If you are logged in as an administrator when you use the ?action=user/new then there is no email address confirmation and the user is automatically created as a verified user.
Password reset via e-mail: ?action=user/resetpasswd
Send a reset link to a user's e-mail address. The link will contain a key which will let the user set a new password.
Edit user account details: ?action=user/edit
Change the password and/or the e-mail address associated with the account. Requires the user to be either logged-in as themselves and to re-enter their passoword, or to have admin access (for UserAdmin-Profiles, this means having attr-level access to the user's profile page).
Activate an account: ?action=user/unlock
This is used as the second step of both account activation and password resets. It will normally be reached by using the link sent in an email address. A random key is sent in the email to assure that the user requesting the activation/reset is the one actually getting the account.
Notes
UserAdmin-AuthUser data format
In a normal authuser environment users are stored in a format such as this:
username: HASH @group HASH2 @group2
When UserAdmin-AuthUser is used, the additional user properties are stored in ParseArgs() format following a second colon:
username: HASH @group : useremail=user@example.com userRealName="John Jacob Jingleheimerschmidt"
UserAdmin-Profiles data format (Currently out-of-step with authuser-core and thus non-functional. In search of a maintainer.)
Information about each user is kept as profile page attributes. The appropriate page is generated from the username using MakePageName, but the page itself also contains the username as an attribute. This means that usernames don't need to be valid page names, but they still each map to a unique profile page.
The attributes used by the recipe share a common prefix user; by default at least the following attributes are used: username, useremail, userpwhash, and userkey. userkey contains a random number that acts as an activation key and a hash of the user's password. Once the account is activated, userkey is removed and userpwhash set to the hash, allowing the account to be used.
Reading user data from profile pages (Currently out-of-step with authuser-core and thus non-functional. In search of a maintainer.)
Reading profile pages for user data is enabled by including the line "userprofilegroup: Profiles" on the SiteAdmin.AuthUser page, which lets AuthUserId call AuthUserProfiles, defined in useradmin-profiles.php. Reading user group data from profile pages (as an attribute usergroups, holding a comma or white space delimited list of @groups to which the user belongs) requires a slight modification to authuser.php, as shown near the bottom of PITS.01197.
Managing user data in other places
In order to put together your own solution for managing users, you may extend the core UserAdmin class by implementing at least the ReadUser and WriteUser methods.
The code includes some PHP silliness for eg. field validation: if you have an input field "userpasswd", you can extend UserAdmin with a class that includes a method called "ValidPasswd" and it'll automagically get used to validate the field. Similar stuff happens for the different sub-actions of the recipe; defining UserAdminX::HandleFroot will make the action accessible via ?action=user/froot as well as listing it in ?action=user.
Custom forms
By default, UserAdmin will generate the forms used by the recipe directly. However, you may also define these forms using wiki markup. For a sample implementation, copy the page Cookbook.UserAdminTemplates to your site with the name Site.UserAdminTemplates. These templates may later become a part of the default UserAdmin installation.
For instance, this source, when placed in your Site.UserAdminTemplates page, will add a new custom field userrealname:
[[#ua-new]]
(:input form action='$PageUrl?action=user/new':)
(:table class=ua-form:)
(:cellnr:)$[UA_txt_username]
(:cell:)(:input text name='username':)
(:cellnr:)$[UA_txt_userpasswd]
(:cell:)(:input password name='userpasswd':)
(:cellnr:)$[UA_txt_userpasswd2]
(:cell:)(:input password name='userpasswd2':)
(:cellnr:)$[UA_txt_useremail]
(:cell:)(:input text name='useremail':)
(:cellnr:)Real Name
(:cell:)(:input text name='userrealname':)
(:cellnr:)
(:cell:)(:input submit name=post value='$[UAnew_submit]':) (:input submit name=cancel value='$[Cancel]':)
(:tableend:)
(:input end:)
[[#ua-newend]]
[[#ua-edit]]
(:input form action='$PageUrl?action=user/edit':)
(:table class=ua-form:)
(:cellnr:)$[UA_txt_username]
(:cell:)(:input text readonly=1 name='username':)
(:cellnr:)$[UA_txt_useroldpasswd]
(:cell:)(:input password name='useroldpasswd':)
(:cellnr:)$[UA_txt_userpasswd]
(:cell:)(:input password name='userpasswd':)
(:cellnr:)$[UA_txt_userpasswd2]
(:cell:)(:input password name='userpasswd2':)
(:cellnr:)$[UA_txt_useremail]
(:cell:)(:input text name='useremail':)
(:cellnr:)Real Name
(:cell:)(:input text name='userrealname':)
(:cellnr:)
(:cell:)(:input submit name=post value='$[UAedit_submit]':) (:input submit name=cancel value='$[Cancel]':)
(:tableend:)
(:input end:)
[[#ua-editend]]
[[#ua-edit-admin]]
(:input form action='$PageUrl?action=user/edit':)
(:table class=ua-form:)
(:cellnr:)$[UA_txt_username]
(:cell:)(:input text readonly=1 name='username':)
(:cellnr:)$[UA_txt_userpasswd]
(:cell:)(:input password name='userpasswd':)
(:cellnr:)$[UA_txt_userpasswd2]
(:cell:)(:input password name='userpasswd2':)
(:cellnr:)$[UA_txt_useremail]
(:cell:)(:input text name='useremail':)
(:cellnr:)Real Name
(:cell:)(:input text name='userrealname':)
(:cellnr:)
(:cell:)(:input submit name=post value='$[UAedit_submit]':) (:input submit name=cancel value='$[Cancel]':)
(:tableend:)
(:input end:)
[[#ua-edit-adminend]]
The naming of the section is significant. It begins with #ua- followed by the action name followed by an option -admin if the form is specific for administrators.
Et cetera
Eemeli?: Depending on how you count, this is either my fourth or sixth approach to solving the same problem. The previous ones were either too domain-specific to be generalisable or too thoroughly tied up in other custom parts to untangle. And even this version will experience further development.
If you look through the code there are a number of globals you can set to control the recipe's behaviour. These should get documented, but they may also get completely renamed, removed or moved within the class declaration.
Proposed Features / Roadmap
- When editing a user it should be possible to add/delete membership in groups from that form
- After I edit an account, I would like to be returned to the UA_return_link that I set. Having UA_return_link specify a location after completing the form would be a new feature. Or having some other way to specify a specific destination rather than just curpage?action=user...
- After adding custom fields, these should be available as template vars (
{$$var}) with appropriate substitution in contexts such as the email being sent to the user. What other contexts [besides the email] should these template variables be substituted?
- Differentiate between an admin "Register a new user" and a non-user "Register AS a new user". The titles in the menu should reflect the different context depending on who is doing it.
- Administrator option: user/suspend (for a certain number of days)
- Administrator option: user/delete
- Add PVs for all (?) fields
- Add for use in conditionals in templates
- Fix #ua-mainmenu template so it works for action=unlock to have just the login option
- Add the ability to lock certain fields from being updated by users (perhaps admins can do this simply by means of templates?)
- Add the ability to lock down certain accounts to not be editable by users (multi-user accounts, for instance) (perhaps admins can do this simply by means of templates?)
- Add the ability to change password
Known problems
- Cannot set
(:title ...:) in UserAdminTemplates sections.
- Logged in as admin, I clicked on email link to reset password. It asked me to select a user. I did. Nothing happened.
- I entered a username that contains a blank, and it accepted.
- The built-in menu includes "account activation". "What's that?" asks the user.
- A logged in user sees an option to sign up in the built-in available actions, even though he's already logged in.
Release notes
- UPCOMING: Fix error when submitting an empty form in user/new. Fix error when including spaces in username in user/new. (perhaps) Got rid of dynamically code-built forms and just use templates exclusively. If you are upgrading from a previous version you need to make sure you have a valid set of templates in Site.UserAdminTemplates. Case problem with usernames is fixed. Added a new PV for use in conditionals in templates.
- 2011-04-11: coreΔ and authuserΔ. Rework the main menu for greater configurability.
$UserAdminAnonActions no longer used. $UserAdminActions is now a multi-dimensional array, allowing administrators to add their own links and give greater or lesser privileges to admins, logged-on-users, and anonymous users. Also capability of adding new template-sections, #ua-mainmenu and #ua-mainmenu-admin, was added. See the configuration section for more details.
- 2011-04-10: coreΔ and authuserΔ. Add capability of setting $UserAdmin->pagename to provide a default page for links and etc. Fix menus to provide only authorized activities. Added configurable
$UserAdminActions['ACTION'] = array(...) to allow for limiting the menu options at the conclusion of certain actions (such as after unlocking a user account - the new default is to only show a "log in to edit your account" option). Fixed group editing to provide appropriate messages, better error checking, added cancel option, etc.
- 2011-04-09: coreΔ and authuserΔ. Remove some debug statements that slipped through in 2011-04-08. No changed/additional functionality.
- 2011-04-08: coreΔ and authuserΔ. No longer require login to reset password. Just require username and email to match in order to get a key emailed. Links in the list of users as well as links in emails now respect current page rather than changing to home page.
- 2011-04-07: coreΔ and authuserΔ. Fix problem related to Superuser() definition in AuthUser. Add email templates for easier customization (See UserAdminTempaltes? for defaults.)
- 2011-04-05: coreΔ and authuserΔ. Definition of Superuser() altered as per Randy's suggestion, whoever has edit privileges on AuthUser. Debugging message removed. Capability to add a new group added. Suppressed viewing of list of users (potential security hole) on account activation. Fixed editing of empty groups.
- 2011-04-04a: coreΔ and authuserΔ. Fixed the same problem with passwords in cleartext, but this time for user/edit since before I just fixed it for user/new.
- 2011-04-04: coreΔ and authuserΔ. Fixed a problem where passwords were being stored in cleartext in authuser as user properties. Added #ua-ACTION-admin template capabilities for administrator-specific forms.
- 2011-04-03: coreΔ and authuserΔ - largely functional. Useradmin-profiles no longer functional. Group editing is functional. New user and edit user work well in limited testing. Use of custom forms in
Site.UserAdminTemplates is now functional. A bug was fixed that previously it was possible to get a list of groups and users even if you were not logged in as administrator - this possibility has been eliminated in known cases.
- 2011-03-29: coreΔ and authuserΔ last (largely untested) versions by Peter Bowers. Almost certainly breaks useradmin-profiles. Implements group editing to some degree, signing up as a new user and editing users has been roughly tested.
- 2010-06-14: coreΔ and profilesΔ last (untested) versions by Eemeli Aro; see PmWikiUsers:2011-March/058558.html for more information
- 2010-06-08: profilesΔ bugfix: removed fifth $authlist parameter from AuthUserProfiles(), which requires PmWiki version 2.2.17 (reported by Dave Cooke)
- 2010-06-07a: useradmin-authuser.phpΔ -- initial release to provide capabilities of storing user info in SiteAdmin.AuthUser page
- 2010-06-07a: coreΔ replaced class constants with global constants for PHP4 compatibility
- 2010-06-07: coreΔ and profilesΔ added $pagename parameter to Superuser(), fixed page title, Form() now outputs markup instead of HTML
- 2010-06-04: coreΔ internal updates, added custom forms
- 2010-06-03: coreΔ and profilesΔ re-released as UserAdmin with completely new internals
- 2010-05-25Δ first public release as AuthUserProfiles
See also
Contributors
Comments
See discussion at UserAdmin-Talk
User notes? : If you use, used or reviewed this recipe, you can add your name. These statistics appear in the Cookbook listings and will help newcomers browsing through the wiki.