Beispiel #1
0
    def add_authorizedkey(self, key, comment=None):
        """
        Add the given key to the user. Adding the key to his `authorized_keys`
        file if it exists and adding it to database.
        """
        # Parse and validate ssh key
        assert key
        key = authorizedkeys.check_publickey(key)
        if not key:
            raise ValueError(_("Invalid SSH key."))
        # Remove option, replace comments.
        key = authorizedkeys.AuthorizedKey(options=None,
                                           keytype=key.keytype,
                                           key=key.key,
                                           comment=comment or key.comment)

        # If a filename exists, use it by default.
        filename = os.path.join(self.user_root, '.ssh', 'authorized_keys')
        if os.path.isfile(filename):
            with open(filename, mode="r+", encoding='utf-8') as fh:
                if authorizedkeys.exists(fh, key):
                    raise ValueError(_("SSH key already exists"))
                logger.info("add key [%s] to [%s] authorized_keys", key,
                            self.username)
                authorizedkeys.add(fh, key)
        else:
            # Also look in database.
            logger.info("add key [%s] to [%s] database", key, self.username)
            self._db.add_authorizedkey(self._username,
                                       fingerprint=key.fingerprint,
                                       key=key.getvalue())
        self._userdb._notify('user_attr_changed', self,
                             {'authorizedkeys': True})
Beispiel #2
0
    def _handle_set_password(self, **kwargs):
        """
        Called when changing user password.
        """
        if 'current' not in kwargs or not kwargs['current']:
            raise RdiffWarning(_("Current password is missing."))
        if 'new' not in kwargs or not kwargs['new']:
            raise RdiffWarning(_("New password is missing."))
        if 'confirm' not in kwargs or not kwargs['confirm']:
            raise RdiffWarning(_("Confirmation password is missing."))

        # Check if confirmation is valid.
        if kwargs['new'] != kwargs['confirm']:
            return {
                'error':
                _("The new password and its confirmation do not match.")
            }

        # Update user password
        try:
            self.app.currentuser.set_password(kwargs['new'],
                                              old_password=kwargs['current'])
            return {'success': _("Password updated successfully.")}
        except ValueError as e:
            return {'warning': str(e)}
Beispiel #3
0
    def _handle_set_password(self, **kwargs):
        """
        Called when changing user password.
        """
        if 'current' not in kwargs or not kwargs['current']:
            raise RdiffWarning(_("Current password is missing."))
        if 'new' not in kwargs or not kwargs['new']:
            raise RdiffWarning(_("New password is missing."))
        if 'confirm' not in kwargs or not kwargs['confirm']:
            raise RdiffWarning(_("Confirmation password is missing."))

        # Check if confirmation is valid.
        if kwargs['new'] != kwargs['confirm']:
            return {
                'error':
                _("The new password and its confirmation do not match.")
            }

        # Update user password
        user = self.app.currentuser.username
        _logger.info("updating user [%s] password", user)
        self.app.userdb.set_password(user,
                                     kwargs['new'],
                                     old_password=kwargs['current'])
        return {'success': _("Password updated successfully.")}
Beispiel #4
0
    def _users_handle_action(self, action, username, email, password,
                             user_root, is_admin):

        success = ""

        # We need to change values. Change them, then give back that main
        # page again, with a message
        if username == self.app.currentuser.username:
            # Don't allow the user to changes it's "admin" state.
            is_admin = self.app.currentuser.is_admin

        is_admin = str(is_admin).lower() in ['on', 'true', '1']

        # Fork the behaviour according to the action.
        if action == "edit":
            user = self.app.userdb.get_user(username)
            logger.info("updating user [%s] info", user)
            if password:
                self.app.userdb.set_password(username, password, old_password=None)
            user.user_root = user_root
            user.is_admin = is_admin
            # Avoid updating the email fields is it didn'T changed. see pdsl/minarca#187
            if email != user.email:
                user.email = email
            success = _("User information modified successfully.")

            # Check and update user directory
            if user.user_root:
                self._check_user_root_dir(user.user_root)
                rdw_spider_repos.find_repos_for_user(user)

        elif action == "add":

            if username == "":
                raise RdiffWarning(_("The username is invalid."))
            logger.info("adding user [%s]", username)

            user = self.app.userdb.add_user(username, password)
            if user_root:
                user.user_root = user_root
            user.is_admin = is_admin
            user.email = email

            # Check and update user directory
            if user.user_root:
                self._check_user_root_dir(user.user_root)
                rdw_spider_repos.find_repos_for_user(user)
            success = _("User added successfully.")

        if action == "delete":
            user = self.app.userdb.get_user(username)
            if username == self.app.currentuser.username:
                raise RdiffWarning(_("You cannot remove your own account!."))
            logger.info("deleting user [%s]", username)
            self.app.userdb.delete_user(user)
            success = _("User account removed.")

        # Return messages
        return {'success': success}
Beispiel #5
0
def get_hwinfo():
    if hasattr(os, 'getloadavg'):
        yield _('Load Average'), ', '.join(
            map(str, map(lambda x: round(x, 2), os.getloadavg())))
    yield _('CPU Count'), psutil.cpu_count()
    meminfo = psutil.virtual_memory()
    yield _('Memory usage'), '%s / %s' % (filesize(
        meminfo.used), filesize(meminfo.total))
Beispiel #6
0
 def _set_encoding(self, repo_obj, new_encoding=None, **kwargs):
     """
     Update repository encoding via Ajax.
     """
     validate(new_encoding)
     try:
         repo_obj.encoding = new_encoding
     except ValueError:
         raise cherrypy.HTTPError(400, _("invalid encoding value"))
     return _("Updated")
Beispiel #7
0
 def check_username_and_password(self, username, password):
     """Validate user credentials."""
     logger.debug("check credentials for [%s]", username)
     try:
         userobj = cherrypy.request.app.userdb.login(
             username, password)  # @UndefinedVariable
     except:
         logger.exception("fail to validate user credential")
         raise RdiffWarning(_("Fail to validate user credential."))
     if not userobj:
         logger.warning("invalid username [%s] or password", username)
         raise RdiffWarning(_("Invalid username or password."))
     return userobj
Beispiel #8
0
def get_osinfo():
    
    def gr_name(gid):
        try:
            return grp.getgrgid(gid).gr_name
        except:
            return

    def pw_name(uid):
        try:
            return pwd.getpwuid(os.getuid()).pw_name
        except:
            return
    
    if hasattr(sys, 'getfilesystemencoding'): yield _('File System Encoding'), sys.getfilesystemencoding()
    if hasattr(os, 'getcwd'):
        yield _('Current Working Directory'), os.getcwd()
    if hasattr(os, 'getegid'):
        yield _('Effective Group'), '%s (%s)' % (os.getegid(), gr_name(os.getegid()))
    if hasattr(os, 'geteuid'):
        yield _('Effective User'), '%s (%s)' % (os.geteuid(), pw_name(os.geteuid))
    if hasattr(os, 'getgid'):
        yield _('Group'), '%s (%s)' % (os.getgid(), gr_name(os.getgid()))
    if hasattr(os, 'getuid'):
        yield _('User'), '%s (%s)' % (os.getuid(), gr_name(os.getuid()))
    if hasattr(os, 'getgroups'):
        yield _('Group Membership'), ', '.join(['%s (%s)' % (gid, gr_name(gid)) for gid in os.getgroups()])
    try:
        if hasattr(os, 'getpid') and hasattr(os, 'getppid'):
            yield _('Process ID'), ('%s (parent: %s)' % (os.getpid(), os.getppid()))
    except:
        pass
Beispiel #9
0
    def set_password(self, username, password, old_password=None):
        assert isinstance(username, str)
        assert old_password is None or isinstance(old_password, str)
        assert isinstance(password, str)
        if not password:
            raise RdiffError(_("Password can't be empty."))

        # Check old password value.
        if old_password and not self.are_valid_credentials(
                username, old_password):
            raise RdiffError(_("Wrong password."))

        # Update password.
        self._set_user_field(username, 'Password',
                             self._hash_password(password))
Beispiel #10
0
    def status(self):
        """Check if a backup is in progress for the current repo."""
        if hasattr(self, '_status'):
            return self._status

        # Check if the repository exists.
        # Make sure repoRoot is a valid rdiff-backup repository
        if (not os.access(self._data_path, os.F_OK)
                or not os.path.isdir(self._data_path)):
            self._status = (
                'failed',
                _('The repository cannot be found or is badly damaged.'))
            return self._status

        pid_re = re.compile(b"^PID\s*([0-9]+)", re.I | re.M)

        def extract_pid(current_mirror):
            """Return process ID from a current mirror marker, if any"""
            entry = IncrementEntry(self, current_mirror)
            match = pid_re.search(entry.read())
            if not match:
                return None
            else:
                return int(match.group(1))

        # Read content of the file and check if pid still exists
        for current_mirror in self._current_mirrors:
            pid = extract_pid(current_mirror)
            try:
                p = psutil.Process(pid)
                if any('rdiff-backup' in c for c in p.cmdline()):
                    self._status = (
                        'in_progress',
                        _('A backup is currently in progress to this repository.'
                          ))
                    return self._status
            except psutil.NoSuchProcess:
                logger.debug('pid [%s] does not exists', pid)
                pass
        # If multiple current_mirror file exists and none of them are associated to a PID, this mean the last backup was interrupted.
        # Also, if the last backup date is undefined, this mean the first initial backup was interrupted.
        if len(self._current_mirrors) > 1 or not self.last_backup_date:
            self._status = ('interrupted',
                            _('The previous backup seams to have failed.'))
            return self._status

        self._status = ('ok', '')
        return self._status
Beispiel #11
0
 def _set_maxage(self, repo_obj, maxage=None, **kwargs):
     """
     Update repository maxage via Ajax.
     """
     validate_int(maxage)
     repo_obj.maxage = maxage
     return _("Updated")
Beispiel #12
0
    def add_user(self, user, password=None, attrs=None):
        """
        Used to add a new user with an optional password.
        """
        assert password is None or isinstance(password, str)
        # Check if user already exists.
        if self.get_user(user):
            raise RdiffError(_("User %s already exists." % (user, )))

        # Find a database where to add the user
        logger.debug("adding new user [%s]", user)
        if password:
            inserted = self._database.insert('users',
                                             username=user,
                                             password=_hash_password(password))
        else:
            inserted = self._database.insert('users',
                                             username=user,
                                             password='')
        assert inserted
        record = self._database.findone('users', username=user)
        userobj = UserObject(self, record)
        self._notify('user_added', userobj, attrs)
        # Return user object
        return userobj
Beispiel #13
0
class NotificationPref(Controller):

    panel_id = 'notification'

    panel_name = _('Notification')

    def _handle_set_notification_info(self, **kwargs):

        # Loop trough user repo and update max age.
        for repo in self.app.currentuser.repo_objs:
            # Get value received for the repo.
            value = kwargs.get(repo.name, None)
            if value:
                # Update the maxage
                repo.maxage = validate_int(value)

    def render_prefs_panel(self,
                           panelid,
                           action=None,
                           **kwargs):  # @UnusedVariable
        # Process the parameters.
        if action == "set_notification_info":
            self._handle_set_notification_info(**kwargs)

        params = {
            'email': self.app.currentuser.email,
            'repos': self.app.currentuser.repo_objs,
        }
        return "prefs_notification.html", params
Beispiel #14
0
    def send_notifications(self):
        """
        Loop trough all the user repository and send notifications.
        """

        now = librdiff.RdiffTime()

        def _user_repos():
            """Return a generator trought user repos to be notified."""
            for user in self.app.store.users():
                # Check if user has email.
                if not user.email:
                    continue
                # Identify old repo for current user.
                old_repos = []
                for repo in user.repo_objs:
                    # Check if repo has age configured (in days)
                    maxage = repo.maxage
                    if not maxage or maxage <= 0:
                        continue
                    # Check repo age.
                    if repo.last_backup_date < (
                            now - datetime.timedelta(days=maxage)):
                        old_repos.append(repo)
                # Return an item only if user had old repo
                if old_repos:
                    yield user, old_repos

        # For each candidate, send mail.
        for user, repos in _user_repos():
            parms = {'user': user, 'repos': repos}
            self.send_mail(user, _('Notification'), 'email_notification.html',
                           **parms)
Beispiel #15
0
    def render_prefs_panel(self, panelid, **kwargs):  # @UnusedVariable

        # Handle action
        params = {}
        if 'action' in kwargs:
            try:
                action = kwargs['action']
                if action == 'add':
                    self._handle_add(**kwargs)
                elif action == 'delete':
                    self._handle_delete(**kwargs)
            except RdiffWarning as e:
                params['warning'] = str(e)
            except RdiffError as e:
                params['error'] = str(e)

        # Get SSH keys if file exists.
        params["sshkeys"] = []
        try:
            params["sshkeys"] = [
                {'title': key.comment or (key.keytype + ' ' + key.key[:18]),
                 'fingerprint': key.fingerprint}
                for key in self.app.currentuser.authorizedkeys]
        except IOError:
            params['error'] = _("error reading SSH keys file")
            _logger.warning("error reading SSH keys", exc_info=1)

        return "prefs_sshkeys.html", params
Beispiel #16
0
    def render_prefs_panel(self, panelid, **kwargs):  # @UnusedVariable
        # Process the parameters.
        params = dict()
        action = kwargs.get('action')
        if action:
            try:
                if action == "set_profile_info":
                    params = self._handle_set_profile_info(**kwargs)
                elif action == "set_password":
                    params = self._handle_set_password(**kwargs)
                elif action == "update_repos":
                    params = self._handle_update_repos()
                else:
                    _logger.info("unknown action: %s", action)
                    raise cherrypy.NotFound("Unknown action")
            except RdiffWarning as e:
                params['warning'] = str(e)
            except RdiffError as e:
                params['error'] = str(e)
            except Exception as e:
                _logger.warning("unknown error processing action",
                                exc_info=True)
                params['error'] = _("Unknown error")

        params.update({
            'email': self.app.currentuser.email,
        })
        return "prefs_general.html", params
Beispiel #17
0
    def set_password(self, password, old_password=None):
        """
        Change the user's password. Raise a ValueError if the username or
        the password are invalid.
        """
        assert isinstance(password, str)
        assert old_password is None or isinstance(old_password, str)
        if not password:
            raise ValueError("password can't be empty")

        # Try to update the user password in LDAP
        for store in self._store._password_stores:
            try:
                valid = store.are_valid_credentials(self.username,
                                                    old_password)
                if valid:
                    store.set_password(self.username, password, old_password)
                    return
            except:
                pass
        # Fallback to database
        if old_password and self._get_attr('password') != _hash_password(
                old_password):
            raise ValueError(_("Wrong password"))
        self._set_attr('password', 'password', _hash_password(password))
        self._store._notify('user_password_changed', self.username, password)
Beispiel #18
0
def get_pyinfo():
    if platform.dist()[0] != '' and platform.dist()[1] != '':
        yield _('OS Version'), '%s %s (%s %s)' % (platform.system(), platform.release(), platform.dist()[0].capitalize(), platform.dist()[1])
    else:
        yield _('OS Version'), '%s %s' % (platform.system(), platform.release())
    if hasattr(os, 'path'): yield _('OS Path'), os.environ['PATH']
    if hasattr(sys, 'version'): yield _('Python Version'), ''.join(sys.version)
    if hasattr(sys, 'subversion'): yield _('Python Subversion'), ', '.join(sys.subversion)
    if hasattr(sys, 'prefix'): yield _('Python Prefix'), sys.prefix
    if hasattr(sys, 'executable'): yield _('Python Executable'), sys.executable
    if hasattr(sys, 'path'): yield _('Python Path'), ', '.join(sys.path)
Beispiel #19
0
    def _set_encoding(self, value):
        """Change the repository encoding"""
        # Validate if the value is a valid encoding before updating the database.
        codec = encodings.search_function(value.lower())
        if not codec:
            raise ValueError(_('invalid encoding %s') % value)

        logger.info("updating repository %s encoding %s", self, codec.name)
        self._set_attr('encoding', codec.name)
        self._encoding = codec
Beispiel #20
0
 def _handle_delete(self, **kwargs):
     """
     Called for delete a key from an authorized_keys file.
     """
     assert kwargs.get('key') , "key is missing"
     try:
         self.app.currentuser.remove_authorizedkey(kwargs['key'])
     except:
         _logger.warn("error removing ssh key", exc_info=1)
         raise RdiffWarning(_("Unknown error while removing the SSH Key"))
Beispiel #21
0
        def check_crendential(l, r):
            # Check results
            if len(r) != 1:
                logger.debug("user [%s] not found in LDAP", username)
                return None

            # Bind using the user credentials. Throws an exception in case of
            # error.
            l.simple_bind_s(r[0][0], password)
            try:
                logger.info("user [%s] found in LDAP", username)

                # Verify the shadow expire
                if self.check_shadow_expire:
                    shadow_expire = self._attr_shadow_expire(r)
                    # Convert nb. days into seconds.
                    if shadow_expire and shadow_expire * 24 * 60 * 60 < time.time(
                    ):
                        logger.warn("user account %s expired: %s", username,
                                    shadow_expire)
                        raise RdiffError(
                            _('User account %s expired.' % username))

                # Get username
                dn = r[0][0]
                new_username = self._decode(r[0][1][self.attribute][0])

                # Verify if the user is member of the required group
                if self.require_group:
                    value = dn if self.group_attribute_is_dn else new_username
                    logger.info("check if user [%s] is member of [%s]", value,
                                self.require_group)
                    if not l.compare_s(self.require_group,
                                       self.group_attribute, value):
                        raise RdiffError(
                            _('Permissions denied for user account %s.' %
                              username))
            finally:
                l.unbind_s()
            # Return the username
            return new_username, r[0][1]
Beispiel #22
0
 def change_passwd(l, r):
     if len(r) != 1:
         raise RdiffError(_("User %s not found." % (username, )))
     # Bind using the user credentials. Throws an exception in case of
     # error.
     if old_password is not None:
         l.simple_bind_s(r[0][0], old_password)
     l.passwd_s(r[0][0], old_password, password)
     l.unbind_s()
     logger.info("password for user [%s] is updated in LDAP", username)
     # User updated, return False
     return False
Beispiel #23
0
    def _execute(self, username, function):
        assert isinstance(username, str)
        """Reusable method to run LDAP operation."""

        assert self.uri, "LdapUri must be define in configuration"
        assert self.base_dn, "LdapBaseDn must be define in configuration"
        if self.scope == "base":
            scope = ldap.SCOPE_BASE
        elif self.scope == "onelevel":
            scope = ldap.SCOPE_ONELEVEL
        else:
            scope = ldap.SCOPE_SUBTREE

        # try STARTLS if configured
        if self.tls:
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)

        # Check LDAP credential only.
        l = ldap.initialize(self.uri)

        # Set v2 or v3
        if self.version == 2:
            l.protocol_version = ldap.VERSION2
        else:
            l.protocol_version = ldap.VERSION3

        try:
            # Bind to the LDAP server
            logger.debug("binding to ldap server {}".format(self.uri))
            l.simple_bind_s(self.bind_dn, self.bind_password)

            # Search the LDAP server
            search_filter = "(&{}({}={}))".format(self.filter, self.attribute,
                                                  username)
            logger.debug("search ldap server: {}/{}?{}?{}?{}".format(
                self.uri, self.base_dn, self.attribute, scope, search_filter))
            r = l.search_s(self.base_dn, scope, search_filter)

            # Execute operation
            return function(l, r)
        except ldap.LDAPError as e:
            l.unbind_s()
            # Handle the LDAP exception and build a nice user message.
            logger.warning('ldap error', exc_info=1)
            msg = _("An LDAP error occurred: %s")
            ldap_msg = str(e)
            if hasattr(e, 'message') and isinstance(e.message, dict):
                if 'desc' in e.message:
                    ldap_msg = e.message['desc']
                if 'info' in e.message:
                    ldap_msg = e.message['info']
            raise RdiffError(msg % ldap_msg)
Beispiel #24
0
    def _handle_set_profile_info(self, **kwargs):
        """
        Called when changing user profile.
        """
        # Check data.
        if 'email' not in kwargs:
            raise RdiffWarning(_("Email is undefined."))

        # Parse the email value to extract a valid email. The following method
        # return an empty string if the email is not valid. This RFC also accept
        # local email address without '@'. So we add verification for '@'
        if not PATTERN_EMAIL.match(kwargs['email'].lower()):
            raise RdiffWarning(_("Invalid email."))

        # Update the user's email
        assert self.app.currentuser
        username = self.app.currentuser.username
        email = kwargs['email']
        _logger.info("updating user [%s] email [%s]", username, email)
        self.app.currentuser.email = kwargs['email']

        return {'success': _("Profile updated successfully.")}
Beispiel #25
0
    def _handle_add(self, **kwargs):
        """
        Called to add a new key to an authorized_keys file.
        """
        assert 'key' in kwargs, "key is missing"

        # Add the key to the current user.
        try:
            self.app.currentuser.add_authorizedkey(key=kwargs['key'], comment=kwargs.get('title', None))
        except ValueError as e:
            _logger.warn("error adding ssh key", exc_info=1)
            raise RdiffWarning(str(e))
        except:
            _logger.error("error adding ssh key", exc_info=1)
            raise RdiffWarning(_("Unknown error while adding the SSH Key"))
Beispiel #26
0
    def set_password(self, username, password, old_password=None):
        """Update the password of the given user."""
        assert isinstance(username, str)
        assert old_password is None or isinstance(old_password, str)
        assert isinstance(password, str)

        # Do nothing if password is empty
        if not password:
            raise RdiffError(_("Password can't be empty."))
        # Check if users are allowed to change their password in LDAP.
        if not self.allow_password_change:
            logger.warn(
                "authentication backend for user [%s] does not support changing the password",
                username)
            raise RdiffError(
                _("LDAP users are not allowed to change their password."))

        # Check if old_password id valid
        if old_password and not self.are_valid_credentials(
                username, old_password):
            raise RdiffError(_("Wrong password."))

        # Update the username password of the given user. If possible.
        return self._set_password_in_ldap(username, old_password, password)
Beispiel #27
0
    def user_password_changed(self, username, password):
        """
        Implementation of IUserChangeListener interface.
        """

        # get User object (to get email)
        userobj = self.app.store.get_user(username)
        assert userobj
        
        if not userobj.email:
            logging.info("can't sent mail to user [%s] without an email", userobj.username)
            return
        
        # If the email attributes was changed, send a mail notification.
        self.send_mail(userobj, _("Password changed"), "password_changed.html")
Beispiel #28
0
 def add_user(self, user, password=None, attrs=None):
     """
     Used to add a new user with an optional password.
     """
     assert password is None or isinstance(password, str)
     # Check if user already exists.
     if self._database.exists(user):
         raise RdiffError(_("User %s already exists." % (user, )))
     # Find a database where to add the user
     logger.debug("adding new user [%s]", user)
     self._database.add_user(user, password)
     userobj = UserObject(self, self._database, user)
     self._notify('user_added', userobj, attrs)
     # Return user object
     return userobj
Beispiel #29
0
    def add_authorizedkey(self, username, fingerprint, key):
        assert isinstance(username, str)
        assert fingerprint
        assert key

        # Query user
        user_id = self._get_user_id(username)
        assert user_id, "user [%s] doesn't exists" % username
        try:
            self._execute_query(
                "INSERT INTO sshkeys (UserID, Fingerprint, Key) values (?, ?, ?)",
                (user_id, fingerprint, key))
        except sqlite3.IntegrityError:  # @UndefinedVariable
            raise ValueError(
                _("Duplicate key. This key already exists or is associated to another user."
                  ))
Beispiel #30
0
    def user_attr_changed(self, userobj, attrs={}):
        """
        Implementation of IUserChangeListener interface.
        """
        if not self._send_change_notification:
            return
        
        # Leave if the mail was not changed.
        if 'email' not in attrs:
            return
        
        if not userobj.email:
            logging.info("can't sent mail to user [%s] without an email", userobj.username)
            return

        # If the email attributes was changed, send a mail notification.
        self.send_mail(userobj, _("Email address changed"), "email_changed.html")