Пример #1
0
def create_password_reset_request(db_session, username):
    try:
        user = db_session.query(User). \
            filter_by(username=username).one()
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, 'User not found')

    # verify if this user have an active password reset request
    old_request = db_session.query(PasswordRequest). \
        filter_by(user_id=user.id).one_or_none()
    if old_request and check_request_validity(db_session, old_request):
        raise HTTPRequestError(409, 'You have a password reset'
                                    ' request in progress')

    request_dict = {
                    'user_id': user.id,
                    'link': str(binascii.hexlify(os.urandom(16)), 'ascii')
                  }

    password_request = PasswordRequest(**request_dict)
    db_session.add(password_request)

    with open('templates/passwordReset.html', 'r') as f:
        html = f.read()
    reset_link = conf.resetPwdView + request_dict['link']
    html = html.format(name=user.name, link=reset_link)
    send_mail(user.email, 'Password Reset', html)
Пример #2
0
def update_perm(db_session, permission: str, perm_data, requester):
    """
    Updates all information about a permission (excluding name and ID, of course).
    :param db_session: The postgres session to be used.
    :param permission: String The permission name or ID.
    :param perm_data: New information for this permission.
    :param requester: Who is creating this user. This is a dictionary with two keys:
                      "userid" and "username".
    :return:
    :raises HTTPRequestError: Can't edit a system permission.
    """
    perm_data = {
        k: perm_data[k]
        for k in perm_data if k in Permission.fillable
    }

    check_perm(perm_data)
    try:
        perm = Permission.get_by_name_or_id(permission)
        if perm.type == PermissionTypeEnum.api:
            if 'name' in perm_data.keys() and perm.name != perm_data['name']:
                raise HTTPRequestError(400, "permission name can't be changed")
            for key, value in perm_data.items():
                setattr(perm, key, value)
            db_session.add(perm)
            LOGGER.info(
                f"permission {perm.name} updated by {requester['username']}")
            LOGGER.info(perm_data)

            db_session.commit()
        else:
            raise HTTPRequestError(405, "Can't edit a system permission ")
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, "No permission found with this ID")
Пример #3
0
def delete_perm(db_session, permission: str, requester):
    """
    Removes a permission from the system
    :param db_session: The postgres session to be used.
    :param permission: String The permission to be removed (name or ID).
    :param requester: Who is creating this user. This is a dictionary with two keys:
                      "userid" and "username".
    :return:
    :raises HTTPRequestError: Can't delete a system permission.
    """
    try:
        perm = Permission.get_by_name_or_id(permission)
        if perm.type == PermissionTypeEnum.api:
            db_session.execute(
                UserPermission.__table__.delete(
                    UserPermission.permission_id == perm.id))
            db_session.execute(
                GroupPermission.__table__.delete(
                    GroupPermission.permission_id == perm.id))
            cache.delete_key(action=perm.method, resource=perm.path)
            LOGGER.info(
                f"permission {perm.name} deleted by {requester['username']}")
            LOGGER.info(perm.safe_dict())
            db_session.delete(perm)
            db_session.commit()
            MVUserPermission.refresh()
            MVGroupPermission.refresh()
        else:
            raise HTTPRequestError(405, "Can't delete a system permission")
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, "No permission found with this ID or name")
Пример #4
0
def deleteUser(dbSession, user, requester):
    try:
        user = User.getByNameOrID(user)
        if user.id == requester['userid']:
            raise HTTPRequestError(400, "a user can't remove himself")
        dbSession.execute(
            UserPermission.__table__.delete(UserPermission.user_id == user.id)
        )
        dbSession.execute(
            UserGroup.__table__.delete(UserGroup.user_id == user.id)
        )
        cache.deleteKey(userid=user.id)

        # The user is not hardDeleted.
        # it should be copied to inactiveUser table
        inactiveTables.PasswdInactive.createInactiveFromUser(dbSession,
                                                             user,)
        inactiveTables.UserInactive.createInactiveFromUser(dbSession,
                                                           user,
                                                           requester['userid'])
        passwd.expirePasswordResetRequests(dbSession, user.id)
        dbSession.delete(user)
        log().info('user ' + user.username + ' deleted by '
                   + requester['username'],
                   user.safeDict())
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No user found with this ID")
Пример #5
0
def createUser(dbSession, user, requester):
    # drop invalid fields
    user = {k: user[k] for k in user if k in User.fillable}
    checkUser(user)

    anotherUser = dbSession.query(User.id) \
                           .filter_by(username=user['username']).one_or_none()
    if anotherUser:
        raise HTTPRequestError(400, "username '"
                               + user['username']
                               + "' is in use.")

    anotherUser = dbSession.query(User.id) \
                           .filter_by(email=user['email']).one_or_none()
    if anotherUser:
        raise HTTPRequestError(400, "Email '" + user['email'] + "' is in use.")

    if conf.emailHost == 'NOEMAIL':
        user['salt'], user['hash'] = passwd.createPwd(conf.temporaryPassword)

    user['created_by'] = requester['userid']
    newUser = User(**user)
    log().info('user ' + user['username'] + ' created by '
               + requester['username'],
               newUser.safeDict())
    return newUser
Пример #6
0
def getJwtPayload(rawJWT):
    if not rawJWT:
        raise HTTPRequestError(401, "not authorized")

    # remove the bearer of the token
    splittedToken = rawJWT.split(' ')
    if len(splittedToken) > 1:
        rawJWT = splittedToken[1]

    try:
        jwtPayload = jwt.decode(rawJWT, verify=False)
    except jwt.exceptions.DecodeError:
        raise HTTPRequestError(401, "Corrupted JWT")

    try:
        user_id = jwtPayload['userid']
    except KeyError:
        raise HTTPRequestError(401, "Invalid JWT payload")

    # now that we know the user, we know the secret
    # and can check the jwt signature
    if conf.checkJWTSign:
        try:
            user = dbSession.query(User). \
                    filter_by(user_id=jwtPayload['userid']).one()
            options = {
                'verify_exp': False,
            }
            jwt.decode(rawJWT, user.secret, algorithm='HS256', options=options)
        except (jwt.exceptions.DecodeError, sqlalchemy.orm.exc.NoResultFound):
            raise HTTPRequestError(401, "Invalid JWT signaure")
        except sqlalchemy.exc.DBAPIError:
            raise HTTPRequestError(500, 'Problem connecting to database')
    return jwtPayload
Пример #7
0
def updateUser(dbSession, user, updatedInfo, requester):
    # Drop invalid fields
    updatedInfo = {
                    k: updatedInfo[k]
                    for k in updatedInfo
                    if k in User.fillable
                  }
    oldUser = User.getByNameOrID(user)

    if 'username' in updatedInfo.keys() \
            and updatedInfo['username'] != oldUser.username:
        raise HTTPRequestError(400, "usernames can't be updated")

    checkUser(updatedInfo)

    # Verify if the email is in use by another user
    if 'email' in updatedInfo.keys() and updatedInfo['email'] != oldUser.email:
        anotherUser = dbSession.query(User) \
                               .filter_by(email=updatedInfo['email']) \
                               .one_or_none()
        if anotherUser:
            raise HTTPRequestError(400, "email already in use")

    log().info('user ' + oldUser.username + ' updated by '
               + requester['username'],
               {'oldUser': oldUser.safeDict(), 'newUser': updatedInfo})
    if 'name' in updatedInfo.keys():
        oldUser.name = updatedInfo['name']
    if 'service' in updatedInfo.keys():
        oldUser.service = updatedInfo['service']
    if 'email' in updatedInfo.keys():
        oldUser.email = updatedInfo['email']

    return oldUser
Пример #8
0
def update(db_session, user, new_password):
    check_password_format(user, new_password)

    # check actual password
    if user.hash and (user.hash == crypt(new_password, user.salt,
                                         1000).split('$').pop()):
        raise HTTPRequestError(
            400, "Please, choose a password"
            " that was not used before.")

    # check all old password from database
    if conf.passwdHistoryLen > 0:
        oldpwds = (db_session.query(PasswdInactive).filter_by(
            user_id=user.id).order_by(
                PasswdInactive.deletion_date.desc()).limit(
                    conf.passwdHistoryLen))

        for pwd in oldpwds:
            if pwd.hash == crypt(new_password, pwd.salt,
                                 1000).split('$').pop():
                raise HTTPRequestError(
                    400, "Please, choose a password"
                    " that was not used before")
    PasswdInactive.createInactiveFromUser(db_session, user)
    return create_pwd(new_password)
Пример #9
0
def add_user_group(db_session, user, group, requester):
    try:
        user = User.get_by_name_or_id(user)
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404,
                               f"No user found with this ID or name: {user}")
    try:
        group = Group.get_by_name_or_id(group)
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(
            404, f"No group found with this ID or name: {group}")

    if db_session.query(UserGroup).filter_by(user_id=user.id,
                                             group_id=group.id).one_or_none():
        raise HTTPRequestError(409, "User is already a member of the group")

    r = UserGroup(user_id=user.id, group_id=group.id)
    db_session.add(r)
    cache.delete_key(userid=user.id)

    user.reset_token()
    db_session.add(user)

    log().info(
        f"user {user.username} added to group {group.name} by {requester['username']}"
    )

    db_session.commit()
Пример #10
0
def search_perm(db_session, path=None, method=None, permission=None):
    """
    Retrieves a set of permissions from database.
    :param db_session: The postgres session to be used.
    :param path: Permission path, if any.
    :param method: Permission allowed methods, if any.
    :param permission: Permission verb (permit or deny), if any.
    :return:
    """
    perm_query = db_session.query(Permission)

    if path:
        perm_query = perm_query.filter(Permission.path.like(f"%{path}%"))

    if method:
        perm_query = perm_query.filter(Permission.method.like(f"%{method}%"))

    if permission:
        if permission not in [p.value for p in PermissionEnum]:
            raise HTTPRequestError(
                400, f"Invalid filter. Permission can't be {permission}")
        perm_query = perm_query.filter_by(permission=permission)

    perms = perm_query.all()
    if not perms:
        raise HTTPRequestError(404, "No results found with these filters")
    return perms
Пример #11
0
def check_password_format(user, password):
    password_len = len(password)
    if password_len < conf.passwdMinLen:
        raise HTTPRequestError(400, 'password must have at least '
                                    + str(conf.passwdMinLen)
                                    + ' characters')
    if password_len > 512:
        raise HTTPRequestError(400, 'Calm down! 512 characters is the '
                                    ' maximum password length')
    lower_pwd = password.lower()

    # check if the password can be guessed with user info
    if (SequenceMatcher(None, lower_pwd, user.username)
        .find_longest_match(0, password_len, 0, len(user.username))
        .size > 4
        or
        SequenceMatcher(None, lower_pwd, user.email)
        .find_longest_match(0, password_len, 0, len(user.email))
        .size > 4
        or
        SequenceMatcher(None, lower_pwd, user.name.lower())
        .find_longest_match(0, password_len, 0, len(user.name.lower()))
            .size > 4):
        raise HTTPRequestError(400, 'Please, choose a password that is'
                                    ' harder to guess. Your user info may'
                                    ' give hints on this password')

    # check for dull sequences
    # like 'aaa' '123' 'abc'
    last_char = '\0'
    count_equals = 1
    count_up = 1
    count_down = 1
    for c in password:
        if ord(c) == ord(last_char) + 1:
            count_up += 1
        else:
            count_up = 1

        if ord(c) == ord(last_char) - 1:
            count_down += 1
        else:
            count_down = 1

        if c == last_char:
            count_equals += 1
        else:
            count_equals = 1

        if count_equals == 3 or count_up == 3 or count_down == 3:
            raise HTTPRequestError(400, 'do not use passwords with '
                                        ' easy to guess'
                                        ' character sequences')
        last_char = c

    # check vs a blacklist
    if password in password_blackList:
        raise HTTPRequestError(400, "This password can't be used, as it is "
                                    " in our blacklist of bad passwords")
Пример #12
0
def update_user(db_session, user: str, updated_info, requester) -> (dict, str):
    """
    Updates all the information about a particular user.
    :param db_session: The postgres session to be used.
    :param user: The user ID to be updated.
    :param updated_info: The new data.
    :param requester: Who is requiring this update.
    :return: The old information (a dictionary containing the old information about the user
             and the old service.
    :raises HTTPRequestError: If the username is different from the original (this field cannot be updated).
    """
    # Drop invalid fields
    updated_info = {
        k: updated_info[k]
        for k in updated_info if k in User.fillable
    }
    user = User.get_by_name_or_id(user)
    old_user = user.safe_dict()
    old_service = user.service

    if 'username' in updated_info.keys() \
            and updated_info['username'] != user.username:
        raise HTTPRequestError(400, "usernames can't be updated")

    # check_user function needs username.
    updated_info['username'] = user.username
    check_user(updated_info)

    # Verify if the email is in use by another user
    if 'email' in updated_info.keys() and updated_info['email'] != user.email:
        if db_session.query(User).filter_by(
                email=updated_info['email']).one_or_none():
            raise HTTPRequestError(400, "email already in use")

    log().info(f"user {user.username} updated by {requester['username']}")
    log().info({'oldUser': user.safe_dict(), 'newUser': updated_info})

    # Update all new data.
    if 'name' in updated_info.keys():
        user.name = updated_info['name']
    if 'service' in updated_info.keys():
        user.service = updated_info['service']
    if 'email' in updated_info.keys():
        user.email = updated_info['email']

    db_session.add(user)
    db_session.commit()

    # Publish messages related to service creation/deletion
    if count_tenant_users(db_session, old_service) == 0:
        log().info(f"will emit tenant lifecycle event {old_service} - DELETE")
        Publisher.send_notification({"type": 'DELETE', 'tenant': old_service})

    if count_tenant_users(db_session, user.service) == 1:
        log().info(f"will emit tenant lifecycle event {user.service} - CREATE")
        Publisher.send_notification({"type": 'CREATE', 'tenant': user.service})

    return old_user, old_service
Пример #13
0
def checkRequest(pdpRequest):
    if 'action' not in pdpRequest.keys() or len(pdpRequest['action']) == 0:
        raise HTTPRequestError(400, "Missing action")

    if 'jwt' not in pdpRequest.keys() or len(pdpRequest['jwt']) == 0:
        raise HTTPRequestError(400, "Missing JWT")

    if 'resource' not in pdpRequest.keys() or len(pdpRequest['resource']) == 0:
        raise HTTPRequestError(400, "Missing resource")
Пример #14
0
def delete_user(db_session, username: str, requester):
    """
    Deletes an user from the system
    :param db_session: The postgres session to be used
    :param username: String The user to be removed
    :param requester: Who is creating this user. This is a dictionary with two keys:
                      "userid" and "username"
    :return: The removed user
    :raises HTTPRequestError: If the user tries to remove itself.
    :raises HTTPRequestError: Can't delete the admin user.
    :raises HTTPRequestError: If the user is not in the database.
    """
    try:
        user = User.get_by_name_or_id(username)
        if user.id == requester['userid']:
            raise HTTPRequestError(400, "a user can't remove himself")
        elif user.username == 'admin':
            raise HTTPRequestError(405, "Can't delete the admin user")

        db_session.execute(
            UserPermission.__table__.delete(UserPermission.user_id == user.id))
        db_session.execute(
            UserGroup.__table__.delete(UserGroup.user_id == user.id))
        cache.delete_key(userid=user.id)

        # The user is not hardDeleted.
        # it should be copied to inactiveUser table
        inactiveTables.PasswdInactive.createInactiveFromUser(
            db_session,
            user,
        )
        inactiveTables.UserInactive.createInactiveFromUser(
            db_session, user, requester['userid'])
        password.expire_password_reset_requests(db_session, user.id)
        db_session.delete(user)
        LOGGER.info(f"user {user.username} deleted by {requester['username']}")
        LOGGER.info(user.safe_dict())

        kongUtils.remove_from_kong(user.username)
        MVUserPermission.refresh()
        MVGroupPermission.refresh()
        db_session.commit()

        if count_tenant_users(db_session, user.service) == 0:
            LOGGER.info(
                f"will emit tenant lifecycle event {user.service} - DELETE")
            Publisher.send_notification({
                "type": 'DELETE',
                'tenant': user.service
            })

        return user
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, "No user found with this ID")
Пример #15
0
def check_group(group):
    if not group.get('name', ""):
        raise HTTPRequestError(400, 'Missing group name')
    if len(group['name']) > GroupLimits.name:
        raise HTTPRequestError(400, "Group name too long")

    if re.match(r'^[a-zA-Z0-9]+$', group['name']) is None:
        raise HTTPRequestError(
            400, 'Invalid group name, only alphanumeric allowed')

    if 'desc' in group.keys() and len(group['desc']) > GroupLimits.description:
        raise HTTPRequestError(400, "Group description is too long")
Пример #16
0
def updatePerm(dbSession, permission, permData, requester):
    permData = {k: permData[k] for k in permData if k in Permission.fillable}
    checkPerm(permData)
    try:
        perm = Permission.getByNameOrID(permission)
        if 'name' in permData.keys() and perm.name != permData['name']:
            raise HTTPRequestError(400, "permission name can't be changed")
        for key, value in permData.items():
            setattr(perm, key, value)
        dbSession.add(perm)
        log().info('permission ' + perm.name + ' updated by '
                   + requester['username'],
                   permData)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No permission found with this ID")
Пример #17
0
def updateGroup(dbSession, group, groupData, requester):
    groupData = {k: groupData[k] for k in groupData if k in Group.fillable}
    checkGroup(groupData)
    try:
        group = Group.getByNameOrID(group)
        if 'name' in groupData.keys() and group.name != groupData['name']:
            raise HTTPRequestError(400, "groups name can't be changed")
        for key, value in groupData.items():
            setattr(group, key, value)
        dbSession.add(group)
        log().info('group ' + group.name + ' updated by '
                   + requester['username'],
                   groupData)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No group found with this ID")
Пример #18
0
def getUserDirectPermissions(dbSession, user):
    try:
        user = User.getByNameOrID(user)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No user found with this username or ID")

    return user.permissions
Пример #19
0
def update_group(db_session, group, group_data, requester):
    group_data = {k: group_data[k] for k in group_data if k in Group.fillable}
    check_group(group_data)
    try:
        group = Group.get_by_name_or_id(group)
        if 'name' in group_data.keys() and group.name != group_data['name']:
            raise HTTPRequestError(400, "groups name can't be changed")
        for key, value in group_data.items():
            setattr(group, key, value)
        db_session.add(group)
        log().info(
            'group ' + group.name + ' updated by ' + requester['username'],
            group_data)
        db_session.commit()
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, "No group found with this ID")
Пример #20
0
def get_group_permissions(db_session, group):
    try:
        group = Group.get_by_name_or_id(group)
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, "No group found with this name or ID")
    else:
        return group.permissions
Пример #21
0
def getGroupUsers(dbSession, group):
    try:
        group = Group.getByNameOrID(group)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No group found with this name or ID")
    else:
        return group.users
Пример #22
0
def getUserGrups(dbSession, user):
    try:
        user = User.getByNameOrID(user)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No user found with this username or ID")
    else:
        return user.groups
Пример #23
0
def reset_kong_secret(username, token_id):
    if conf.kongURL == 'DISABLED':
        return
    try:
        delete_response = requests.delete("%s/consumers/%s/jwt/%s" %
                                          (conf.kongURL, username, token_id))

        if not (200 <= delete_response.status_code < 300):
            LOGGER.error("failed to delete key: %d %s" %
                         (delete_response.status_code, delete_response.reason))
            LOGGER.error(delete_response.json())
            return None

        headers = {"content-type": "application/x-www-form-urlencoded"}
        response = requests.post('%s/consumers/%s/jwt' %
                                 (conf.kongURL, username),
                                 headers=headers)
        if not (200 <= response.status_code < 300):
            LOGGER.error("failed to create key: %d %s" %
                         (response.status_code, response.reason))
            LOGGER.error(response.json())
            return None

        reply = response.json()

        return {
            'key': reply['key'],
            'secret': reply['secret'],
            'kongid': reply['id']
        }
    except ConnectionError:
        LOGGER.error("Failed to connect to kong")
        raise HTTPRequestError(500, "Failed to connect to kong")
Пример #24
0
def get_group_users(db_session, group):
    try:
        group = Group.getByNameOrID(group)
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, "No group found with this name or ID")
    else:
        return group.users
Пример #25
0
def get_user_groups(db_session, user):
    try:
        user = User.getByNameOrID(user)
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, "No user found with this username or ID")
    else:
        return user.groups
Пример #26
0
def create_group(db_session, group_data, requester):
    """
    Create a new group
    :param db_session: The postgres session to be used.
    :param group_data: The group data. This is a simple dictionary with "name" and
                       "description" keys.
    :param requester: Who is creating this user. This is a dictionary with two keys:
                      "userid" and "username".
    :return: The new group.
    """
    group_data = {k: group_data[k] for k in group_data if k in Group.fillable}
    check_group(group_data)

    if db_session.query(
            Group.name).filter_by(name=group_data['name']).one_or_none():
        raise HTTPRequestError(400,
                               f"Group name {group_data['name']} is in use.")

    group_data['created_by'] = requester['userid']
    group = Group(**group_data)
    LOGGER.info(f"group {group.name} created by {requester['username']}")
    LOGGER.info(group.safe_dict())
    db_session.add(group)
    db_session.commit()
    return group
Пример #27
0
def list_tenants(db_session):
    try:
        tenants = []
        for tenant in db_session.query(User.service).distinct():
            tenants.append(tenant[0])
        return tenants
    except orm_exceptions.NoResultFound:
        raise HTTPRequestError(404, "No registered tenants found")
Пример #28
0
def removeFromKong(user):
    if conf.kongURL == 'DISABLED':
        return
    try:
        requests.delete("%s/consumers/%s" % (conf.kongURL, user))
    except ConnectionError:
        LOGGER.error("Failed to connect to kong")
        raise HTTPRequestError(500, "Failed to connect to kong")
Пример #29
0
def removeGroupPermission(dbSession, group, permission, requester):
    try:
        group = Group.getByNameOrID(group)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No group found with this ID or name")
    try:
        perm = Permission.getByNameOrID(permission)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No permission found with this ID")
    try:
        relation = dbSession.query(GroupPermission) \
            .filter_by(group_id=group.id, permission_id=perm.id).one()
        dbSession.delete(relation)
        cache.deleteKey(action=perm.method, resource=perm.path)
        log().info('permission ' + perm.name + ' removed from '
                   ' group ' + group.name + ' by ' + requester['username'])
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "Group does not have this permission")
Пример #30
0
def removeUserGroup(dbSession, user, group, requester):
    try:
        user = User.getByNameOrID(user)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No user found with this ID or name")
    try:
        group = Group.getByNameOrID(group)
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "No group found with this ID or name")
    try:
        relation = dbSession.query(UserGroup) \
            .filter_by(user_id=user.id, group_id=group.id).one()
        dbSession.delete(relation)
        cache.deleteKey(userid=user.id)
        log().info('user ' + user.username + ' removed from ' + group.name +
                   ' by ' + requester['username'])
    except sqlalchemy.orm.exc.NoResultFound:
        raise HTTPRequestError(404, "User is not a member of the group")