Пример #1
0
    def put(self, user_id):
        self.reqparse.add_argument('password', type=str, required=False)
        args = self.reqparse.parse_args()
        AuditLog.log('user.passwordReset', session['user'].username, args)

        user = User.query.filter(User.user_id == user_id).first()
        if not user:
            return self.make_response('User not found', HTTP.NOT_FOUND)

        if ROLE_ADMIN not in session[
                'user'].roles and user_id != session['user'].user_id:
            self.log.warning(
                '{} tried to change the password for another user'.format(
                    session['user'].user_id))
            return self.make_response(
                'You cannot change other users passwords', HTTP.FORBIDDEN)

        authsys = current_app.available_auth_systems[user.auth_system]
        if authsys.readonly:
            return self.make_response(
                'You cannot reset passwords for the {} based users'.format(
                    authsys.name), HTTP.FORBIDDEN)

        new_pass = args['password'] or generate_password()

        user.password = hash_password(new_pass)
        db.session.add(user)
        db.session.commit()

        return self.make_response(
            {
                'user': user.to_json(),
                'newPassword': new_pass if not args['password'] else None
            }, HTTP.OK)
Пример #2
0
def auditlog(*, event, actor, data, level=logging.INFO):
    """Generate and insert a new event

    Args:
        event (`str`): Action performed
        actor (`str`): Actor (user or subsystem) triggering the event
        data (`dict`): Any extra data necessary for describing the event
        level (`str` or `int`): Log level for the message. Uses standard python logging level names / numbers

    Returns:
        `None`
    """
    try:
        entry = AuditLog()
        entry.event = event
        entry.actor = actor
        entry.data = data

        db.session.add(entry)
        db.session.commit()

        _AUDIT_LOGGER.log(
            logging.getLevelName(level) if type(level) == str else level, {
                'event': event,
                'actor': actor,
                'data': data,
            })

    except Exception:
        logging.getLogger(__name__).exception('Failed adding audit log event')
        db.session.rollback()
Пример #3
0
    def delete(self, user_id):
        """Delete a user"""
        AuditLog.log('user.delete', session['user'].username,
                     {'userId': user_id})
        if session['user'].user_id == user_id:
            return self.make_response(
                'You cannot delete the user you are currently logged in as',
                HTTP.FORBIDDEN)

        user = User.query.filter(User.user_id == user_id).first()
        if not user:
            return self.make_response(
                'No such user id found: {}'.format(user_id), HTTP.UNAUTHORIZED)

        if user.username == 'admin' and user.auth_system == 'builtin':
            return self.make_response(
                'You cannot delete the built-in admin user', HTTP.FORBIDDEN)

        username = user.username
        auth_system = user.auth_system
        db.session.delete(user)
        db.session.commit()

        return self.make_response(
            'User {}/{} has been deleted'.format(auth_system, username),
            HTTP.OK)
Пример #4
0
    def put(self, user_id):
        """Update a user object"""
        self.reqparse.add_argument('roles', type=str, action='append')
        args = self.reqparse.parse_args()
        AuditLog.log('user.create', session['user'].username, args)

        user = User.query.filter(User.user_id == user_id).first()
        roles = Role.query.filter(Role.name.in_(args['roles'])).all()
        if not user:
            return self.make_response('No such user found: {}'.format(user_id),
                                      HTTP.NOT_FOUND)

        if user.username == 'admin' and user.auth_system == 'builtin':
            return self.make_response(
                'You cannot modify the built-in admin user', HTTP.FORBIDDEN)

        user.roles = []
        for role in roles:
            if role in args['roles']:
                user.roles.append(role)

        db.session.add(user)
        db.session.commit()

        return self.make_response({'message': 'User roles updated'}, HTTP.OK)
Пример #5
0
    def delete(self, namespace, key):
        """Delete a specific configuration item"""
        AuditLog.log('configItem.delete', session['user'].username, {'namespace': namespace, 'key': key})
        if not self.dbconfig.key_exists(namespace, key):
            return self.make_response('No such config entry exists: {}/{}'.format(namespace, key), HTTP.BAD_REQUEST)

        self.dbconfig.delete(namespace, key)
        return self.make_response('Config entry deleted')
Пример #6
0
    def post(self):
        """Create a new account"""
        self.reqparse.add_argument('accountName', type=str, required=True)
        self.reqparse.add_argument('accountNumber', type=str, required=True)
        self.reqparse.add_argument('contacts',
                                   type=str,
                                   required=True,
                                   action='append')
        self.reqparse.add_argument('enabled',
                                   type=int,
                                   required=True,
                                   choices=(0, 1))
        self.reqparse.add_argument('requiredGroups',
                                   type=str,
                                   action='append',
                                   default=())
        self.reqparse.add_argument('adGroupBase', type=str, default=None)
        args = self.reqparse.parse_args()
        AuditLog.log('account.create', session['user'].username, args)

        for contact in args['contacts']:
            if not contact.startswith('#') and (contact.find('@') >= 0 and
                                                not validate_email(contact)):
                raise Exception(
                    'Invalid email address or slack channel name supplied: {}'.
                    format(contact))

        for key in ('accountName', 'accountNumber', 'contacts', 'enabled'):
            value = args[key]
            if type(value) == str:
                value = value.strip()

            if type(value) in (int, tuple, list, str):
                if not value:
                    raise Exception('{} cannot be empty'.format(
                        key.replace('_', ' ').title()))
            else:
                raise ValueError(
                    'Invalid type: {} for value {} for argument {}'.format(
                        type(value), value, key))

        if Account.query.filter_by(
                account_name=args['accountName']).count() > 0:
            raise Exception('Account already exists')

        acct = Account(args['accountName'], args['accountNumber'].zfill(12),
                       args['contacts'], args['enabled'], args['adGroupBase'])
        acct.required_groups = json.dumps(args['requiredGroups'])
        db.session.add(acct)
        db.session.commit()

        # Add the newly created account to the session so we can see it right away
        session['accounts'].append(acct.account_id)
        return self.make_response(
            {
                'message': 'Account created',
                'accountId': acct.account_id
            }, HTTP.CREATED)
Пример #7
0
    def delete(self):
        self.reqparse.add_argument('maxAge', type=int, default=31)
        args = self.reqparse.parse_args()
        AuditLog.log('logs.prune', session['user'].username, args)

        LogEvent.query.filter(
            func.datesub(LogEvent.timestamp < datetime.now() -
                         timedelta(days=args['maxAge']))).delete()

        db.session.commit()
Пример #8
0
    def delete(self, accountId):
        """Delete an account"""
        AuditLog.log('account.delete', session['user'].username,
                     {'accountId': accountId})
        acct = Account.query.filter_by(account_id=accountId).first()
        if not acct:
            raise Exception('No such account found')

        acct.delete()

        return self.make_response('Account deleted')
Пример #9
0
    def delete(self, namespacePrefix):
        """Delete a specific configuration namespace"""
        AuditLog.log('configNamespace.delete', session['user'].username, {'namespacePrefix': namespacePrefix})
        ns = ConfigNamespace.query.filter(ConfigNamespace.namespace_prefix == namespacePrefix).first()
        if not ns:
            return self.make_response('No such namespace: {}'.format(namespacePrefix), HTTP.NOT_FOUND)

        db.session.delete(ns)
        db.session.commit()

        self.dbconfig.reload_data()
        return self.make_response('Namespace deleted')
Пример #10
0
    def post(self):
        """Create a new role"""
        self.reqparse.add_argument('name', type=str, required=True)
        self.reqparse.add_argument('color', type=str, required=True)
        args = self.reqparse.parse_args()
        AuditLog.log('role.create', session['user'].username, args)

        role = Role()
        role.name = args['name']
        role.color = args['color']

        db.session.add(role)
        db.session.commit()

        return self.make_response(
            'Role {} has been created'.format(role.role_id), HTTP.CREATED)
Пример #11
0
    def put(self, accountId):
        """Update an account"""
        self.reqparse.add_argument('accountName', type=str, required=True)
        self.reqparse.add_argument('accountNumber', type=str, required=True)
        self.reqparse.add_argument('contacts',
                                   type=str,
                                   required=True,
                                   action='append')
        self.reqparse.add_argument('enabled',
                                   type=int,
                                   required=True,
                                   choices=(0, 1))
        self.reqparse.add_argument('requiredRoles',
                                   type=str,
                                   action='append',
                                   default=())
        self.reqparse.add_argument('adGroupBase', type=str, default=None)
        args = self.reqparse.parse_args()
        AuditLog.log('account.update', session['user'].username, args)

        for contact in args['contacts']:
            if not contact.startswith('#') and not validate_email(contact):
                raise Exception(
                    'Invalid email address or slack channel name supplied: {}'.
                    format(contact))

        if not args['accountName'].strip():
            raise Exception('You must provide an account name')

        if not args['contacts']:
            raise Exception('You must provide at least one contact')

        acct = Account.query.filter_by(account_id=accountId).first()
        acct.account_name = args['accountName']
        acct.account_number = args['accountNumber'].zfill(12)
        acct.contacts = args['contacts']
        acct.enabled = args['enabled']
        acct.required_roles = args['requiredRoles']
        acct.ad_group_base = args['adGroupBase']

        db.session.add(acct)
        db.session.commit()

        return self.make_response({
            'message': 'Object updated',
            'account': acct.to_json(is_admin=True)
        })
Пример #12
0
    def put(self, roleId):
        """Update a user role"""
        self.reqparse.add_argument('color', type=str, required=True)
        args = self.reqparse.parse_args()
        AuditLog.log('role.update', session['user'].username, args)

        role = Role.query.filter(Role.role_id == roleId).first()
        if not role:
            self.make_response({'message': 'No such role found'},
                               HTTP.NOT_FOUND)

        role.color = args['color']

        db.session.add(role)
        db.session.commit()

        return self.make_response('Role {} has been updated'.format(role.name))
Пример #13
0
    def delete(self, roleId):
        """Delete a user role"""
        AuditLog.log('role.delete', session['user'].username,
                     {'roleId': roleId})

        role = Role.query.filter(Role.role_id == roleId).first()
        if not role:
            return self.make_response('No such role found', HTTP.NOT_FOUND)

        if role.name in ('User', 'Admin'):
            return self.make_response('Cannot delete the built-in roles',
                                      HTTP.BAD_REQUEST)

        db.session.delete(role)
        db.session.commit()

        return self.make_response('Role has been deleted')
Пример #14
0
    def put(self, namespacePrefix):
        """Update a specific configuration namespace"""
        self.reqparse.add_argument('name', type=str, required=True)
        self.reqparse.add_argument('sortOrder', type=int, required=True)
        args = self.reqparse.parse_args()
        AuditLog.log('configNamespace.update', session['user'].username, args)

        ns = ConfigNamespace.query.filter(ConfigNamespace.namespace_prefix == namespacePrefix).first()
        if not ns:
            return self.make_response('No such namespace: {}'.format(namespacePrefix), HTTP.NOT_FOUND)

        ns.name = args['name']
        ns.sort_order = args['sortOrder']
        db.session.add(ns)
        db.session.commit()

        self.dbconfig.reload_data()

        return self.make_response('Namespace updated')
Пример #15
0
    def post(self):
        """Create a new config item"""
        self.reqparse.add_argument('namespacePrefix', type=str, required=True)
        self.reqparse.add_argument('description', type=str, required=True)
        self.reqparse.add_argument('key', type=str, required=True)
        self.reqparse.add_argument('value', required=True)
        self.reqparse.add_argument('type', type=str, required=True)
        args = self.reqparse.parse_args()
        AuditLog.log('configItem.create', session['user'].username, args)

        if not self.dbconfig.namespace_exists(args['namespacePrefix']):
            return self.make_response('The namespace doesnt exist', HTTP.NOT_FOUND)

        if self.dbconfig.key_exists(args['namespacePrefix'], args['key']):
            return self.make_response('This config item already exists', HTTP.CONFLICT)

        self.dbconfig.set(args['namespacePrefix'], args['key'], _to_dbc_class(args), description=args['description'])

        return self.make_response('Config item added', HTTP.CREATED)
Пример #16
0
    def put(self, namespace, key):
        """Update a single configuration item"""
        args = request.json
        AuditLog.log('configItem.update', session['user'].username, args)

        if not self.dbconfig.key_exists(namespace, key):
            return self.make_response('No such config entry: {}/{}'.format(namespace, key), HTTP.BAD_REQUEST)

        if (args['type'] == 'choice' and
                not args['value']['min_items'] <= len(args['value']['enabled']) <= args['value']['max_items']):
            return self.make_response(
                'You should select {} {}item{}'.format(
                    args['value']['min_items'],
                    '' if args['value']['min_items'] == args['value']['max_items'] else 'to {} '.format(
                        args['value']['max_items']
                    ),
                    's' if args['value']['max_items'] > 1 else ''
                ),
                HTTP.BAD_REQUEST
            )

        if args['type'] == 'choice' and not set(args['value']['enabled']).issubset(args['value']['available']):
            return self.make_response('Invalid item', HTTP.BAD_REQUEST)

        item = (ConfigItem.query
            .filter(ConfigItem.namespace_prefix == namespace, ConfigItem.key == key)
            .first()
        )

        if item.value != args['value']:
            item.value = args['value']

        if item.type != args['type']:
            item.type = args['type']

        if item.description != args['description']:
            item.description = args['description']

        self.dbconfig.set(namespace, key, _to_dbc_class(args))

        return self.make_response('Config entry updated')
Пример #17
0
    def post(self):
        """Create a new configuration namespace"""
        self.reqparse.add_argument('namespacePrefix', type=str, required=True)
        self.reqparse.add_argument('name', type=str, required=True)
        self.reqparse.add_argument('sortOrder', type=int, required=True)
        args = self.reqparse.parse_args()
        AuditLog.log('configNamespace.create', session['user'].username, args)

        if self.dbconfig.namespace_exists(args['namespacePrefix']):
            return self.make_response('Namespace {} already exists'.format(args['namespacePrefix']), HTTP.CONFLICT)

        ns = ConfigNamespace()

        ns.namespace_prefix = args['namespacePrefix']
        ns.name = args['name']
        ns.sort_order = args['sortOrder']

        db.session.add(ns)
        db.session.commit()

        self.dbconfig.reload_data()
        return self.make_response('Namespace created', HTTP.CREATED)
Пример #18
0
    def put(self, emailId):
        AuditLog.log('email.resend', session['user'].username,
                     {'emailId': emailId})

        email = Email.query.filter(Email.email_id == emailId).first()
        if not email:
            return self.make_response(
                {
                    'message': 'Email not found',
                    'email': None
                }, HTTP.NOT_FOUND)

        try:
            send_email(email.subsystem, email.sender, email.recipients,
                       email.subject, email.message_html, email.message_text)

            return self.make_response('Email resent successfully')

        except EmailSendError as ex:
            self.log.exception('Failed resending email {0}: {1}'.format(
                email.email_id, ex))
            return self.make_response(
                'Failed resending the email: {0}'.format(ex), HTTP.UNAVAILABLE)
Пример #19
0
    def post(self):
        """Create a new user"""
        self.reqparse.add_argument('username', type=str, required=True)
        self.reqparse.add_argument('authSystem', type=str, required=True)
        self.reqparse.add_argument('password',
                                   type=str,
                                   required=False,
                                   default=None)
        self.reqparse.add_argument('roles',
                                   type=str,
                                   action='append',
                                   default=[])
        args = self.reqparse.parse_args()
        AuditLog.log('user.create', session['user'].username, args)

        user = User.query.filter(
            User.username == args['username'],
            User.auth_system == args['authSystem']).first()
        roles = []
        if user:
            return self.make_response('User already exists', HTTP.BAD_REQUEST)

        if args['authSystem'] not in current_app.available_auth_systems:
            return self.make_response(
                'The {} auth system does not allow local edits'.format(
                    args['authSystem']), HTTP.BAD_REQUEST)

        if current_app.available_auth_systems[args['authSystem']].readonly:
            return self.make_response(
                'You cannot create users for the {} auth system as it is handled externally'
                .format(args['authSystem']), HTTP.BAD_REQUEST)

        for roleName in args['roles']:
            role = Role.query.filter(Role.name == roleName).first()

            if not role:
                return self.make_response('No such role {}'.format(roleName),
                                          HTTP.BAD_REQUEST)

            if roleName == ROLE_ADMIN and ROLE_ADMIN not in session[
                    'user'].roles:
                self.log.error(
                    'User {} tried to grant admin privileges to {}'.format(
                        session['user'].username, args['username']))

                return self.make_response(
                    'You do not have permission to grant admin privileges',
                    HTTP.FORBIDDEN)

            roles.append(role)

        authSys = current_app.available_auth_systems[args['authSystem']]
        password = args['password'] or generate_password()

        user = User()
        user.username = args['username']
        user.password = hash_password(password)
        user.auth_system = authSys.name
        db.session.add(user)
        db.session.commit()
        db.session.refresh(user)
        User.add_role(user, roles)

        return self.make_response({
            'message':
            'User {}/{} has been created'.format(user.auth_system,
                                                 user.username),
            'user':
            user,
            'password':
            password if not args['password'] else None
        })