Commit 00c0591c authored by Yakubov, Sergey's avatar Yakubov, Sergey
Browse files

Merge branch 'update-tokens' into 'dev'

change tokens to sync with code in PR

See merge request !40
parents b89f5dd9 7999be3c
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -623,7 +623,7 @@ class PulsarJobRunner(AsynchronousJobRunner):
        if self.app.config.nginx_upload_job_files_path:
            endpoint_base = "%s" + self.app.config.nginx_upload_job_files_path + "?job_id=%s&job_key=%s"
        files_endpoint = endpoint_base % (self.galaxy_url, encoded_job_id, job_key)
        secret = self.runner_params.secret or "jobs_token"
        secret = job_destination_params.get("job_secret_base", "jobs_token")
        job_key = self.app.security.encode_id(job_id, kind=secret)
        token_endpoint = "%s/api/jobs/%s/oidc-tokens?job_key=%s" % (self.galaxy_url, encoded_job_id, job_key)
        get_client_kwds = dict(
+0 −1
Original line number Diff line number Diff line
@@ -99,7 +99,6 @@ DeferrableObjectsT = Union[
class ToolEvaluator:
    """An abstraction linking together a tool and a job runtime to evaluate
    tool inputs in an isolated, testable manner.
    tool inputs in an isolated, testable manner.
    """

    app: MinimalToolApp
+1 −3
Original line number Diff line number Diff line
@@ -311,10 +311,8 @@ class GalaxyWebTransaction(base.DefaultWebTransaction, context.ProvidesHistoryCo
            # This is a web request, get or create session.
            self._ensure_valid_session(session_cookie)

        try:
        if hasattr(self.app, "authnz_manager") and self.app.authnz_manager is not None:
            self.app.authnz_manager.refresh_expiring_oidc_tokens(self)  # type: ignore[attr-defined]
        except Exception:
            pass

        if self.galaxy_session:
            # When we've authenticated by session, we have to check the
+42 −52
Original line number Diff line number Diff line
""" API for asynchronous job running mechanisms can use to fetch or put files
related to running and queued jobs.
""" API asynchronous job running mechanisms can use to get a fresh OIDC token.
"""
import logging

from fastapi import Query
from fastapi.responses import PlainTextResponse

from galaxy import (
    exceptions,
    model,
    util,
)
from galaxy.authnz.util import provider_name_to_backend
from galaxy.web import (
    expose_api_raw_anonymous_and_sessionless,
from galaxy.managers.context import ProvidesAppContext
from galaxy.schema.fields import EncodedDatabaseIdField
from galaxy.webapps.galaxy.api import (
    DependsOnTrans,
    Router,
)
from . import BaseGalaxyAPIController

log = logging.getLogger(__name__)
router = Router(tags=["remote files"])


class JobTokensAPIController(BaseGalaxyAPIController):
    """This job token controller allows remote job running mechanisms to
    get a fresh OIDC token that can be used on remote side to authorize user.
    It is not meant to represent part of Galaxy's stable, user
    facing API.
    """

    @expose_api_raw_anonymous_and_sessionless
    def get_token(self, trans, job_id, **kwargs):
        """
        GET /api/jobs/{job_id}/oidc-tokens

        Get a fresh OIDC token

        :type   job_id: str
        :param  job_id: encoded id string of the job
        :type   provider: str
        :param  provider: Path to file.
        :type   job_key: str
        :param  job_key: A key used to authenticate this request as acting on
                         behalf or a job runner for the specified job.

        ..note:
            This API method is intended only for consumption by job runners,
            not end users.

        :rtype:     str
        :returns:   OIDC ID token
        """
        job = self.__authorize_job_access(trans, job_id, **kwargs)
@router.cbv
class FastAPIJobTokens:
    @router.get("/api/jobs/{job_id}/oidc-tokens",
                summary="Get a fresh OIDC token",
                description="Allows remote job running mechanisms to get a fresh OIDC token that "
                            "can be used on remote side to authorize user. "
                            "It is not meant to represent part of Galaxy's stable, user facing API",
                tags=["oidc_tokens"],
                response_class=PlainTextResponse,
                )
    def get_token(
            self,
            job_id: EncodedDatabaseIdField,
            job_key: str = Query(
                description=(
                        "A key used to authenticate this request as acting on"
                        "behalf or a job runner for the specified job"
                ),
            ),
            provider: str = Query(
                description=(
                        "OIDC provider name"
                ),
            ),
            trans: ProvidesAppContext = DependsOnTrans,
    ) -> str:
        job = self.__authorize_job_access(trans, job_id, job_key)
        trans.app.authnz_manager.refresh_expiring_oidc_tokens(trans, job.user)  # type: ignore[attr-defined]
        provider = kwargs.get("provider", None)
        tokens = job.user.get_oidc_tokens(provider_name_to_backend(provider))
        return tokens["id"]

    def __authorize_job_access(self, trans, encoded_job_id, **kwargs):
        for key in ["provider", "job_key"]:
            if key not in kwargs:
                error_message = f"Job files action requires a valid '{key}'."
                raise exceptions.ObjectAttributeMissingException(error_message)

    def __authorize_job_access(self, trans, encoded_job_id, job_key):
        job_id = trans.security.decode_id(encoded_job_id)
        job = trans.sa_session.query(model.Job).get(job_id)
        secret = "jobs_token"
        try:
            for plugin in self.app.job_config.runner_plugins:
                if plugin["id"] == job.job_runner_name:
                    secret = plugin["kwds"]["secret"]
        except:
            raise exceptions.InternalServerError("Cannot get runner secret")
        secret = job.destination_params.get("job_secret_base", "jobs_token")

        job_key = trans.security.encode_id(job_id, kind=secret)
        if not util.safe_str_cmp(kwargs["job_key"], job_key):
            raise exceptions.ItemAccessibilityException("Invalid job_key supplied.")
        job_key_internal = trans.security.encode_id(job_id, kind=secret)
        if not util.safe_str_cmp(job_key_internal, job_key):
            raise exceptions.AuthenticationFailed("Invalid job_key supplied.")

        # Verify job is active
        job = trans.sa_session.query(model.Job).get(job_id)
+0 −7
Original line number Diff line number Diff line
@@ -1127,13 +1127,6 @@ def populate_api_routes(webapp, app):
        path_prefix="/api/jobs/{job_id}",
        parent_resources=dict(member_name="job", collection_name="jobs"),
    )
    webapp.mapper.connect(
        "job_tokens",
        "/api/jobs/{job_id}/oidc-tokens",
        controller="job_tokens",
        action="get_token",
        conditions=dict(method=["GET"]),
    )

    webapp.mapper.resource(
        "port",
Loading