|
Cookbook /
AuthUserSignupSummary: Allow users to sign up themselves (with email verification) for authuser accounts
Version: 2009-04-19
Prerequisites: pmwiki 2.2.x, WikiSh version 2008-09-28 or later, MiscMX version 2008-09-13 or flater, WikiMail version 2008-08-08 or later, Toolbox
Status: Beta
Maintainer: Peter Bowers
Categories: Administration and Security
Questions answered by this recipe
DescriptionAllow users to sign up via a form for an authuser account. Includes email and other validation. Installation & ConfigurationThe following steps must be followed to fully install the AuthUserSignup recipe
Installation of WikiSh
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);
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
include_once("$FarmD/cookbook/MiscMX.php");
Installation of WikiMail
include_once("$FarmD/cookbook/wikimail.php");
$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
%comment% AuthUserSignup VERSION 2009-04-19 %%
(: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 2009-04-19 %%
(: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 2009-04-19 %% 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 editYou 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.) NotesNow 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
See Also
ContributorsRoadmap
Comments
Well is there a way for the Admin to check, who is registering, before comfirmation is send? The original idea of this recipe is to allow admin-free registration. It's not too difficult to add in an additional [send-email-to-admin-and-get-his-confirmation] step before allowing the user to be approved. Unfortunately it's probably not something I'm going to be working on anytime too soon... If somebody has shell scripting background (or wants to learn) feel free... (But do make sure to keep it separate from the existing, simpler script.) Thx for fast response. Keep on to set up. Now I got an email-response, but can't confirm, because of an error like this in my first and only AuthUserExtra: fratz:fname:lname::mail@some.de:7676:UNKNOWN MARKUP EXPRESSION COMMAND: crypt . Is that an WikiSh or MX - thing? Something is wrong with your MiscMX installation. That's the source for the "crypt" MX. Thx first, it was the MX - i forgot the leading include_once in the config . But sorry, it still don't works. Two things happened. 1. If I signup a user the script flushes former entries (I assume, that happens while filetesting,
if ! test -f ${AuthUserExtra}
then
echo "" >${AuthUserExtra}
fi
although i couldn't explain. (I use clean URLs if that will help) So i found always only one user in my AuthUserExtra 2.Even if - let's say - the AuthUserExtra first line goes like this and i come back with my link I'm just kicked out, with the second Please use the email-link-message. Got a clue? Need more information? (I use a math module, interpreting the dollarsigns for its surrounding) It would help if we could communicate by email. Please drop me a line at xian.5.pbowers@spamgourmet.com - That address will only work temporarily (5 emails) but once we are communicating by email I can give you my real address. Basically we need to establish either (1) a problem in installation or (2) an incompatibility with another recipe or (3) an incompatibility with your hosting setup. Let's start by checking versions -- can you send me a list containing the $Version line in each of the scripts that are involved in the install? Are the issues (above) addressed? Is the problem solved? --Peter Bowers November 16, 2009, at 11:21 AM Hi, it's me again. I wrote to the given mail, hope you got it. Otherwise I take a look here. As I said, problem isn't solve wether in a flat system nor in the subdirectories. Well, I guess that didn't work. It must have been caught in my spam filters because I never saw anything. So, if we proceed differently -- can you give me a site to look at or is it inaccessible? --Peter Bowers November 20, 2009, at 12:06 PM Line 60 of SecLayer.php should be Thanks for the report - addressed in version 2009-11-14 of SecLayer.php --Peter Bowers November 16, 2009, at 11:21 AM Function split() is deprecated in php 5.3 and causes errors. This function is used quite a lot throughout the code included for AuthUserSignup. Scott Connard November 03, 2009, at 04:49 PM Thanks for the report - addressed in version 2009-11-14 of SecLayer and WikiSh and etc. --Peter Bowers November 16, 2009, at 11:21 AM
User notes: If you use, used or reviewed this recipe, you can add your name. The following format is recognized:
* (+) Optional positive comment. Name, date * (-) Optional negative comment. Name, date These statistics appear in the Cookbook listings and will help newcomers browsing through the wiki. |