Short description
I have several public wikis that are read-only for the general public, with any known user being able to edit pages. However, I don't want just anyone to register themselves, I want to only let my friends and friends of my friends be able to get access: you need to have someone who already has wiki access create a username for you.
The changes discussed below add an ACL line that lets you define who has permission to create new users on the wiki, and then also lets already-logged-in users create new users without logging out (since logged out users now can't create users at all). There are a couple of usability improvements to go along with it, and all of these changes have been tested and are in production right now.
FlorianFesti suggested the ACL path, and AlexanderSchremmer initially voiced concerns on IRC, but these were quickly assuaged.
Here are eight sets of changes that need to be made:
First, the default value goes in multiconfig.py, between acl_rights_after and acl_rights_valid:
acl_rights_createuser = u"All:write"
Second, add the following class to the end of wikiacl.py:
class CreateUserAccessControlList(AccessControlList): ''' Access Control List for Creating Users Control who may create new user accounts on the system. This has to be in your config, can't use #acl lines. Configuration options cfg.acl_rights_createuser Defines who is able to create users. Permission is either "write" or nothing. Default: "All:write" ''' def __init__(self, request): """Initialize an ACL, starting from <nothing>. """ self.setLines(request.cfg) def setLines(self, cfg): self.clean() self.addCreateuser(cfg) def addCreateuser(self, cfg): self.addLine(cfg, cfg.acl_rights_createuser, remember=0)
Third, since we need ACLs on every major screen of the userform, let's import wikiacl at the top. Around line 10 of userform.py, change:
from MoinMoin import config, user, util, wikiutil
to:
from MoinMoin import config, user, util, wikiutil, wikiacl
All of the remaining changes are in userform.py.
Fourth, around line 144, right after the else:, add:
createuseracl = wikiacl.CreateUserAccessControlList(self.request).may(self.request, self.request.user.name, "write")
Fifth, around line 164 of userform.py, between the newuser = 1 and password blocks, replace the entire user.getUserId block with:
# create key is for existing users creating new users # save key is for users creating or updating themselves if form.has_key('save'): if user.getUserId(self.request, theuser.name): if theuser.name != self.request.user.name: return _("This user name already belongs to somebody else.") else: newuser = 0 # Now that we know if it's a new user or not, we can check the acl if newuser and not createuseracl: return _("You are not allowed to create a user account.") # create key is for existing users creating new users # save key is for users creating or updating themselves if newuser and form.has_key('create'): theuserisnew = self.request theuserisnew.saved_cookie = '' theuserisnew.auth_username = '' theuser = user.User(theuserisnew) theuser.name = form['username'][0]
Sixth, around line 279, after theuser.save(), we need to only reset the cookie if actually needed. Change the lines between theuser.save() and result = _("User preferences saved!") to:
# create key is for existing users creating new users # save key is for users creating or updating themselves if form.has_key('save'): self.request.user = theuser self.request.setCookie()
Seventh, we have to add the Create Profile button back into the form for users with ACL access. Around line 408, in asHTML() after self.make_form(), change the whole if self.request.user.valid: block to:
createuseracl = wikiacl.CreateUserAccessControlList(self.request).may(self.request, self.request.user.name, "write") if self.request.user.valid: # User preferences interface buttons = [ ('save', _('Save')) ] if createuseracl: buttons.append(('create', _('Create Profile'))) buttons.append(('logout', _('Logout'))) else: # Login / register interface buttons = [ # IMPORTANT: login should be first to be the default # button when a user click enter. ('login', _('Login')), ] if createuseracl: buttons.append(("save", _('Create Profile'))) if self.cfg.mail_smarthost: buttons.append(("login_sendmail", _('Mail me my account data')))
This only adds the Create Profile button if the user has the right to create a new user. createuseracl will be true even if ACLs are disabled or if there is no custom new user creation ACL. You'll also notice that for logged in users, the Create Profile button has a new name, create. This will let us tell whether a logged in user is creating a new user, or updating their own user.
Eighth, the next change is purely cosmetic, but increases the usability of the page a bit. They remove the password verification box if the user isn't allowed to create a user or isn't already logged in (e.g. all they can do is log in). They also remove the email verification box if mailing isn't configured and the user isn't allowed to create a user or isn't already logged in, or adds a clarification quote in parethesis if they're logged out but mailing is configured.
Around line 444, replace the self.make_row(_('Password repeat'), [ and self.make_row(_('Email'), [ blocks with the following:
if self.request.user.valid or createuseracl: self.make_row(_('Password repeat'), [ html.INPUT( type="password", size="36", name="password2", ), ' ', _('(Only when changing passwords)'), ]) if self.cfg.mail_smarthost and not createuseracl: self.make_row(_('Email'), [ html.INPUT( type="text", size="36", name="email", value=self.request.user.email ), ' ', _('(Only for mailing your account data)', formatted=False), ]) elif createuseracl: self.make_row(_('Email'), [ html.INPUT( type="text", size="36", name="email", value=self.request.user.email ), ' ', ])
That's it! You can now set a line in your wikiconfig.py like:
acl_rights_createuser = u"VitoMiliano:write All:"
to only let you register new users. Or you could do:
acl_rights_createuser = u"Known:write All:"
to let anyone who already has an account add a new one.
If you want all the userform.py changes, I've attached my version here (drop in replacement for 1.3.4's userform.py, but don't forget to make the changes to wikiacl.py and multiconfig.py!): userform.py
I would like to get a patch with all those changes, so I can test this on my test wiki. If you work with tla, getting this patch is very easy, just run tla changes --diffs > createuser.patch. If you don't work with tla I think that diff -ur original-moin-dir modified-moin-dir > createuser.patch will do the same. Both are much easier then to write manually the patch description on this page, and very easy to apply by other developers or users that want to try the patch. -- NirSoffer 2005-03-27 00:44:28
Alright! I believe I did it correctly: createuser.patch
The patch have some problems:
- Adding a "create account" button in the user preferences form is confusing and wrong. Create user account is either free, or an admin stuff, that only certain user can access. Its not related to the user preferences.
There is no need to create a new type of AccessControlList to add new acl right.
There is no need to patch userform.py - UserPreference is a macro - just provide you private wiki macro, and implement the ui as you like.
For a general solution, we can do this:
Add new 'register' right
Add new acl right to the valid rights, 'register' which is the right to register a user acount. The default install will give this right to the All group. It will look like this in multiconfig:
acl_rights_before = u"All:+register" acl_rights_valid = ['read', 'write', 'revert', 'delete', 'register', 'admin',]
In a wiki that only known users are allowed to register accounts, this setting will be used in the configuration file:
acl_rights_before = u"Known:+register"
In a wiki where only certain user in group RegisterGroup should register accounts:
acl_rights_before = u"RegisterGroup:+register"
This change is trivial.
User interface change
Start redesign the login/register/user pref as described in UserPreferencesRedesign. This change is bigger but its a simpler user interface change.
Create new macro [[CreateAcount]], that will be in the new CreateAcount page that will show this:
Welcome to MoinMoin Wiki!
- To create a new user account, please fill this form (all fields are required):
name: |
[ ] |
password: |
[ ] |
repeat: |
[ ] |
email:
[ ]
This macro will validate the user using standard acl calls:
if not user.may.register(''): return _("You may not create user acounts in this wiki.")
This wil use the acl right defined in the config.
In userform.py, simplify the code and the login user interface to this:
Welcome to MoinMoin Wiki!
- Please enter your user name and password:
name: |
[ ] |
password: |
[ ] |
If you don't have an user account, you are invited to CreateAcount.
The line about creating user account will show only if All have register right in the wiki of course, so a visitor will not be sent to a page just to tell "you are not allowed".
There is no need to enter an email address for the "Send Account Data", because in most cases the user also forgot what was the email address that he used when he registered. We should simply send the data to the email address in our data base.
- Hmmm, ok this is great if it works, but how do I add this to version 1.5? It's really hard to follow instructions such as "insert around line number n" need to know which methods are being edited and where. Hopefully this will be included already in the next version. Thanks --Stan
- Ditto... I have just been requested to lock down account creation to registered (or admin) only users.... v1.5x needs this ability.
Meanwhile, I have personally limited account creations to SuperUser by patching userform.py/UserSettingsHandler.handleData by adding two lines:
if (form.has_key('create') or form.has_key('create_only') or form.has_key('create_and_mail')): if not self.request.user.isSuperUser(): # added return _("User creation disabled in 'userform.py'.") # added
Is there a better way to do this?
...Ah... just discovered that a page (for instance "UserCreation") is also needed with content:
[[UserPreferences(createonly)]]
I'm' confused by the discussion above -- not sure which parts override which others, and the patch file didn't work with my Linux patch. I'd appreciate a set of instructions for 1.5.5 and very much want to see this feature in the next version. Thank you. -- MitchellModel
What's the status for this feature in 1.5.x? I need to start a wiki project and MoinMoin looks the most promising for all the features I'm looking for in a wiki software with the exception that for my project, not everyone should be allowed to just register an account. (Read this as: I really don't want to use TikiWiki).
--FSB
1.5.7 is the old stable version, it won't get any big new features. You can simple use an EditorGroup and restrict write rights to that group. So anyone can register, but that doesn't get them additional rights. -- ThomasWaldmann 2007-02-23 17:37:57
I've been a moin user for a long time, and the issue of not being able to 'clamp down' a site when serving it publicly has always been a problem for me. In particular, I've noticed that people can use the site to spam other people, eg:
- create an account
- set the new email address to point o someone I don't like
- subscribe to ".*"
and hey presto: instant spamming! So, I'm very keen to get a solution to this issue.
This has to be solved by roundtripping an email for account creation, not by locking down user registration.
One of the main problems seems to be the lack of separation of the 'User Preferences' page and the 'Create New User' page. Wouldn't it be simple to just:
separate these pages
- has been done in 1.7
- allow people to restrict access to the 'Create New User' page (ie using the existing ACL techniques)
(This would have the nice side effect of getting rid of the confusing password-change vs password-enter behavior)
Another related note: it might be useful to me (and the general community) to have a nice overview write-up of the techniques used on the Moin site itself. I've noticed that you guys have done a great job of writing the code and using it yourselves to manage your codebase (eg the Bugs/Features)
Thanks for listening, Tushar.
This feature request is totally mangled and seems to consist of at least three different ones. In 1.7 it is possible to disable new user creation by disallowing the "newaccount" action. Please create a new one. -- JohannesBerg 2008-03-18 00:02:53