def project_author_set_listener(project: Project, author: User, old_author: User, initiator: attributes.Event): author.projects.append(project) if old_author not in [NEVER_SET, NO_VALUE]: old_author.projects.remove(project) log.debug( f'{author.email}\'s own project "{project.name}" added also to her full list of projects' )
def private_key(self): """ For lazy loading so we can set key's files beforehand """ if not self._private_key: log.debug( f'Loading private key from {settings.config.jwt_secret_key_file}' ) self._private_key = open(settings.config.jwt_secret_key_file, 'rb').read() return self._private_key
def decode(self, encoded: str) -> dict: try: decoded = jwt.decode( encoded, self.public_key, algorithms='RS256', ) except PyJWTError as e: decoded = None log.debug(f'Decode error for jwt "{encoded}": {e}') return decoded
def users_list(auth_user: AuthUser, email: str = None, per_page: int = PER_PAGE_DEFAULT, page: int = PAGE_DEFAULT, order_by=DEFAULT_ORDER_BY): """ Users list """ order_by_options = { 'createddatetime': { 'field': 'createdDatetime', 'model': db.models.User }, 'email': { 'field': 'email', 'model': db.models.User }, } if not auth_user.is_admin: return 'Only admin can get list of users', HttpCode.unauthorized pager = Paging(dict(page=page, per_page=per_page)) pager.validate() if order_by.strip() == '': order_by = DEFAULT_ORDER_BY if order_by[0] == '-': order_by = order_by[1:] sort_dir = 'desc' if order_by[0] == '+': order_by = order_by[1:] if order_by.lower() not in order_by_options: raise APIError( f'Wrong order by option "{order_by}". Possible options for order by: {", ".join([key for key in order_by_options.keys()])}' ) sort_by = order_by_options[order_by.lower()] order_by = getattr(getattr(sort_by['model'], sort_by['field']), sort_dir)() if email: users = [db.models.User.by_email(email, check=False)] if users[0] is None: users = [] total = len(users) else: users = db.models.User.query().order_by(order_by) total = users.count() users = users.limit(pager.per_page).offset( (pager.page - 1) * pager.per_page) # db.session..query(db.models.User).from_statement( # text("SELECT * FROM users where name=:name")).\ # params(name='john').all() result = [] for user in users: result.append(controllers.models.UserShort().from_orm(user).as_dict) log.debug(f'List of users: {[user["email"] for user in result]}') return {'data': result, 'total': total}
def wrapper(*args, **kwargs): if kwargs['Authorization'] is not None: token_tokens = kwargs['Authorization'].split(" ") token_value = token_tokens[1] if len( token_tokens) > 1 else token_tokens[0] kwargs.update({'auth_token': token.decode(token_value)}) del kwargs['Authorization'] result = handler(*args, **kwargs) if result[1] != 200: log.debug(f'Error response: {result}') return Response(result[0], result[1]) return result[0]
def by_id(cls, id, check=True): """ Find object by ID. If `check` then raise exception if not found. """ result = cls.query().filter(cls.id == id).first() if not result: if check: raise APIError(f'There is no {cls.__name__} with id="{id}"') else: log.debug(f'{cls.__name__} with id="{id}" was not found') return result
def public_key(self): """ For lazy loading so we can set key's files beforehand """ if not self._public_key: log.debug( f'Loading public key from {settings.config.jwt_public_key_file}' ) cert_str = open(settings.config.jwt_public_key_file, 'rb').read() cert_obj = load_pem_x509_certificate(cert_str, default_backend()) self._public_key = cert_obj.public_key() return self._public_key
def options_handler(): """ Handles only unspecified below paths. Others handles by application logic and CORS headers added in after-request flask hook So I this this is unecessary part but I am too lazy to check.. """ log.debug(f'Options were requested for {request.full_path}') response = Response() response.headers['Content-Type'] = 'text/plain; charset=utf-8' response.status_code = 204 if settings.config.web_enableCrossOriginRequests: response.headers['Access-Control-Max-Age'] = 1728000 return response
def test_delete_fail(user_id, admin_token): """ Tries to delete user in empty DB. """ data = api.users_list(admin_token) log.debug('empty db users ' + str(data)) existed_users = set() for user in data: existed_users.add(user['id']) log.debug('existed id ' + str(existed_users)) while str(user_id) in existed_users: user_id += 1 api.delete_user(admin_token, user_id, expected_statuses=[400])
def by_email(email, check=True): """ Find user by email. If `check` then raise exception if not found. """ user = User.query().filter( func.lower(db.models.User.email) == email.lower()).first() if not user: if check: raise APIError(f'There is no user with email "{email}"') else: log.debug(f'User with email "{email}" was not found') return user
def token_to_auth_user_wrapper(*args, **kwargs): if 'auth_token' in kwargs: if kwargs['auth_token'] is not None: log.debug(f'Add auth_user to {handler.__name__}\n{kwargs["auth_token"]}') auth_user = AuthUser(kwargs['auth_token']) args = (auth_user, ) + args journaling.user = auth_user.email else: log.warning('No or wrong user token in request') return 'No or wrong user token in request', HttpCode.no_token del kwargs['auth_token'] try: return handler(*args, **kwargs) finally: journaling.user = None
def make_session(): global session global engine log.debug(f'...Connecting to DB {settings.config.db_uri}...') engine = create_engine(settings.config.db_uri, echo=settings.config.db_sqltrace) session = scoped_session(sessionmaker(bind=engine)) # () Base.metadata.bind = engine if settings.config.db_autometa: refresh_metadata() create_admin_user() session.close() session.get_bind().dispose() log.debug('Connections dropped after creating meta-data') return session
def delete_user(auth_user: AuthUser, user_id: str): """ Deletes user. Returns deleted user id. """ if not auth_user.is_admin: return 'Only admin can delete users', HttpCode.unauthorized user_to_delete = db.models.User.by_id(user_id, check=False) if user_to_delete: log.debug(f'Deletion of user with id={user_id}') db.conn.session.delete(user_to_delete) db.conn.session.commit() return {} else: log.debug(f'No user with id={user_id}') return f'No user with id={user_id}', HttpCode.logic_error
def create_user(auth_user: AuthUser, new_user: NewUser): """ Creates user. Returns new user id. """ if not auth_user.is_admin: return 'Only admin can create users', HttpCode.unauthorized new_user = NewUser(new_user) new_user.validate() user = db.models.User.by_email(new_user.email, check=False) if user: return f'User with email="{new_user["email"]}" already exists', HttpCode.logic_error db_user = db.models.User(**new_user.to_orm) db.conn.session.add(db_user) db.conn.session.commit() log.debug(f'Created user: [{db_user}]') return {'id': db_user.id}
def api_wrapper(*args, **kwargs): try: if bparams: body_obj = request.get_json() for param in bparams: if isinstance(body_obj, dict) and param in body_obj: val = body_obj[param] else: if len(bparams) == 1: val = body_obj else: log.debug( f'No parameter {param} in request:\n{request.data} ({body_obj})' ) return f'No parameter {param} in request:\n{request.data}', HttpCode.wrong_request kwargs.update({param: val}) if request.args: for param in request.args: kwargs.update({param: request.args[param]}) # should be last so nothing could inject decoded token log.debug( f'API wraps handler with args: {inspect.getfullargspec(handler).args}' ) # if 'auth_user' in inspect.getfullargspec(handler).args: """ If the handler expects authenticated user (has 'auth_user' param), we pass token to it. Controller's wrapper (@auth_user) will convert token into auth_user param for the handler. Here is transport layer so we just pass decoded token data to controller's logic. """ kwargs.update({'auth_token': auth_token()}) result = handler(*args, **kwargs) except APPNoTokenError as e: log.debug(f'Wrong token format: {e}', exc_info=True) result = {'status': str(e)}, HttpCode.no_token except Exception as e: log.debug(f'Transport exception: {e}', exc_info=True) result = {'status': str(e)}, HttpCode.wrong_request else: if raw: # Only if success, if exception we return API error return result if isinstance(result, tuple): code = result[1] result = result[0] else: code = HttpCode.success if code not in HttpCode.successes and isinstance(result, str): result = {'status': result} return result, code
def refresh_metadata(): log.debug('Refreshing metadata...') insp = reflection.Inspector.from_engine(session().get_bind()) table_names = insp.get_table_names() if 'users' not in table_names: log.info('Use alchemy to create meta DB') Base.metadata.create_all(session().get_bind()) else: log.info('Use alembic to upgrade meta DB') # In fact settings.config is not None only for test alembic_root = 'src/' if isinstance(settings.config, settings.ConfigTest) else '' alembic_cfg = alembic.config.Config(f'{alembic_root}alembic.ini') alembic_cfg.set_main_option('script_location', f'{alembic_root}alembic') alembic_cfg.set_main_option('sqlalchemy.url', settings.config.db_uri) with session().get_bind().begin() as connection: alembic_cfg.attributes['connection'] = connection alembic.command.upgrade(alembic_cfg, 'head', sql=False)
def create_admin_user(): """ Creates default admin if no users with admin right are in DB """ # if session.info.get('has_flushed', False): users = db.models.User.query().filter( db.models.User.group == controllers.models.UserGroup.ADMIN) if not users.count(): log.debug('!' * 25 + f""" Creating default admin user <{settings.config.default_admin_email}> with password '{settings.config.default_admin_password}' - please change her password """ + '!' * 25) admin_user = db.models.User( email=settings.config.default_admin_email, password=settings.config.default_admin_password, group=controllers.models.UserGroup.ADMIN) session.add(admin_user) session.commit() else: log.debug( f'In db found users with admin roles: {", ".join([user.email for user in users])}' )
def get_token(email: str, password: str, auth_token=None): #todo: remove auth_token """ Returns JWT for the email/password. """ user = db.models.User.by_email(email) if not user: log.debug(f'No user with email={email}') raise APILogicError(f'No user with email={email}') if not password_hash.verify(password, user.password_hash): log.debug(f'Invalid email/password for user {email}') raise APIUnauthError(f'Invalid email/password for user {email}') log.debug(f'Issuing JWT for {email}') payload = { JWT_EXPIRATION: token.datetime2jwt(settings.config.now() + settings.config.token_expiration_delta), JWT_CREATED: token.datetime2jwt(settings.config.now()), JWT_EMAIL: user.email, JWT_GROUP: user.group.value } assert '.' not in payload['exp'] return {'token': token.encode(payload)}