authentik.sources.oauth.tasks

OAuth Source tasks

 1"""OAuth Source tasks"""
 2
 3from json import dumps
 4
 5from django.utils.translation import gettext_lazy as _
 6from dramatiq.actor import actor
 7from requests import RequestException
 8from structlog.stdlib import get_logger
 9
10from authentik.lib.utils.http import get_http_session
11from authentik.sources.oauth.models import OAuthSource
12from authentik.tasks.middleware import CurrentTask
13
14LOGGER = get_logger()
15
16
17@actor(
18    description=_(
19        "Update OAuth sources' config from well_known, and JWKS info from the configured URL."
20    )
21)
22def update_well_known_jwks():
23    self = CurrentTask.get_task()
24    session = get_http_session()
25    for source in OAuthSource.objects.all().exclude(oidc_well_known_url=""):
26        try:
27            well_known_config = session.get(source.oidc_well_known_url)
28            well_known_config.raise_for_status()
29        except RequestException as exc:
30            text = exc.response.text if exc.response else str(exc)
31            LOGGER.warning("Failed to update well_known", source=source, exc=exc, text=text)
32            self.info(f"Failed to update OIDC configuration for {source.slug}")
33            continue
34        config: dict = well_known_config.json()
35        try:
36            dirty = False
37            source_attr_key = (
38                ("authorization_url", "authorization_endpoint"),
39                ("access_token_url", "token_endpoint"),
40                ("profile_url", "userinfo_endpoint"),
41                ("oidc_jwks_url", "jwks_uri"),
42            )
43            for source_attr, config_key in source_attr_key:
44                # Check if we're actually changing anything to only
45                # save when something has changed
46                if config_key not in config:
47                    continue
48                if getattr(source, source_attr, "") != config.get(config_key, ""):
49                    dirty = True
50                setattr(source, source_attr, config[config_key])
51        except (IndexError, KeyError) as exc:
52            LOGGER.warning(
53                "Failed to update well_known",
54                source=source,
55                exc=exc,
56            )
57            self.info(f"Failed to update OIDC configuration for {source.slug}")
58            continue
59        if dirty:
60            LOGGER.info("Updating sources' OpenID Configuration", source=source)
61            source.save()
62
63    for source in OAuthSource.objects.all().exclude(oidc_jwks_url=""):
64        try:
65            jwks_config = session.get(source.oidc_jwks_url)
66            jwks_config.raise_for_status()
67        except RequestException as exc:
68            text = exc.response.text if exc.response else str(exc)
69            LOGGER.warning("Failed to update JWKS", source=source, exc=exc, text=text)
70            self.info(f"Failed to update JWKS for {source.slug}")
71            continue
72        config = jwks_config.json()
73        if dumps(source.oidc_jwks, sort_keys=True) != dumps(config, sort_keys=True):
74            source.oidc_jwks = config
75            LOGGER.info("Updating sources' JWKS", source=source)
76            source.save()
LOGGER = <BoundLoggerLazyProxy(logger=None, wrapper_class=None, processors=None, context_class=None, initial_values={}, logger_factory_args=())>