Replace the RS256withJWKS driver with the simplified OpenIDConnect driver. The new driver doesn't require the 'keys_url' parameter, all needed parameters are fetched from the well-known config endpoint inferred from the issuer_id. Add a simple workflow test of the OpenIDConnect driver. Change-Id: I4b0936a587918d6051a4206e20cad68577617e3dchanges/72/701972/11
@ -0,0 +1,7 @@ | |||
--- | |||
deprecations: | |||
- | | |||
Authentication: the JWT driver "RS256withJWKS" is deprecated in favor of the | |||
"OpenIDConnect" driver. The "OpenIDConnect" driver simplifies configuration | |||
for administrators and is better aligned with OIDC configuration discovery | |||
conventions. |
@ -0,0 +1,51 @@ | |||
-----BEGIN RSA PRIVATE KEY----- | |||
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 | |||
-----END RSA PRIVATE KEY----- |
@ -0,0 +1,14 @@ | |||
-----BEGIN PUBLIC KEY----- | |||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsaUXr+7qhvCcHniUgZWz | |||
RHtMqeYMT6obdd7zh6ZKLPVb6G13Sn8aVGM0C+sei6tcCTSBkbb0vjPa/z3pWSF7 | |||
Ozvt68fjUDElJImb7RUC7g8gTU/pHCqW7UKiSjTpggUbgU2Driz45/890CAguG5m | |||
efQ918ITy3MPBR9/yDgPsy7b+Opml6fuodSvm6FCv90CZW+Y3o/bSLvTIUxbVhmj | |||
rDLYk4TpeaGPGV3CxopPEE3KQXoFCE8V7OCK+KB82gUqDD5e3Gk2cIwNoh90nCqc | |||
XCnR7+lGZJxK9D+00xeKBFvhIgD0wlt86T47sr1hwWTT8Ds5lKsE1JhGYs01/9Ia | |||
6QIqpW9sEUa61OMiaROM9IhI5PGUSeOA+9NZokEWfMkYeV1W2ziuKerCpRGjUgHF | |||
e9aDh3T2ssQIznaIvxMgWg10XuVl8bxY4pusPizpMuxOb4R+7KVkSBPd7HnuXOs2 | |||
xatOABoNms7plHbrEVsnpX6hfta3z47H+MkXAuo10/8SKl0MYhQAMo/bYqYaZUY8 | |||
4+tgxN6twZzTj3vf5zDD1N7oYCt+pneRmywQmDJvXXG9uwF6E5BqMxHwNGdB980g | |||
6oJWUqJ1HdQG7ML2r/DHEe06DeIQ2bN87ihiQifgZ1U+oyp0a2zkAOWCDEx4RQqw | |||
c/EE7rmq5NpcSvpbVaXLOeMCAwEAAQ== | |||
-----END PUBLIC KEY----- |
@ -0,0 +1,130 @@ | |||
{ | |||
"issuer": "https://my.oidc.provider/auth/realms/realm-one", | |||
"authorization_endpoint": "https://my.oidc.provider/auth/realms/realm-one/protocol/openid-connect/auth", | |||
"token_endpoint": "https://my.oidc.provider/auth/realms/realm-one/protocol/openid-connect/token", | |||
"token_introspection_endpoint": "https://my.oidc.provider/auth/realms/realm-one/protocol/openid-connect/token/introspect", | |||
"userinfo_endpoint": "https://my.oidc.provider/auth/realms/realm-one/protocol/openid-connect/userinfo", | |||
"end_session_endpoint": "https://my.oidc.provider/auth/realms/realm-one/protocol/openid-connect/logout", | |||
"jwks_uri": "https://my.oidc.provider/auth/realms/realm-one/protocol/openid-connect/certs", | |||
"check_session_iframe": "https://my.oidc.provider/auth/realms/realm-one/protocol/openid-connect/login-status-iframe.html", | |||
"grant_types_supported": [ | |||
"authorization_code", | |||
"implicit", | |||
"refresh_token", | |||
"password", | |||
"client_credentials" | |||
], | |||
"response_types_supported": [ | |||
"code", | |||
"none", | |||
"id_token", | |||
"token", | |||
"id_token token", | |||
"code id_token", | |||
"code token", | |||
"code id_token token" | |||
], | |||
"subject_types_supported": [ | |||
"public", | |||
"pairwise" | |||
], | |||
"id_token_signing_alg_values_supported": [ | |||
"PS384", | |||
"ES384", | |||
"RS384", | |||
"HS256", | |||
"HS512", | |||
"ES256", | |||
"RS256", | |||
"HS384", | |||
"ES512", | |||
"PS256", | |||
"PS512", | |||
"RS512" | |||
], | |||
"id_token_encryption_alg_values_supported": [ | |||
"RSA-OAEP", | |||
"RSA1_5" | |||
], | |||
"id_token_encryption_enc_values_supported": [ | |||
"A128GCM", | |||
"A128CBC-HS256" | |||
], | |||
"userinfo_signing_alg_values_supported": [ | |||
"PS384", | |||
"ES384", | |||
"RS384", | |||
"HS256", | |||
"HS512", | |||
"ES256", | |||
"RS256", | |||
"HS384", | |||
"ES512", | |||
"PS256", | |||
"PS512", | |||
"RS512", | |||
"none" | |||
], | |||
"request_object_signing_alg_values_supported": [ | |||
"PS384", | |||
"ES384", | |||
"RS384", | |||
"ES256", | |||
"RS256", | |||
"ES512", | |||
"PS256", | |||
"PS512", | |||
"RS512", | |||
"none" | |||
], | |||
"response_modes_supported": [ | |||
"query", | |||
"fragment", | |||
"form_post" | |||
], | |||
"registration_endpoint": "https://my.oidc.provider/auth/realms/realm-one/clients-registrations/openid-connect", | |||
"token_endpoint_auth_methods_supported": [ | |||
"private_key_jwt", | |||
"client_secret_basic", | |||
"client_secret_post", | |||
"client_secret_jwt" | |||
], | |||
"token_endpoint_auth_signing_alg_values_supported": [ | |||
"RS256" | |||
], | |||
"claims_supported": [ | |||
"aud", | |||
"sub", | |||
"iss", | |||
"auth_time", | |||
"name", | |||
"given_name", | |||
"family_name", | |||
"preferred_username", | |||
"email" | |||
], | |||
"claim_types_supported": [ | |||
"normal" | |||
], | |||
"claims_parameter_supported": false, | |||
"scopes_supported": [ | |||
"openid", | |||
"web-origins", | |||
"email", | |||
"profile", | |||
"microprofile-jwt", | |||
"address", | |||
"zuul_audience", | |||
"offline_access", | |||
"phone", | |||
"roles" | |||
], | |||
"request_parameter_supported": true, | |||
"request_uri_parameter_supported": true, | |||
"code_challenge_methods_supported": [ | |||
"plain", | |||
"S256" | |||
], | |||
"tls_client_certificate_bound_access_tokens": true, | |||
"introspection_endpoint": "https://my.oidc.provider/auth/realms/realm-one/protocol/openid-connect/token/introspect" | |||
} |
@ -0,0 +1,97 @@ | |||
# Copyright 2020 OpenStack Foundation | |||
# Copyright 2020 Red Hat, Inc. | |||
# | |||
# Licensed under the Apache License, Version 2.0 (the "License"); you may | |||
# not use this file except in compliance with the License. You may obtain | |||
# a copy of the License at | |||
# | |||
# http://www.apache.org/licenses/LICENSE-2.0 | |||
# | |||
# Unless required by applicable law or agreed to in writing, software | |||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||
# License for the specific language governing permissions and limitations | |||
# under the License. | |||
import json | |||
from unittest import mock | |||
import os.path | |||
import jwt | |||
import time | |||
from zuul.driver import auth | |||
from tests.base import BaseTestCase, FIXTURE_DIR | |||
with open(os.path.join(FIXTURE_DIR, | |||
'auth/openid-configuration.json'), 'r') as well_known: | |||
FAKE_WELL_KNOWN_CONFIG = json.loads(well_known.read()) | |||
algo = jwt.algorithms.RSAAlgorithm(jwt.algorithms.RSAAlgorithm.SHA256) | |||
with open(os.path.join(FIXTURE_DIR, | |||
'auth/oidc-key'), 'r') as k: | |||
OIDC_PRIVATE_KEY = algo.prepare_key(k.read().encode('utf-8')) | |||
with open(os.path.join(FIXTURE_DIR, | |||
'auth/oidc-key.pub'), 'r') as k: | |||
pub_key = algo.prepare_key(k.read().encode('utf-8')) | |||
pub_jwk = algo.to_jwk(pub_key) | |||
key = { | |||
"kid": "OwO", | |||
"use": "sig", | |||
"alg": "RS256" | |||
} | |||
key.update(json.loads(pub_jwk)) | |||
# not present in keycloak jwks | |||
if "key_ops" in key: | |||
del key["key_ops"] | |||
FAKE_CERTS = { | |||
"keys": [ | |||
key | |||
] | |||
} | |||
def mock_get(url, params=None, **kwargs): | |||
if url == ("https://my.oidc.provider/auth/realms/realm-one/" | |||
".well-known/openid-configuration"): | |||
return FakeResponse(FAKE_WELL_KNOWN_CONFIG) | |||
elif url == ("https://my.oidc.provider/auth/realms/realm-one/" | |||
"protocol/openid-connect/certs"): | |||
return FakeResponse(FAKE_CERTS) | |||
else: | |||
raise Exception("Unknown URL %s" % url) | |||
class FakeResponse: | |||
def __init__(self, json_dict): | |||
self._json = json_dict | |||
def json(self): | |||
return self._json | |||
class TestOpenIDConnectAuthenticator(BaseTestCase): | |||
def test_decodeToken(self): | |||
"""Test the decoding workflow""" | |||
config = { | |||
'issuer_id': FAKE_WELL_KNOWN_CONFIG['issuer'], | |||
'client_id': 'zuul-app', | |||
'realm': 'realm-one', | |||
} | |||
OIDCAuth = auth.jwt.OpenIDConnectAuthenticator(**config) | |||
payload = { | |||
'iss': FAKE_WELL_KNOWN_CONFIG['issuer'], | |||
'aud': config['client_id'], | |||
'exp': time.time() + 3600, | |||
'sub': 'someone' | |||
} | |||
token = jwt.encode( | |||
payload, | |||
OIDC_PRIVATE_KEY, | |||
algorithm='RS256', | |||
headers={'kid': 'OwO'}) | |||
with mock.patch('requests.get', side_effect=mock_get): | |||
decoded = OIDCAuth.decodeToken(token) | |||
for claim in payload.keys(): | |||
self.assertEqual(payload[claim], decoded[claim]) |