def assign_users(request): """ Assigns specific report group to user for review - send email notification """ report_group = request.context.report_group application = request.context.resource currently_assigned = [u.user_name for u in report_group.assigned_users] new_assigns = request.unsafe_json_body # first unassign old users for user_name in new_assigns["unassigned"]: if user_name in currently_assigned: user = UserService.by_user_name(user_name) report_group.assigned_users.remove(user) comment = ReportComment(owner_id=request.user.id, report_time=report_group.first_timestamp) comment.body = "Unassigned group from @%s" % user_name report_group.comments.append(comment) # assign new users for user_name in new_assigns["assigned"]: if user_name not in currently_assigned: user = UserService.by_user_name(user_name) if user in report_group.assigned_users: report_group.assigned_users.remove(user) DBSession.flush() assignment = ReportAssignment( owner_id=user.id, report_time=report_group.first_timestamp, group_id=report_group.id, ) DBSession.add(assignment) comment = ReportComment(owner_id=request.user.id, report_time=report_group.first_timestamp) comment.body = "Assigned report_group to @%s" % user_name report_group.comments.append(comment) email_vars = { "user": user, "request": request, "application": application, "report_group": report_group, "email_title": "AppEnlight :: Assigned Report", } UserService.send_email( request, recipients=[user.email], variables=email_vars, template="/email_templates/assigned_report.jinja2", ) return True
def register_user_with_group(user_name, group_name, email, password, db_session): # type: (Str, Str, Str, Str, Session) -> None """ Registers the user if missing and associate him to a group specified by name, also created if missing. :param user_name: name of the user to create (if missing) and to make part of the group (if specified) :param group_name: name of the group to create (if missing and specified) and to make the user join (if not already) :param email: email of the user to be created (if missing) :param password: password of the user to be created (if missing) :param db_session: database connexion to apply changes .. warning:: Should be employed only for **special** users/groups in this module as other expected API behaviour and operations will not be applied (ex: create additional permissions or user-group references). """ if not GroupService.by_group_name(group_name, db_session=db_session): new_group = models.Group(group_name=group_name) # noqa db_session.add(new_group) registered_group = GroupService.by_group_name(group_name=group_name, db_session=db_session) registered_user = UserService.by_user_name(user_name, db_session=db_session) if not registered_user: new_user = models.User(user_name=user_name, email=email) # noqa UserService.set_password(new_user, password) UserService.regenerate_security_code(new_user) db_session.add(new_user) if group_name is not None: registered_user = UserService.by_user_name(user_name, db_session=db_session) else: print_log("User '{}' already exist".format(user_name), level=logging.DEBUG) try: # ensure the reference between user/group exists (user joined the group) user_group_refs = BaseService.all(models.UserGroup, db_session=db_session) user_group_refs_tup = [(ref.group_id, ref.user_id) for ref in user_group_refs] if (registered_group.id, registered_user.id) not in user_group_refs_tup: group_entry = models.UserGroup(group_id=registered_group.id, user_id=registered_user.id) # noqa db_session.add(group_entry) except Exception: # noqa: W0703 # nosec: B110 # in case reference already exists, avoid duplicate error db_session.rollback()
def groups_users_add(request): """ Get list of permissions assigned to specific resources """ group = GroupService.by_id(request.matchdict.get("group_id")) user = UserService.by_user_name(request.unsafe_json_body.get("user_name")) if not user: user = UserService.by_email(request.unsafe_json_body.get("user_name")) if not group or not user: return HTTPNotFound() if user not in group.users: group.users.append(user) group.member_count = group.users_dynamic.count() props = [ "user_name", "id", "first_name", "last_name", "email", "last_login_date", "status", ] u_dict = user.get_dict(include_keys=props) u_dict["gravatar_url"] = UserService.gravatar_url(user, s=20) return u_dict
def test_by_user_name_not_existing(self, db_session): add_user(db_session) queried_user = UserService.by_user_name( "not_existing_user", db_session=db_session ) assert queried_user is None
def user_resource_permission_create(request): """ Set new permissions for user for a resource """ resource = request.context.resource user_name = request.unsafe_json_body.get("user_name") user = UserService.by_user_name(user_name) if not user: user = UserService.by_email(user_name) if not user: return False for perm_name in request.unsafe_json_body.get("permissions", []): permission = UserResourcePermissionService.by_resource_user_and_perm( user.id, perm_name, resource.resource_id ) if not permission: permission = UserResourcePermission(perm_name=perm_name, user_id=user.id) resource.user_permissions.append(permission) DBSession.flush() perms = [ p.perm_name for p in ResourceService.perms_for_user(resource, user) if p.type == "user" ] result = {"user_name": user.user_name, "permissions": list(set(perms))} return result
def user_requested(self): user = self.request.user if not user: anonymous = get_constant("MAGPIE_ANONYMOUS_USER", self.request) user = UserService.by_user_name(anonymous, db_session=self.request.db) if user is None: raise RuntimeError("No Anonymous user in the database") return user
def validate_user_name(self, value): request = self.context['request'] modified_obj = self.context.get('modified_obj') user = UserService.by_user_name(value, db_session=request.dbsession) by_admin = request.has_permission('root_administration') if modified_obj and not by_admin and (modified_obj.user_name != value): msg = _('Only administrator can change usernames') raise validate.ValidationError(msg) if user: if not modified_obj or modified_obj.id != user.id: msg = _('User already exists in database') raise validate.ValidationError(msg)
def __getitem__(self, user_name): context = UserFactory(self.request) if user_name == get_constant("MAGPIE_LOGGED_USER", self.request): self.path_user = self.request.user else: self.path_user = UserService.by_user_name(user_name, self.request.db) if self.path_user is not None: self.path_user.__parent__ = self self.path_user.__name__ = user_name context.path_user = self.path_user return context
def by_user_name(cls, user_name, db_session=None): """ .. deprecated:: 0.8 :param user_name: :param db_session: :return: """ db_session = get_db_session(db_session) return UserService.by_user_name(user_name=user_name, db_session=db_session)
def post(self): resource = self.request.context.resource schema = UserResourcePermissionSchema(context={ 'request': self.request, 'resource': resource }) data = schema.load(self.request.unsafe_json_body).data user = UserService.by_user_name(data['user_name'], db_session=self.request.dbsession) perm_inst = self.shared.user_permission_post(resource, user.id, data['perm_name']) self.request.dbsession.flush() return perm_inst.get_dict()
def get_user(request, user_name_or_token=None): # type: (Request, Optional[Str]) -> models.User """ Obtains the user corresponding to the provided user-name, token or via lookup of the logged user request session. :param request: request from which to obtain application settings and session user as applicable. :param user_name_or_token: reference value to employ for lookup of the user. :returns: found user. :raises HTTPForbidden: if the requesting user does not have sufficient permission to execute this request. :raises HTTPNotFound: if the specified user name or token does not correspond to any existing user. """ logged_user_name = get_constant("MAGPIE_LOGGED_USER", settings_container=request) if user_name_or_token is None: user_name_or_token = logged_user_name if user_name_or_token == logged_user_name: curr_user = request.user if curr_user: return curr_user anonymous_user = get_constant("MAGPIE_ANONYMOUS_USER", settings_container=request) anonymous = ax.evaluate_call(lambda: UserService.by_user_name(anonymous_user, db_session=request.db), fallback=lambda: request.db.rollback(), http_error=HTTPForbidden, msg_on_fail=s.User_CheckAnonymous_ForbiddenResponseSchema.description) ax.verify_param(anonymous, not_none=True, http_error=HTTPNotFound, msg_on_fail=s.User_CheckAnonymous_NotFoundResponseSchema.description) return anonymous ax.verify_param(user_name_or_token, not_none=True, not_empty=True, matches=True, param_compare=ax.PARAM_REGEX, param_name="user_name", http_error=HTTPBadRequest, msg_on_fail=s.User_Check_BadRequestResponseSchema.description) user = ax.evaluate_call(lambda: UserService.by_user_name(user_name_or_token, db_session=request.db), fallback=lambda: request.db.rollback(), http_error=HTTPInternalServerError, msg_on_fail=s.User_GET_InternalServerErrorResponseSchema.description) ax.verify_param(user, not_none=True, http_error=HTTPNotFound, msg_on_fail=s.User_GET_NotFoundResponseSchema.description) return user
def init_admin(db_session, settings=None): # type: (Session, Optional[AnySettingsContainer]) -> None """ Registers into the database the user and group matching configuration values of. :py:data:`magpie.constants.MAGPIE_ADMIN_USER` and :py:data:`magpie.constants.MAGPIE_ADMIN_GROUP` respectively if not defined. Also associates the created admin user with the admin group and give it admin permissions. Finally, updates the group's parameters to ensure integrity with `Magpie` settings. """ admin_usr_name = get_constant("MAGPIE_ADMIN_USER", settings_container=settings) admin_grp_name = get_constant("MAGPIE_ADMIN_GROUP", settings_container=settings) if not (UserService.by_user_name(admin_usr_name, db_session=db_session) and GroupService.by_group_name(admin_grp_name, db_session=db_session)): register_user_with_group( user_name=admin_usr_name, group_name=admin_grp_name, email=get_constant("MAGPIE_ADMIN_EMAIL", settings_container=settings), password=get_constant("MAGPIE_ADMIN_PASSWORD", settings_container=settings), db_session=db_session) # Check if MAGPIE_ADMIN_GROUP has permission MAGPIE_ADMIN_PERMISSION magpie_admin_group = GroupService.by_group_name( admin_grp_name, db_session=db_session) # type: models.Group permission_names = [ permission.perm_name for permission in magpie_admin_group.permissions ] admin_perm = get_constant("MAGPIE_ADMIN_PERMISSION", settings_container=settings) if admin_perm not in permission_names: new_group_permission = models.GroupPermission( perm_name=admin_perm, group_id=magpie_admin_group.id) # noqa try: db_session.add(new_group_permission) except Exception as exc: db_session.rollback() raise_log("Failed to create admin user-group permission", exception=type(exc)) # enforce some admin group fields magpie_admin_group.description = "Administrative group that grants full access management control to its members." magpie_admin_group.discoverable = False
def groups_users_remove(request): """ Get list of permissions assigned to specific resources """ group = GroupService.by_id(request.matchdict.get("group_id")) user = UserService.by_user_name(request.GET.get("user_name")) if not group or not user: return HTTPNotFound() if len(group.users) > 1: group.users.remove(user) msg = "User removed from group" request.session.flash(msg) group.member_count = group.users_dynamic.count() return True msg = "Administrator group needs to contain at least one user" request.session.flash(msg, "warning") return False
def application_ownership_transfer(request): """ Allows application owner to transfer application ownership to other user """ resource = request.context.resource form = forms.ChangeApplicationOwnerForm( MultiDict(request.safe_json_body or {}), csrf_context=request ) form.password.user = request.user if form.validate(): user = UserService.by_user_name(form.user_name.data) user.resources.append(resource) # remove integrations to not leak security data of external applications for integration in resource.integrations[:]: resource.integrations.remove(integration) request.session.flash(_("Application transfered")) else: return HTTPUnprocessableEntity(body=form.errors_json) return True
def user_permission_post(self): request = self.request resource = self.request.context.resource came_from = request.headers.get('Referer') schema = UserResourcePermissionSchema(context={ 'request': self.request, 'resource': resource }) data = { 'user_name': self.request.POST.get('user_name'), 'perm_name': self.request.POST.get('perm_name') } data = schema.load(data).data user = UserService.by_user_name(data['user_name'], db_session=self.request.dbsession) perm_inst = self.shared.user_permission_post(resource, user.id, data['perm_name']) location = came_from or request.route_url('admin') return httpexceptions.HTTPFound(location=location)
def delete(self): resource = self.request.context.resource schema = UserResourcePermissionSchema(context={ 'request': self.request, 'resource': resource }) params = { 'user_name': self.request.GET.get('user_name'), 'perm_name': self.request.GET.get('perm_name') } data = schema.load(params).data user = UserService.by_user_name(data['user_name'], db_session=self.request.dbsession) self.shared.user_permission_delete( resource, user.id, data['perm_name'], ) return True
def sign_in(self, request): came_from = request.params.get(self.signin_came_from_key, "/") db_session = self.session_getter(request) user = UserService.by_user_name(request.params.get( self.signin_username_key), db_session=db_session) if user is None: # if no result, test to see if email exists user = UserService.by_email(request.params.get( self.signin_username_key), db_session=db_session) if user: password = request.params.get(self.signin_password_key) if UserService.check_password(user, password): headers = pyramid.security.remember(request, user.id) return ZigguratSignInSuccess(headers=headers, came_from=came_from, user=user) headers = pyramid.security.forget(request) return ZigguratSignInBadAuth(headers=headers, came_from=came_from)
def sign_in(self, request): came_from = request.params.get(self.signin_came_from_key, "/") db_session = self.session_getter(request) user = UserService.by_user_name( request.params.get(self.signin_username_key), db_session=db_session ) if user is None: # if no result, test to see if email exists user = UserService.by_email( request.params.get(self.signin_username_key), db_session=db_session ) if user: password = request.params.get(self.signin_password_key) if UserService.check_password(user, password): headers = pyramid.security.remember(request, user.id) return ZigguratSignInSuccess( headers=headers, came_from=came_from, user=user ) headers = pyramid.security.forget(request) return ZigguratSignInBadAuth(headers=headers, came_from=came_from)
def new_user_external(external_user_name, external_id, email, provider_name, db_session): # type: (Str, Str, Str, Str, Session) -> models.User """ Create new user with an External Identity. """ internal_user_name = external_id + "_" + provider_name internal_user_name = internal_user_name.replace(" ", "_") group_name = get_constant("MAGPIE_USERS_GROUP") create_user(internal_user_name, password=None, email=email, group_name=group_name, db_session=db_session) user = UserService.by_user_name(internal_user_name, db_session=db_session) ex_identity = models.ExternalIdentity(external_user_name=external_user_name, external_id=external_id, # noqa local_user_id=user.id, provider_name=provider_name) # noqa ax.evaluate_call(lambda: db_session.add(ex_identity), fallback=lambda: db_session.rollback(), http_error=HTTPConflict, msg_on_fail=s.Signin_POST_ConflictResponseSchema.description, content={"provider_name": str(provider_name), "internal_user_name": str(internal_user_name), "external_user_name": str(external_user_name), "external_id": str(external_id)}) user.external_identities.append(ex_identity) return user
def user_resource_permission_delete(request): """ Removes user permission from specific resource """ resource = request.context.resource user = UserService.by_user_name(request.GET.get("user_name")) if not user: return False for perm_name in request.GET.getall("permissions"): permission = UserResourcePermissionService.by_resource_user_and_perm( user.id, perm_name, resource.resource_id ) resource.user_permissions.remove(permission) DBSession.flush() perms = [ p.perm_name for p in ResourceService.perms_for_user(resource, user) if p.type == "user" ] result = {"user_name": user.user_name, "permissions": list(set(perms))} return result
def user_permission_delete(self): request = self.request resource = self.request.context.resource user = UserService.by_user_name(request.GET.get('user_name'), db_session=self.request.dbsession) permission = self.shared.user_permission_get( resource.resource_id, user.id, request.GET.get('perm_name')) back_url = request.route_url('admin_object', object=resource.plural_type, object_id=resource.resource_id, verb='GET') if request.method == "POST": self.shared.user_permission_delete(resource, user.id, request.GET.get('perm_name')) return httpexceptions.HTTPFound(location=back_url) return { "parent_obj": user, "member_obj": permission, "confirm_url": request.current_route_url(), "back_url": back_url }
def validate_user_name(self, value): request = self.context['request'] user = UserService.by_user_name(value, db_session=request.dbsession) if not user: raise validate.ValidationError(_('User not found'))
def update_user_view(request): """ Update user information by user name. """ user = ar.get_user_matchdict_checked_or_logged(request) new_user_name = ar.get_multiformat_body(request, "user_name", default=user.user_name) new_email = ar.get_multiformat_body(request, "email", default=user.email) new_password = ar.get_multiformat_body(request, "password", default=user.user_password) update_username = user.user_name != new_user_name and new_user_name is not None update_password = user.user_password != new_password and new_password is not None update_email = user.email != new_email and new_email is not None ax.verify_param( any([update_username, update_password, update_email]), is_true=True, with_param=False, # params are not useful in response for this case content={"user_name": user.user_name}, http_error=HTTPBadRequest, msg_on_fail=s.User_PATCH_BadRequestResponseSchema.description) # user name change is admin-only operation if update_username: ax.verify_param( get_constant("MAGPIE_ADMIN_GROUP"), is_in=True, param_compare=uu.get_user_groups_checked(request.user, request.db), with_param=False, http_error=HTTPForbidden, msg_on_fail=s.User_PATCH_ForbiddenResponseSchema.description) # logged user updating itself is forbidden if it corresponds to special users # cannot edit reserved keywords nor apply them to another user forbidden_user_names = [ get_constant("MAGPIE_ADMIN_USER", request), get_constant("MAGPIE_ANONYMOUS_USER", request), get_constant("MAGPIE_LOGGED_USER", request), ] check_user_name_cases = [user.user_name, new_user_name ] if update_username else [user.user_name] for check_user_name in check_user_name_cases: ax.verify_param( check_user_name, not_in=True, param_compare=forbidden_user_names, param_name="user_name", http_error=HTTPForbidden, content={"user_name": str(check_user_name)}, msg_on_fail=s.User_PATCH_ForbiddenResponseSchema.description) if update_username: uu.check_user_info(user_name=new_user_name, check_email=False, check_password=False, check_group=False) existing_user = ax.evaluate_call( lambda: UserService.by_user_name(new_user_name, db_session=request.db), fallback=lambda: request.db.rollback(), http_error=HTTPForbidden, msg_on_fail=s.User_PATCH_ForbiddenResponseSchema.description) ax.verify_param( existing_user, is_none=True, with_param=False, http_error=HTTPConflict, msg_on_fail=s.User_PATCH_ConflictResponseSchema.description) user.user_name = new_user_name if update_email: uu.check_user_info(email=new_email, check_name=False, check_password=False, check_group=False) user.email = new_email if update_password: uu.check_user_info(password=new_password, check_name=False, check_email=False, check_group=False) UserService.set_password(user, new_password) UserService.regenerate_security_code(user) return ax.valid_http(http_success=HTTPOk, detail=s.Users_PATCH_OkResponseSchema.description)
def found_username_validator(form, field): user = UserService.by_user_name(field.data) # sets user to recover in email validator form.field_user = user if not user: raise wtforms.ValidationError("This username does not exist")
def test_delete_user(self, db_session): add_user(db_session) to_delete = UserService.by_user_name("username", db_session=db_session) db_session.delete(to_delete) db_session.commit()
def test_by_user_name_existing(self, db_session): created_user = add_user(db_session) queried_user = UserService.by_user_name("username", db_session=db_session) assert created_user == queried_user
def test_by_user_name_none(self, db_session): queried_user = UserService.by_user_name(None, db_session=db_session) assert queried_user is None
def create_user(user_name, password, email, group_name, db_session): # type: (Str, Optional[Str], Str, Optional[Str], Session) -> HTTPException """ Creates a user if it is permitted and not conflicting. Password must be set to ``None`` if using external identity. Created user will immediately assigned membership to the group matching :paramref:`group_name` (can be :py:data:`MAGPIE_ANONYMOUS_GROUP` for minimal access). If no group is provided, this anonymous group will be applied by default, creating a user effectively without any permissions other than ones set directly for him. Furthermore, the user will also *always* be associated with :py:data:`MAGPIE_ANONYMOUS_GROUP` (if not already explicitly or implicitly requested with :paramref:`group_name`) to allow access to resources with public permission. Argument :paramref:`group_name` **MUST** be an existing group if provided. :returns: valid HTTP response on successful operation. """ def _get_group(grp_name): # type: (Str) -> models.Group ax.verify_param(grp_name, not_none=True, not_empty=True, matches=True, param_compare=ax.PARAM_REGEX, param_name="group_name", http_error=HTTPBadRequest, msg_on_fail=s.UserGroup_Check_BadRequestResponseSchema.description) grp = ax.evaluate_call(lambda: GroupService.by_group_name(grp_name, db_session=db_session), http_error=HTTPForbidden, msg_on_fail=s.UserGroup_GET_ForbiddenResponseSchema.description) ax.verify_param(grp, not_none=True, http_error=HTTPNotFound, with_param=False, msg_on_fail=s.UserGroup_Check_NotFoundResponseSchema.description) return grp # Check that group already exists if group_name is None: group_name = get_constant("MAGPIE_ANONYMOUS_GROUP") is_internal = password is not None check_user_info(user_name, email, password, group_name, check_password=is_internal) group_checked = _get_group(group_name) # Check if user already exists user_checked = ax.evaluate_call(lambda: UserService.by_user_name(user_name=user_name, db_session=db_session), http_error=HTTPForbidden, msg_on_fail=s.User_Check_ForbiddenResponseSchema.description) ax.verify_param(user_checked, is_none=True, with_param=False, http_error=HTTPConflict, msg_on_fail=s.User_Check_ConflictResponseSchema.description) # Create user with specified name and group to assign new_user = models.User(user_name=user_name, email=email) # noqa if is_internal: UserService.set_password(new_user, password) UserService.regenerate_security_code(new_user) ax.evaluate_call(lambda: db_session.add(new_user), fallback=lambda: db_session.rollback(), http_error=HTTPForbidden, msg_on_fail=s.Users_POST_ForbiddenResponseSchema.description) # Fetch user to update fields new_user = ax.evaluate_call(lambda: UserService.by_user_name(user_name, db_session=db_session), http_error=HTTPForbidden, msg_on_fail=s.UserNew_POST_ForbiddenResponseSchema.description) def _add_to_group(usr, grp): # type: (models.User, models.Group) -> None group_entry = models.UserGroup(group_id=grp.id, user_id=usr.id) # noqa ax.evaluate_call(lambda: db_session.add(group_entry), fallback=lambda: db_session.rollback(), http_error=HTTPForbidden, msg_on_fail=s.UserGroup_GET_ForbiddenResponseSchema.description) # Assign user to group new_user_groups = [group_name] _add_to_group(new_user, group_checked) # Also add user to anonymous group if not already done anonym_grp_name = get_constant("MAGPIE_ANONYMOUS_GROUP") if group_checked.group_name != anonym_grp_name: _add_to_group(new_user, _get_group(anonym_grp_name)) new_user_groups.append(anonym_grp_name) return ax.valid_http(http_success=HTTPCreated, detail=s.Users_POST_CreatedResponseSchema.description, content={"user": uf.format_user(new_user, new_user_groups)})
def unique_username_validator(form, field): user = UserService.by_user_name(field.data) if user: raise wtforms.ValidationError("This username already exists in system")