Plugin for cone.app providing a user and group management UI.
- Users and Groups CRUD
- Principal membership of users and groups
- Roles support
- Local Manager Support
- User and group form configuration
While installation lxml
gets compiled, the required dev headers must be
installed on the system.
On debian based systems install:
$ apt-get install -y libxml2-dev libxslt1-dev
For testing and development, cone.ugm
contains a buildout configuration.
Download or checkout package and run:
cone.ugm$ ./bootstrap.sh python3
For testing and demo purposes, an example UGM configuration is contained in the
cfg
folder of the source package.
It contains the configuration file ugm.xml
, containing the general UGM
configuration and localmanager.xml
, containing the configuration about
local users and groups management. These two files can be edited TTW via the
settings UI.
The ugm.ini
file contains the application configuration:
[app:ugm]
...
cone.plugins =
cone.ugm
ugm.backend = file
ugm.config = %(here)s/ugm.xml
ugm.localmanager_config = %(here)s/localmanager.xml
ugm.users_file = %(here)s/../parts/ugm/users
ugm.groups_file = %(here)s/../parts/ugm/groups
ugm.roles_file = %(here)s/../parts/ugm/roles
ugm.datadir = %(here)s/../parts/ugm/data
...
In this example the file
backend is configured as UGM backend. For
configuring SQL or LDAP based backends, see documentation at cone.sql
respective cone.ldap
.
Start the application:
cone.ugm$ ./bin/pserver cfg/ugm.ini
and browse http://localhost:8081/
. Default admin
user password is
admin
.
For customizing the plugin, make an integration package and include it in your setup.
cone.ugm
internally uses 3 roles in order to permit user actions.
editor
is permitted to manage membership, admin
additionally is
permitted to add, edit and delete users and groups, and manager
is a
superuser. If UGM is the only plugin used, you can reduce the available roles
to this three:
cone.app.security.DEFAULT_ROLES = [
('editor', 'Editor'),
('admin', 'Admin'),
('manager', 'Manager')
]
The basic principal form customization happens in the ugm XML configuration
file. Each field to render must have an entry in users_form_attrmap
respective groups_form_attrmap
:
<users_form_attrmap>
<elem>
<key>my_field</key>
<value>My Field</value>
</elem>
</users_form_attrmap>
By default, a non required text field gets rendered for each custom entry in the XML configuration.
To make a custom field required, the easiest way is to use
default_form_field_factory
and register it with user_field
respective group_field
:
from cone.ugm.browser.principal import default_form_field_factory
from cone.ugm.browser.principal import user_field
from functools import partial
my_field_factory = user_field('my_field')(
partial(default_form_field_factory, required=True)
)
It's possible to register custom principal field factories for dedicated
UGM backends. This example is taken from cone.ldap
and registers a
user field factory for cn
attribute in ldap
backend:
ldap_cn_field_factory = user_field('cn', backend='ldap')(
partial(default_form_field_factory, required=True)
)
The most flexible way for principal form field customization is to provide a callback function and call the yafowil factory directly:
from yafowil.base import factory
@user_field('age')
def age_field_factory(form, label, value):
return factory(
'field:label:error:number',
value=value,
props={
'label': label,
'datatype': int
})
Note. The value of the custom field gets written to principal attributes as extracted from the widget. Make sure to define the expected datatype in the widget properties or define a suitable custom extractor.
XXX
You can react to creation, modification and deletion of users and groups by binding to the given event classes.
These events are fired when the user manipulations are done in the UGM management forms.
necessary imports:
from zope.event import classhandler
from cone.ugm import events
for users:
@classhandler.handler(events.UserCreatedEvent)
def on_user_created(event):
print(f"user {event.principal} with id {event.principal.name} created")
@classhandler.handler(events.UserModifiedEvent)
def on_user_modified(event):
print(f"user {event.principal} with id {event.principal.name} modified")
@classhandler.handler(events.UserDeletedEvent)
def on_user_deleted(event):
print(f"user {event.principal} with id {event.principal.name} deleted")
and for groups:
@classhandler.handler(events.GroupCreatedEvent)
def on_group_created(event):
print(f"group {event.principal} with id {event.principal.name} created")
@classhandler.handler(events.GroupModifiedEvent)
def on_group_modified(event):
print(f"group {event.principal} with id {event.principal.name} modified")
@classhandler.handler(events.GroupDeletedEvent)
def on_group_deleted(event):
print(f"group {event.principal} with id {event.principal.name} deleted")
- Robert Niederreiter (Author)
- Florian Friesdorf
- Jens Klein