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
def normalize_ids(where): if not where: return {} if '_id' in where: if type(where['_id']) == dict and "$in" in where['_id']: _ids = [maybe_object_id(_id) for _id in where['_id']['$in']] where['_id']['$in'] = _ids return where elif type(where['_id']) == str: where['_id'] = maybe_object_id(where['_id']) return where return where
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
async def revoke_and_delete_old_active_tokens(self, user): membership = await self.db.memberships.find_one( {'_id': maybe_object_id(user['membership_id'])}) where = { 'membership_id': user['membership_id'], 'user_id': str(user['_id']) } active_tokens_document = self.db.active_tokens.find(where) active_tokens_document = await active_tokens_document.to_list( length=None) for active_token in active_tokens_document: now = datetime.datetime.utcnow() await self.db.revoked_tokens.insert_one({ 'token': active_token['token'], 'refreshable': True if active_token['type'] == 'refresh' else False, 'revoked_at': now, 'token_owner': user, 'expire_date': now + datetime.timedelta(0, membership['refresh_token_ttl'] * 60) }) await self.db.active_tokens.delete_many(where)
async def _update_user_with_token(self, token, user): user_token = copy.deepcopy(token) user_token['created_at'] = datetime.datetime.utcnow() user_token['access_token_status'] = 'active' user_token['refresh_token_status'] = 'active' await self.db.users.update_one({'_id': maybe_object_id(user['_id'])}, { '$set': { 'token': user_token, 'ip_info': user.get('ip_info', {}) } })
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))
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))
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
async def get_application(self, application_id): application = await self.db.applications.find_one({ '_id': maybe_object_id(application_id) }) if not application: raise ErtisError( err_code="errors.applicationNotFound", err_msg="Application was not found in db by given id: <{}>".format(str(application_id)), status_code=404 ) return application
async def _find_role(self, role_id, membership_id): role = await self.db.roles.find_one({ '_id': maybe_object_id(role_id), 'membership_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
async def find_provider(db, membership_id, provider_id): provider = await db.providers.find_one({ '_id': maybe_object_id(provider_id), 'membership_id': membership_id }) if not provider: raise ErtisError( err_code="errors.providerNotFound", err_msg="Provider was not found by given id: <{}>".format( provider_id), status_code=404) return provider
async def _find_user(self, user_id, membership_id): 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
async def find_event(db, membership_id, event_id): event_doc = await db.events.find_one({ '_id': maybe_object_id(event_id), 'membership_id': membership_id }) if not event_doc: raise ErtisError( err_code="errors.notFound", err_msg="Event not found by given id: <{}> in membership: <{}>". format(str(event_id), str(membership_id)), status_code=404) return event_doc
async def update_user_type_with_body(db, user_type_id, membership_id, data): try: await db.user_types.update_one( { '_id': maybe_object_id(user_type_id), 'membership_id': membership_id }, {'$set': data}) except Exception as e: raise ErtisError( err_code="errors.errorOccurredWhileUpdatingUserType", err_msg= "An error occurred while updating user type with provided body", status_code=500, context={'provided_body': data}, reason=str(e)) user_type = await find_user_type(membership_id, db, user_type_id) return user_type
async def update_user_with_body(self, user_id, membership_id, body): try: await self.db.users.update_one( { '_id': maybe_object_id(user_id), 'membership_id': membership_id }, {'$set': body}) 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': body}, reason=str(e)) user = await self._find_user(user_id, membership_id) return user
async def _update_user_token_status(self, user, revoked_token, status): token = user.get('token', {}) for key, val in token.items(): if val != revoked_token: continue field_name = key + '_status' token[field_name] = status await self.db.users.update_one( { '_id': maybe_object_id(user['_id']), 'membership_id': user['membership_id'] }, {'$set': { 'token': token, 'ip_info': user.get('ip_info', {}) }})
async def me(self, application): app_role = await self.db.roles.find_one({ 'slug': application['role'], 'membership_id': application['membership_id'] }) role_permissions = app_role.get('permissions', []) if app_role else [] application['role_permissions'] = role_permissions application['membership_owner'] = app_role.get('membership_owner') membership = await self.db.memberships.find_one({ '_id': maybe_object_id(application['membership_id']) }) application['membership'] = membership application.pop('membership_id', None) application.pop('role_definition', None) return application
async def find_user_type(membership_id, db, user_type_id=None, raise_exec=True): where = {'membership_id': membership_id} if user_type_id: where['_id'] = maybe_object_id(user_type_id) user_type = await db.user_types.find_one(where) if not user_type and raise_exec: raise ErtisError( err_msg="User type not found in membership: <{}>".format( membership_id), err_code="errors.userTypeNotFound", status_code=404) return user_type
async def revoke_token(self, token, settings, event_service, user=None): if not user: user = await self.validate_token(token, settings['application_secret'], verify=True) membership = await self.db.memberships.find_one( {'_id': maybe_object_id(user['membership_id'])}) await ensure_token_is_not_revoked(self.db, token) now = datetime.datetime.utcnow() await self.db.revoked_tokens.insert_one({ 'token': token, 'refreshable': user['decoded_token']['rf'], 'revoked_at': now, 'token_owner': user, 'expire_date': now + datetime.timedelta(0, membership['refresh_token_ttl'] * 60) }) await self._remove_from_active_tokens(user, token, user['decoded_token']['rf']) await asyncio.gather( self._update_user_token_status(user, token, 'revoked'), event_service.on_event( Event( **{ 'document': { 'token': token }, 'prior': {}, 'utilizer': user, 'type': 'TokenRevokedEvent', 'membership_id': user['membership_id'], 'sys': { 'created_at': datetime.datetime.utcnow() } })))
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
async def _reset_user_password(self, user, password): is_expired = check_expire_date_for_reset_token( user['reset_password']['expire_date']) if is_expired: raise ErtisError( err_msg="Provided password reset token has expired", err_code="errors.passwordResetTokenHasExpired", status_code=400) new_password = hash_user_password(password) await self.db.users.update_one({'_id': maybe_object_id(user['_id'])}, { '$set': { 'password': new_password }, '$unset': { 'reset_password': 1 } })
async def on_event(self, event): data = { "_id": getattr(event, '_id', ObjectId()), "type": event.type, "document": getattr(event, 'document'), "prior": getattr(event, 'prior'), "utilizer": getattr(event, 'utilizer'), "membership_id": getattr(event, 'membership_id', None), "custom": getattr(event, 'custom', None), "sys": { "created_at": datetime.datetime.utcnow(), "created_by": getattr(event, 'utilizer').get('username', getattr(event, 'utilizer').get('name')) } } dumped = json.loads(json.dumps(data, default=bson_to_json), object_hook=object_hook) dumped['_id'] = maybe_object_id(dumped['_id']) await self.db.events.insert_one(dumped) logger.info("Persisted event <{}>.".format(event.type))
async def me(self, user): user_role = await self.db.roles.find_one({ 'slug': user['role'], 'membership_id': user['membership_id'] }) user_permissions = user_role.get('permissions', []) if user_role else [] user['role_permissions'] = user_permissions user['membership_owner'] = user_role.get('membership_owner') membership = await self.db.memberships.find_one( {'_id': maybe_object_id(user['membership_id'])}) user['membership'] = membership user.pop('membership_id', None) user.pop('password', None) user.pop('decoded_token', None) user.pop('role_definition', None) return user
async def _update_role_with_body(self, role_id, membership_id, body): try: await self.db.roles.update_one( { '_id': maybe_object_id(role_id), 'membership_id': membership_id }, { '$set': body } ) except Exception as e: raise ErtisError( err_code="errors.errorOccurredWhileUpdatingRole", err_msg="An error occurred while updating role with provided body", status_code=500, context={ 'provided_body': body }, reason=str(e) ) role = await self._find_role(role_id, membership_id) return role
async def update_user(self, exists_user, exists_provider, token, provided_user): providers = exists_user.get('providers', []) is_provider_found = False for provider in providers: if provider['slug'] != exists_provider['slug']: continue is_provider_found = True break if is_provider_found: provider.update({ 'provider_slug': exists_provider['slug'], 'provider_type': exists_provider['type'], 'token': token, 'user_id': provided_user['user_id'] }) else: providers.append({ 'provider': exists_provider['name'], 'token': token, 'user_id': provided_user['user_id'], 'slug': exists_provider['slug'] }) await self.db.users.update_one( { '_id': maybe_object_id(exists_user['_id']), 'membership_id': exists_user['membership_id'] }, {'$set': { 'providers': providers }}) exists_user['providers'] = providers return exists_user
def remove_mock_data(membership, user, role): db.memberships.delete_one({'_id': maybe_object_id(membership['_id'])}) db.users.delete_one({'_id': maybe_object_id(user['_id'])}) db.roles.delete_one({'_id': maybe_object_id(role['_id'])})
def remove_user_type(user_type_id): db.user_types.delete_one({'_id': maybe_object_id(user_type_id)})