auth_oidc/management: add remote jwksets refresh command (#83841)
This commit is contained in:
parent
51820dcdbd
commit
57dd6b1a08
|
@ -23,6 +23,7 @@ cron2 = minute=0,hour=0,week=0 /usr/bin/authentic2-multitenant-manage tenant_com
|
|||
cron2 = minute=0,hour=0,week=0 /usr/bin/authentic2-multitenant-manage tenant_command update-ldap-mapped-roles-list --all-tenants
|
||||
# random sleep: try to avoid multiple machines overloading ldap server
|
||||
cron2 = minute=10,unique=1,harakiri=14400 /bin/bash -c '/bin/sleep $[RANDOM %% 180]' && /usr/bin/authentic2-multitenant-manage tenant_command sync-ldap-users --all-tenants
|
||||
cron2 = minute=20,unique=1,harakiri=14400 /bin/bash -c '/bin/sleep $[RANDOM %% 180]' && /usr/bin/authentic2-multitenant-manage tenant_command oidc-refresh-jwkset-json --all-tenants
|
||||
cron2 = minute=30,hour=5,unique=1,harakiri=14400 /bin/bash -c '/bin/sleep $[RANDOM %% 180]' && /usr/bin/authentic2-multitenant-manage tenant_command deactivate-orphaned-ldap-users --all-tenants
|
||||
cron2 = minute=0,hour=2,unique=1 /usr/bin/authentic2-multitenant-manage tenant_command roles-summary --all-tenants
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ cron2 = minute=5,unique=1 /usr/bin/authentic2-manage cleanupauthentic
|
|||
cron2 = minute=0,hour=5,unique=1 /usr/bin/authentic2-manage clean-unused-accounts
|
||||
cron2 = minute=0,hour=0,week=0,unique=1 /usr/bin/authentic2-manage clean-user-exports
|
||||
cron2 = minute=10,unique=1,harakiri=14400 /usr/bin/authentic2-manage sync-ldap-users
|
||||
cron2 = minute=20,unique=1,harakiri=14400 /usr/bin/authentic2-manage oidc-refresh-jwkset-json
|
||||
cron2 = minute=30,hour=5,unique=1,harakiri=14400 /usr/bin/authentic2-manage deactivate-orphaned-ldap-users
|
||||
|
||||
master = true
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# authentic2 - versatile identity manager
|
||||
# Copyright (C) 2010-2023 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
|
||||
from authentic2.base_commands import LogToConsoleCommand
|
||||
from authentic2_auth_oidc.models import OIDCProvider
|
||||
|
||||
|
||||
class Command(LogToConsoleCommand):
|
||||
loggername = 'authentic2_auth_oidc.models'
|
||||
|
||||
def core_command(self, *args, **kwargs):
|
||||
logger = logging.getLogger(self.loggername)
|
||||
providers = OIDCProvider.objects.exclude(jwkset_url='')
|
||||
if not providers.count():
|
||||
logger.error('no provider whose JWKSet needs refresh, exiting')
|
||||
return
|
||||
logger.info(
|
||||
'got %s provider(s): %s',
|
||||
providers.count(),
|
||||
' '.join(providers.values_list('slug', flat=True)),
|
||||
)
|
||||
for provider in providers:
|
||||
provider.set_jwkset_json_from_url()
|
||||
provider.save()
|
|
@ -24,6 +24,7 @@ from io import BufferedReader, BufferedWriter, TextIOWrapper
|
|||
import httmock
|
||||
import py
|
||||
import pytest
|
||||
import responses
|
||||
import webtest
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
|
@ -895,3 +896,68 @@ def test_oidc_sync_provider(
|
|||
assert User.objects.filter(first_name='Mod', last_name='Ified').count() in range(
|
||||
20 - deletion_number, 21
|
||||
)
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_auth_oidc_refresh_jwkset_json(db, app, admin, settings, caplog):
|
||||
jwkset_url = 'https://www.example.com/common/discovery/v3.0/keys'
|
||||
kid_rsa = '123'
|
||||
kid_ec = '456'
|
||||
|
||||
def generate_remote_jwkset_json():
|
||||
key_rsa = JWK.generate(kty='RSA', size=512, kid=kid_rsa)
|
||||
key_ec = JWK.generate(kty='EC', size=256, kid=kid_ec)
|
||||
jwkset = JWKSet()
|
||||
jwkset.add(key_rsa)
|
||||
jwkset.add(key_ec)
|
||||
return jwkset.export(as_dict=True)
|
||||
|
||||
responses.get(
|
||||
jwkset_url,
|
||||
json={
|
||||
'headers': {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
'status_code': 200,
|
||||
**generate_remote_jwkset_json(),
|
||||
},
|
||||
)
|
||||
|
||||
issuer = ('https://www.example.com',)
|
||||
provider = OIDCProvider.objects.create(
|
||||
ou=get_default_ou(),
|
||||
name='Foo',
|
||||
slug='foo',
|
||||
client_id='abc',
|
||||
client_secret='def',
|
||||
enabled=True,
|
||||
issuer=issuer,
|
||||
authorization_endpoint='%s/authorize' % issuer,
|
||||
token_endpoint='%s/token' % issuer,
|
||||
end_session_endpoint='%s/logout' % issuer,
|
||||
userinfo_endpoint='%s/user_info' % issuer,
|
||||
token_revocation_endpoint='%s/revoke' % issuer,
|
||||
jwkset_url=jwkset_url,
|
||||
idtoken_algo=OIDCProvider.ALGO_RSA,
|
||||
claims_parameter_supported=False,
|
||||
button_label='Connect with Foo',
|
||||
)
|
||||
assert {key['kid'] for key in provider.jwkset_json['keys']} == {'123', '456'}
|
||||
|
||||
kid_rsa = 'abcdefg'
|
||||
kid_ec = 'hijklmn'
|
||||
|
||||
responses.get(
|
||||
jwkset_url,
|
||||
json={
|
||||
'headers': {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
'status_code': 200,
|
||||
**generate_remote_jwkset_json(),
|
||||
},
|
||||
)
|
||||
|
||||
call_command('oidc-refresh-jwkset-json', '-v1')
|
||||
provider.refresh_from_db()
|
||||
assert {key['kid'] for key in provider.jwkset_json['keys']} == {'abcdefg', 'hijklmn'}
|
||||
|
|
Loading…
Reference in New Issue