async def _set_reset_password_to_user(self, user_id, membership_id,
                                          reset_password_model):
        try:
            await self.db.users.update_one(
                {
                    '_id': maybe_object_id(user_id),
                    'membership_id': membership_id
                }, {'$set': reset_password_model})
        except Exception as e:
            raise ErtisError(
                err_code="errors.errorOccurredWhileUpdatingUser",
                err_msg=
                "An error occurred while updating user with provided body",
                status_code=500,
                context={'provided_body': reset_password_model},
                reason=str(e))

        user = await self.db.users.find_one({
            '_id': maybe_object_id(user_id),
            'membership_id': membership_id
        })

        if not user:
            raise ErtisError(
                err_msg="User not found in db by given _id: <{}>".format(
                    user_id),
                err_code="errors.userNotFound",
                status_code=404)

        return user
Exemple #2
0
    def me():
        auth_header = request.headers.get('Authorization')
        if not auth_header:
            raise ErtisError(
                err_code="errors.authorizationHeaderRequired",
                err_msg="Authorization header is required for using ME API",
                status_code=401)
        try:
            auth_header = auth_header.split(' ')
        except Exception as e:
            ErtisError(err_msg="Invalid authorization header provided.",
                       err_code="errors.authorizationHeaderIsInvalid",
                       status_code=401,
                       context={'message': str(e)})

        if len(auth_header) != 2:
            raise ErtisError(err_msg="Bearer token usage is invalid",
                             err_code="errors.invalidBearerTokenUsage",
                             status_code=401)

        token = auth_header[1]

        security_manager = ErtisSecurityManager(app.db)
        user = security_manager.load_user(token,
                                          settings['application_secret'],
                                          settings['verify_token'])
        user.pop('password', None)

        return Response(json.dumps(user, default=bson_to_json),
                        mimetype='application/json',
                        status=200)
    async def validate_token(self, token, secret, verify):
        try:
            decoded = jwt.decode(token,
                                 key=secret,
                                 algorithms='HS256',
                                 verify=verify)

        except ExpiredSignatureError as e:
            raise ErtisError(status_code=401,
                             err_msg="Provided token has expired",
                             err_code="errors.tokenExpiredError",
                             context={'message': str(e)})
        except Exception as e:
            raise ErtisError(status_code=401,
                             err_msg="Provided token is invalid",
                             err_code="errors.tokenIsInvalid",
                             context={'e': str(e)})

        where = {'_id': maybe_object_id(decoded['prn'])}

        user = await self.db.users.find_one(where)
        if not user:
            raise ErtisError(err_msg="User could not be found with this token",
                             err_code="errors.userNotFound",
                             status_code=404)
        user['decoded_token'] = decoded

        return user
Exemple #4
0
    def refresh_token():
        try:
            body = json.loads(request.data)
        except ValueError as e:
            raise ErtisError(err_code="errors.badRequest",
                             err_msg="Invalid json provided",
                             status_code=400,
                             context={'message': str(e)})

        token = body.get('token')
        if not token:
            raise ErtisError(err_msg="Token is required",
                             err_code="errors.tokenRequired",
                             status_code=400)

        security_manager = ErtisSecurityManager(app.db)
        user = security_manager.load_user(token,
                                          settings['application_secret'],
                                          settings['verify_token'])

        new_token = ErtisTokenService.refresh_token(
            user,
            settings['application_secret'],
            settings['token_ttl'],
        )

        response = {'token': new_token}

        return Response(json.dumps(response),
                        mimetype='application/json',
                        status=201)
Exemple #5
0
    async def create_provider(self, resource, utilizer):
        resource['membership_id'] = utilizer['membership_id']
        resource['_id'] = ObjectId()
        resource['sys'] = {
            'created_at': datetime.datetime.utcnow(),
            'created_by': utilizer.get('username', utilizer.get('name'))
        }

        resource['slug'] = slugify(resource['name'])

        default_role = resource.get('default_role')
        exists_role = await self.db.roles.find_one({
            "slug":
            default_role,
            "membership_id":
            utilizer['membership_id']
        })

        if not exists_role:
            raise ErtisError(
                err_code="errors.roleNotFound",
                err_msg="Role not found by given slug: <{}>".format(
                    default_role),
                status_code=400)

        exist_provider = await self.db.providers.find_one({
            'slug':
            resource['slug'],
            'membership_id':
            utilizer['membership_id']
        })

        if exist_provider:
            raise ErtisError(
                err_msg=
                "Provider already exists in db with given generated slug: <{}>"
                .format(resource['slug']),
                err_code="errors.resourceAlreadyExists",
                status_code=409)

        await self.db.providers.insert_one(resource)
        await self.event_service.on_event((Event(
            **{
                'document': resource,
                'prior': {},
                'utilizer': utilizer,
                'type': 'ProviderCreatedEvent',
                'membership_id': utilizer['membership_id'],
                'sys': {
                    'created_at': datetime.datetime.utcnow(),
                    'created_by': utilizer.get('username', utilizer.get(
                        'name'))
                }
            })))
        return resource
Exemple #6
0
async def query(db,
                membership_id=None,
                where=None,
                select=None,
                limit=None,
                skip=None,
                sort=None,
                collection=None):
    try:
        where = _pre_process_where(where)
        if not membership_id:
            raise ErtisError(err_msg="membership_id not passed to query",
                             err_code="errors.internalServerError",
                             status_code=500)

        where.update({'membership_id': membership_id})

        if not select:
            select = None

        if not limit or limit > 500:
            limit = 200

        cursor = db[collection].find(where, select)

        total_count = await cursor.explain()

        if skip:
            cursor.skip(int(skip))

        if limit:
            cursor.limit(int(limit))

        if sort:
            cursor.sort(sort)

        items = await cursor.to_list(None)

        return items, total_count["executionStats"]["nReturned"]

    except OperationFailure as e:
        if e.code in [2, 4]:
            raise ErtisError(context=e.details,
                             err_msg='Please provide valid query...',
                             err_code='errors.badQuery',
                             status_code=400)

        raise
Exemple #7
0
def check_property_name(property_name):
    if not PROPERTY_NAME_REGEX.match(property_name):
        raise ErtisError(err_code="errors.invalidPropertyName",
                         err_msg="Property name should match: " +
                         PROPERTY_NAME_PATTERN,
                         status_code=400,
                         context={"property_name": property_name})
Exemple #8
0
def check_keywords_by_type(schema):
    properties = schema.get('properties', {})
    for property_name, keywords in properties.items():

        check_property_name(property_name)
        check_property_type(property_name, keywords)
        _type = keywords['type']

        valid_keywords = KEYWORDS_BASED_ON_TYPES[_type]
        for keyword, value in keywords.items():
            if keyword == 'type':
                continue

            if keyword not in valid_keywords:
                raise ErtisError(
                    err_code="errors.invalidKeywordForPropertyType",
                    err_msg=
                    "Given <{}> keyword is not allowed for this property type."
                    .format(keyword),
                    status_code=400,
                    context={
                        "property_name": property_name,
                        "property": keywords,
                        "valid_keywords_for_{}_type".format(_type):
                        valid_keywords
                    })
Exemple #9
0
def fill_min_max_fields_if_not_given(resource):
    """
    Auto complete min & max fields to properties of user type
    :param resource:
    :return: resource
    """
    schema = resource.get('schema', {})

    if not schema:
        raise ErtisError(err_code="errors.resourceMustContainSchema",
                         err_msg="Resource must contain schema.",
                         status_code=400,
                         context={"given_resource": resource})

    for prop, keywords in schema.get('properties', {}).items():
        property_type = keywords.get('type')
        if property_type == 'string':
            if 'minLength' not in keywords:
                keywords['minLength'] = 0

            if 'maxLength' not in keywords:
                keywords['maxLength'] = 100

        if property_type in ['integer', 'number']:
            if 'minimum' not in keywords:
                keywords['minimum'] = 0

            if 'maximum' not in keywords:
                keywords['maximum'] = 100

    return resource
Exemple #10
0
    def save(self, document, collection, force=False):
        if "_id" not in document:
            document["_id"] = create_id()
        else:
            document['_id'] = maybe_object_id(document['_id'])
        try:
            if force:
                self.db[collection].replace_one(
                    {'_id': document['_id']},
                    document,
                    upsert=True
                )
            else:
                self.db[collection].save(document)

        except DuplicateKeyError as e:
            raise ErtisError(
                err_code="errors.duplicateKeyError",
                status_code=409,
                err_msg="There is already existing record in collection<{}>.".format(collection),
                context={
                    'collection': collection,
                    'error_message': e.details['errmsg']
                }
            )

        return document
Exemple #11
0
def get_where(request):
    try:
        _json = request.json.get("where", None)
        return _json
    except Exception as ex:
        logging.error(ex)
        raise ErtisError(err_code="errors.BadJsonGiven",
                         err_msg="Body Json is Invalid",
                         status_code=400)
Exemple #12
0
def get_select(request):
    try:
        _json = json.loads(request.data.decode("utf-8")).get("select", None)
        return _json
    except Exception as ex:
        logging.error(ex)
        raise ErtisError(err_code="errors.BadJsonGiven",
                         err_msg="Body Json is Invalid",
                         status_code=400)
Exemple #13
0
async def ensure_utilizer_is_permitted(role, required_permission):
    permissions = role.get('permissions', [])
    has_permission = implies_any(permissions, required_permission)
    if not has_permission:
        raise ErtisError(
            err_code="errors.permissionDenied",
            err_msg="Permission denied for this action <{}>".format(
                required_permission),
            status_code=403)
 def _check_user_status(user):
     if not user.get('status', None) or user['status'] not in [
             'active', 'warning'
     ]:
         raise ErtisError(
             err_msg="User status: <{}> is not valid to generate token".
             format(user.get('status', None)),
             err_code="errors.userStatusIsNotValid",
             status_code=401)
Exemple #15
0
def disallow_predefined_permission_group_operations(resource):
    if resource.get('is_default', None):
        raise ErtisError(
            err_msg="Predefined permission groups cant be deleted or changed",
            err_code="errors.predefinedPermissionGroupsCantBeChangedOrDeleted",
            status_code=403
        )

    return resource
Exemple #16
0
    async def update_user(self, resource_id, data, utilizer, user_type_service,
                          event_service):
        membership_id = utilizer['membership_id']
        resource = await self._find_user(resource_id, membership_id)

        provided_data = pop_non_updatable_fields(data)
        await validate_user_model_by_user_type(membership_id,
                                               resource,
                                               user_type_service,
                                               operation=OperationTypes.UPDATE)

        resource = prepare_user_fields(resource,
                                       utilizer['membership_id'],
                                       data.get('password'),
                                       opt='update')

        _resource = copy.deepcopy(resource)
        _resource.update(provided_data)
        if _resource == resource:
            raise ErtisError(err_code="errors.identicalDocument",
                             err_msg="Identical document error",
                             status_code=409)

        if _resource['username'] != resource['username']:
            await self.revoke_and_delete_old_active_tokens(_resource)

        resource['sys'].update({
            'modified_at':
            datetime.datetime.utcnow(),
            'modified_by':
            utilizer.get('username', utilizer.get('name'))
        })

        provided_data['sys'] = resource['sys']

        resource = await self.update_user_with_body(resource_id,
                                                    utilizer['membership_id'],
                                                    provided_data)
        resource.pop('password')

        resource['_id'] = str(resource['_id'])
        _resource['_id'] = str(_resource['_id'])
        await event_service.on_event((Event(
            **{
                'document': resource,
                'prior': _resource,
                'utilizer': utilizer,
                'type': 'UserUpdatedEvent',
                'membership_id': utilizer['membership_id'],
                'sys': {
                    'created_at': datetime.datetime.utcnow(),
                    'created_by': utilizer.get('username', utilizer.get(
                        'name'))
                }
            })))
        return resource
    def _check_identicality(resource, provided_body):
        _resource = copy.deepcopy(resource)

        resource.update(provided_body)
        if resource == _resource:
            raise ErtisError(err_msg="Identical document error",
                             err_code="errors.identicalDocument",
                             status_code=409)

        return _resource
Exemple #18
0
def raise_resource_not_found_err(collection_name, key):
    raise ErtisError(
        err_code="errors.resourceNotFound",
        status_code=404,
        err_msg="Not found any resource in collection<{}> with given key <{}>".format(collection_name, key),
        context={
            'collection_name': collection_name,
            'key': key
        }
    )
Exemple #19
0
async def ensure_membership_is_exists(db, membership_id, user=None):
    membership = await db.memberships.find_one(
        {'_id': maybe_object_id(membership_id)})

    if not membership:
        raise ErtisError(
            err_msg="Membership not found in db by given membership_id: <{}>".
            format(membership_id),
            err_code="errors.MembershipNotFound",
            status_code=404)

    if user and str(user['membership_id']) != membership_id:
        raise ErtisError(
            err_code="errors.userNotPermittedForMembership",
            err_msg="User is not permitted for membership: <{}>".format(
                membership_id),
            status_code=401)

    return membership
Exemple #20
0
    def site_map():
        auth_header = request.headers.get('Authorization')
        if not auth_header:
            raise ErtisError(
                err_code="errors.authorizationHeaderRequired",
                err_msg="Authorization header is required for using ME API",
                status_code=401)
        try:
            auth_header = auth_header.split(' ')
        except Exception as e:
            ErtisError(err_msg="Invalid authorization header provided.",
                       err_code="errors.authorizationHeaderIsInvalid",
                       status_code=401,
                       context={'message': str(e)})

        if len(auth_header) != 2:
            raise ErtisError(err_msg="Bearer token usage is invalid",
                             err_code="errors.invalidBearerTokenUsage",
                             status_code=401)

        token = auth_header[1]

        security_manager = ErtisSecurityManager(app.db)
        security_manager.load_user(token, settings['application_secret'],
                                   settings['verify_token'])

        links = []
        for rule in app.url_map.iter_rules():
            options = {}
            for arg in rule.arguments:
                options[arg] = "[{0}]".format(arg)

            methods = ','.join(rule.methods)
            url = str(rule)
            if rule.endpoint == 'static':
                continue

            line = "{:50s} {:20s} {}".format(rule.endpoint, methods, url)
            links.append(line)

        return Response(json.dumps(links, default=bson_to_json),
                        mimetype='application/json',
                        status=200)
Exemple #21
0
    async def _find_user_by_query(self, where):
        users = await self.db.users.find(where).to_list(length=None)
        if not users:
            raise ErtisError(
                err_msg="User not found by given query <{}>".format(
                    json.dumps(where)),
                err_code="errors.userNotFound",
                status_code=404)

        return users[0]
Exemple #22
0
def disallow_update_fields(resource, _resource):
    for field in DISALLOW_UPDATE_FILEDS:
        if resource[field] != _resource[field]:
            raise ErtisError(
                err_msg=
                "{} is not updatable. Because its generated automatically by system"
                .format(field),
                err_code="errors.badRequest",
                status_code=400)

    return resource
Exemple #23
0
    async def get_role(self, role_id, membership_id):
        role = await self._find_role(role_id, membership_id)

        if not role:
            raise ErtisError(
                err_msg="Role not found by given _id: <{}> in membership".format(role_id),
                err_code="errors.roleNotFoundError",
                status_code=404
            )

        return role
Exemple #24
0
def ensure_token_provided(auth_header):
    if not auth_header:
        raise ErtisError(
            err_code="errors.authorizationHeaderRequired",
            err_msg="Authorization header is required for using this api<{}>",
            status_code=401)
    try:
        auth_header = auth_header.split(' ')
    except Exception as e:
        ErtisError(err_msg="Invalid authorization header provided.",
                   err_code="errors.authorizationHeaderIsInvalid",
                   status_code=401,
                   context={'message': str(e)})

    if len(auth_header) != 2:
        raise ErtisError(err_msg="Bearer token usage is invalid",
                         err_code="errors.invalidBearerTokenUsage",
                         status_code=401)

    return auth_header
Exemple #25
0
async def remove_provider(db, membership_id, provider_id):
    try:
        await db.providers.delete_one({
            '_id': maybe_object_id(provider_id),
            'membership_id': membership_id
        })
    except Exception as e:
        raise ErtisError(err_msg="An error occurred while deleting provider",
                         err_code="errors.errorOccurredWhileDeletingProvider",
                         status_code=500,
                         context={'_id': provider_id},
                         reason=str(e))
Exemple #26
0
def ensure_keys_of_schema_properties_is_in_valid_keywords(properties):
    for key, val in properties.items():
        if key not in VALID_KEYWORDS:
            raise ErtisError(err_code="errors.invalidKeyword",
                             err_msg="Invalid keyword",
                             status_code=400,
                             context={
                                 "given_keyword": key,
                                 "valid_keywords": VALID_KEYWORDS
                             })

        elif key == 'properties':

            if type(val) != dict:
                raise ErtisError(err_code="errors.invalidKeyword",
                                 err_msg="Properties must be a dictionary",
                                 status_code=400,
                                 context={"given_properties": val})

            for _key, _val in val.items():
                ensure_keys_of_schema_properties_is_in_valid_keywords(_val)
    async def refresh_token(self, do_revoke, refreshable_token, settings,
                            event_service):
        revoke_flag = True if do_revoke == 'true' else False

        user = await self._load_user(refreshable_token,
                                     settings['application_secret'],
                                     settings['verify_token'])

        if user['decoded_token']['rf'] is False:
            raise ErtisError(err_msg="Provided token is not refreshable",
                             err_code="errors.refreshableTokenError",
                             status_code=400)

        membership = await self.db.memberships.find_one(
            {'_id': maybe_object_id(user['membership_id'])})

        await ensure_token_is_not_revoked(self.db, refreshable_token)

        refreshed_token = await self._refresh_token(
            refreshable_token, user, settings['application_secret'],
            membership['token_ttl'], membership['refresh_token_ttl'])

        tasks = [
            self._update_user_with_token(refreshed_token, user),
            event_service.on_event((Event(
                **{
                    'document': refreshed_token,
                    'prior': {},
                    'utilizer': user,
                    'type': 'TokenRefreshedEvent',
                    'membership_id': user['membership_id'],
                    'sys': {
                        'created_at': datetime.datetime.utcnow()
                    }
                })))
        ]

        if revoke_flag:
            tasks.append(
                self.revoke_token(refreshable_token,
                                  settings,
                                  event_service,
                                  user=user))

        tasks.append(
            self._remove_from_active_tokens(user, refreshable_token,
                                            user['decoded_token']['rf']))
        tasks.append(
            self._insert_active_tokens(user, refreshed_token, membership))

        await asyncio.gather(*tasks)

        return refreshed_token
Exemple #28
0
 async def _remove_user(self, user_id, membership_id):
     try:
         await self.db.users.delete_one({
             '_id': maybe_object_id(user_id),
             'membership_id': membership_id
         })
     except Exception as e:
         raise ErtisError(err_msg="An error occurred while deleting user",
                          err_code="errors.errorOccurredWhileDeletingUser",
                          status_code=500,
                          context={'user_id': user_id},
                          reason=str(e))
Exemple #29
0
    async def me_api(request, **kwargs):
        if request.ctx.utilizer_type == UtilizerTypes.USER:
            utilizer = await app.bearer_token_service.me(request.ctx.utilizer)
        elif request.ctx.utilizer_type == UtilizerTypes.APPLICATION:
            utilizer = await app.basic_token_service.me(request.ctx.utilizer)
        else:
            raise ErtisError(err_code="errors.authorizationError",
                             err_msg="Unsupported authorization header",
                             status_code=401)

        return response.json(
            json.loads(json.dumps(utilizer, default=bson_to_json)))
Exemple #30
0
def ensure_db_is_available(generic_service):
    try:
        generic_service.find_one_by(collection='healtcheck')
    except Exception as e:
        raise ErtisError(
            err_msg="Ertis DB is not available",
            err_code="errors.dbConnectionError",
            status_code=500,
            context={
                'message': str(e)
            }
        )