コード例 #1
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_map_iss_sub_pair_to_user_with_no_prior_DRS_access(db_session):
    """
    Test RASOauth2Client.map_iss_sub_pair_to_user when the username passed in
    (e.g. eRA username) does not already exist in the Fence database and that
    user's <iss, sub> combination has not already been mapped through a prior
    DRS access request.
    """
    # reset users table
    db_session.query(User).delete()
    db_session.commit()

    iss = "https://domain.tld"
    sub = "123_abc"
    username = "******"
    email = "*****@*****.**"
    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    assert not query_for_user(db_session, username)
    iss_sub_pair_to_user_records = db_session.query(IssSubPairToUser).all()
    assert len(iss_sub_pair_to_user_records) == 0

    username_to_log_in = ras_client.map_iss_sub_pair_to_user(
        iss, sub, username, email, db_session=db_session)

    assert username_to_log_in == username
    iss_sub_pair_to_user = db_session.query(IssSubPairToUser).get((iss, sub))
    assert iss_sub_pair_to_user.user.username == username
    assert iss_sub_pair_to_user.user.email == email
    iss_sub_pair_to_user_records = db_session.query(IssSubPairToUser).all()
    assert len(iss_sub_pair_to_user_records) == 1
コード例 #2
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_map_iss_sub_pair_to_user_with_prior_DRS_access_and_arborist_error(
        db_session, mock_arborist_requests):
    """
    Test that RASOauth2Client.map_iss_sub_pair_to_user raises an internal error
    when Arborist fails to return a successful response.
    """
    mock_arborist_requests(
        {"arborist/user/123_abcdomain.tld": {
            "PATCH": (None, 500)
        }})

    # reset users table
    db_session.query(User).delete()
    db_session.commit()

    iss = "https://domain.tld"
    sub = "123_abc"
    username = "******"
    email = "*****@*****.**"
    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )
    get_or_create_gen3_user_from_iss_sub(iss, sub, db_session=db_session)

    with pytest.raises(InternalError):
        ras_client.map_iss_sub_pair_to_user(iss,
                                            sub,
                                            username,
                                            email,
                                            db_session=db_session)
コード例 #3
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_map_iss_sub_pair_to_user_with_prior_login_and_prior_DRS_access(
    db_session, ):
    """
    Test RASOauth2Client.map_iss_sub_pair_to_user when the username passed in
    (e.g. eRA username) already exists in the Fence database and that
    user's <iss, sub> combination has already been mapped to a separate user
    created during a prior DRS access request. In this case,
    map_iss_sub_pair_to_user returns the user created from prior DRS/data
    access, rendering the other user (e.g. the eRA one) inaccessible.
    """
    iss = "https://domain.tld"
    sub = "123_abc"
    username = "******"
    email = "*****@*****.**"
    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    # reset users table
    db_session.query(User).delete()
    db_session.commit()

    user = User(username=username, email=email)
    db_session.add(user)
    db_session.commit()

    get_or_create_gen3_user_from_iss_sub(iss, sub, db_session=db_session)
    username_to_log_in = ras_client.map_iss_sub_pair_to_user(
        iss, sub, username, email, db_session=db_session)
    assert username_to_log_in == "123_abcdomain.tld"
    iss_sub_pair_to_user = db_session.query(IssSubPairToUser).get((iss, sub))
    assert iss_sub_pair_to_user.user.username == "123_abcdomain.tld"
コード例 #4
0
    def __init__(
        self,
        chunk_size=None,
        concurrency=None,
        thread_pool_size=None,
        buffer_size=None,
        logger=logger,
    ):
        """
        args:
            chunk_size: size of chunk of users we want to take from each iteration
            concurrency: number of concurrent users going through the visa update flow
            thread_pool_size: number of Docker container CPU used for jwt verifcation
            buffer_size: max size of queue
        """
        self.chunk_size = chunk_size or 10
        self.concurrency = concurrency or 5
        self.thread_pool_size = thread_pool_size or 3
        self.buffer_size = buffer_size or 10
        self.n_workers = self.thread_pool_size + self.concurrency
        self.logger = logger

        self.visa_types = config.get("USERSYNC", {}).get("visa_types", {})

        # Initialize visa clients:
        oidc = config.get("OPENID_CONNECT", {})
        if "ras" not in oidc:
            self.logger.error("RAS client not configured")
            self.ras_client = None
        else:
            self.ras_client = RASClient(
                oidc["ras"],
                HTTP_PROXY=config.get("HTTP_PROXY"),
                logger=logger,
            )
コード例 #5
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_store_refresh_token(db_session):
    """
    Test to check if store_refresh_token replaces the existing token with a new one in the db
    """

    test_user = add_test_ras_user(db_session)
    add_refresh_token(db_session, test_user)
    initial_query = db_session.query(UpstreamRefreshToken).first()
    assert initial_query.refresh_token

    new_refresh_token = "newtoken1234567"
    new_expire = 50000

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    ras_client.store_refresh_token(test_user,
                                   new_refresh_token,
                                   new_expire,
                                   db_session=db_session)

    final_query = db_session.query(UpstreamRefreshToken).first()
    assert final_query.refresh_token == new_refresh_token
    assert final_query.expires == new_expire
コード例 #6
0
def _setup_oidc_clients(app):
    if config["LOGIN_OPTIONS"]:
        enabled_idp_ids = [option["idp"] for option in config["LOGIN_OPTIONS"]]
    else:
        # fall back on "providers"
        enabled_idp_ids = list(
            config.get("ENABLED_IDENTITY_PROVIDERS", {}).get("providers",
                                                             {}).keys())
    oidc = config.get("OPENID_CONNECT", {})

    # Add OIDC client for Google if configured.
    if "google" in oidc:
        app.google_client = GoogleClient(
            config["OPENID_CONNECT"]["google"],
            HTTP_PROXY=config.get("HTTP_PROXY"),
            logger=logger,
        )

    # Add OIDC client for ORCID if configured.
    if "orcid" in oidc:
        app.orcid_client = ORCIDClient(
            config["OPENID_CONNECT"]["orcid"],
            HTTP_PROXY=config.get("HTTP_PROXY"),
            logger=logger,
        )

    # Add OIDC client for RAS if configured.
    if "ras" in oidc:
        app.ras_client = RASClient(
            oidc["ras"],
            HTTP_PROXY=config.get("HTTP_PROXY"),
            logger=logger,
        )

    # Add OIDC client for Synapse if configured.
    if "synapse" in oidc:
        app.synapse_client = SynapseClient(oidc["synapse"],
                                           HTTP_PROXY=config.get("HTTP_PROXY"),
                                           logger=logger)

    # Add OIDC client for Microsoft if configured.
    if "microsoft" in oidc:
        app.microsoft_client = MicrosoftClient(
            config["OPENID_CONNECT"]["microsoft"],
            HTTP_PROXY=config.get("HTTP_PROXY"),
            logger=logger,
        )

    # Add OIDC client for Amazon Cognito if configured.
    if "cognito" in oidc:
        app.cognito_client = CognitoClient(oidc["cognito"],
                                           HTTP_PROXY=config.get("HTTP_PROXY"),
                                           logger=logger)

    # Add OIDC client for multi-tenant fence if configured.
    configured_fence = "fence" in oidc and "fence" in enabled_idp_ids
    if configured_fence:
        app.fence_client = OAuthClient(**config["OPENID_CONNECT"]["fence"])
コード例 #7
0
def test_update_visa_empty_passport_returned(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    rsa_public_key,
    kid,
):
    """
    Test to handle empty passport sent from RAS
    """
    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": "abcd-asdj-sajpiasj12iojd-asnoin",
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": "admin_user",
        "email": "",
        "passport_jwt_v11": "",
    }
    mock_userinfo.return_value = userinfo_response

    test_user = add_test_user(db_session)
    add_visa_manually(db_session, test_user, rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    pkey_cache = {
        "https://stsstg.nih.gov": {
            kid: rsa_public_key,
        }
    }
    ras_client.update_user_visas(test_user, pkey_cache=pkey_cache)

    query_visa = db_session.query(GA4GHVisaV1).first()
    assert query_visa == None
コード例 #8
0
ファイル: test_ras.py プロジェクト: rolinge/fence
def test_update_visa_empty_visa_returned(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    kid,
    kid_2,
):
    """
    Test to check if the db is emptied if the ras userinfo sends back an empty visa
    """

    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": "abcd-asdj-sajpiasj12iojd-asnoin",
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": "admin_user",
        "email": "",
    }
    userinfo_response["ga4gh_passport_v1"] = []

    mock_userinfo.return_value = userinfo_response

    test_user = add_test_user(db_session)
    add_visa_manually(db_session, test_user, rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    ras_client.update_user_visas(test_user)

    query_visa = db_session.query(GA4GHVisaV1).first()
    assert query_visa == None
コード例 #9
0
ファイル: __init__.py プロジェクト: cilogon/fence
def _setup_oidc_clients(app):
    oidc = config.get("OPENID_CONNECT", {})

    # Add OIDC client for Google if configured.
    if "google" in oidc:
        app.google_client = GoogleClient(
            config["OPENID_CONNECT"]["google"],
            HTTP_PROXY=config.get("HTTP_PROXY"),
            logger=logger,
        )

    # Add OIDC client for ORCID if configured.
    if "orcid" in oidc:
        app.orcid_client = ORCIDClient(
            config["OPENID_CONNECT"]["orcid"],
            HTTP_PROXY=config.get("HTTP_PROXY"),
            logger=logger,
        )

    # Add OIDC client for RAS if configured.
    if "ras" in oidc:
        app.ras_client = RASClient(
            oidc["ras"],
            HTTP_PROXY=config.get("HTTP_PROXY"),
            logger=logger,
        )

    # Add OIDC client for Synapse if configured.
    if "synapse" in oidc:
        app.synapse_client = SynapseClient(oidc["synapse"],
                                           HTTP_PROXY=config.get("HTTP_PROXY"),
                                           logger=logger)

    # Add OIDC client for Microsoft if configured.
    if "microsoft" in oidc:
        app.microsoft_client = MicrosoftClient(
            config["OPENID_CONNECT"]["microsoft"],
            HTTP_PROXY=config.get("HTTP_PROXY"),
            logger=logger,
        )

    # Add OIDC client for Amazon Cognito if configured.
    if "cognito" in oidc:
        app.cognito_client = CognitoClient(oidc["cognito"],
                                           HTTP_PROXY=config.get("HTTP_PROXY"),
                                           logger=logger)

    # Add OIDC client for multi-tenant fence if configured.
    if "fence" in oidc:
        app.fence_client = OAuthClient(**config["OPENID_CONNECT"]["fence"])
コード例 #10
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_map_iss_sub_pair_to_user_with_prior_DRS_access(
        db_session, mock_arborist_requests):
    """
    Test RASOauth2Client.map_iss_sub_pair_to_user when the username passed in
    (e.g. eRA username) does not already exist in the Fence database but that
    user's <iss, sub> combination has already been mapped to an existing user
    created during a prior DRS access request. In this case, that
    existing user's username is changed from sub+iss to the username passed
    in.
    """
    mock_arborist_requests(
        {"arborist/user/123_abcdomain.tld": {
            "PATCH": (None, 204)
        }})

    # reset users table
    db_session.query(User).delete()
    db_session.commit()

    iss = "https://domain.tld"
    sub = "123_abc"
    username = "******"
    email = "*****@*****.**"
    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    get_or_create_gen3_user_from_iss_sub(iss, sub, db_session=db_session)
    iss_sub_pair_to_user_records = db_session.query(IssSubPairToUser).all()
    assert len(iss_sub_pair_to_user_records) == 1
    iss_sub_pair_to_user = db_session.query(IssSubPairToUser).get((iss, sub))
    assert iss_sub_pair_to_user.user.username == "123_abcdomain.tld"

    username_to_log_in = ras_client.map_iss_sub_pair_to_user(
        iss, sub, username, email, db_session=db_session)

    assert username_to_log_in == username
    iss_sub_pair_to_user_records = db_session.query(IssSubPairToUser).all()
    assert len(iss_sub_pair_to_user_records) == 1
    iss_sub_pair_to_user = db_session.query(IssSubPairToUser).get((iss, sub))
    assert iss_sub_pair_to_user.user.username == username
    assert iss_sub_pair_to_user.user.email == email
コード例 #11
0
ファイル: visa_update_cronjob.py プロジェクト: uc-cdis/fence
    def __init__(
        self,
        chunk_size=None,
        concurrency=None,
        thread_pool_size=None,
        buffer_size=None,
        logger=logger,
    ):
        """
        args:
            chunk_size: size of chunk of users we want to take from each iteration
            concurrency: number of concurrent users going through the visa update flow
            thread_pool_size: number of Docker container CPU used for jwt verifcation
            buffer_size: max size of queue
        """
        self.chunk_size = chunk_size or 10
        self.concurrency = concurrency or 5
        self.thread_pool_size = thread_pool_size or 3
        self.buffer_size = buffer_size or 10
        self.n_workers = self.thread_pool_size + self.concurrency
        self.logger = logger

        # This job runs without an application context, so it cannot use the
        # current_app.jwt_public_keys cache.
        # This is a simple dict with the same lifetime as the job.
        # When there are many visas from many issuers it will make sense to
        # implement a more persistent cache.
        self.pkey_cache = {}

        self.visa_types = config.get("USERSYNC", {}).get("visa_types", {})

        # Initialize visa clients:
        oidc = config.get("OPENID_CONNECT", {})
        if "ras" not in oidc:
            self.logger.error("RAS client not configured")
            self.ras_client = None
        else:
            self.ras_client = RASClient(
                oidc["ras"],
                HTTP_PROXY=config.get("HTTP_PROXY"),
                logger=logger,
            )
コード例 #12
0
def test_update_visa_token_with_invalid_visa(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    rsa_public_key,
    kid,
):
    """
    Test to check the following case:
    Received visa: [good1, bad2, good3]
    Processed/stored visa: [good1, good3]
    """

    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": "abcd-asdj-sajpiasj12iojd-asnoin",
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": "admin_user",
        "email": "",
    }

    test_user = add_test_user(db_session)
    add_visa_manually(db_session, test_user, rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    new_visa = {
        "iss": "https://stsstg.nih.gov",
        "sub": "abcde12345aspdij",
        "iat": int(time.time()),
        "exp": int(time.time()) + 1000,
        "scope": "openid ga4gh_passport_v1 email profile",
        "jti": "jtiajoidasndokmasdl",
        "txn": "sapidjspa.asipidja",
        "name": "",
        "ga4gh_visa_v1": {
            "type": "https://ras.nih.gov/visas/v1",
            "asserted": int(time.time()),
            "value": "https://nig/passport/dbgap",
            "source": "https://ncbi/gap",
        },
    }

    headers = {"kid": kid}

    encoded_visa = jwt.encode(new_visa,
                              key=rsa_private_key,
                              headers=headers,
                              algorithm="RS256").decode("utf-8")

    passport_header = {
        "type": "JWT",
        "alg": "RS256",
        "kid": kid,
    }
    new_passport = {
        "iss": "https://stsstg.nih.gov",
        "sub": "abcde12345aspdij",
        "iat": int(time.time()),
        "scope": "openid ga4gh_passport_v1 email profile",
        "exp": int(time.time()) + 1000,
    }
    new_passport["ga4gh_passport_v1"] = [encoded_visa, [], encoded_visa]

    encoded_passport = jwt.encode(new_passport,
                                  key=rsa_private_key,
                                  headers=passport_header,
                                  algorithm="RS256").decode("utf-8")
    userinfo_response["passport_jwt_v11"] = encoded_passport

    mock_userinfo.return_value = userinfo_response

    pkey_cache = {
        "https://stsstg.nih.gov": {
            kid: rsa_public_key,
        }
    }
    ras_client.update_user_visas(test_user, pkey_cache=pkey_cache)

    query_visas = db_session.query(GA4GHVisaV1).filter_by(user=test_user).all()
    assert len(query_visas) == 2
    for query_visa in query_visas:
        assert query_visa.ga4gh_visa
        assert query_visa.ga4gh_visa == encoded_visa
コード例 #13
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_update_visa_token_with_invalid_visa(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    rsa_public_key,
    kid,
    mock_arborist_requests,
    no_app_context_no_public_keys,
):
    """
    Test to check the following case:
    Received visa: [good1, bad2, good3]
    Processed/stored visa: [good1, good3]
    """
    mock_arborist_requests(
        {f"arborist/user/{TEST_RAS_USERNAME}": {
            "PATCH": (None, 204)
        }})

    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": TEST_RAS_SUB,
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": TEST_RAS_USERNAME,
        "email": "",
    }

    test_user = add_test_ras_user(db_session)
    existing_encoded_visa, _ = add_visa_manually(db_session, test_user,
                                                 rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    new_visa = {
        "iss": "https://stsstg.nih.gov",
        "sub": TEST_RAS_SUB,
        "iat": int(time.time()),
        "exp": int(time.time()) + 1000,
        "scope": "openid ga4gh_passport_v1 email profile",
        "jti": "jtiajoidasndokmasdl",
        "txn": "sapidjspa.asipidja",
        "name": "",
        "ga4gh_visa_v1": {
            "type": "https://ras.nih.gov/visas/v1",
            "asserted": int(time.time()),
            "value": "https://stsstg.nih.gov/passport/dbgap/v1.1",
            "source": "https://ncbi.nlm.nih.gov/gap",
        },
    }

    headers = {"kid": kid}

    encoded_visa = jwt.encode(new_visa,
                              key=rsa_private_key,
                              headers=headers,
                              algorithm="RS256").decode("utf-8")

    passport_header = {
        "type": "JWT",
        "alg": "RS256",
        "kid": kid,
    }
    new_passport = {
        "iss": "https://stsstg.nih.gov",
        "sub": TEST_RAS_SUB,
        "iat": int(time.time()),
        "scope": "openid ga4gh_passport_v1 email profile",
        "exp": int(time.time()) + 1000,
    }
    new_passport["ga4gh_passport_v1"] = [encoded_visa, [], encoded_visa]

    encoded_passport = jwt.encode(new_passport,
                                  key=rsa_private_key,
                                  headers=passport_header,
                                  algorithm="RS256").decode("utf-8")
    userinfo_response["passport_jwt_v11"] = encoded_passport

    mock_userinfo.return_value = userinfo_response

    pkey_cache = {
        "https://stsstg.nih.gov": {
            kid: rsa_public_key,
        }
    }

    ras_client.update_user_authorization(
        test_user,
        pkey_cache=pkey_cache,
        db_session=db_session,
    )
    # at this point we expect the existing visa to stay around (since it hasn't expired)
    # and 2 new good visas
    query_visas = [
        item.ga4gh_visa
        for item in db_session.query(GA4GHVisaV1).filter_by(user=test_user)
    ]
    assert len(query_visas) == 3
    for query_visa in query_visas:
        assert query_visa == existing_encoded_visa or query_visa == encoded_visa
コード例 #14
0
ファイル: test_ras.py プロジェクト: rolinge/fence
def test_update_visa_token(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    kid,
    kid_2,
):
    """
    Test to check visa table is updated when getting new visa
    """

    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": "abcd-asdj-sajpiasj12iojd-asnoin",
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": "admin_user",
        "email": "",
    }

    test_user = add_test_user(db_session)
    add_visa_manually(db_session, test_user, rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    new_visa = {
        "iss": "https://stsstg.nih.gov",
        "sub": "abcde12345aspdij",
        "iat": int(time.time()),
        "exp": int(time.time()) + 1000,
        "scope": "openid ga4gh_passport_v1 email profile",
        "jti": "jtiajoidasndokmasdl",
        "txn": "sapidjspa.asipidja",
        "name": "",
        "ga4gh_visa_v1": {
            "type": "https://ras.nih.gov/visas/v1",
            "asserted": int(time.time()),
            "value": "https://nig/passport/dbgap",
            "source": "https://ncbi/gap",
        },
    }

    headers = {"kid": kid_2}

    encoded_visa = jwt.encode(new_visa,
                              key=rsa_private_key,
                              headers=headers,
                              algorithm="RS256").decode("utf-8")

    userinfo_response["ga4gh_passport_v1"] = [encoded_visa]
    mock_userinfo.return_value = userinfo_response

    ras_client.update_user_visas(test_user)

    query_visa = db_session.query(GA4GHVisaV1).first()
    assert query_visa.ga4gh_visa
    assert query_visa.ga4gh_visa == encoded_visa
コード例 #15
0
def test_update_visa_fetch_pkey(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    mock_httpx_get,
    db_session,
    rsa_private_key,
    kid,
):
    """
    Test that when the RAS client's pkey cache is empty, the client's
    update_user_visas can fetch and serialize the visa issuer's public keys and
    validate a visa using the correct key.
    """
    mock_discovery.return_value = "https://ras/token_endpoint"
    mock_get_token.return_value = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": "refresh12345abcdefg",
    }
    # New visa that will be returned by userinfo
    new_visa = {
        "iss": "https://stsstg.nih.gov",
        "sub": "abcde12345aspdij",
        "iat": int(time.time()),
        "exp": int(time.time()) + 1000,
        "scope": "openid ga4gh_passport_v1 email profile",
        "jti": "jtiajoidasndokmasdl",
        "txn": "sapidjspa.asipidja",
        "name": "",
        "ga4gh_visa_v1": {
            "type": "https://ras.nih.gov/visas/v1",
            "asserted": int(time.time()),
            "value": "https://nig/passport/dbgap",
            "source": "https://ncbi/gap",
        },
    }
    headers = {"kid": kid}
    encoded_visa = jwt.encode(new_visa,
                              key=rsa_private_key,
                              headers=headers,
                              algorithm="RS256").decode("utf-8")

    passport_header = {
        "type": "JWT",
        "alg": "RS256",
        "kid": kid,
    }
    new_passport = {
        "iss": "https://stsstg.nih.gov",
        "sub": "abcde12345aspdij",
        "iat": int(time.time()),
        "scope": "openid ga4gh_passport_v1 email profile",
        "exp": int(time.time()) + 1000,
        "ga4gh_passport_v1": [encoded_visa],
    }

    encoded_passport = jwt.encode(new_passport,
                                  key=rsa_private_key,
                                  headers=passport_header,
                                  algorithm="RS256").decode("utf-8")

    mock_userinfo.return_value = {
        "passport_jwt_v11": encoded_passport,
    }

    # Mock the call to the jwks endpoint so it returns the test app's keypairs,
    # one of which is rsa_private_key (and its corresponding public key), which
    # we just used to sign new_visa.
    keys = [
        keypair.public_key_to_jwk() for keypair in flask.current_app.keypairs
    ]
    mock_httpx_get.return_value = httpx.Response(200, json={"keys": keys})

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )
    test_user = add_test_user(db_session)

    # Pass in an empty pkey cache so that the client will have to hit the jwks endpoint.
    ras_client.update_user_visas(test_user, pkey_cache={})

    # Check that the new visa passed validation, indicating a successful pkey fetch
    query_visa = db_session.query(GA4GHVisaV1).first()
    assert query_visa.ga4gh_visa == encoded_visa
コード例 #16
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_update_visa_token(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    rsa_public_key,
    kid,
    mock_arborist_requests,
    no_app_context_no_public_keys,
):
    """
    Test to check visa table is updated when getting new visa
    """

    # ensure we don't actually try to reach out to external sites to refresh public keys
    def validate_jwt_no_key_refresh(*args, **kwargs):
        kwargs.update({"attempt_refresh": False})
        return validate_jwt(*args, **kwargs)

    # ensure there is no application context or cached keys
    temp_stored_public_keys = flask.current_app.jwt_public_keys
    temp_app_context = flask.has_app_context
    del flask.current_app.jwt_public_keys

    def return_false():
        return False

    flask.has_app_context = return_false

    mock_arborist_requests(
        {f"arborist/user/{TEST_RAS_USERNAME}": {
            "PATCH": (None, 204)
        }})

    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": TEST_RAS_SUB,
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": TEST_RAS_USERNAME,
        "email": "",
    }

    test_user = add_test_ras_user(db_session)
    existing_encoded_visa, _ = add_visa_manually(db_session, test_user,
                                                 rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    # use default user and passport
    subjects_to_passports = get_subjects_to_passports(
        kid=kid, rsa_private_key=rsa_private_key)

    userinfo_response["passport_jwt_v11"] = subjects_to_passports[
        TEST_RAS_SUB]["encoded_passport"]
    mock_userinfo.return_value = userinfo_response

    pkey_cache = {
        "https://stsstg.nih.gov": {
            kid: rsa_public_key,
        }
    }
    ras_client.update_user_authorization(
        test_user,
        pkey_cache=pkey_cache,
        db_session=db_session,
    )

    # restore public keys and context
    flask.current_app.jwt_public_keys = temp_stored_public_keys
    flask.has_app_context = temp_app_context

    query_visas = [
        item.ga4gh_visa
        for item in db_session.query(GA4GHVisaV1).filter_by(user=test_user)
    ]

    # at this point we expect the existing visa to stay around (since it hasn't expired)
    # and the new visa should also show up
    assert len(query_visas) == 2
    assert existing_encoded_visa in query_visas
    for visa in subjects_to_passports[TEST_RAS_SUB]["encoded_visas"]:
        assert visa in query_visas
コード例 #17
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_update_visa_empty_passport_returned(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    rsa_public_key,
    kid,
    mock_arborist_requests,
):
    """
    Test to handle empty passport sent from RAS
    """
    mock_arborist_requests(
        {f"arborist/user/{TEST_RAS_USERNAME}": {
            "PATCH": (None, 204)
        }})

    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": TEST_RAS_SUB,
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": TEST_RAS_USERNAME,
        "email": "",
        "passport_jwt_v11": "",
    }
    mock_userinfo.return_value = userinfo_response

    test_user = add_test_ras_user(db_session)
    existing_encoded_visa, _ = add_visa_manually(db_session, test_user,
                                                 rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    pkey_cache = {
        "https://stsstg.nih.gov": {
            kid: rsa_public_key,
        }
    }
    ras_client.update_user_authorization(
        test_user,
        pkey_cache=pkey_cache,
        db_session=db_session,
    )

    # at this point we expect the existing visa to stay around (since it hasn't expired)
    # but no new visas
    query_visas = [
        item.ga4gh_visa
        for item in db_session.query(GA4GHVisaV1).filter_by(user=test_user)
    ]
    assert len(query_visas) == 1
    assert existing_encoded_visa in query_visas
コード例 #18
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_update_visa_empty_visa_returned(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    kid,
    mock_arborist_requests,
):
    """
    Test to check if the db is emptied if the ras userinfo sends back an empty visa
    """
    mock_arborist_requests(
        {f"arborist/user/{TEST_RAS_USERNAME}": {
            "PATCH": (None, 204)
        }})

    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": TEST_RAS_SUB,
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": TEST_RAS_USERNAME,
        "email": "",
    }

    passport_header = {
        "type": "JWT",
        "alg": "RS256",
        "kid": kid,
    }
    new_passport = {
        "iss": "https://stsstg.nih.gov",
        "sub": TEST_RAS_SUB,
        "iat": int(time.time()),
        "scope": "openid ga4gh_passport_v1 email profile",
        "exp": int(time.time()) + 1000,
        "ga4gh_passport_v1": [],
    }
    encoded_passport = jwt.encode(new_passport,
                                  key=rsa_private_key,
                                  headers=passport_header,
                                  algorithm="RS256").decode("utf-8")

    userinfo_response["passport_jwt_v11"] = encoded_passport
    mock_userinfo.return_value = userinfo_response

    test_user = add_test_ras_user(db_session)
    existing_encoded_visa, _ = add_visa_manually(db_session, test_user,
                                                 rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    ras_client.update_user_authorization(test_user,
                                         pkey_cache={},
                                         db_session=db_session)

    # at this point we expect the existing visa to stay around (since it hasn't expired)
    # but no new visas
    query_visas = [
        item.ga4gh_visa
        for item in db_session.query(GA4GHVisaV1).filter_by(user=test_user)
    ]
    assert len(query_visas) == 1
    assert existing_encoded_visa in query_visas
コード例 #19
0
ファイル: test_ras.py プロジェクト: uc-cdis/fence
def test_update_visa_fetch_pkey(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    mock_httpx_get,
    db_session,
    rsa_private_key,
    kid,
    mock_arborist_requests,
):
    """
    Test that when the RAS client's pkey cache is empty, the client's
    update_user_authorization can fetch and serialize the visa issuer's public keys and
    validate a visa using the correct key.
    """
    # ensure there is no application context or cached keys
    temp_stored_public_keys = flask.current_app.jwt_public_keys
    temp_app_context = flask.has_app_context
    del flask.current_app.jwt_public_keys

    def return_false():
        return False

    flask.has_app_context = return_false

    mock_arborist_requests(
        {f"arborist/user/{TEST_RAS_USERNAME}": {
            "PATCH": (None, 204)
        }})

    mock_discovery.return_value = "https://ras/token_endpoint"
    mock_get_token.return_value = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": "refresh12345abcdefg",
    }
    # New visa that will be returned by userinfo
    new_visa = {
        "iss": "https://stsstg.nih.gov",
        "sub": TEST_RAS_SUB,
        "iat": int(time.time()),
        "exp": int(time.time()) + 1000,
        "scope": "openid ga4gh_passport_v1 email profile",
        "jti": "jtiajoidasndokmasdl",
        "txn": "sapidjspa.asipidja",
        "name": "",
        "ga4gh_visa_v1": {
            "type": "https://ras.nih.gov/visas/v1",
            "asserted": int(time.time()),
            "value": "https://stsstg.nih.gov/passport/dbgap/v1.1",
            "source": "https://ncbi.nlm.nih.gov/gap",
        },
    }
    headers = {"kid": kid}
    encoded_visa = jwt.encode(new_visa,
                              key=rsa_private_key,
                              headers=headers,
                              algorithm="RS256").decode("utf-8")

    passport_header = {
        "type": "JWT",
        "alg": "RS256",
        "kid": kid,
    }
    new_passport = {
        "iss": "https://stsstg.nih.gov",
        "sub": TEST_RAS_SUB,
        "iat": int(time.time()),
        "scope": "openid ga4gh_passport_v1 email profile",
        "exp": int(time.time()) + 1000,
        "ga4gh_passport_v1": [encoded_visa],
    }

    encoded_passport = jwt.encode(new_passport,
                                  key=rsa_private_key,
                                  headers=passport_header,
                                  algorithm="RS256").decode("utf-8")

    mock_userinfo.return_value = {
        "passport_jwt_v11": encoded_passport,
    }

    # Mock the call to the jwks endpoint so it returns the test app's keypairs,
    # one of which is rsa_private_key (and its corresponding public key), which
    # we just used to sign new_visa.
    keys = [
        keypair.public_key_to_jwk() for keypair in flask.current_app.keypairs
    ]
    mock_httpx_get.return_value = httpx.Response(200, json={"keys": keys})

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )
    test_user = add_test_ras_user(db_session)

    # Pass in an empty pkey cache so that the client will have to hit the jwks endpoint.
    ras_client.update_user_authorization(test_user,
                                         pkey_cache={},
                                         db_session=db_session)

    # restore public keys and context
    flask.current_app.jwt_public_keys = temp_stored_public_keys
    flask.has_app_context = temp_app_context

    # Check that the new visa passed validation, indicating a successful pkey fetch
    query_visas = [
        item.ga4gh_visa
        for item in db_session.query(GA4GHVisaV1).filter_by(user=test_user)
    ]
    for visa in query_visas:
        assert visa == encoded_visa
コード例 #20
0
def test_update_visa_empty_visa_returned(
    mock_discovery,
    mock_get_token,
    mock_userinfo,
    config,
    db_session,
    rsa_private_key,
    kid,
):
    """
    Test to check if the db is emptied if the ras userinfo sends back an empty visa
    """

    mock_discovery.return_value = "https://ras/token_endpoint"
    new_token = "refresh12345abcdefg"
    token_response = {
        "access_token": "abcdef12345",
        "id_token": "id12345abcdef",
        "refresh_token": new_token,
    }
    mock_get_token.return_value = token_response

    userinfo_response = {
        "sub": "abcd-asdj-sajpiasj12iojd-asnoin",
        "name": "",
        "preferred_username": "******",
        "UID": "",
        "UserID": "admin_user",
        "email": "",
    }

    passport_header = {
        "type": "JWT",
        "alg": "RS256",
        "kid": kid,
    }
    new_passport = {
        "iss": "https://stsstg.nih.gov",
        "sub": "abcde12345aspdij",
        "iat": int(time.time()),
        "scope": "openid ga4gh_passport_v1 email profile",
        "exp": int(time.time()) + 1000,
        "ga4gh_passport_v1": [],
    }
    encoded_passport = jwt.encode(new_passport,
                                  key=rsa_private_key,
                                  headers=passport_header,
                                  algorithm="RS256").decode("utf-8")

    userinfo_response["passport_jwt_v11"] = encoded_passport
    mock_userinfo.return_value = userinfo_response

    test_user = add_test_user(db_session)
    add_visa_manually(db_session, test_user, rsa_private_key, kid)
    add_refresh_token(db_session, test_user)

    visa_query = db_session.query(GA4GHVisaV1).filter_by(
        user=test_user).first()
    initial_visa = visa_query.ga4gh_visa
    assert initial_visa

    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    ras_client.update_user_visas(test_user, pkey_cache={})

    query_visa = db_session.query(GA4GHVisaV1).first()
    assert query_visa == None