UserAuth

Summary: User-based authorization
Version: 0.70, 25 January 2006
Prerequisites: Last tested on PmWiki version: pmwiki-2.0.beta36; pmwiki-2.0.beta51 needs userauth-0.63 (0.62 incompatibility with basicauth)
Status: Obsolete
Maintainer:
Note
Do not confuse this recipe, UserAuth, with AuthUser, which is part of the standard distribution of PmWiki (stored in scripts/). This recipe, UserAuth is an addon that you must download and install into your cookbook/ directory.
Note2
There is now a reimplementation, Cookbook.UserAuth2, of this module with extended functionality that clears up all remaining bugs (see below) still present in this module. Find a comparison list here. ThomasP March 30, 2007, at 10:54 PM
Note3
Something based on UserAuth is Presence Awareness and interesting in this context too (login, admin, registration). (PKHG)

Goal

To create greater access control for PmWiki installations where the admin does not want the whole world able to change pages or wishes to only allow select users to have editing access.

Files

Userauth provides:

cookbook/userauth.php
cookbook/userauth-pwchange.php
cookbook/userauth-admintool.php
cookbook/userauth/HtPasswd.php
cookbook/userauth/UserSessionVars.php

Description

This PmWiki plugin makes it possible to restrict access to the entire wiki by requiring a username and password for certain actions. Individual pages and groups can still be password restricted in the same way that PmWiki does by default. However, user authentication happens before wiki password authentication. Additionally, the username doubles as the author name.

The UserAuth package also contains two optional scripts that add functionality. One of the scripts, userauth-pwchange.php adds the ability for users to change their own passwords. Another script, userauth-admintool.php adds the ability for the admin user to edit user abilities and passwords as well as add new users. Please see the details within the scripts on how to install and configure them.

By default this plugin reads username, password and ability information from a .htpasswd file. This file is created when the script is first run in the PmWiki "local" directory with the default restrictions that non authorized users can only read pages. The htpasswd file has an additional third field where abilities are stored. This field should not interfere if you wish to use the same htpassword file with Apache basic authentication. A typical htpassword file would look like the following:

GuestUser::read,rss
LoggedInUser::pwchange
FredFlintstone:HWxwafxAweaXefafdae:read_all,edit_all
BarneyRubble:AsafasfAfadfadfad:read_group-PrivateArea,edit_group-PrivateArea,edit
WilmaFlintstone:GFSDGfgdfgsdfgdf:edit,upload
Admin:XwasgeGGGaaceexeadeE:admin

Version 0.70 adds a column to the htpassword file to store a full user name or description. htpassword files of the old format are automatically converted

How would I allow edit access to Main.WikiSandbox? edit_page-WikiSanbox, edit_page-Main/WikiSanbox, edit_page-Main.WikiSanbox, edit_group-Main and edit_page-WikiSanbox?

The abilities field is a list of actions the user can perform separated by commas. Abilities correspond to the same type of actions defined by PmWiki in the $DefaultPassword array as well as some custom actions:

PmWiki Actions:

  • admin, attr, edit, read, upload - If a PmWiki action is defined for a user then the user can perform the action for all groups that do not have a action_group-GroupName style ability defined.

UserAuth Actions:

  • admin - Admin is also checked explicitly by this plugin. This allows an admin user to be able to access any PmWiki password protected page without supplying the password.
  • read_all, edit_all, attr_all, upload_all - Allows the user to perform action on any page, even if it is PmWiki password protected or protected by a group specific ability.
  • read_group-GroupName, edit_group-GroupName, attr_group-GroupName, upload_group-GroupName - Allows the user to perform action on all pages in GroupName, for example: read_group-PrivateArea or edit_group-PrivateArea
  • attr_page-PageName, upload_page-PageName - Allows user to perform action on a specific page. This ability beats out any group level ability that is defined.

UserAuth User Groups:

  • Version 0.70 allows a user group name to be used as action where the user automatically inherits the abilities of the user group. A user group name starts with the @ character.

Installation

  • Unpack the distribution file into your PmWiki cookbook directory
  • Include the plugin from your config.php file:
require_once("cookbook/userauth.php");
  • Load your PmWiki once to create the default .htpasswd file
    The .htpasswd file is stored in the "local" directory. On Unix-like systems this directory needs to be owned by the web server user for the password file to be automatically created.
  • Modify the created .htpasswd file to include a user that has "edit" ability. Use your wiki to create the password by appending ?action=crypt to the url to load the PmWiki password encryption page. Create the user's line in the htpasswd file in the usual Apache htpasswd format but make sure to add an extra field to contain the user's abilities. See the description above for an example of how to format the file.
  • Create the page Main.LoginPage so that the login page will show up within your wiki layout, otherwise a default standalone page will be used. Simply put the following on Main.LoginPage:
(:loginform:)
Main.LoginPage is just the default and the login page can be changed to whatever you like. See the configuration details below.
  • Optionally install userauth-pwchange.php and userauth-admintool.php scripts. See scripts source for details.

Configuration

The following variables can be defined before userauth.php is included in config.php:

$GuestUsername - Specifies the username that is used by default when no user is logged in.

$LoginPage - Name of the page which has the "(:loginform:)" markup on it to display the login form.

$LackProperAbilitiesFmt - Message displayed when the user unsuccesfully tries to login.

$UserInfoObj - Specified the object used to obtain information on users and their abilities. By default HtPasswd.php will be used to grab user information unless the $UserInfoObj is already set. This allows someone to write a new user info object that gets its information from a database or some other format. This new class would only need to implement the contract as can bee seen in the HtPasswd.php file. Only implement those methods below the line that says something to the effect in that file.

$HtPasswdFile - Alternative location of the HtPassword file. Not used if $UserInfoObj is set to a different object before the script is included in config.php. Note: if you want to set up a wikifarm field to use a different HtPassword file, just set $HtPasswdFile to "local/.htpasswd" in the field's index.php before including the wikifarm copy of pmwiki.php.

$UserInstanceVars - Defines the class that manages user information such as username and password for the instance. This information is for the current logged in user, or blank if the person accessing the site is not logged in. The default class, UserSessionVars will be used unless this variable is defined before UserAuth is loaded. If someone wants to handle instance user information with a method other than the $_SESSION array then create a class that has the same contract as UserSessionVars and set this variable.

$RedirectToPrevious - This variable determines if upon succesful login or logout UserAuth redirects to the page that originally called the login or logout action. The default is true. If for instance you want to always redirect to $DefaultRedirectionPage then set this variable to false.

$DefaultRedirectionPage - If there is no information about which page orignially called the login or logout action then redirect to this page. The default is to redirect to Main.HomePage when there is no previous page information. One could possibly write a script that gets called before UserAuth and sets up this variable based upon things such as the current group, username or whatever.

$UserAuthAllowCookie - Defaults to true, which allows a cookie to be used to store username and password information between browser sessions. The password is stored in its encrypted form. V0.70

$UserAuthCookieExp - The expiration time for the cookie, in seconds. Defaults to 30 days. V0.70

Userauth-NewUser

This creates a form that allows users to request a new account. By installing this, you receive the (:newuser:) macro. This macro creates a form asking for the Username and Email address. When completed, the form data is then emailed to the email address in the form, sent by the $SiteAdmin email address. The user is then instructed to reply back that email. This ensures there is a real user who will receive the account.

This is an alpha. It lacks all customization and documentation. I wrote this before the later builds of userauth where the admintool and other scripts were added. I hope those who are working on this can find use for it. I presently use it to arrange for user accounts on three web sites--although before I started using userauth-admintool. BenWilson

Here's an idea for how to use this script--that is the perfect solution for my needs. Maybe it will help someone else. When user fills out the registration form, get their confirmation email, and reply, it goes to a simple autoresponder which gives them a password for authuser! Plus it forwards their verified email on to me to add to my mailing list which is the whole reason I had them sign up in the first place. Caveman

Userauth-Register

This is a much more trusting version of the above script, which automatically creates the user immediately. No email is stored. Use macro (:registerform:). It detects password mismatch and username-already-taken type errors, but not much more. It would be nice if it incorporated some sort of CAPTCHA or email verification, but right now, it doesn't. Note that this enables anyone to get LoggedInUser privileges for free. GregManning?

After enabling the userauth-register.php script, my RSS feeds stopped working. Disabling userauth-register fixes RSS. Is there a fix avaiable for this item so I can use both RSS and userauth-register? Thanks TRhodes July 19, 2006, at 03:33 PM

Thanks to ErnieLogan for this workaround:

if ($action != 'rss' & $action != 'atom' & $action != 'rdf' & $action != 'dc') require_once("cookbook/userauth-register.php");

HTML Customization

The HTML that is displayed on the LoginPage can be easily changed. By default the [loginform] inline replacement calls a function that returns the login page. To specify different HTML then either redefine the definition of [loginform] in the Markup() or use some other method that correctly calls the login action.

If you wish to change your template to include a link that displays "Login" or "Logout" depending on whether or not a user is logged in then add the following to the template:

<a href='$PageUrl?action=$LoginAction'>$LoginName</a>

The $IsUserLoggedIn variable can be use with the conditional directive. To use it you need to add something like the following to you config.php:

$Conditions['loggedin'] = "\$GLOBALS['IsUserLoggedIn']==\$condparm";

Then you can use the following markup to display certain page data only for logged in/out users:

(:if loggedin:) You are logged in (:if:)
(:if !loggedin:) Please login (:if:)

There is a new conditional variable member that allows to check against a specific user group membership V0.70

(:if member @editors:) conditional text (:ifend:)

The .userauthinput and userauthbutton CSS classes can be used to control the look of input fields and buttons defined in the userauth class

History

  • September 12, 2004 - Version 0.1
    • Initial version
  • November 22, 2004 - Version 0.2
    • Added ability for allowing a user to view an entire view password protected group
    • Many other clean ups and improvements to code.
  • December 16, 2004 - Version 0.3
    • Made Pmwiki v2.0 compliant.
  • February 26, 2005 - Version 0.3a
    • Fixed HtPasswd.php to allow usage of .htpasswd's with Windows newlines, and/or on systems with PHP older than 4.3. -- RM
  • February 27, 2005 - Version 0.4
    • Changed loginform directive so that urls are not formatted by PmWiki
    • Implemented group specific abilities that are needed whenever a group specific abilities is defined for any user
    • Improved greatly how forms and messages are displayed -- JamesMcDuffie
  • March 3, 2005 - Version 0.5
    • Added $IsUserLoggedIn variable for use by conditional markup
    • Added CSS class tags userauthinput and userauthbutton for controlling the look of input field and buttons
    • Added $LoggedInUsername defintion for future expansion of actions that have abilities defined globally for all logged in users. -- JamesMcDuffie
  • March 13, 2005 - Version 0.6
    • Now using BasicAuth from PmWiki instead of checking Wiki password directly
    • First check user password as Wiki password in case user used the same password to protect a page
    • Renamed some variables and functions to make purpose even clearer
    • Fixed issue with &nbsp in form instead of &nbsp;
    • Implemented redirection configuration variables: $RedirectToPrevious and $DefaultRedirectionPage
    • Added a new class type, UserInstanceVars and implementation, UserSessionVars to manage handling of instance username and password information. This change will hopefully allow people to write code to store user info in a database or whatever is needed for expanding functionality.
    • Added page level abilities that rule over group level abilities just as a PmWiki page password would rule over a PmWiki group password.
    • Added $[internationalization] substitutions to GetUserLoginForm() and GetWikiPasswordForm().
    • Fixed infinite redirection problem that occurs when $LoginPage is defined yet there is no read abilities defined for the GuestUser
    • Changed markup for loginform from [loginform] to (:loginform:) to make syntax more consistent with PmWiki version 2's markup -- JamesMcDuffie
    • Fixed problem where the $IsUserLoggedIn variable was always set to true
  • March 15, 2005 - Version 0.61
    • Fixed problem where previous page was not set when not using an embedded login page instead of a Wiki page with the loginform markup on it
    • Fixed problem where CheckUserAuthPassword might display a prompt if called from another module. Now its safe to call UserAuth directly from another module as long as $authprompt = false
  • March 16, 2005 - Version 0.62
    • Fixed issue where "_all" attributes were not properly overriding wiki passwords as they should
  • May 14, 2005 - Version 0.63
    • Fixed so that the new name for PmWiki's basic authentification is called
    • Added session_destory to HandleLogout
  • August 17, 2005 - Version 0.64
    • Fixed so that PmWiki basic authentification called correctly under PHP safe mode
  • January 25, 2006 - Version 0.70
    • Added support for user groups
    • Added support for cookies to optionally allow user to stay logged in between sessions
    • Enhanced the admin page with a reporting feature to show all users and user groups, and their abilities, at once
    • Some changes to make UserAuth work properly with PmWiki 2.1beta
    • More details are at the UserAuthDevel page

See Also

Check out the EvolverSkin? for examples of how to integrate UserAuth and CMSLike functionality into a skin.

The AuthUser recipe explains how to use a passwd-formatted (.htpasswd) file for user-based authentication.

Notes and Comments

Additional comments, bugs and suggestions are always welcome on the UserAuthDevel page. Please try to debug any bug as much as possible to help the problem get resolved faster. Also when commenting please refer to the version of the software you are using.

Pagelist not showing

If your pagelist are not showing for users like guest it might be because guest doesn't have permission to read your PageListTemplates page. Add the permission: read_page-Site.PageListTemplates to your guest account and the problem should resolve. -CMH

Expiration of Session
I experienced this problem many times
If you work with many tabs (or browser windows), in every tab/window (of the same wiki) the same user is active.
If you don't know, whether your session has expired, you can open a new tab and login there.
If you like to save your content, but a password is prompted, because the session has expired, log in in a other tab. Then go back to the previous tab, press back and then forward again. If you are lucky the data are still there:-)

Author and Contributors

Pardon, I really couldn't work out where I can put questions, so please delete this, if it is not appropriate here... I tried to install the script, uploaded the files and everything, and then after loading my page again I got this:
@Notice: userauth htpasswd file does not exist! in @/srv/www/htdocs/web287/html/sw/pmwiki/cookbook/userauth/HtPasswd.php on line 88 @ @Warning: Invalid argument supplied for foreach() in @/srv/www/htdocs/web287/html/sw/pmwiki/cookbook/userauth/HtPasswd.php on line 93 @ @Warning: Cannot modify header information - headers already sent by (output started at @/srv/www/htdocs/web287/html/sw/pmwiki/cookbook/userauth/HtPasswd.php:88) in @/srv/www/htdocs/web287/html/sw/pmwiki/cookbook/userauth/UserSessionVars.php on line 87 @ @Warning: Cannot modify header information - headers already sent by (output started at @/srv/www/htdocs/web287/html/sw/pmwiki/cookbook/userauth/HtPasswd.php:88) in @/srv/www/htdocs/web287/html/sw/pmwiki/cookbook/userauth/UserSessionVars.php on line 88 @ @Warning: Cannot modify header information - headers already sent by (output started at @/srv/www/htdocs/web287/html/sw/pmwiki/cookbook/userauth/HtPasswd.php:88) in @/srv/www/htdocs/web287/html/sw/pmwiki/pmwiki.php on line 884
below that the login-Form, but no chance to navigate through the wiki, all layout gone... what did I do wrong? Or how can I create a .htpasswd file manually?
Thanks for any help, Dagmar: szandor_dubois(att)yahoo.de


----

UserAuth should allow GuestUser to be given access to certain public areas, eg page groups "Main" and "MyPublicStore" for example.

In userauth.php line 465, replace:

if($UserInfoObj->UserHasAbility($GuestUsername, "read")) {

with:

if(UserAuth($pagename, 'read', False)) {

(jonw at improov dot com)


There's a bug with UserAuth's integration with PmWiki's authentication. Group-level access is obliterated by page-level access control flags.

To reproduce:

Create a user UserA with abilities read_group-GroupA, edit_group-GroupA. Create 2 pages GroupA.pageOne and GroupB.pageTwo . UserA can read and edit both pages. Now, enter "id:UserA" into GroupA.pageOne's access control. You'll see that UserA can no longer edit GroupA.pageOne .

Seems to be a missing link or bad integration with PmWiki's authentication routines.

(jonw at improov dot com)


How use this recipe with MySQL? I want to integrate it with [(approve links) edit diff].


I'm a little confused concerning this recipe. Is it recommended to use this in combination with AuthUser or are they mutually exclusive? I use AuthUser on one site already and it works pretty well but I was hoping to beef up the user accounts with more information and make the user permissions easier to manage. However, I'm having several issues and I'm not sure if they are inherent or pebcak.

  1. I have conditional markup in my site sidebar including login/logout and other items that disappear if the user does not have permission to use them. When I use the login action and the login page is visible, the conditional markup in the sidebar believes I am already logged in before authentication. Is that the prescribed behavior?
  2. On my AuthUser site, I can see a note about the attr values to the right of the form fields when I am editing them using an action=attr and I can tell where the authentication is coming from. Using UserAuth without AuthUser, passwords entered in those fields appear to work but the notes are not there so I can't tell by looking if there is an attribute entered or not. Is that the way that is supposed to work?
  3. I have not tried using the two together yet because I thought they were mutually exclusive and it's not intuitive how they will interact, but I am not happy with the lack of ability to protect individual pages with UserAuth by itself or maybe I just don't understand how to do it. Did I miss the part of the documentation that says I am supposed to use both at the same time to get them to work properly?

Thanks,
BillReveile March 27, 2007, at 09:07 AM


Hi, Bill. Thanks for introducing me to the word pebcak.

  1. Which conditional markup are you using in your sidebar, (:if loggedin:) or (:if auth read:)?
  2. If you are using UserAuth without AuthUser, you should not be using action=attr, but rather action=admin to set permissions. UserAuth does not, in my experience, play well with attr, since attr permissions will generate login forms that ask for just a password, confusing users who are expecting to enter a username and password.
  3. To protect individual pages with UserAuth, you edit the user (not the page) and set edit_page-Group.Name (or read or upload or whatever). Doing so restricts everyone else from editing (or reading, etc.) that page, unless they have edit_all (read_all) or admin permissions. It is a different approach, useful for some sites, not for all.

Hope this helps! Ben Stallings March 28, 2007, at 08:05 AM


Hello Bill, AuthUser and UserAuth are NOT supposed to work together - they are as you thought mutually exclusive. Protecting individual (i.e. single) pages using UserAuth should be fairly easy, unless you meant personalized pages. In the latter case have a look at Cookbook.UserAuth2 which is a kind of reimplementation with a lot more features than before. It should also give you the power to "beef up the user accounts with more information", creating "MyWiki" pages readable by the corresponding user only, etc. (see UserAuth2.Help). ThomasP March 31, 2007, at 11:35 PM


Hi. I didn't seem to get the $DefaultRedirectionPage to work. I went and looked into the userauth.php code and replaced the

$_SERVER['REQUEST_URI'] with
$_SERVER['HTTP_REFERER'] in the form action.

Now the Main.LoginPage redirects as it should, at least for me. But how should this be working for real?
Yours, LasseS May 4, 2007


I am attempting to install the UserAuth and following the instructions I get confused at this point, "Include the plugin from your config.php file:

require_once("cookbook/userauth.php");" I don't have that in my config.php. am I missing something or misinterpreting. I am new to php so I could be confused.

Thanks for any assistance

AJ Oct, 9 2008 blazn40@gmail.com

See Initial Setup Tasks for some information about config.php. This instruction means to copy that line verbatim and paste it into your config.php file.

See also How To Get Assistance and Local Customizations. Note you might be better to use UserAuth2

Copyright

Copyright 2004-2006 under the GNU GPL License

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.