AuthUserSignup
Questions answered by this recipe
- I need to allow users to be able to self-register to sign up for an authuser account. Where do I find such a form with email verification?
- I would like to maintain other information about users (address, email, telephone, etc) and allow them to update it - how?
- I would like a form-based method where users can change their own password and the administrator can change anyone's password - how?
- I would like to handle user administration via forms rather than by editing the SiteAdmin.AuthUser page directly - how?
Description
Allow users to sign up via a form for an authuser account. Includes email and other validation.
Installation & Configuration
The following steps must be followed to fully install the AuthUserSignup recipe
- Install WikiSh
- Install MiscMX
- Install WikiMail
- Create the page Login.Signup
- Create the page Login.Confirm
- Create the page Login.Confirmed
- Ensure proper authorization of Login.Signup and Login.Confirm
- (optional) Change which fields are collected
Installation of WikiSh
- Download the WikiSh.zip file from the WikiSh page. Unzip it and place the php files in your cookbook. (Note that you must have at least version 2008-09-13 or later.)
- Place the following lines in your config.php (This is the simplest installation for AuthUserSignup and would be used instead of any other config.php options listed in the WikiSh and WikiShConfig pages. Of course you can also mix&match the various configurations as long as you know what you are doing.):
include_once("$FarmD/cookbook/toolbox.php"); $DebugLevel = 5; include_once("$FarmD/cookbook/WikiSh.php"); include_once("$FarmD/cookbook/SecLayer.php"); $EnableWikiShWritePage = true; $EnableWikiShCreatePage = true; $EnableWikiShOverwritePage = true; $EnableWikiShMailx = true; slParsePage($pagename, "SiteAdmin.WikiShAuth", $wshAuthPage);
- Create the page SiteAdmin.WikiShAuth with the following information:
- Note that the display of this page when browsing is unimportant -- it is the actual source that is important. This page gives the appropriate read/write authorizations to be able to access and write to key administrative pages.
edit=append,prepend,insert,overwrite,create all=read,edit Temp.*: all (:if name Login.Confirm:) SiteAdmin.AuthUser:read,append,forceread,forceedit SiteAdmin.AuthUserExtra*:read,overwrite,forceread,forceedit Login.Confirm:read (:if name Login.Signup:) SiteAdmin.AuthUser:read,append,overwrite,forceread,forceedit SiteAdmin.AuthUserExtra*:read,append,overwrite,forceread,forceedit,create Login.Signup:read (:ifend:)
(Someone suggested the need for WikiShCrypt. The recipe AuthUserSignup does not make use of WikiShCrypt and so it is not necessary to install WikiShCrypt. Thus the comment has been removed.) Peter Bowers June 12, 2009, at 08:18 AM
Installation of MiscMX
- Download MiscMX.php from MiscMX page (version 2008-09-13 or later) and place it in your cookbook directory
- Place the usual line in your config.php:
include_once("$FarmD/cookbook/MiscMX.php");
Installation of WikiMail
- Download wikimail.php (version 2008-08-08 or later) from the WikiMail page and place it in your cookbook directory
- Place the usual line in your config.php:
include_once("$FarmD/cookbook/wikimail.php");
- Configure the $WikiMailSMTP array as indicated on WikiMail page. Below might be a typical setting (replace the username, password, and domain as appropriate):
$WikiMailSMTP['Host'] = 'mail.example.com'; // only used on win32 systems $WikiMailSMTP['User'] = 'wikimail'; // user for SMTP $WikiMailSMTP['Passwd'] = 'mysecret'; // passwd for SMTP #$WikiMailSMTP['Port'] = 25; // only used on win32 systems - 0=default #$WikiMailSMTP['SendmailPath'] = '/usr/bin/sendmail'; // only used on unix systems $WikiMailSMTP['From'] = 'wikimail@example.com'; // must be set in config.php unless already set via php.ini
Installation of scripts for AuthUserSignup
- Create a page Login.Signup (YOU MUST HAVE THE EDIT PASSWORD SET TO @admin or @lock OR SIMILAR for this page) with the following source:
- Note that you will need to edit the line setting the URL -- search for example.com below and edit it to point to YOUR Login.Confirm page
%comment% AuthUserSignup VERSION 2010-04-14 %% (:messages:) ---- {(wikish if test -n "$AuthId"; then; echo "You are logged in as $AuthId(:if auth admin:) (admin)(:ifend:). [[{$FullName}?action=logout|logout]]"; else; echo "Click [[{$FullName}?action=login|here]] to log in." fi)} {(wikish source {$FullName}#signup)} >>lframe width=350px<< (:if equal "${create_edit}" "${CreateNewUser}":)Fill in the form and press "${CreateNewUser}" to create a user ID:(:else:)Make any changes and press "${SaveExistingUser}" to modify the information on this user.(:ifend:) ||width=350px || Username:||(:input text username ${readonly}:)|| || Password:||(:input password password:)|| || Email:||(:input text email:)|| || Fname:||(:input text fname:)|| || Lname:||(:input text lname:)|| || Telephone:||(:input text phone:)|| (:if [ equal "${create_edit}" "${CreateNewUser}" && auth admin ] :)(:input checkbox bypassconfirm:) Bypass Email Confirmation(:ifend:) (:input submit save_button "${create_edit}":) (:if equal "${create_edit}" "${SaveExistingUser}":)(:input submit del_button "Delete":)(:input submit resend_button "Resend Confirmation Email":)(:ifend:) >><< >>rframe width=350px<< Enter your username and password, then click "Load Form" to view and edit your user details in the form on the left ||width=350px || Username:||(:input text edituser:)|| || Password:||(:input password editpass:)|| (:input submit load_form "Load Form":) (:input submit forgot_passwd "Forgot Password":) >><< (:input end:) [[<<]] (:messages:) (:if false:) [[#signup]] function clearform { set -s --form username = set -s --form password = set -s --form email = set -s --form fname = set -s --form lname = set -s --form phone = # ANY CHANGE TO THE FIELDS REQUIRES ADDING/DELETING FIELDS IN THIS FUNCTION } function require { if test -z ${${1}} then echo "%red%${2}%%\\" set err ++ fi } wikish_form quickform process method=POST ## THE LINE IMMEDIATELY BELOW THIS MUST BE MODIFIED TO MATCH *YOUR* URL set -s confirmurl = 'http://www.example.com/pmwiki/pmwiki.php?n=Login.Confirm' set -s readonly = '' set -s AuthUserExtra = 'SiteAdmin.AuthUserExtra' set -s CreateNewUser = 'Create New User' set -s SaveExistingUser = 'Update Information' set -s create_edit = ${CreateNewUser} # Default if not over-ridden below set -s PAGEVARS = '' # suppress fmtpagename() if ! test -f ${AuthUserExtra} then echo "" >${AuthUserExtra} fi if test -n "${save_button}" then # # The user has pressed "Save" - validate the data # if test "${username}" ~= "/[^a-z0-9_]/i" then echo "%red%Only alphabetic characters, numeric digits, and underscore are allowed in the username.%%" exit fi if test "${password}" ~= "/ /" then echo "%red%No spaces allowed in the password.%%" exit fi # PUT ANY OTHER PASSWORD VALIDATION ROUTINES HERE if test "${save_button}" == "${CreateNewUser}" then # # We are "saving" the info for a NEW user (not editing existing) # set err = 0 require username "You must provide a username." require password "You must provide a password." require email "You must provide an email address." require fname "You must provide a first name." require lname "You must provide a last name." if test -n ${username} then if grep -q "^${username}:" SiteAdmin.AuthUser then echo "%red%That user already exists and is confirmed.%%\\" set err ++ else if grep -q "^${username}:" ${AuthUserExtra} then echo "%red%That user already exists awaiting confirmation.%%\\" set err ++ fi fi fi # CHECK FOR ANY DISALLOWED EMAIL DOMAINS HERE if test ${err} -gt 0 then echo "%red%Cannot create due to ${err} error(s) listed above.%%" exit fi # OK, I think we're legitimate at this point - go ahead and add it to the ${AuthUserExtra} table if test -n ${bypassconfirm} && test --pmwiki auth admin then set -s random = 0 else set random = ${RANDOM} fi set -s npass = "`crypt ${password}`" # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW echo "${username}:${fname}:${lname}:${phone}:${email}:${random}:${npass}" >>${AuthUserExtra} if test -n ${bypassconfirm} && test --pmwiki auth admin then echo "${username}:${npass}" >>SiteAdmin.AuthUser else # This link must point to the Confirm page with the ?code… appended to the end. # You might want to change the wording on the email since this is pretty basic… mailx -t ${email} -s "Please reply to complete subscription" - "Please click on this link ${confirmurl}?code=${random}?user=${username}" fi echo "%red%Success%%" clearform else # # We are "saving" the info for an existing user (not creating a new user) # set err = 0 require username "You must provide a username." require password "You must provide a password." require email "You must provide an email address." require fname "You must provide a first name." require lname "You must provide a last name." # CHECK FOR ANY INVALID EMAIL DOMAINS HERE if test ${err} -gt 0 then echo "%red%Cannot create due to ${err} error(s) listed above.%%" exit fi set -s pass_source = 'authuser' set -s oldpass = "`grep '^${username}:' SiteAdmin.AuthUser | cut -d: -f2`" if test -z ${oldpass} then set -s oldpass = "`grep '^${username}:' ${AuthUserExtra} | cut -d: -f7`" set -s pass_source = 'extra' fi set -s oldpass = "`trim ${oldpass}`" if test "${password}" == "${oldpass}" || test ${oldpass} == "`crypt --salt:"${oldpass}" ${editpass}`" || test --pmwiki auth admin then if test "${password}" == "${oldpass}" # loaded via admin privs, already crypt'd then set -s newpass = "${password}" # the password has been entered in the form - crypt it # NOTE THAT PASSWORD VALIDATION (no space, require numeric, # require uppercase, etc.) # IS NOT BEING DONE HERE AND IT SHOULD PROBABLY BE DONE! else set -s newpass = "`crypt --salt:'${oldpass}' ${password}`" fi set -s code = "`grep '^${username}:' ${AuthUserExtra} | cut -d: -f6`" grep -v '^${username}:' ${AuthUserExtra} >Temp.AuthUserExtra # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW echo "${username}:${fname}:${lname}:${phone}:${email}:${code}:${newpass}" >>Temp.AuthUserExtra cp -q Temp.AuthUserExtra ${AuthUserExtra} if test ${pass_source} == 'authuser' then grep -v '^${username}:' SiteAdmin.AuthUser >Temp.AuthUser echo '${username}:${newpass}' >>Temp.AuthUser cp -q Temp.AuthUser SiteAdmin.AuthUser fi echo "%red%Success%%" clearform else echo "%red%Error. The password does not match.%%" fi fi fi if test -n "${load_form}" then # # The user filled something in on the RIGHT side form and pressed "load form" # if test -z ${edituser} then echo "Please specify an existing username." clearform exit fi if test -z ${editpass} && ! test --pmwiki auth admin then echo "Please specify the password for '${edituser}." clearform exit fi # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW grep '^${edituser}:' ${AuthUserExtra} | read --initialize --IFS:: username fname lname phone email code readpass if test -z ${username} # Presumably does not exist in AuthUserExtra then grep '^${edituser}:' SiteAdmin.AuthUser | read --initialize --IFS:: username readpass set -s pass_src = authuser else set -s pass_src = extra fi if test -n ${username} # We found it in one or the other... then set -s readpass = "`trim ${readpass}`" if test --pmwiki auth admin || test "`crypt --salt:${readpass} ${editpass}`" == "${readpass}" then # Set defaults as we found in ${AuthUserExtra} (they'll be blank if no AuthUserExtra record) set -s --form username = ${edituser} set -s --form password = ${readpass} set -s --form email = ${email} set -s --form fname = ${fname} set -s --form lname = ${lname} set -s --form phone = ${phone} # ANY CHANGE TO THE FIELDS REQUIRES ADDITION/DELETION OF LINES ABOVE set -s readonly = 'readonly=1' #Can't change username else echo "%red%ERROR: Username / Password do not match. %%" clearform exit fi else echo "%red%ERROR: Username / Password does not exist. Did you mean to create a new user?%%" clearform exit fi set -s create_edit = ${SaveExistingUser} fi if test -n ${del_button} then # # The user pressed the "delete" button # if test -z ${edituser} then echo "%red%ERROR: Must specify username and load form before deleting%%" exit fi if grep -q "^${edituser}:" SiteAdmin.AuthUser then grep -v "^${edituser}:" SiteAdmin.AuthUser >SiteAdmin.AuthUser fi if grep -q "^${edituser}:" ${AuthUserExtra} then grep -v "^${edituser}:" ${AuthUserExtra} >${AuthUserExtra} fi set -s --form username = '' set -s --form password = '' set -s --form email = '' set -s --form fname = '' set -s --form lname = '' set -s --form phone = '' # ANY CHANGE TO THE FIELDS REQUIRES ADDITION/DELETION OF LINES ABOVE echo "User '${edituser}' Deleted." fi if test -n ${forgot_passwd} then # # The user pressed the "forgot password" link # if test -z ${edituser} then echo "%red%ERROR: Must specify username and load form before resending confirmation%%" exit fi if ! grep -q "^${edituser}:" ${AuthUserExtra} then echo "%red%ERROR: User '${edituser}' does not exist." exit fi # Rewrite the authuserextra line for this user with a new code # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW grep '^${edituser}:' ${AuthUserExtra} | read --initialize --IFS:: username fname lname phone email code readpass if test -z ${email} then echo "%red%ERROR: No email address is specified for that user. An administrator must reset your password manually.%%" exit fi grep -v "^${edituser}:" ${AuthUserExtra} >${AuthUserExtra} set code = ${RANDOM} # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW echo "${username}:${fname}:${lname}:${phone}:${email}:${code}:${readpass}" >>${AuthUserExtra} mailx -t ${email} -s "Please reply to confirm a password change" - "Please click on this link ${confirmurl}?code=${code}?user=${username}?newpass=1" echo "Request Sent." fi if test -n ${resend_button} then # # The user requested a resend of the confirmation email # if test -z ${edituser} then echo "%red%ERROR: Must specify username and load form before resending confirmation%%" exit fi # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW grep '^${edituser}:' ${AuthUserExtra} | read --initialize --IFS:: username fname lname phone email code readpass mailx -t ${email} -s "Please reply to complete subscription" - "Please click on this link ${confirmurl}?code=${code}?user=${username}" echo "Resent." fi [[#signupend]] (:ifend:)
Create a page Login.Confirm (YOU MUST HAVE THE EDIT PASSWORD SET TO @admin OR SIMILAR) with the following source:
%comment% AuthUserSignup VERSION 2010-04-14 %% (:linebreaks:) {(wikish source {$FullName}#finishsignup)} (:if false:) [[#finishsignup]] wikish_form process if test -z ${user} || test -z ${code} || test ${code} == 0 then echo "Please use the link provided in the email to access this page." exit fi set -s AuthUserExtra = "SiteAdmin.AuthUserExtra" set -s PAGEVARS = '' # suppress fmtpagename due to funky chars in passwd if test -n ${newpass} then read --clear # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW grep "^${user}:" ${AuthUserExtra} | while read --IFS:: username fname lname phone email pagecode pass do if test ${pagecode} == ${code} then set -s newpass = 'a${RANDOM}' set -s newcrypt = '`crypt ${newpass}`' # Change the password in AuthUser if the username is confirmed there if grep -q "^${username}:" SiteAdmin.AuthUser then grep -v "^${username}:" >SiteAdmin.AuthUser echo "${username}:${newcrypt}" >>SiteAdmin.AuthUser fi # Now change the password in AuthUserExtra (also zero the code) grep -v '^${username}:' ${AuthUserExtra} >Temp.AuthUserExtra # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW echo "${username}:${fname}:${lname}:${phone}:${email}:0:${newcrypt}" >>Temp.AuthUserExtra cp -q Temp.AuthUserExtra ${AuthUserExtra} echo "Password changed for user ${username}. The new password is '''${newpass}'''. It is recommended to go directly to [[Login.Signup]] to change your password." exit fi done echo "%red%Error: Your email link is not synchronized with the state of the password file. Please reissue your change-password request.%%" else if grep -q "^${user}:" SiteAdmin.AuthUser then echo "User ${user} already exists. Cannot add this user." exit fi read --clear # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW grep "^${user}:" ${AuthUserExtra} | while read --IFS:: username fname lname phone email pagecode pass do if test ${pagecode} == ${code} then echo "${username}:${pass}" >>SiteAdmin.AuthUser # Now make the code from a random number to a 0 to indicate it's confirmed grep -v '^${username}:' ${AuthUserExtra} >Temp.AuthUserExtra # ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW echo "${username}:${fname}:${lname}:${phone}:${email}:0:${pass}" >>Temp.AuthUserExtra cp -q Temp.AuthUserExtra ${AuthUserExtra} echo "User ${username} confirmed. You may log in immediately by clicking on [[Confirmed?action=logout|this link]]. " echo "(By clicking on this link you will automatically be logged OUT before allowing you to log in again.)" exit fi done echo "Please use the link provided in the email to access this page." # Actually a wrong code, but let's avoid encouraging them trying a million times fi [[#finishsignupend]] (:ifend:)
Create a page Login.Confirmed (SET THE READ PASSWORD TO id:* FOR THIS PAGE) with the following source:
%comment% AuthUserSignup VERSION 2010-04-14 %% Congratulations! Your new user has been confirmed and logged in.
Check to make sure that both Login.Signup and Login.Confirm have the edit password set such that only an administrator can edit
You can change the information you are collecting to include fewer or additional or different fields. First you will change the form found on Login.Signup and then you will change both lines which are preceded (one on each page) with the comment "# ANY CHANGE TO THE FIELDS REQUIRES A CHANGE ON THE LINE BELOW"
If you wish to add an additional field to the 6 already collected (username, first name, last name, email, telephone #, password) then you will need to carefully scan through both Login.Signup and Login.Confirm. You will need to find each occurrence of the text "ANY CHANGE TO THE FIELDS" and check carefully in that vicinity for any changes that need to be made. If you wish to remove an existing field then it is easier to simply remove it from the form in Login.Signup and then locate the "require FIELDNAME" for that field and comment that out. (Note that telephone number is not a required field so removing it from the form at the top of Login.Signup suffices to remove it completely.)
Notes
Now users will go to Login.Signup to fill in the form. If all fields validate correctly then their information will be stored in SiteAdmin.AuthUserExtra and they will be sent an email with a link which they must click on. When they click on that link it will take them to the Login.Confirm page with an appropriate code specified and then their subscription will be confirmed and their information will be added to SiteAdmin.AuthUser.
A user can also fill in a username and password on the right-hand-form and click on "load form" to load the left-hand form with existing data in order to make modifications. Both SiteAdmin.AuthUserExtra fields as well as the password itself in SiteAdmin.AuthUser can be changed using this method.
You should make sure that SiteAdmin.AuthUserExtra and SiteAdmin.AuthUser have appropriate permissions. Presumably you want protected read AND protected edit for the former and at least protected edit for the latter.
Note that this recipe deals comfortably with users defined in the SiteAdmin.AuthUser page. It has no knowledge of LDAP nor htpasswd nor other methods of storing user accounts.
Release Notes
- 2010-04-14 - added an explicit line break (
[[<<]]
) after the form to prevent footers overwriting the form in certain skins. If you are upgrading from 2009-04-19 there is just that single addition to Login.Signup - no other changes for this release. - 2009-04-19 - Fixed a problem with a read --initialize, restructured install instructions, added version info on each page
- 2009-04-15 - Added an explicit setting of
$DebugLevel
during installation - 2009-04-14 - Added a check for existence of AuthUserExtra with a more graceful handling
- 2008-11-18 - It's gone live on at least one site and is working.
- 2008-09-28 - Most bugs worked out. Added lots of new capabilities for user admin.
- 2008-09-17 - I think this can be called a release now.
- 2008-09-14 - Still not formally released, but closer.
- 2008-09-10 - Not yet released formally. Still in testing.
See Also
- UserAdmin - this is already probably superior to AuthUserSignup and will certainly be the successor (besides being much easier to install)
- AuthUserDbase - a database based method of maintaining user auth information and allowing users to sign up.
Contributors
Roadmap
Comments
See discussion at AuthUserSignup-Talk
User notes +5: 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.