mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-24 02:04:04 +08:00
Accept access token for api auth
This commit is contained in:
@@ -60,6 +60,7 @@ class CustosAuthnzConfiguration:
|
||||
redirect_uri: str
|
||||
ca_bundle: Optional[str]
|
||||
pkce_support: bool
|
||||
accepted_audiences: List[str]
|
||||
extra_params: Optional[dict]
|
||||
authorization_endpoint: Optional[str]
|
||||
token_endpoint: Optional[str]
|
||||
@@ -68,6 +69,8 @@ class CustosAuthnzConfiguration:
|
||||
iam_client_secret: Optional[str]
|
||||
userinfo_endpoint: Optional[str]
|
||||
credential_url: Optional[str]
|
||||
issuer: Optional[str]
|
||||
jwks_uri: Optional[str]
|
||||
|
||||
|
||||
class OIDCAuthnzBase(IdentityProvider):
|
||||
@@ -84,6 +87,7 @@ class OIDCAuthnzBase(IdentityProvider):
|
||||
redirect_uri=oidc_backend_config["redirect_uri"],
|
||||
ca_bundle=oidc_backend_config.get("ca_bundle", None),
|
||||
pkce_support=oidc_backend_config.get("pkce_support", False),
|
||||
accepted_audiences=oidc_backend_config.get("accepted_audiences", []),
|
||||
extra_params={},
|
||||
authorization_endpoint=None,
|
||||
token_endpoint=None,
|
||||
@@ -92,6 +96,8 @@ class OIDCAuthnzBase(IdentityProvider):
|
||||
iam_client_secret=None,
|
||||
userinfo_endpoint=None,
|
||||
credential_url=None,
|
||||
issuer=None,
|
||||
jwks_uri=None,
|
||||
)
|
||||
|
||||
def _decode_token_no_signature(self, token):
|
||||
@@ -457,6 +463,12 @@ class OIDCAuthnzBase(IdentityProvider):
|
||||
self.config.token_endpoint = well_known_oidc_config["token_endpoint"]
|
||||
self.config.userinfo_endpoint = well_known_oidc_config["userinfo_endpoint"]
|
||||
self.config.end_session_endpoint = well_known_oidc_config.get("end_session_endpoint")
|
||||
self.config.issuer = well_known_oidc_config.get("issuer")
|
||||
self.config.jwks_uri = well_known_oidc_config.get("jwks_uri")
|
||||
if self.config.jwks_uri:
|
||||
self.jwks_client = jwt.PyJWKClient(self.config.jwks_uri, cache_jwk_set=True, lifespan=360)
|
||||
else:
|
||||
self.jwks_client = None
|
||||
|
||||
def _get_verify_param(self):
|
||||
"""Return 'ca_bundle' if 'verify_ssl' is true and 'ca_bundle' is configured."""
|
||||
@@ -587,3 +599,25 @@ class OIDCAuthnzBaseCustos(OIDCAuthnzBase):
|
||||
params = {"client_id": self.config.client_id}
|
||||
|
||||
self._load_config(headers, params)
|
||||
|
||||
def match_access_token_to_user(self, sa_session, access_token):
|
||||
signing_key = self.jwks_client.get_signing_key_from_jwt(access_token)
|
||||
decoded_jwt = jwt.decode(
|
||||
access_token,
|
||||
signing_key.key,
|
||||
algorithms=["RS256"],
|
||||
issuer=self.config["issuer"],
|
||||
audience=self.config["accepted_audiences"],
|
||||
options={
|
||||
"verify_signature": True,
|
||||
"verify_exp": True,
|
||||
"verify_nbf": True,
|
||||
"verify_iat": True,
|
||||
"verify_aud": self.config["accepted_audiences"] is not None,
|
||||
"verify_iss": True,
|
||||
},
|
||||
)
|
||||
# jwt verified, we can now fetch the user
|
||||
user_id = decoded_jwt["sub"]
|
||||
custos_authnz_token = self._get_custos_authnz_token(sa_session, user_id, self.config["provider"])
|
||||
return custos_authnz_token.user
|
||||
|
||||
@@ -404,6 +404,33 @@ class AuthnzManager:
|
||||
log.exception(msg)
|
||||
return False, msg, (None, None)
|
||||
|
||||
def find_user_by_access_token_in_provider(self, sa_session, provider, access_token):
|
||||
try:
|
||||
success, message, backend = self._get_authnz_backend(provider)
|
||||
if success is False:
|
||||
msg = f"An error occurred when obtaining user by token with provider `{provider}`: {message}"
|
||||
log.error(msg)
|
||||
return None
|
||||
user = backend.match_access_token_to_user(sa_session, access_token)
|
||||
if user:
|
||||
log.debug(f"Found user: {user} via `{provider}` identity provider")
|
||||
return user
|
||||
return None
|
||||
except Exception as e:
|
||||
msg = f"An error occurred when finding user by token: {e}"
|
||||
log.error(msg)
|
||||
return None
|
||||
|
||||
def find_user_by_access_token(self, sa_session, access_token):
|
||||
# decoded_token = jwt.decode(access_token, options={"verify_signature": False})
|
||||
# issuer = decoded_token["iss"]
|
||||
# audience = decoded_token["aud"]
|
||||
for provider in self.oidc_backends_config:
|
||||
user = self.find_user_by_access_token_in_provider(sa_session, provider, access_token)
|
||||
if user:
|
||||
return user
|
||||
return None
|
||||
|
||||
def logout(self, provider, trans, post_user_logout_href=None):
|
||||
"""
|
||||
Log the user out of the identity provider.
|
||||
|
||||
@@ -295,6 +295,13 @@ class UserManager(base.ModelManager, deletable.PurgableManagerMixin):
|
||||
raise exceptions.AuthenticationFailed("Provided API key has expired.")
|
||||
return provided_key.user
|
||||
|
||||
def by_oidc_access_token(self, access_token: str):
|
||||
if hasattr(self.app, "authnz_manager") and self.app.authnz_manager:
|
||||
user = self.app.authnz_manager.find_user_by_access_token(self.app.model.session, access_token) # type: ignore[attr-defined]
|
||||
return user
|
||||
else:
|
||||
return None
|
||||
|
||||
def check_bootstrap_admin_api_key(self, api_key):
|
||||
bootstrap_admin_api_key = getattr(self.app.config, "bootstrap_admin_api_key", None)
|
||||
if not bootstrap_admin_api_key:
|
||||
|
||||
@@ -532,6 +532,8 @@ class GalaxyWebTransaction(base.DefaultWebTransaction, context.ProvidesHistoryCo
|
||||
"""
|
||||
Authenticate for the API via key or session (if available).
|
||||
"""
|
||||
oidc_access_token = self.request.headers.get("Authorization", None)
|
||||
oidc_token_supplied = self.environ.get("is_api_request", False) and oidc_access_token and "Bearer " in oidc_access_token
|
||||
api_key = self.request.params.get("key", None) or self.request.headers.get("x-api-key", None)
|
||||
secure_id = self.get_cookie(name=session_cookie)
|
||||
api_key_supplied = self.environ.get("is_api_request", False) and api_key
|
||||
@@ -554,6 +556,14 @@ class GalaxyWebTransaction(base.DefaultWebTransaction, context.ProvidesHistoryCo
|
||||
)
|
||||
self.user = None
|
||||
self.galaxy_session = None
|
||||
elif oidc_token_supplied:
|
||||
# Sessionless API transaction with oidc token, we just need to associate a user.
|
||||
oidc_access_token = oidc_access_token.replace("Bearer ", "")
|
||||
try:
|
||||
user = self.user_manager.by_oidc_access_token(oidc_access_token)
|
||||
except AuthenticationFailed as e:
|
||||
return str(e)
|
||||
self.set_user(user)
|
||||
else:
|
||||
# Anonymous API interaction -- anything but @expose_api_anonymous will fail past here.
|
||||
self.user = None
|
||||
|
||||
@@ -36,6 +36,7 @@ from fastapi.security import (
|
||||
APIKeyCookie,
|
||||
APIKeyHeader,
|
||||
APIKeyQuery,
|
||||
HTTPBearer
|
||||
)
|
||||
from fastapi_utils.cbv import cbv
|
||||
from fastapi_utils.inferring_router import InferringRouter
|
||||
@@ -80,6 +81,7 @@ from galaxy.work.context import (
|
||||
api_key_query = APIKeyQuery(name="key", auto_error=False)
|
||||
api_key_header = APIKeyHeader(name="x-api-key", auto_error=False)
|
||||
api_key_cookie = APIKeyCookie(name="galaxysession", auto_error=False)
|
||||
api_bearer_token = HTTPBearer()
|
||||
|
||||
|
||||
def get_app() -> StructuredApp:
|
||||
@@ -139,6 +141,7 @@ def get_api_user(
|
||||
user_manager: UserManager = depends(UserManager),
|
||||
key: str = Security(api_key_query),
|
||||
x_api_key: str = Security(api_key_header),
|
||||
bearer_token: str = Security(api_bearer_token),
|
||||
run_as: Optional[DecodedDatabaseIdField] = Header(
|
||||
default=None,
|
||||
title="Run as User",
|
||||
@@ -149,9 +152,12 @@ def get_api_user(
|
||||
),
|
||||
) -> Optional[User]:
|
||||
api_key = key or x_api_key
|
||||
if not api_key:
|
||||
if api_key:
|
||||
user = user_manager.by_api_key(api_key=api_key)
|
||||
elif bearer_token:
|
||||
user = user_manager.by_oidc_access_token(access_token=bearer_token.credentials)
|
||||
else:
|
||||
return None
|
||||
user = user_manager.by_api_key(api_key=api_key)
|
||||
if run_as:
|
||||
if user_manager.user_can_do_run_as(user):
|
||||
return user_manager.by_id(run_as)
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDVzCCAj+gAwIBAgIUCYRtnqxm/HMxGPpE6VpTmPacZMQwDQYJKoZIhvcNAQEL
|
||||
BQAwOzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxFzAVBgNVBAoM
|
||||
DkdhbGF4eSBQcm9qZWN0MB4XDTIzMDkxMDE5MjAwOFoXDTMzMDkwNzE5MjAwOFow
|
||||
OzELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxFzAVBgNVBAoMDkdh
|
||||
bGF4eSBQcm9qZWN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwF+F
|
||||
iXMW2emcYCvSkiZCh00RDVCcKUfB/i7Q+Rxl0y0HG6sTJWN8ELf4SVR7Zaq3b30w
|
||||
5Yx6tmXY0lfzHkfjRXG/WdAjPDeN8j54RK74UAOM72KFySm/CxX2w5peNyBHA4BX
|
||||
mHKGagIgWH4VUCeJ0z7GkI0ESrdlwOix8Qi8n/l0hjmmS2NOvM1dq1ehNVfOtB4K
|
||||
DF1AANffiCEz2OkAIWwczwVZrgHg7ILvga+g4GnX6SEioEHMCfyk7E6ASbLb2mDj
|
||||
iaIVT1PpwtRLgL+yhC7QRWK66IuurcRAJsLL/isIeZGtF0xfvP5nfiWC07lzYior
|
||||
J3M1I14I7LTpEwmEIwIDAQABo1MwUTAdBgNVHQ4EFgQUbAYXkXuWm8xrOWmsbN5w
|
||||
rQoaLG4wHwYDVR0jBBgwFoAUbAYXkXuWm8xrOWmsbN5wrQoaLG4wDwYDVR0TAQH/
|
||||
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAhvHjMe20W7TO299iI1fEhob4Ihyr
|
||||
tm/4hPPBLC9HSiKokKYvgOU0dK2dh/X7ax9N+ouuDmWYCLCP7AcaWS+HHDVyCv+0
|
||||
j8YNVTaqoD/u9qnvx9/2Zv1TqGaLhw9UPmro0MnUUOMoQRYQKaH3fatidCMQJt2j
|
||||
rzvyrkOuicOr1lRh8Hj1+pdKzar4rmskz9SLkoKRiXjsAUrC1JvQxVxORzf4CoD/
|
||||
eR+ZXeglmAZu8AbwFd/y5OPaHuqsXXHpzg8oJffymOo8L3jp3fZjHFhzUBIHZX2u
|
||||
ZVmpT0COKu69yQ1EoHmKpVFCinYVqbfOsu7s4qWOIt8qpoHPdaElzMD/2w==
|
||||
MIIDkzCCAnugAwIBAgIUQFOsGXws9PtauKu5YhjKynETHVowDQYJKoZIhvcNAQEL
|
||||
BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X
|
||||
DTIzMTAxNTIwMzYyNloXDTMzMTAxMjIwMzYyNlowWTELMAkGA1UEBhMCQVUxEzAR
|
||||
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
|
||||
IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA1rp3CEgQRHmpgK4NFwqxfnhfwJMJeH9rFlSQ1XjN1JPCoICSwNDO
|
||||
g1NWoPGFIImRnZ34X9CLsLeZdlcE/RaThdzwLbwbExl0mKP+rDSLP5/90K3utVD8
|
||||
DWfNSWnCaeXcnhaosl5z8ZhpI5xWN20ajCj3VnrPEbhVDAChxlZvVh+a6uvsEMP0
|
||||
SHOcy0OKe0g2I+x1Yw5J62ApC21pDMuFrjyualkpFEx+b7JY9lNhDjSPW8Iu4wRC
|
||||
7TK0q3MRyyw+er0P7lPobw/khfVTTFmDrc1V8ui+271Bu8L5EvlcOADGM47jgt5j
|
||||
Y3Q77gy7fVKDwFSS6Y2jpQRBgocUq9qN1QIDAQABo1MwUTAdBgNVHQ4EFgQUHlYS
|
||||
w56dunNy35FN3D1JG3ZaZRAwHwYDVR0jBBgwFoAUHlYSw56dunNy35FN3D1JG3Za
|
||||
ZRAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAIoEdTs1B1h9Q
|
||||
WOO+zK5kcd6pbOJnfqvZh44TvQs0DnezENQb4y1lR0USPjgyWSF1VHxP1yrm3H64
|
||||
tx5E7ZeVMO/Uq2x2x9qgEjJfk9y88+RzYmZyR3PvmtTPaf7ftokGi9eZSsj3khP3
|
||||
8YqKDpty5siA+Wd5HkAE/z1xoBAzxQ+D9JNA8miiCkmSMUWuTHXbH8nYaS7a4rWx
|
||||
YvJJXxdAv7JsoLvSVgMgaiee+MtKhMPxDBJoCeuk8nGt8HXZh615JqYSkNDrfzwQ
|
||||
C74INkovM6emUW9ehQ6sOK5ROprM7fXlnrH4Klc9BGRgJu5Lsj0VkrBfN2LQ03D2
|
||||
77yHVwzrgQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAX4WJcxbZ6Zxg
|
||||
K9KSJkKHTRENUJwpR8H+LtD5HGXTLQcbqxMlY3wQt/hJVHtlqrdvfTDljHq2ZdjS
|
||||
V/MeR+NFcb9Z0CM8N43yPnhErvhQA4zvYoXJKb8LFfbDml43IEcDgFeYcoZqAiBY
|
||||
fhVQJ4nTPsaQjQRKt2XA6LHxCLyf+XSGOaZLY068zV2rV6E1V860HgoMXUAA19+I
|
||||
ITPY6QAhbBzPBVmuAeDsgu+Br6DgadfpISKgQcwJ/KTsToBJstvaYOOJohVPU+nC
|
||||
1EuAv7KELtBFYrroi66txEAmwsv+Kwh5ka0XTF+8/md+JYLTuXNiKisnczUjXgjs
|
||||
tOkTCYQjAgMBAAECggEAR4Jah8z11hwuSluP408AlP3zVEE+Q2QOuzdY6/j/6t+G
|
||||
kGTn8ZKJGEfirhOO6SxsEq/1QKcXKH00e4BA+eUcGQDe8fpaVrSJ+d355AIsgMXJ
|
||||
GmVDuRLhFrRb7bsQwaooa6dGKH+N8pMGxg5cStbft1xTAIHC8ik5VFvLZX9raoVw
|
||||
DyfLPg3CtWQID9Jbb4lODqHpjSP5J5v+IskCbbk1sihelEoyFQxka8y1UYglSB7E
|
||||
ntz5j83OqH7qFes/J/g3K8eNvhd3RQZCozzCwjaUUNHpAeTOEmQqdu9joVvQu1pp
|
||||
/iQcwqCb0TSzezUssCRGJNHCVzb0UwBgqCH4stt+8QKBgQD/NZSj0ofY8GA1XMcK
|
||||
s1R9dc/iz6FTeFOz4/36xoTSWoLUFVUpP+1XVVzjV98j65D+CtC6RDBso3tf5Jeo
|
||||
JB0u4Jy86iyVVN8VMgxDLmNsNSPWOdQCfa6ASQRjnlSwa99L+fZ3ITjz71fDR+0E
|
||||
RKMEzRAu9CYS7X6dy2/6ccRP0QKBgQDA+Bo7VE3HMeSQkT8hJWZpEmFseJ8AdM+/
|
||||
2+dwQRFvyBO25hlaaedF3fv52D5S3hiM40tHxSyRmd0qJBQAF5gXVMAtsDD/SZru
|
||||
maAQXGR0gorGuWkBkyKHDpZmYnK4TWAE5Tikp2638Zrtik6gSZtJVaBqz9oj1Z56
|
||||
8elxUxSlswKBgA6lU4dnQJaJjOvjDCUoD3Q3u5tnkPmKUTtknSG0HNE5koJ7SuzY
|
||||
F1XIt1DwrQSRsztxAXN/EExbwWvKYY2rrOUQzM3mnnJfcYH04lFEqz39erYDkZAn
|
||||
CEmiZxcUcgXB2wmwKZ3CkVMmbCHv0cFJ8xUGc6ROLJUvffGuSBnWR47RAoGBAJr0
|
||||
4IOyD/8cVpGswUgJs3I+m1MyjWQdaVKE8RXYensL7KDbp5JOJrSZLKWV+34p8Qb5
|
||||
4tLQSBjnuI0FibYFPFHH8cb+jGoEHlDptnpM5zIUPgKUkvj7wSc5FJdFCSBsqeVk
|
||||
eJboCOXXMvT7MmZOlU9PXlFHdcF+4hOSPUaOU683AoGAdj+MsVxRgnCEmUCl05EJ
|
||||
kd5H8bBFB/vq+Rn3erJFXKLM3vpjBV3Yi2RGC06YGe4L1+krrMIrnEFno3G5yi4Z
|
||||
UWuakpvEDV+esu9s/EcZxv4WtHkQQ+2g3CGqy5BqDefe5YOJrQaCVuwIga1WIV0q
|
||||
JNY3E9bDmpvvDBw+SEzcJug=
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDWuncISBBEeamA
|
||||
rg0XCrF+eF/Akwl4f2sWVJDVeM3Uk8KggJLA0M6DU1ag8YUgiZGdnfhf0Iuwt5l2
|
||||
VwT9FpOF3PAtvBsTGXSYo/6sNIs/n/3Qre61UPwNZ81JacJp5dyeFqiyXnPxmGkj
|
||||
nFY3bRqMKPdWes8RuFUMAKHGVm9WH5rq6+wQw/RIc5zLQ4p7SDYj7HVjDknrYCkL
|
||||
bWkMy4WuPK5qWSkUTH5vslj2U2EONI9bwi7jBELtMrSrcxHLLD56vQ/uU+hvD+SF
|
||||
9VNMWYOtzVXy6L7bvUG7wvkS+Vw4AMYzjuOC3mNjdDvuDLt9UoPAVJLpjaOlBEGC
|
||||
hxSr2o3VAgMBAAECggEAAVbB4RtEyGmqE9WvtexIygrgP68UKxw/tgwl8QtjASwc
|
||||
HsenmXV4bC2ix7ey9E573FBhWQS9hIcRsBxtglIzN22JCGyLDmOlUNRWqdQUC6CW
|
||||
i+yht5+Rb1g/2af6qdsXa7buBshpRjyW1hjvq9SpHO4wv3uCsgapbjzxV5PmQIlt
|
||||
H59GPNcMJTnBLktPfLQ3fNZRjOiE/aFvGoe1YyFNbl5RADzq5YkmuUSFhkBbyNz4
|
||||
wOzhfPr8cnthStFY17GGKmu9nueFoiQhmaiUIIIgeHuSg+0tMZa/PrGsnbfdhoKZ
|
||||
ifvv5Fyi44COEpzcDjfQqQlHAMRPzWnJNdI4phRzoQKBgQDZDJYAt+Eq8sU6ZLVG
|
||||
W47k6WouDro9ndf7ZLd0j39KwQ2GAxyHvL8JNmphVa2T8yrvG6QRTrUJ/t2WpXYl
|
||||
sOfTwPXZh4udMLA+ia0fBHB1X7c2grPlQILLhcvqP5ZUAT3+iOg2j17Aa91B+36g
|
||||
w/OEwgBWfIt4rW8BBfFfjpXtZQKBgQD9Q0KhqoFs2YZk4Dq5tgl5YMFPBKJUbmED
|
||||
B4cRGDqPtI7R9kGDTQ06boLZ1W72iX4eroPKhosYVIJ0ILRUvdApbc+ZVi5iRp7Q
|
||||
lR3fkHdGwJznPH4SLgl6XU3O0JRTSeELDGT5dgJSM2hY7kHLSyZVIsrhsfIxwxVr
|
||||
sLa0hd6PsQKBgCRmjvWZ4QJh6p/LafddvY44cx08TRGuWh2IG5hJxJBV5h22gd9l
|
||||
0SgLXzXpt42bd3TYTuC0MXp2qtTr9O+HRqnlr5WGvOxk0Pn7/vO3u+CDZ+eVbfQh
|
||||
qI3XZ4ZmmaCHAM2iSkd0LfDZZib9tZPiqQF3w7S9eGqJs5cZVwyujghdAoGBAM75
|
||||
g9/JD4KcdtfD5FpXKYD3kKN6HwuvNTsbkMdorJs6rSlr/fhHJRNmsytA4TE8BkUe
|
||||
y/fcYppcnkw3WgiTIyZoZqtiof+QxUOjScmmL8Qzr0bOyh0jYH2O+QKWtVEn5HF6
|
||||
DJ9OUPFKr/FVrZFtdgNHrtQp78u5Ka1busTnTo7RAoGAQFdl7sIDPaO0OIXJEuk9
|
||||
89OBMPQbuMdyQ63FFl8SADCBLuqZLxxNQArVdelPPCVCgi6sL3w23GrGG0LibfrM
|
||||
Ts8FQ5cXXFwa+qvYjskazBsiDAJ5LjHWXFQ9ZAg1dpYwToTalaXKer4TBgxMTnte
|
||||
e05IvlRad2fy9xnaBHoQ0wY=
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -18,12 +18,13 @@ KEYCLOAK_ADMIN_USERNAME = "admin"
|
||||
KEYCLOAK_ADMIN_PASSWORD = "admin"
|
||||
KEYCLOAK_TEST_USERNAME = "gxyuser"
|
||||
KEYCLOAK_TEST_PASSWORD = "gxypass"
|
||||
KEYCLOAK_URL = "https://localhost:8443/realms/gxyrealm"
|
||||
|
||||
|
||||
OIDC_BACKEND_CONFIG_TEMPLATE = """<?xml version="1.0"?>
|
||||
OIDC_BACKEND_CONFIG_TEMPLATE = f"""<?xml version="1.0"?>
|
||||
<OIDC>
|
||||
<provider name="keycloak">
|
||||
<url>https://localhost:8443/realms/gxyrealm</url>
|
||||
<url>{KEYCLOAK_URL}</url>
|
||||
<client_id>gxyclient</client_id>
|
||||
<client_secret>gxytestclientsecret</client_secret>
|
||||
<redirect_uri>$galaxy_url/authnz/keycloak/callback</redirect_uri>
|
||||
@@ -125,6 +126,8 @@ class AbstractTestCases:
|
||||
if "OAUTHLIB_INSECURE_TRANSPORT" in os.environ:
|
||||
cls.saved_oauthlib_insecure_transport = os.environ["OAUTHLIB_INSECURE_TRANSPORT"]
|
||||
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "true"
|
||||
os.environ["REQUESTS_CA_BUNDLE"] = os.path.dirname(__file__) + "/keycloak-server.crt.pem"
|
||||
os.environ["SSL_CERT_FILE"] = os.path.dirname(__file__) + "/keycloak-server.crt.pem"
|
||||
|
||||
@classmethod
|
||||
def restoreOauthlibHttps(cls):
|
||||
@@ -189,3 +192,22 @@ class TestGalaxyOIDCLoginIntegration(AbstractTestCases.BaseKeycloakIntegrationTe
|
||||
# make sure we can no longer request the user
|
||||
response = session.get(self._api_url("users/current"))
|
||||
self._assert_status_code_is(response, 400)
|
||||
|
||||
def test_auth_by_access_token(self):
|
||||
# login at least once
|
||||
self._login_via_keycloak(KEYCLOAK_TEST_USERNAME, KEYCLOAK_TEST_PASSWORD)
|
||||
access_token = self.get_keycloak_access_token()
|
||||
response = self._get("users/current", headers={"Authorization": f"Bearer {access_token}"})
|
||||
self._assert_status_code_is(response, 200)
|
||||
assert response.json()["email"] == "gxyuser@galaxy.org"
|
||||
|
||||
def get_keycloak_access_token(self, username=KEYCLOAK_TEST_USERNAME, password=KEYCLOAK_TEST_PASSWORD):
|
||||
data = {
|
||||
"client_id": "gxyclient",
|
||||
"client_secret": "gxytestclientsecret",
|
||||
"grant_type": "password",
|
||||
"username": username,
|
||||
"password": password
|
||||
}
|
||||
response = requests.post(f"{KEYCLOAK_URL}/protocol/openid-connect/token", data=data, verify=False)
|
||||
return response.json()["access_token"]
|
||||
|
||||
Reference in New Issue
Block a user