예제 #1
0
파일: user.py 프로젝트: qyqx/tracim
    def put(self, user_id, name, email, timezone, next_url=None):
        user_id = tmpl_context.current_user.user_id
        current_user = tmpl_context.current_user
        user_api = UserApi(current_user)
        assert user_id == current_user.user_id
        if next_url:
            next = tg.url(next_url)
        else:
            next = self.url()

        try:
            email_user = user_api.get_one_by_email(email)
            if email_user != current_user:
                tg.flash(_('Email already in use'), CST.STATUS_ERROR)
                tg.redirect(next)
        except NoResultFound:
            pass

        # Only keep allowed field update
        updated_fields = self._clean_update_fields({
            'name': name,
            'email': email,
            'timezone': timezone,
        })

        api = UserApi(tmpl_context.current_user)
        api.update(current_user, do_save=True, **updated_fields)
        tg.flash(_('profile updated.'))
        tg.redirect(next)
예제 #2
0
파일: user.py 프로젝트: lebouquetin/tracim
    def put(self, user_id, name, email, timezone, next_url=None):
        user_id = tmpl_context.current_user.user_id
        current_user = tmpl_context.current_user
        user_api = UserApi(current_user)
        assert user_id==current_user.user_id
        if next_url:
            next = tg.url(next_url)
        else:
            next = self.url()

        try:
            email_user = user_api.get_one_by_email(email)
            if email_user != current_user:
                tg.flash(_('Email already in use'), CST.STATUS_ERROR)
                tg.redirect(next)
        except NoResultFound:
            pass

        # Only keep allowed field update
        updated_fields = self._clean_update_fields({
            'name': name,
            'email': email,
            'timezone': timezone,
        })

        api = UserApi(tmpl_context.current_user)
        api.update(current_user, do_save=True, **updated_fields)
        tg.flash(_('profile updated.'))
        tg.redirect(next)
예제 #3
0
    def test_get_one_by_email(self):
        api = UserApi(None)
        u = api.create_user()
        api.update(u, 'bibi', 'bibi@bibi', True)
        uid = u.user_id
        transaction.commit()

        eq_(uid, api.get_one_by_email('bibi@bibi').user_id)
예제 #4
0
    def test_get_one_by_email(self):
        api = UserApi(None)
        u = api.create_user()
        api.update(u, 'bibi', 'bibi@bibi', True)
        uid = u.user_id
        transaction.commit()

        eq_(uid, api.get_one_by_email('bibi@bibi').user_id)
예제 #5
0
    def test_create_and_update_user(self):
        api = UserApi(None)
        u = api.create_user()
        api.update(u, 'bob', 'bob@bob', True)

        nu = api.get_one_by_email('bob@bob')
        ok_(nu!=None)
        eq_('bob@bob', nu.email)
        eq_('bob', nu.display_name)
예제 #6
0
    def test_create_and_update_user(self):
        api = UserApi(None)
        u = api.create_user()
        api.update(u, 'bob', 'bob@bob', True)

        nu = api.get_one_by_email('bob@bob')
        ok_(nu != None)
        eq_('bob@bob', nu.email)
        eq_('bob', nu.display_name)
예제 #7
0
class TracimDomainController(object):
    """
    The domain controller is used by http_authenticator to authenticate the user every time a request is
    sent
    """
    def __init__(self, presetdomain=None, presetserver=None):
        self._api = UserApi(None)

    def getDomainRealm(self, inputURL, environ):
        return '/'

    def requireAuthentication(self, realmname, environ):
        return True

    def isRealmUser(self, realmname, username, environ):
        """
        Called to check if for a given root, the username exists (though here we don't make difference between
        root as we're always starting at tracim's root
        """
        try:
            self._api.get_one_by_email(username)
            return True
        except:
            return False

    def get_left_digest_response_hash(self, realmname, username, environ):
        """
        Called by our http_authenticator to get the hashed md5 digest for the current user that is also sent by
        the webdav client
        """
        try:
            user = self._api.get_one_by_email(username)
            return user.webdav_left_digest_response_hash
        except:
            return None

    def authDomainUser(self, realmname, username, password, environ):
        """
        If you ever feel the need to send a request al-mano with a curl, this is the function that'll be called by
        http_authenticator to validate the password sent
        """

        return self.isRealmUser(realmname, username, environ) and \
            self._api.get_one_by_email(username).validate_password(password)
예제 #8
0
class TracimDomainController(object):
    """
    The domain controller is used by http_authenticator to authenticate the user every time a request is
    sent
    """
    def __init__(self, presetdomain = None, presetserver = None):
        self._api = UserApi(None)

    def getDomainRealm(self, inputURL, environ):
        return '/'

    def requireAuthentication(self, realmname, environ):
        return True

    def isRealmUser(self, realmname, username, environ):
        """
        Called to check if for a given root, the username exists (though here we don't make difference between
        root as we're always starting at tracim's root
        """
        try:
            self._api.get_one_by_email(username)
            return True
        except:
            return False

    def get_left_digest_response_hash(self, realmname, username, environ):
        """
        Called by our http_authenticator to get the hashed md5 digest for the current user that is also sent by
        the webdav client
        """
        try:
            user = self._api.get_one_by_email(username)
            return user.webdav_left_digest_response_hash
        except:
            return None

    def authDomainUser(self, realmname, username, password, environ):
        """
        If you ever feel the need to send a request al-mano with a curl, this is the function that'll be called by
        http_authenticator to validate the password sent
        """

        return self.isRealmUser(realmname, username, environ) and \
            self._api.get_one_by_email(username).validate_password(password)
예제 #9
0
파일: ldap.py 프로젝트: Nonolost/tracim
class LDAPSearchAuthenticatorPlugin(BaseLDAPSearchAuthenticatorPlugin):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._auth = None
        self._user_api = UserApi(None)

    def set_auth(self, auth):
        self._auth = auth

    def authenticate(self, environ, identity, allow_auth_token: bool=False):
        # Note: super().authenticate return None if already authenticated or not found
        email = super().authenticate(environ, identity)

        if email:
            self._sync_ldap_user(email, environ, identity)

        if not email and allow_auth_token and self.user_exist(email):
            # Proceed to internal token auth
            user = self.sa_auth.dbsession.query(self.sa_auth.user_class).filter(
                and_(
                    self.sa_auth.user_class.is_active == True,
                    self.sa_auth.user_class.email == identity['login']
                )
            ).first()
            if user:
                user.ensure_auth_token()
                if user.auth_token == identity['password']:
                    email = identity['login']

        return email

    def _sync_ldap_user(self, email, environ, identity):
        # Create or get user for connected email
        if not self._user_api.user_with_email_exists(email):
            user = User(email=email, imported_from=LDAPAuth.name)
            DBSession.add(user)
        else:
            user = self._user_api.get_one_by_email(email)

        # Retrieve ldap user attributes
        self._auth.ldap_user_provider.add_metadata_for_auth(environ, identity)

        # Update user with ldap attributes
        user_ldap_values = identity.get('user').copy()
        for field_name in user_ldap_values:
            setattr(user, field_name, user_ldap_values[field_name])

        DBSession.flush()
        transaction.commit()

    def user_exist(self, email):
        with make_connection(self.url, self.bind_dn, self.bind_pass) as conn:
            if self.start_tls:
                conn.start_tls()

            if not conn.bind():
                return False

            search = self.search_pattern % email
            conn.search(self.base_dn, search, self.search_scope)

            if len(conn.response) > 0:
                return True

            return False
예제 #10
0
파일: user.py 프로젝트: Nonolost/tracim
class UserCommand(AppContextCommand):

    ACTION_CREATE = 'create'
    ACTION_UPDATE = 'update'

    action = NotImplemented

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._session = DBSession
        self._transaction = transaction
        self._user_api = UserApi(None)
        self._group_api = GroupApi(None)

    def get_description(self):
        return '''Create or update user.'''

    def get_parser(self, prog_name):
        parser = super().get_parser(prog_name)

        parser.add_argument(
            "-l",
            "--login",
            help='User login (email)',
            dest='login',
            required=True
        )

        parser.add_argument(
            "-p",
            "--password",
            help='User password',
            dest='password',
            required=False,
            default=None
        )

        parser.add_argument(
            "-g",
            "--add-to-group",
            help='Add user to group',
            dest='add_to_group',
            nargs='*',
            action=Extender,
            default=[],
        )

        parser.add_argument(
            "-rmg",
            "--remove-from-group",
            help='Remove user from group',
            dest='remove_from_group',
            nargs='*',
            action=Extender,
            default=[],
        )

        parser.add_argument(
            "--send-email",
            help='Send mail to user',
            dest='send_email',
            required=False,
            action='store_true',
            default=False,
        )

        return parser

    def _user_exist(self, login):
        return self._user_api.user_with_email_exists(login)

    def _get_group(self, name):
        return self._group_api.get_one_with_name(name)

    def _add_user_to_named_group(self, user, group_name):
        group = self._get_group(group_name)
        if user not in group.users:
            group.users.append(user)
        self._session.flush()

    def _remove_user_from_named_group(self, user, group_name):
        group = self._get_group(group_name)
        if user in group.users:
            group.users.remove(user)
        self._session.flush()

    def _create_user(self, login, password, **kwargs):
        if not password:
            if self._password_required():
                raise CommandAbortedError("You must provide -p/--password parameter")
            password = ''

        try:
            user = User(email=login, password=password, **kwargs)
            self._session.add(user)
            self._session.flush()
        except IntegrityError:
            self._session.rollback()
            raise AlreadyExistError()

        return user

    def _update_password_for_login(self, login, password):
        user = self._user_api.get_one_by_email(login)
        user.password = password
        self._session.flush()
        transaction.commit()

    def take_action(self, parsed_args):
        super().take_action(parsed_args)

        user = self._proceed_user(parsed_args)
        self._proceed_groups(user, parsed_args)

        print("User created/updated")

    def _proceed_user(self, parsed_args):
        self._check_context(parsed_args)

        if self.action == self.ACTION_CREATE:
            try:
                user = self._create_user(login=parsed_args.login, password=parsed_args.password)
            except AlreadyExistError:
                raise CommandAbortedError("Error: User already exist (use `user update` command instead)")
            if parsed_args.send_email:
                email_manager = get_email_manager()
                email_manager.notify_created_account(
                    user=user,
                    password=parsed_args.password,
                )

        else:
            if parsed_args.password:
                self._update_password_for_login(login=parsed_args.login, password=parsed_args.password)
            user = self._user_api.get_one_by_email(parsed_args.login)

        return user

    def _proceed_groups(self, user, parsed_args):
        # User always in "users" group
        self._add_user_to_named_group(user, 'users')

        for group_name in parsed_args.add_to_group:
            self._add_user_to_named_group(user, group_name)

        for group_name in parsed_args.remove_from_group:
            self._remove_user_from_named_group(user, group_name)

    def _password_required(self):
        if config.get('auth_type') == LDAPAuth.name:
            return False
        return True

    def _check_context(self, parsed_args):
        if config.get('auth_type') == LDAPAuth.name:
            auth_instance = config.get('auth_instance')
            if not auth_instance.ldap_auth.user_exist(parsed_args.login):
                raise LDAPUserUnknown(
                    "LDAP is enabled and user with login/email \"%s\" not found in LDAP" % parsed_args.login
                )
예제 #11
0
 def test_get_one_by_email_exception(self):
     api = UserApi(None)
     api.get_one_by_email('unknown')
예제 #12
0
class UserCommand(AppContextCommand):

    ACTION_CREATE = 'create'
    ACTION_UPDATE = 'update'

    action = NotImplemented

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._session = DBSession
        self._transaction = transaction
        self._user_api = UserApi(None)
        self._group_api = GroupApi(None)

    def get_description(self):
        return '''Create or update user.'''

    def get_parser(self, prog_name):
        parser = super().get_parser(prog_name)

        parser.add_argument("-l",
                            "--login",
                            help='User login (email)',
                            dest='login',
                            required=True)

        parser.add_argument("-p",
                            "--password",
                            help='User password',
                            dest='password',
                            required=False,
                            default=None)

        parser.add_argument(
            "-g",
            "--add-to-group",
            help='Add user to group',
            dest='add_to_group',
            nargs='*',
            action=Extender,
            default=[],
        )

        parser.add_argument(
            "-rmg",
            "--remove-from-group",
            help='Remove user from group',
            dest='remove_from_group',
            nargs='*',
            action=Extender,
            default=[],
        )

        parser.add_argument(
            "--send-email",
            help='Send mail to user',
            dest='send_email',
            required=False,
            action='store_true',
            default=False,
        )

        return parser

    def _user_exist(self, login):
        return self._user_api.user_with_email_exists(login)

    def _get_group(self, name):
        return self._group_api.get_one_with_name(name)

    def _add_user_to_named_group(self, user, group_name):
        group = self._get_group(group_name)
        if user not in group.users:
            group.users.append(user)
        self._session.flush()

    def _remove_user_from_named_group(self, user, group_name):
        group = self._get_group(group_name)
        if user in group.users:
            group.users.remove(user)
        self._session.flush()

    def _create_user(self, login, password, **kwargs):
        if not password:
            if self._password_required():
                raise CommandAbortedError(
                    "You must provide -p/--password parameter")
            password = ''

        try:
            user = User(email=login, password=password, **kwargs)
            user.update_webdav_digest_auth(password)
            self._session.add(user)
            self._session.flush()

            # We need to enable radicale if it not already done
            daemons = DaemonsManager()
            daemons.run('radicale', RadicaleDaemon)

            user_api = UserApi(user)
            user_api.execute_created_user_actions(user)
        except IntegrityError:
            self._session.rollback()
            raise AlreadyExistError()

        return user

    def _update_password_for_login(self, login, password):
        user = self._user_api.get_one_by_email(login)
        user.password = password
        user.update_webdav_digest_auth(password)
        self._session.flush()
        transaction.commit()

    def take_action(self, parsed_args):
        super().take_action(parsed_args)

        user = self._proceed_user(parsed_args)
        self._proceed_groups(user, parsed_args)

        print("User created/updated")

    def _proceed_user(self, parsed_args):
        self._check_context(parsed_args)

        if self.action == self.ACTION_CREATE:
            try:
                user = self._create_user(login=parsed_args.login,
                                         password=parsed_args.password)
            except AlreadyExistError:
                raise CommandAbortedError(
                    "Error: User already exist (use `user update` command instead)"
                )
            if parsed_args.send_email:
                email_manager = get_email_manager()
                email_manager.notify_created_account(
                    user=user,
                    password=parsed_args.password,
                )

        else:
            if parsed_args.password:
                self._update_password_for_login(login=parsed_args.login,
                                                password=parsed_args.password)
            user = self._user_api.get_one_by_email(parsed_args.login)

        return user

    def _proceed_groups(self, user, parsed_args):
        # User always in "users" group
        self._add_user_to_named_group(user, 'users')

        for group_name in parsed_args.add_to_group:
            self._add_user_to_named_group(user, group_name)

        for group_name in parsed_args.remove_from_group:
            self._remove_user_from_named_group(user, group_name)

    def _password_required(self):
        if config.get('auth_type') == LDAPAuth.name:
            return False
        return True

    def _check_context(self, parsed_args):
        if config.get('auth_type') == LDAPAuth.name:
            auth_instance = config.get('auth_instance')
            if not auth_instance.ldap_auth.user_exist(parsed_args.login):
                raise LDAPUserUnknown(
                    "LDAP is enabled and user with login/email \"%s\" not found in LDAP"
                    % parsed_args.login)
예제 #13
0
파일: events.py 프로젝트: norsig/tracim
    def post(self) -> Response:
        cfg = CFG.get_instance()

        try:
            json = request.json_body
        except ValueError:
            return Response(
                status=400,
                json_body={'msg': 'Bad json'},
            )

        if json.get('token', None) != cfg.EMAIL_REPLY_TOKEN:
            # TODO - G.M - 2017-11-23 - Switch to status 403 ?
            # 403 is a better status code in this case.
            # 403 status response can't now return clean json, because they are
            # handled somewhere else to return html.
            return Response(
                status=400,
                json_body={'msg': 'Invalid token'}
            )

        if 'user_mail' not in json:
            return Response(
                status=400,
                json_body={'msg': 'Bad json: user_mail is required'}
            )

        if 'content_id' not in json:
            return Response(
                status=400,
                json_body={'msg': 'Bad json: content_id is required'}
            )

        if 'payload' not in json:
            return Response(
                status=400,
                json_body={'msg': 'Bad json: payload is required'}
            )

        uapi = UserApi(None)
        try:
            user = uapi.get_one_by_email(json['user_mail'])
        except NoResultFound:
            return Response(
                status=400,
                json_body={'msg': 'Unknown user email'},
            )
        api = ContentApi(user)

        try:
            thread = api.get_one(json['content_id'],
                                 content_type=ContentType.Any)
        except NoResultFound:
            return Response(
                status=400,
                json_body={'msg': 'Unknown content_id'},
            )

        # INFO - G.M - 2017-11-17
        # When content_id is a sub-elem of a main content like Comment,
        # Attach the thread to the main content.
        if thread.type == ContentType.Comment:
            thread = thread.parent
        if thread.type == ContentType.Folder:
            return Response(
                status=400,
                json_body={'msg': 'comment for folder not allowed'},
            )
        if 'content' in json['payload']:
            api.create_comment(
                workspace=thread.workspace,
                parent=thread,
                content=json['payload']['content'],
                do_save=True,
            )
            return Response(
                status=204,
            )
        else:
            return Response(
                status=400,
                json_body={'msg': 'No content to add new comment'},
            )
예제 #14
0
파일: ldap.py 프로젝트: qyqx/tracim
class LDAPSearchAuthenticatorPlugin(BaseLDAPSearchAuthenticatorPlugin):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._auth = None
        self._user_api = UserApi(None)

    def set_auth(self, auth):
        self._auth = auth

    def authenticate(self, environ, identity, allow_auth_token: bool = False):
        # Note: super().authenticate return None if already authenticated or not found
        email = super().authenticate(environ, identity)

        if email:
            self._sync_ldap_user(email, environ, identity)

        if not email and allow_auth_token and self.user_exist(email):
            # Proceed to internal token auth
            user = self.sa_auth.dbsession.query(
                self.sa_auth.user_class).filter(
                    and_(self.sa_auth.user_class.is_active == True,
                         self.sa_auth.user_class.email ==
                         identity['login'])).first()
            if user:
                user.ensure_auth_token()
                if user.auth_token == identity['password']:
                    email = identity['login']

        return email

    def _sync_ldap_user(self, email, environ, identity):
        # Create or get user for connected email
        if not self._user_api.user_with_email_exists(email):
            user = User(email=email, imported_from=LDAPAuth.name)
            DBSession.add(user)
        else:
            user = self._user_api.get_one_by_email(email)

        # Retrieve ldap user attributes
        self._auth.ldap_user_provider.add_metadata_for_auth(environ, identity)

        # Update user with ldap attributes
        user_ldap_values = identity.get('user').copy()
        for field_name in user_ldap_values:
            setattr(user, field_name, user_ldap_values[field_name])

        DBSession.flush()
        transaction.commit()

    def user_exist(self, email):
        with make_connection(self.url, self.bind_dn, self.bind_pass) as conn:
            if self.start_tls:
                conn.start_tls()

            if not conn.bind():
                return False

            search = self.search_pattern % email
            conn.search(self.base_dn, search, self.search_scope)

            if len(conn.response) > 0:
                return True

            return False
예제 #15
0
 def test_get_one_by_email_exception(self):
     api = UserApi(None)
     api.get_one_by_email('unknown')