def __init__(self, settings): # cone.ugm active, users and groups attributes are read from ugm config if settings.get('cone.plugins').find('cone.ugm') > -1: from cone.ugm.utils import general_settings model = get_root() ugm_settings = general_settings(model).attrs self.user_attrs = ugm_settings.users_form_attrmap.keys() self.group_attrs = ugm_settings.groups_form_attrmap.keys() # users and groups attributes are read from application ini file else: self.user_attrs = [ attr.strip() for attr in settings.get('sql.user_attrs', '').split(',') if attr.strip() ] self.group_attrs = [ attr.strip() for attr in settings.get('sql.group_attrs', '').split(',') if attr.strip() ] self.binary_attrs = [ attr.strip() for attr in settings.get('sql.binary_attrs', '').split(',') if attr.strip() ] self.log_auth = settings.get('sql.log_auth') in ['true', 'True', '1']
def group_default_sort_column(self): settings = general_settings(self.model) attrs = self.group_attrs sort = settings.attrs.groups_listing_default_column if sort not in attrs: return attrs[0] return sort
def prepare(_next, self): """Hook after prepare and set expiration widget to ``self.form``. """ _next(self) settings = general_settings(self.model) if settings.attrs.users_account_expiration != 'True': return mode = 'edit' if not self.request.has_permission('manage_expiration', self.model.parent): mode = 'display' if self.action_resource == 'edit': attr = settings.attrs.users_expires_attr unit = int(settings.attrs.users_expires_unit) value = int(self.model.attrs.get(attr, 0)) # if format days, convert to seconds if unit == 0: value *= 86400 else: value = UNSET expires_widget = factory( 'field:label:expiration', name='active', value=value, props={'label': _('active', default='Active')}, mode=mode) save_widget = self.form['save'] self.form.insertbefore(expires_widget, save_widget)
def save(self, widget, data): extracted = dict() for attr_name in itertools.chain(self.reserved_attrs, self.form_attrmap): value = data[attr_name].extracted if not value: continue extracted[attr_name] = value # possible values extracted by other user form behaviors extracted.update(self.model.attrs) users = ugm_backend.ugm.users user_id = extracted.pop('id') password = extracted.pop('password') login_name = general_settings(self.model).attrs.users_login_name_attr if login_name: extracted[login_name] = extracted.pop('login') user = users.create(user_id, **extracted) users() if self.model.local_manager_consider_for_user: groups = ugm_backend.ugm.groups for gid in self.model.local_manager_default_gids: groups[gid].add(user_id) groups() self.request.environ['next_resource'] = user_id if password is not UNSET: users.passwd(user_id, None, password) notify(events.UserCreatedEvent( principal=user, password=password )) self.model.parent.invalidate()
def wrapper(inst): try: w(inst) finally: settings = general_settings(get_root()) settings.attrs.users_portrait = u'True' settings()
def next_principal_id(self): settings = general_settings(self.model) prefix = settings.attrs.user_id_autoincrement_prefix default = int(settings.attrs.user_id_autoincrement_start) search = u'%s*' % prefix backend = self.model.parent.backend backend.invalidate() result = backend.search(attrlist=['id'], criteria={'id': search}) if result and isinstance(result[0][1]['id'], list): # XXX: is node.ext.ldap behavior attr list values are lists. # keep until node.ext.ldap supports single valued fields. principlal_ids = [_[1]['id'][0] for _ in result] else: principlal_ids = [_[1]['id'] for _ in result] matching = list() for principal_id in principlal_ids: if prefix: principal_id = principal_id[len(prefix):] try: principal_id = int(principal_id) except ValueError: continue matching.append(principal_id) if not matching: principal_id = default else: principal_id = sorted(matching)[-1] + 1 if principal_id < default: principal_id = default return u'%s%i' % (prefix, principal_id)
def wrapper(inst): try: w(inst) finally: settings = general_settings(get_root()) settings.attrs.user_id_autoincrement = 'False' settings.attrs.user_id_autoincrement_prefix = '' settings()
def test_autoincrement(self): root = get_root() users = root['users'] settings = general_settings(users) self.assertEqual(settings.attrs.user_id_autoincrement, 'False') self.assertEqual(settings.attrs.user_id_autoincrement_prefix, '') vessel = user_vessel(users) request = self.layer.new_request() with self.layer.authenticated('manager'): res = render_tile(vessel, request, 'addform') self.checkOutput(""" ...<input class="form-control required text" id="input-userform-id" name="userform.id" required="required" type="text" value="" />... """, res) settings.attrs.user_id_autoincrement = 'True' settings() vessel = user_vessel(users) with self.layer.authenticated('manager'): res = render_tile(vessel, request, 'addform') self.checkOutput(""" ...<input class="form-control text" disabled="disabled" id="input-userform-id" name="userform.id" type="text" value="auto_incremented" />... """, res) request = user_request(self.layer) vessel = user_vessel(users) with self.layer.authenticated('manager'): res = render_tile(vessel, request, 'addform') self.assertEqual(sorted(users.keys()), ['100', 'manager']) request = user_request(self.layer) vessel = user_vessel(users) with self.layer.authenticated('manager'): res = render_tile(vessel, request, 'addform') self.assertEqual(sorted(users.keys()), ['100', '101', 'manager']) settings.attrs.user_id_autoincrement_prefix = 'uid' settings() request = user_request(self.layer) vessel = user_vessel(users) with self.layer.authenticated('manager'): res = render_tile(vessel, request, 'addform') self.assertEqual(sorted(users.keys()), [ '100', '101', 'manager', 'uid100' ]) request = user_request(self.layer) vessel = user_vessel(users) with self.layer.authenticated('manager'): res = render_tile(vessel, request, 'addform') self.assertEqual(sorted(users.keys()), [ '100', '101', 'manager', 'uid100', 'uid101' ])
def portrait_image(model, request): """XXX: needs polishing. Return configured default portrait if not set on user. """ response = Response() settings = general_settings(model) response.body = model.attrs[settings.attrs.users_portrait_attr] response.headers['Content-Type'] = 'image/jpeg' response.headers['Cache-Control'] = 'max-age=0' return response
def test_portrait(self): root = get_root() users = root['users'] user = users['user_1'] # Portrait related config properties settings = general_settings(users) self.assertEqual(settings.attrs.users_portrait, 'True') self.assertEqual(settings.attrs.users_portrait_attr, 'portrait') self.assertEqual(settings.attrs.users_portrait_accept, 'image/jpeg') self.assertEqual(settings.attrs.users_portrait_width, '50') self.assertEqual(settings.attrs.users_portrait_height, '50') # Portrait enabled, widget is rendered request = self.layer.new_request() with self.layer.authenticated('manager'): res = render_tile(user, request, 'editform') self.assertTrue(res.find('id="input-userform-portrait"') > -1) # No portrait, default portrait is shown expected = ('src="http://example.com/cone.ugm.static/images/' 'default_portrait.jpg?nocache=') self.assertTrue(res.find(expected) > -1) # Submit portrait dummy_jpg = dummy_file_data('dummy.jpg') portrait = { 'file': BytesIO(dummy_jpg), 'mimetype': 'image/jpeg', } request = user_portrait_request(self.layer, user, portrait) with self.layer.authenticated('manager'): res = render_tile(user, request, 'editform') # New portrait set on user expected = b'\xff\xd8\xff\xe0\x00\x10JFIF' self.assertTrue(user.attrs['portrait'].startswith(expected)) # Portrait present, link to user portrait is shown request = self.layer.new_request() with self.layer.authenticated('manager'): res = render_tile(user, request, 'editform') expected = 'src="http://example.com/users/user_1/portrait_image?nocache=' self.assertTrue(res.find(expected) > -1) # Portrait disabled, widget is skipped settings.attrs.users_portrait = u'False' settings() request = self.layer.new_request() with self.layer.authenticated('manager'): res = render_tile(user, request, 'editform') self.assertFalse(res.find('id="input-userform-portrait"') > -1)
def login_name_field_factory(form, label, value): settings = general_settings(form.model).attrs login_attr = settings.users_login_name_attr if login_attr == 'login': factory = default_form_field_factory else: factory = user_field.factory(login_attr, backend=ugm_backend.name) widget = factory(form, label, value) login_extractor = LoginNameExtractor(form.model, login_attr) widget.blueprints.append('*login') widget.custom['login'] = dict(extractors=[login_extractor]) widget.extractors.insert(0, ('login', login_extractor)) widget.mode = 'edit' if login_attr else 'skip' return widget
def prepare(_next, self): """Hook after prepare and set 'portrait' as image widget to ``self.form``. """ _next(self) if not self.portrait_support: return model = self.model request = self.request if request.has_permission('edit_user', model.parent): mode = 'edit' else: mode = 'display' settings = general_settings(model) image_attr = settings.attrs.users_portrait_attr image_accept = settings.attrs.users_portrait_accept image_width = int(settings.attrs.users_portrait_width) image_height = int(settings.attrs.users_portrait_height) image_data = model.attrs.get(image_attr) if image_data: image_value = { 'file': BytesIO(image_data), 'mimetype': 'image/jpeg', } image_url = make_url(request, node=model, resource='portrait_image') else: image_value = UNSET resource = 'cone.ugm.static/images/default_portrait.jpg' image_url = make_url(request, node=model.root, resource=resource) portrait_widget = factory('field:label:error:image', name='portrait', value=image_value, props={ 'label': _('portrait', default='Portrait'), 'src': image_url, 'alt': _('portrait', default='Portrait'), 'accept': image_accept, 'minsize': (image_width, image_height), 'crop': { 'size': (image_width, image_height), 'fitting': True, } }, mode=mode) save_widget = self.form['save'] self.form.insertbefore(portrait_widget, save_widget)
def ldap_gcfg(self): ugm_settings = general_settings(self).attrs settings = self.attrs attr_map = odict(settings.groups_aliases_attrmap.items()) for attr in ugm_settings.groups_form_attrmap: if attr in attr_map: continue attr_map[attr] = attr return GroupsConfig( baseDN=settings.groups_dn, attrmap=attr_map, scope=int(settings.groups_scope), queryFilter=settings.groups_query, objectClasses=settings.groups_object_classes, # member_relation=settings.groups_relation, defaults=factory_defaults.group)
def save(_next, self, widget, data): if not self.portrait_support or \ not self.request.has_permission('edit_user', self.model.parent): _next(self, widget, data) return settings = general_settings(self.model) image_attr = settings.attrs.users_portrait_attr portrait = data.fetch('userform.portrait').extracted if portrait: if portrait['action'] in ['new', 'replace']: cropped = portrait['cropped'] image_data = BytesIO() cropped.save(image_data, 'jpeg', quality=100) image_data.seek(0) self.model.attrs[image_attr] = image_data.read() if portrait['action'] == 'delete': del self.model.attrs[image_attr] _next(self, widget, data)
def ldap_ucfg(self): ugm_settings = general_settings(self).attrs settings = self.attrs attr_map = odict(settings.users_aliases_attrmap.items()) login_name = ugm_settings.users_login_name_attr if login_name: attr_map['login'] = login_name if login_name not in attr_map: attr_map[login_name] = login_name else: # XXX: Not sure whether login attr fallback is needed. Keep for now # since this is the behavior as before introducing # users_login_name_attr setting. attr_map['login'] = attr_map['id'] for attr in ugm_settings.users_form_attrmap: if attr in attr_map: continue attr_map[attr] = attr if ugm_settings.users_exposed_attributes: for attr in ugm_settings.users_exposed_attributes: if attr in attr_map: continue attr_map[attr] = attr expires_attr = None expires_unit = EXPIRATION_DAYS if ugm_settings.users_account_expiration == 'True': expires_attr = ugm_settings.users_expires_attr expires_unit = int(ugm_settings.users_expires_unit) if expires_attr not in attr_map: attr_map[expires_attr] = expires_attr if ugm_settings.users_portrait == 'True': image_attr = ugm_settings.users_portrait_attr if image_attr not in attr_map: attr_map[image_attr] = image_attr return UsersConfig(baseDN=settings.users_dn, attrmap=attr_map, scope=int(settings.users_scope), queryFilter=settings.users_query, objectClasses=settings.users_object_classes, defaults=factory_defaults.user, expiresAttr=expires_attr, expiresUnit=expires_unit)
def save(_next, self, widget, data): if self.request.has_permission('manage_expiration', self.model.parent): settings = general_settings(self.model) if settings.attrs.users_account_expiration == 'True': attr = settings.attrs.users_expires_attr unit = int(settings.attrs.users_expires_unit) value = data.fetch('userform.active').extracted if value is UNSET: if unit == 0: value = 99999 else: value = 8639913600 elif value != 0: if unit == 0: add = 0 if value % 86400 != 0: add = 1 value /= 86400 value += add value = int(value) self.model.attrs[attr] = str(value) _next(self, widget, data)
def test_login_name_field_factory(self): factory = user_field.factory('login') self.assertEqual(factory, login_name_field_factory) users = get_root()['users'] user = BaseNode(name='user', parent=users) form = Tile() form.model = user form.request = self.layer.new_request() settings = general_settings(users) settings.attrs.users_login_name_attr = '' widget = factory(form, 'Login Name', UNSET) self.assertEqual(widget.getter, UNSET) self.assertEqual(widget.blueprints, [ 'field', 'label', 'error', 'text', '*login' ]) self.assertEqual(widget.properties, { 'label': 'Login Name', 'required': False }) self.assertTrue(isinstance( widget.custom['login']['extractors'][0], LoginNameExtractor )) self.assertEqual(widget.mode, 'skip') settings.attrs.users_login_name_attr = 'login' widget = factory(form, 'Login Name', UNSET) self.assertEqual(widget.mode, 'edit') settings.attrs.users_login_name_attr = 'mail' widget = factory(form, 'Login Name', UNSET) self.assertEqual(widget.blueprints, [ 'field', 'label', 'error', 'email', '*login' ])
def user_attrs(self): settings = general_settings(self.model) return settings.attrs.users_listing_columns.keys()
def autoincrement_support(self): settings = general_settings(self.model) return settings.attrs.user_id_autoincrement == 'True'
def remote_add_user(model, request): """Add user via remote service. Returns a JSON response containing success state and a message indicating what happened:: { success: true, // respective false message: 'message' } Expected request parameters: id New user id. password User password to be set initially (optional). roles Comma seperated role names the user initially has. groups Comma seperated groups names the user should initially be member of. attr.* User attributes to be set. I.e. ``attr.mail`` would set the mail attribute for newly created user. All request parameters prefixed with ``attr`` get checked against user attribute attrmap from settings. Restrictions - All values, whether single or multi valued, are passed as string or list of strings to the create function. """ params = request.params uid = params.get('id') if not uid: return { 'success': False, 'message': u"No user ID given.", } users = model.backend if uid in users: return { 'success': False, 'message': u"User with given ID already exists.", } password = params.get('password') add_roles = params.get('roles', '') add_roles = [val.strip() for val in add_roles.split(',') if val] add_groups = params.get('groups', '') add_groups = [val.strip() for val in add_groups.split(',') if val] attrs = dict() for key, val in params.items(): if not key.startswith('attr.'): continue key = key[key.find('.') + 1:] attrs[key] = val settings = general_settings(model) attrmap = settings.attrs.users_form_attrmap exposed = settings.attrs.users_exposed_attributes if not exposed: exposed = list() valid_attrs = attrmap.keys() + exposed checked_attrs = dict() for key in valid_attrs: val = attrs.get(key) if not val: continue checked_attrs[key] = val try: user = users.create(uid, **checked_attrs) message = u"" from cone.app.security import DEFAULT_ROLES available_roles = [role[0] for role in DEFAULT_ROLES] for role in add_roles: if role not in available_roles: message += u"Role '%s' given but inexistent. " % role continue user.add_role(role) groups = users.parent.groups for group in add_groups: if group not in groups: message += u"Group '%s' given but inexistent. " % group continue groups[group].add(uid) users.parent() if password is not None: users.passwd(uid, None, password) message += u"Created user with ID '%s'." % uid return { 'success': True, 'message': message, } except Exception as e: return { 'success': False, 'message': str(e), } finally: model.invalidate()
def roles_enabled(self): settings = general_settings(self.model).attrs return settings.roles_principal_roles_enabled == 'True'
def enabled(self): settings = general_settings(self.root) return settings.attrs.users_local_management_enabled == 'True'
def portrait_support(self): settings = general_settings(self.model) return settings.attrs.users_portrait == 'True'
def form_attrmap(self): return general_settings(self.model).attrs.groups_form_attrmap
def test_general_settings(self): settings = general_settings(root) self.assertTrue(isinstance(settings, GeneralSettings)) self.assertEqual(settings.name, 'ugm_general')
def group_attrs(self): settings = general_settings(self.model) return settings.attrs.groups_listing_columns.keys()
def local_management_enabled(self): """Flag whether local management is enabled. """ settings = general_settings(self.root) return settings.attrs.users_local_management_enabled == 'True'