async def verify_contact_method(request, ctx: AppConfig, session: AuthnSession): try: user_profile_id = UUID(request.match_info['user_profile_id']) contact_method_id = UUID(request.match_info['contact_method_id']) except ValueError: raise HTTPNotFound() challenge_response = AuthnChallengeResponseRequest.unmarshal_request( await request.json()) if user_profile_id != session.user_profile_id: raise HTTPForbidden() if challenge_response.challenge_id != session.pending_challenge.challenge_id: raise HTTPBadRequest() session.pending_challenge.attempts += 1 session.changed() if session.pending_challenge.attempts > security.MaxVerificationChallengeAttempts: session.invalidate() raise HTTPForbidden(body="Too many invalid attempts") if challenge_response.passcode != session.pending_challenge.secret: raise HTTPUnauthorized(body="Incorrect passcode") async with op.session(ctx) as ss: await op.user_profile.\ mark_contact_method_verified(contact_method_id, user_profile_id=user_profile_id).\ execute(ss) session.clear_pending_challenge() return HTTPOk()
async def list_distributions(self, request): """ The handler for an HTML listing all distributions Args: request (:class:`aiohttp.web.request`): The request from the client. Returns: :class:`aiohttp.web.HTTPOk`: The response back to the client. """ self._reset_db_connection() def get_base_paths_blocking(): if self.distribution_model is None: base_paths = list( Distribution.objects.values_list("base_path", flat=True)) else: base_paths = list( self.distribution_model.objects.values_list("base_path", flat=True)) return base_paths base_paths = await sync_to_async(get_base_paths_blocking)() directory_list = ["{}/".format(path) for path in base_paths] return HTTPOk(headers={"Content-Type": "text/html"}, body=self.render_html(directory_list))
def _add_acl(self, user_identity_id: str, shared_directory_basename: str): """ Attempt to add acl for the given user id and directory """ try: resp = self.globus_transfer_client.add_endpoint_acl_rule( self.endpoint_id, dict(DATA_TYPE="access", principal=user_identity_id, principal_type='identity', path=shared_directory_basename, permissions='rw'), ) response = {'success': True, 'principal': user_identity_id, 'path': shared_directory_basename, 'permissions': 'rw'} logging.info(response) logging.info('Shared %s with %s\n' % (shared_directory_basename, user_identity_id)) logging.info(response) return response except globus_sdk.TransferAPIError as error: response = {'success': False, 'error_type': 'TransferAPIError', 'error': error.message, 'error_code': error.code, 'shared_directory_basename': shared_directory_basename} logging.error(response) if error.code == "Exists": raise HTTPOk(text=json.dumps(response), content_type='application/json') raise HTTPInternalServerError(text=json.dumps(response), content_type='application/json')
async def get_application(self): test_app = Application() test_app.middlewares.append(logger_middleware) test_app['DISTRIBUTOR_CLIENT'] = TestClient(HTTPOk()) test_app['DISTRIBUTOR_DB'] = prepare_connection() cursor: sqlite3.Cursor = test_app['DISTRIBUTOR_DB'] with open('asynctransaction/data/model/transaction.sql') as prepare_db: prepare_sql = prepare_db.read() cursor.executescript(str(prepare_sql)) with open('asynctransaction/data/model/test_data.sql') as prepare_db: prepare_sql = prepare_db.read() cursor.executescript(str(prepare_sql)) apply_routes(test_app) return test_app
async def list_distributions(self, request): """ The handler for an HTML listing all distributions Args: request (:class:`aiohttp.web.request`): The request from the client. Returns: :class:`aiohttp.web.HTTPOk`: The response back to the client. """ if self.distribution_model is None: distributions = BaseDistribution.objects.only("base_path").all() else: distributions = self.distribution_model.objects.only("base_path").all() directory_list = ['{}/'.format(d.base_path) for d in distributions] return HTTPOk(headers={"Content-Type": "text/html"}, body=self.render_html(directory_list))
async def verify_authn_challenge(request, ctx: AppConfig, session: AuthnSession): if not session.pending_challenge: raise HTTPBadRequest() challenge_response =\ AuthnChallengeResponseRequest.unmarshal_request(await request.json()) if challenge_response.challenge_id != session.pending_challenge.challenge_id: raise ValueError("invalid challenge") session.pending_challenge.attempts += 1 session.changed() if session.pending_challenge.attempts > security.MaxVerificationChallengeAttempts: session.invalidate() raise HTTPForbidden(text="Too many invalid attempts") otp_types = [AuthnChallengeType.Email, AuthnChallengeType.SMS] if session.pending_challenge.challenge_type in otp_types: if challenge_response.passcode != session.pending_challenge.secret: raise HTTPUnauthorized(text="Incorrect passcode") elif session.pending_challenge.challenge_type is AuthnChallengeType.Password: async with op.session(ctx) as ss: result = await op.authn.\ authenticate_user( user_profile_id=session.user_profile_id, password=challenge_response.passcode).\ execute(ss) if not result: raise HTTPUnauthorized(text="Incorrect passcode") else: raise HTTPBadRequest() session.clear_pending_challenge() async with op.session(ctx) as ss: u = await op.user_profile.\ get_user_profile(user_profile_id=session.user_profile_id).\ execute(ss) if session.required_challenges: session.next_challenge_for_user(u) return HTTPAccepted(), session.pending_challenge.get_view('public') session.authenticated = True session.set_role(u.role) session.remove_capabilities(Capability.Authenticate) return HTTPOk()
def _add_acl(self, user_identity_id: str, shared_directory_basename: str): """ Attempt to add acl for the given user id and directory """ try: resp = self.globus_transfer_client.add_endpoint_acl_rule( self.endpoint_id, dict( DATA_TYPE="access", principal=user_identity_id, principal_type="identity", path=shared_directory_basename, permissions="rw", ), ) response = { "success": True, "principal": user_identity_id, "path": shared_directory_basename, "permissions": "rw", } logging.info(response) logging.info("Shared %s with %s\n" % (shared_directory_basename, user_identity_id)) logging.info(response) return response except globus_sdk.TransferAPIError as error: response = { "success": False, "error_type": "TransferAPIError", "error": error.message, "error_code": error.code, "shared_directory_basename": shared_directory_basename, } logging.error(response) if error.code == "Exists": raise HTTPOk(text=json.dumps(response), content_type="application/json") raise HTTPInternalServerError(text=json.dumps(response), content_type="application/json")
async def init_authn_session(request, ctx: AppConfig, session: AuthnSession): sr = InitiateAuthnSessionRequest.unmarshal_request(await request.json()) async with op.session(ctx) as ss: if sr.principal_type is AuthnPrincipalType.Email: u = await op.user_profile.get_user_profile( email_address=sr.principal_name).execute(ss) session.require_challenge(AuthnChallengeType.Email) elif sr.principal_type is AuthnPrincipalType.Phone: u = await op.user_profile.get_user_profile( phone_number=sr.principal_name).execute(ss) session.require_challenge(AuthnChallengeType.SMS) else: raise ValueError(sr.principal_type) if u is None: raise HTTPUnauthorized() session.user_profile_id = u.user_profile_id if u.role in {UserRole.Superuser, UserRole.Manager, UserRole.Creator}: session.require_challenge(AuthnChallengeType.Password) session.add_capabilities(Capability.Authenticate) return HTTPOk()
async def _match_and_stream(self, path, request): """ Match the path and stream results either from the filesystem or by downloading new data. After deciding the client can access the distribution at ``path``, this function calls :meth:`BaseDistribution.content_handler`. If that function returns a not-None result, it is returned to the client. Then the publication linked to the Distribution is used to determine what content should be served. If ``path`` is a directory entry (i.e. not a file), the directory contents are served to the client. This method calls :meth:`BaseDistribution.content_handler_list_directory` to acquire any additional entries the Distribution's content_handler might serve in that directory. If there is an actifact to be served, it is served to the client. If there's no publication, the above paragraph is applied to the lastest repository linked to the matched Distribution. Finally, when nothing is served to client yet, we check if there is a remote for the Distribution. If so, the artifact is pulled from the remote and streamed to the client. Args: path (str): The path component of the URL. request(:class:`~aiohttp.web.Request`): The request to prepare a response for. Raises: PathNotResolved: The path could not be matched to a published file. PermissionError: When not permitted. Returns: :class:`aiohttp.web.StreamResponse` or :class:`aiohttp.web.FileResponse`: The response streamed back to the client. """ distro = self._match_distribution(path) self._permit(request, distro) rel_path = path.lstrip("/") rel_path = rel_path[len(distro.base_path) :] rel_path = rel_path.lstrip("/") content_handler_result = distro.content_handler(rel_path) if content_handler_result is not None: return content_handler_result headers = self.response_headers(rel_path) publication = getattr(distro, "publication", None) if publication: if rel_path == "" or rel_path[-1] == "/": try: index_path = "{}index.html".format(rel_path) publication.published_artifact.get(relative_path=index_path) rel_path = index_path headers = self.response_headers(rel_path) except ObjectDoesNotExist: dir_list = await self.list_directory(None, publication, rel_path) dir_list.update(distro.content_handler_list_directory(rel_path)) return HTTPOk( headers={"Content-Type": "text/html"}, body=self.render_html(dir_list) ) # published artifact try: pa = publication.published_artifact.get(relative_path=rel_path) ca = pa.content_artifact except ObjectDoesNotExist: pass else: if ca.artifact: return self._serve_content_artifact(ca, headers) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca ) # pass-through if publication.pass_through: try: ca = ContentArtifact.objects.get( content__in=publication.repository_version.content, relative_path=rel_path ) except MultipleObjectsReturned: log.error( _("Multiple (pass-through) matches for {b}/{p}"), {"b": distro.base_path, "p": rel_path}, ) raise except ObjectDoesNotExist: pass else: if ca.artifact: return self._serve_content_artifact(ca, headers) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca ) repo_version = getattr(distro, "repository_version", None) repository = getattr(distro, "repository", None) if repository or repo_version: if repository: repo_version = distro.repository.latest_version() if rel_path == "" or rel_path[-1] == "/": try: index_path = "{}index.html".format(rel_path) ContentArtifact.objects.get( content__in=repo_version.content, relative_path=index_path ) rel_path = index_path except ObjectDoesNotExist: dir_list = await self.list_directory(repo_version, None, rel_path) dir_list.update(distro.content_handler_list_directory(rel_path)) return HTTPOk( headers={"Content-Type": "text/html"}, body=self.render_html(dir_list) ) try: ca = ContentArtifact.objects.get( content__in=repo_version.content, relative_path=rel_path ) except MultipleObjectsReturned: log.error( _("Multiple (pass-through) matches for {b}/{p}"), {"b": distro.base_path, "p": rel_path}, ) raise except ObjectDoesNotExist: pass else: if ca.artifact: return self._serve_content_artifact(ca, headers) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca ) if distro.remote: remote = distro.remote.cast() try: url = remote.get_remote_artifact_url(rel_path) ra = RemoteArtifact.objects.get(remote=remote, url=url) ca = ra.content_artifact if ca.artifact: return self._serve_content_artifact(ca, headers) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca ) except ObjectDoesNotExist: ca = ContentArtifact(relative_path=rel_path) ra = RemoteArtifact(remote=remote, url=url, content_artifact=ca) return await self._stream_remote_artifact( request, StreamResponse(headers=headers), ra ) raise PathNotResolved(path)
async def _match_and_stream(self, path, request): """ Match the path and stream results either from the filesystem or by downloading new data. After deciding the client can access the distribution at ``path``, this function calls :meth:`Distribution.content_handler`. If that function returns a not-None result, it is returned to the client. Then the publication linked to the Distribution is used to determine what content should be served. If ``path`` is a directory entry (i.e. not a file), the directory contents are served to the client. This method calls :meth:`Distribution.content_handler_list_directory` to acquire any additional entries the Distribution's content_handler might serve in that directory. If there is an Artifact to be served, it is served to the client. If there's no publication, the above paragraph is applied to the latest repository linked to the matched Distribution. Finally, when nothing is served to client yet, we check if there is a remote for the Distribution. If so, the Artifact is pulled from the remote and streamed to the client. Args: path (str): The path component of the URL. request(:class:`~aiohttp.web.Request`): The request to prepare a response for. Raises: PathNotResolved: The path could not be matched to a published file. PermissionError: When not permitted. Returns: :class:`aiohttp.web.StreamResponse` or :class:`aiohttp.web.FileResponse`: The response streamed back to the client. """ distro = await sync_to_async(self._match_distribution)(path) await sync_to_async(self._permit)(request, distro) rel_path = path.lstrip("/") rel_path = rel_path[len(distro.base_path):] rel_path = rel_path.lstrip("/") content_handler_result = await sync_to_async(distro.content_handler )(rel_path) if content_handler_result is not None: return content_handler_result headers = self.response_headers(rel_path) repository = distro.repository publication = distro.publication repo_version = distro.repository_version if repository: def get_latest_publication_or_version_blocking(): nonlocal repo_version nonlocal publication # Search for publication serving the closest latest version if not publication: try: versions = repository.versions.all() publications = Publication.objects.filter( repository_version__in=versions, complete=True) publication = publications.select_related( "repository_version").latest( "repository_version", "pulp_created") repo_version = publication.repository_version except ObjectDoesNotExist: pass if not repo_version: repo_version = repository.latest_version() await sync_to_async(get_latest_publication_or_version_blocking)() if publication: if rel_path == "" or rel_path[-1] == "/": try: index_path = "{}index.html".format(rel_path) await sync_to_async(publication.published_artifact.get )(relative_path=index_path) rel_path = index_path headers = self.response_headers(rel_path) except ObjectDoesNotExist: dir_list = await self.list_directory( None, publication, rel_path) dir_list.update(await sync_to_async( distro.content_handler_list_directory)(rel_path)) return HTTPOk(headers={"Content-Type": "text/html"}, body=self.render_html(dir_list)) # published artifact try: def get_contentartifact_blocking(): return (publication.published_artifact.select_related( "content_artifact", "content_artifact__artifact", ).get(relative_path=rel_path).content_artifact) ca = await sync_to_async(get_contentartifact_blocking)() except ObjectDoesNotExist: pass else: if ca.artifact: return await self._serve_content_artifact( ca, headers, request) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca) # pass-through if publication.pass_through: try: def get_contentartifact_blocking(): ca = ContentArtifact.objects.select_related( "artifact").get( content__in=publication.repository_version. content, relative_path=rel_path, ) return ca ca = await sync_to_async(get_contentartifact_blocking)() except MultipleObjectsReturned: log.error( _("Multiple (pass-through) matches for {b}/{p}"), { "b": distro.base_path, "p": rel_path }, ) raise except ObjectDoesNotExist: pass else: if ca.artifact: return await self._serve_content_artifact( ca, headers, request) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca) if repo_version and not publication and not distro.SERVE_FROM_PUBLICATION: if rel_path == "" or rel_path[-1] == "/": index_path = "{}index.html".format(rel_path) def contentartifact_exists_blocking(): return ContentArtifact.objects.filter( content__in=repo_version.content, relative_path=index_path).exists() contentartifact_exists = await sync_to_async( contentartifact_exists_blocking)() if contentartifact_exists: rel_path = index_path else: dir_list = await self.list_directory( repo_version, None, rel_path) dir_list.update(await sync_to_async( distro.content_handler_list_directory)(rel_path)) return HTTPOk(headers={"Content-Type": "text/html"}, body=self.render_html(dir_list)) try: def get_contentartifact_blocking(): ca = ContentArtifact.objects.select_related( "artifact").get(content__in=repo_version.content, relative_path=rel_path) return ca ca = await sync_to_async(get_contentartifact_blocking)() except MultipleObjectsReturned: log.error( _("Multiple (pass-through) matches for {b}/{p}"), { "b": distro.base_path, "p": rel_path }, ) raise except ObjectDoesNotExist: pass else: if ca.artifact: return await self._serve_content_artifact( ca, headers, request) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca) if distro.remote: def cast_remote_blocking(): return distro.remote.cast() remote = await sync_to_async(cast_remote_blocking)() try: url = remote.get_remote_artifact_url(rel_path, request=request) def get_remote_artifact_blocking(): ra = RemoteArtifact.objects.select_related( "content_artifact", "content_artifact__artifact", "remote", ).get(remote=remote, url=url) return ra ra = await sync_to_async(get_remote_artifact_blocking)() ca = ra.content_artifact if ca.artifact: return await self._serve_content_artifact( ca, headers, request) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca) except ObjectDoesNotExist: ca = ContentArtifact(relative_path=rel_path) ra = RemoteArtifact(remote=remote, url=url, content_artifact=ca) return await self._stream_remote_artifact( request, StreamResponse(headers=headers), ra) raise PathNotResolved(path)
async def _match_and_stream(self, path, request): """ Match the path and stream results either from the filesystem or by downloading new data. Args: path (str): The path component of the URL. request(:class:`~aiohttp.web.Request`): The request to prepare a response for. Raises: PathNotResolved: The path could not be matched to a published file. PermissionError: When not permitted. Returns: :class:`aiohttp.web.StreamResponse` or :class:`aiohttp.web.FileResponse`: The response streamed back to the client. """ distro = self._match_distribution(path) self._permit(request, distro) rel_path = path.lstrip('/') rel_path = rel_path[len(distro.base_path):] rel_path = rel_path.lstrip('/') headers = self.response_headers(rel_path) publication = getattr(distro, 'publication', None) if publication: if rel_path == '' or rel_path[-1] == '/': try: index_path = '{}index.html'.format(rel_path) publication.published_artifact.get( relative_path=index_path) rel_path = index_path except ObjectDoesNotExist: dir_list = await self.list_directory( None, publication, rel_path) return HTTPOk(headers={"Content-Type": "text/html"}, body=dir_list) # published artifact try: pa = publication.published_artifact.get(relative_path=rel_path) ca = pa.content_artifact except ObjectDoesNotExist: pass else: if ca.artifact: return self._handle_file_response(ca.artifact.file, headers) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca) # pass-through if publication.pass_through: try: ca = ContentArtifact.objects.get( content__in=publication.repository_version.content, relative_path=rel_path) except MultipleObjectsReturned: log.error(_('Multiple (pass-through) matches for {b}/{p}'), { 'b': distro.base_path, 'p': rel_path, }) raise except ObjectDoesNotExist: pass else: if ca.artifact: return self._handle_file_response( ca.artifact.file, headers) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca) repo_version = getattr(distro, 'repository_version', None) repository = getattr(distro, 'repository', None) if repository or repo_version: if repository: repo_version = distro.repository.latest_version() if rel_path == '' or rel_path[-1] == '/': try: index_path = '{}index.html'.format(rel_path) ContentArtifact.objects.get( content__in=repo_version.content, relative_path=index_path) rel_path = index_path except ObjectDoesNotExist: dir_list = await self.list_directory( repo_version, None, rel_path) return HTTPOk(headers={"Content-Type": "text/html"}, body=dir_list) try: ca = ContentArtifact.objects.get( content__in=repo_version.content, relative_path=rel_path) except MultipleObjectsReturned: log.error(_('Multiple (pass-through) matches for {b}/{p}'), { 'b': distro.base_path, 'p': rel_path, }) raise except ObjectDoesNotExist: pass else: return self._handle_file_response(ca.artifact.file, headers) if distro.remote: remote = distro.remote.cast() try: url = remote.get_remote_artifact_url(rel_path) ra = RemoteArtifact.objects.get(remote=remote, url=url) ca = ra.content_artifact if ca.artifact: return self._handle_file_response(ca.artifact.file, headers) else: return await self._stream_content_artifact( request, StreamResponse(headers=headers), ca) except ObjectDoesNotExist: ca = ContentArtifact(relative_path=rel_path) ra = RemoteArtifact(remote=remote, url=url, content_artifact=ca) return await self._stream_remote_artifact( request, StreamResponse(headers=headers), ra) raise PathNotResolved(path)
async def post(self): post_data = await self.request.post() print(post_data) return HTTPOk()
async def error(request): raise HTTPOk(text='hello')