diff --git a/.github/workflows/release-next-branch.yml b/.github/workflows/release-next-branch.yml new file mode 100644 index 00000000000..b48cd84884c --- /dev/null +++ b/.github/workflows/release-next-branch.yml @@ -0,0 +1,25 @@ +name: authentik-on-release-next-branch + +on: + schedule: + - cron: "0 12 * * *" # every day at noon + workflow_dispatch: + +permissions: + contents: write + +jobs: + update-next: + runs-on: ubuntu-latest + environment: internal-production + steps: + - uses: actions/checkout@v3 + with: + ref: main + - id: main-status + run: | + status=$(curl -fsSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ github.token }}" "https://api.github.com/repos/${{ github.repository }}/commits/HEAD/status" | jq -r '.status') + echo "status=${status}" >> $GITHUB_OUTPUT + - if: ${{ steps.main-status.outputs.status == 'success' }} + run: | + git push origin next --force diff --git a/authentik/core/models.py b/authentik/core/models.py index 3fd8a44a0b1..3104978563a 100644 --- a/authentik/core/models.py +++ b/authentik/core/models.py @@ -376,10 +376,10 @@ def get_meta_icon(self) -> Optional[str]: def get_launch_url(self, user: Optional["User"] = None) -> Optional[str]: """Get launch URL if set, otherwise attempt to get launch URL based on provider.""" url = None - if provider := self.get_provider(): - url = provider.launch_url if self.meta_launch_url: url = self.meta_launch_url + elif provider := self.get_provider(): + url = provider.launch_url if user and url: if isinstance(user, SimpleLazyObject): user._setup() diff --git a/authentik/providers/ldap/api.py b/authentik/providers/ldap/api.py index 96b3a592621..870d66ee50e 100644 --- a/authentik/providers/ldap/api.py +++ b/authentik/providers/ldap/api.py @@ -105,7 +105,9 @@ class Meta: class LDAPOutpostConfigViewSet(ReadOnlyModelViewSet): """LDAPProvider Viewset""" - queryset = LDAPProvider.objects.filter(application__isnull=False) + queryset = LDAPProvider.objects.filter( + Q(application__isnull=False) | Q(backchannel_application__isnull=False) + ) serializer_class = LDAPOutpostConfigSerializer ordering = ["name"] search_fields = ["name"] diff --git a/authentik/providers/ldap/tests/__init__.py b/authentik/providers/ldap/tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/authentik/providers/ldap/tests/test_api.py b/authentik/providers/ldap/tests/test_api.py new file mode 100644 index 00000000000..1271f7640fc --- /dev/null +++ b/authentik/providers/ldap/tests/test_api.py @@ -0,0 +1,52 @@ +"""LDAP Provider API tests""" +from json import loads + +from django.urls import reverse +from rest_framework.test import APITestCase + +from authentik.core.models import Application +from authentik.core.tests.utils import create_test_admin_user, create_test_flow +from authentik.lib.generators import generate_id +from authentik.providers.ldap.models import LDAPProvider + + +class TestLDAPProviderAPI(APITestCase): + """LDAP Provider API tests""" + + def test_outpost_application(self): + """Test outpost-like provider retrieval (direct connection)""" + provider = LDAPProvider.objects.create( + name=generate_id(), + authorization_flow=create_test_flow(), + ) + Application.objects.create( + name=generate_id(), + slug=generate_id(), + provider=provider, + ) + user = create_test_admin_user() + self.client.force_login(user) + res = self.client.get(reverse("authentik_api:ldapprovideroutpost-list")) + self.assertEqual(res.status_code, 200) + data = loads(res.content.decode()) + self.assertEqual(data["pagination"]["count"], 1) + self.assertEqual(len(data["results"]), 1) + + def test_outpost_application_backchannel(self): + """Test outpost-like provider retrieval (backchannel connection)""" + provider = LDAPProvider.objects.create( + name=generate_id(), + authorization_flow=create_test_flow(), + ) + app: Application = Application.objects.create( + name=generate_id(), + slug=generate_id(), + ) + app.backchannel_providers.add(provider) + user = create_test_admin_user() + self.client.force_login(user) + res = self.client.get(reverse("authentik_api:ldapprovideroutpost-list")) + self.assertEqual(res.status_code, 200) + data = loads(res.content.decode()) + self.assertEqual(data["pagination"]["count"], 1) + self.assertEqual(len(data["results"]), 1) diff --git a/authentik/providers/ldap/urls.py b/authentik/providers/ldap/urls.py index fc32e49541e..ae916f9f74d 100644 --- a/authentik/providers/ldap/urls.py +++ b/authentik/providers/ldap/urls.py @@ -2,6 +2,6 @@ from authentik.providers.ldap.api import LDAPOutpostConfigViewSet, LDAPProviderViewSet api_urlpatterns = [ - ("outposts/ldap", LDAPOutpostConfigViewSet), + ("outposts/ldap", LDAPOutpostConfigViewSet, "ldapprovideroutpost"), ("providers/ldap", LDAPProviderViewSet), ] diff --git a/authentik/providers/oauth2/models.py b/authentik/providers/oauth2/models.py index 837940832f8..1357b21011a 100644 --- a/authentik/providers/oauth2/models.py +++ b/authentik/providers/oauth2/models.py @@ -17,6 +17,7 @@ from django.utils.translation import gettext_lazy as _ from jwt import encode from rest_framework.serializers import Serializer +from structlog.stdlib import get_logger from authentik.core.models import ExpiringModel, PropertyMapping, Provider, User from authentik.crypto.models import CertificateKeyPair @@ -26,6 +27,8 @@ from authentik.providers.oauth2.id_token import IDToken, SubModes from authentik.sources.oauth.models import OAuthSource +LOGGER = get_logger() + def generate_client_secret() -> str: """Generate client secret with adequate length""" @@ -251,8 +254,12 @@ def launch_url(self) -> Optional[str]: if self.redirect_uris == "": return None main_url = self.redirect_uris.split("\n", maxsplit=1)[0] - launch_url = urlparse(main_url)._replace(path="") - return urlunparse(launch_url) + try: + launch_url = urlparse(main_url)._replace(path="") + return urlunparse(launch_url) + except ValueError as exc: + LOGGER.warning("Failed to format launch url", exc=exc) + return None @property def component(self) -> str: diff --git a/authentik/providers/oauth2/tests/test_api.py b/authentik/providers/oauth2/tests/test_api.py index 2bd0c5c9820..5aecb3a0ebf 100644 --- a/authentik/providers/oauth2/tests/test_api.py +++ b/authentik/providers/oauth2/tests/test_api.py @@ -1,5 +1,7 @@ """Test OAuth2 API""" from json import loads +from sys import version_info +from unittest import skipUnless from django.urls import reverse from rest_framework.test import APITestCase @@ -42,3 +44,14 @@ def test_setup_urls(self): self.assertEqual(response.status_code, 200) body = loads(response.content.decode()) self.assertEqual(body["issuer"], "http://testserver/application/o/test/") + + # https://github.com/goauthentik/authentik/pull/5918 + @skipUnless(version_info >= (3, 11, 4), "This behaviour is only Python 3.11.4 and up") + def test_launch_url(self): + """Test launch_url""" + self.provider.redirect_uris = ( + "https://[\\d\\w]+.pr.test.goauthentik.io/source/oauth/callback/authentik/\n" + ) + self.provider.save() + self.provider.refresh_from_db() + self.assertIsNone(self.provider.launch_url) diff --git a/authentik/providers/proxy/urls.py b/authentik/providers/proxy/urls.py index fa4706de677..384cc1d6f63 100644 --- a/authentik/providers/proxy/urls.py +++ b/authentik/providers/proxy/urls.py @@ -2,6 +2,6 @@ from authentik.providers.proxy.api import ProxyOutpostConfigViewSet, ProxyProviderViewSet api_urlpatterns = [ - ("outposts/proxy", ProxyOutpostConfigViewSet), + ("outposts/proxy", ProxyOutpostConfigViewSet, "proxyprovideroutpost"), ("providers/proxy", ProxyProviderViewSet), ] diff --git a/authentik/providers/radius/urls.py b/authentik/providers/radius/urls.py index b0c1bd33fb8..9cbef52ef01 100644 --- a/authentik/providers/radius/urls.py +++ b/authentik/providers/radius/urls.py @@ -2,6 +2,6 @@ from authentik.providers.radius.api import RadiusOutpostConfigViewSet, RadiusProviderViewSet api_urlpatterns = [ - ("outposts/radius", RadiusOutpostConfigViewSet), + ("outposts/radius", RadiusOutpostConfigViewSet, "radiusprovideroutpost"), ("providers/radius", RadiusProviderViewSet), ] diff --git a/authentik/root/middleware.py b/authentik/root/middleware.py index 353a58ff02f..a6b0d9c7e44 100644 --- a/authentik/root/middleware.py +++ b/authentik/root/middleware.py @@ -1,5 +1,4 @@ """Dynamically set SameSite depending if the upstream connection is TLS or not""" -from functools import lru_cache from hashlib import sha512 from time import time from timeit import default_timer @@ -17,16 +16,10 @@ from structlog.stdlib import get_logger from authentik.lib.utils.http import get_client_ip -from authentik.root.install_id import get_install_id LOGGER = get_logger("authentik.asgi") ACR_AUTHENTIK_SESSION = "goauthentik.io/core/default" - - -@lru_cache -def get_signing_hash(): - """Get cookie JWT signing hash""" - return sha512(get_install_id().encode()).hexdigest() +SIGNING_HASH = sha512(settings.SECRET_KEY.encode()).hexdigest() class SessionMiddleware(UpstreamSessionMiddleware): @@ -54,7 +47,7 @@ def decode_session_key(key: str) -> str: # for testing setups, where the session is directly set session_key = key if settings.TEST else None try: - session_payload = decode(key, get_signing_hash(), algorithms=["HS256"]) + session_payload = decode(key, SIGNING_HASH, algorithms=["HS256"]) session_key = session_payload["sid"] except (KeyError, PyJWTError): pass @@ -121,7 +114,7 @@ def process_response(self, request: HttpRequest, response: HttpResponse) -> Http } if request.user.is_authenticated: payload["sub"] = request.user.uid - value = encode(payload=payload, key=get_signing_hash()) + value = encode(payload=payload, key=SIGNING_HASH) if settings.TEST: value = request.session.session_key response.set_cookie( diff --git a/authentik/sources/ldap/auth.py b/authentik/sources/ldap/auth.py index 5cc21f99184..508aacb3eac 100644 --- a/authentik/sources/ldap/auth.py +++ b/authentik/sources/ldap/auth.py @@ -57,13 +57,13 @@ def auth_user_by_bind(self, source: LDAPSource, user: User, password: str) -> Op # Try to bind as new user LOGGER.debug("Attempting to bind as user", user=user) try: - temp_connection = source.connection( + # source.connection also attempts to bind + source.connection( connection_kwargs={ "user": user.attributes.get(LDAP_DISTINGUISHED_NAME), "password": password, } ) - temp_connection.bind() return user except LDAPInvalidCredentialsResult as exc: LOGGER.debug("invalid LDAP credentials", user=user, exc=exc) diff --git a/authentik/sources/ldap/models.py b/authentik/sources/ldap/models.py index ad08880d7d5..4a6c2fd2e3b 100644 --- a/authentik/sources/ldap/models.py +++ b/authentik/sources/ldap/models.py @@ -173,7 +173,9 @@ def connection( if self.start_tls: connection.start_tls(read_server_info=False) try: - connection.bind() + successful = connection.bind() + if successful: + return connection except (LDAPSchemaError, LDAPInsufficientAccessRightsResult) as exc: # Schema error, so try connecting without schema info # See https://github.com/goauthentik/authentik/issues/4590 @@ -182,7 +184,7 @@ def connection( raise exc server_kwargs["get_info"] = NONE return self.connection(server_kwargs, connection_kwargs) - return connection + return RuntimeError("Failed to bind") class Meta: verbose_name = _("LDAP Source") diff --git a/authentik/sources/ldap/tests/test_auth.py b/authentik/sources/ldap/tests/test_auth.py index 3ba6ae3863b..715edc139c4 100644 --- a/authentik/sources/ldap/tests/test_auth.py +++ b/authentik/sources/ldap/tests/test_auth.py @@ -29,6 +29,37 @@ def setUp(self): additional_group_dn="ou=groups", ) + def test_auth_direct_user_ad(self): + """Test direct auth""" + self.source.property_mappings.set( + LDAPPropertyMapping.objects.filter( + Q(managed__startswith="goauthentik.io/sources/ldap/default-") + | Q(managed__startswith="goauthentik.io/sources/ldap/ms-") + ) + ) + raw_conn = mock_ad_connection(LDAP_PASSWORD) + bind_mock = Mock(wraps=raw_conn.bind) + raw_conn.bind = bind_mock + connection = MagicMock(return_value=raw_conn) + with patch("authentik.sources.ldap.models.LDAPSource.connection", connection): + user_sync = UserLDAPSynchronizer(self.source) + user_sync.sync() + + user = User.objects.get(username="user0_sn") + # auth_user_by_bind = Mock(return_value=user) + backend = LDAPBackend() + self.assertEqual( + backend.authenticate(None, username="user0_sn", password=LDAP_PASSWORD), + user, + ) + connection.assert_called_with( + connection_kwargs={ + "user": "cn=user0,ou=users,dc=goauthentik,dc=io", + "password": LDAP_PASSWORD, + } + ) + bind_mock.assert_not_called() + def test_auth_synced_user_ad(self): """Test Cached auth""" self.source.property_mappings.set( diff --git a/go.mod b/go.mod index 30fa667ebb8..63348448b7e 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/garyburd/redigo v1.6.4 github.com/getsentry/sentry-go v0.21.0 github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1 - github.com/go-ldap/ldap/v3 v3.4.4 + github.com/go-ldap/ldap/v3 v3.4.5 github.com/go-openapi/runtime v0.26.0 github.com/go-openapi/strfmt v0.21.7 github.com/golang-jwt/jwt v3.2.2+incompatible @@ -36,7 +36,7 @@ require ( ) require ( - github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/go.sum b/go.sum index e635b24000f..41c7a00d01e 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,15 @@ beryju.io/ldap v0.1.0 h1:rPjGE3qR1Klbvn9N+iECWdzt/tK87XHgz8W5wZJg9B8= beryju.io/ldap v0.1.0/go.mod h1:sOrYV+ZlDTDu/IvIiEiuAaXzjcpMBE+XXr4V+NJ0pWI= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft7pkxDf6WoUvEZJ/uOKsvtpjLnn8MU= -github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb h1:w9IDEB7P1VzNcBpOG7kMpFkZp2DkyJIUt0gDx5MBhRU= github.com/Netflix/go-env v0.0.0-20210215222557-e437a7e7f9fb/go.mod h1:9XMFaCeRyW7fC9XJOWQ+NdAv8VLG7ys7l3x4ozEGLUQ= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= +github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -37,8 +39,8 @@ github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 h1:O6yi4xa9b2D github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27/go.mod h1:AYvN8omj7nKLmbcXS2dyABYU6JB1Lz1bHmkkq1kf4I4= github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno= github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw= -github.com/go-ldap/ldap/v3 v3.4.4 h1:qPjipEpt+qDa6SI/h1fzuGWoRUY+qqQ9sOZq67/PYUs= -github.com/go-ldap/ldap/v3 v3.4.4/go.mod h1:fe1MsuN5eJJ1FeLT/LEBVdWfNWKh459R7aXgXtJC+aI= +github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= +github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -216,7 +218,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -265,6 +266,7 @@ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= @@ -294,11 +296,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -307,6 +311,7 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/poetry.lock b/poetry.lock index cf6fb6d50c8..7fe769d9f28 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2692,13 +2692,13 @@ files = [ [[package]] name = "pytest" -version = "7.3.1" +version = "7.3.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, - {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, + {file = "pytest-7.3.2-py3-none-any.whl", hash = "sha256:cdcbd012c9312258922f8cd3f1b62a6580fdced17db6014896053d47cddf9295"}, + {file = "pytest-7.3.2.tar.gz", hash = "sha256:ee990a3cc55ba808b80795a79944756f315c67c12b56abd3ac993a7b8c17030b"}, ] [package.dependencies] @@ -2708,7 +2708,7 @@ packaging = "*" pluggy = ">=0.12,<2.0" [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-django" diff --git a/web/package-lock.json b/web/package-lock.json index 50e6736008a..68f0d13b6ac 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -15,7 +15,7 @@ "@codemirror/lang-xml": "^6.0.2", "@codemirror/legacy-modes": "^6.3.2", "@codemirror/theme-one-dark": "^6.1.2", - "@formatjs/intl-listformat": "^7.3.0", + "@formatjs/intl-listformat": "^7.4.0", "@fortawesome/fontawesome-free": "^6.4.0", "@goauthentik/api": "^2023.5.3-1685646044", "@lit/localize": "^0.11.4", @@ -28,7 +28,7 @@ "chartjs-adapter-moment": "^1.0.1", "codemirror": "^6.0.1", "construct-style-sheets-polyfill": "^3.1.0", - "core-js": "^3.30.2", + "core-js": "^3.31.0", "country-flag-icons": "^1.5.7", "fuse.js": "^6.6.2", "lit": "^2.7.5", @@ -50,7 +50,7 @@ "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.6.9", "@rollup/plugin-babel": "^6.0.3", - "@rollup/plugin-commonjs": "^25.0.0", + "@rollup/plugin-commonjs": "^25.0.1", "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-typescript": "^11.1.1", @@ -2955,28 +2955,28 @@ "dev": true }, "node_modules/@formatjs/ecma402-abstract": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.16.0.tgz", - "integrity": "sha512-qIH2cmG/oHGrVdApbqDf6/YR+B2A4NdkBjKLeq369OMVkqMFsC5oPSP1xpiyL1cAn+PbNEZHxwOVMYD/C76c6g==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.17.0.tgz", + "integrity": "sha512-6ueQTeJZtwKjmh23bdkq/DMqH4l4bmfvtQH98blOSbiXv/OUiyijSW6jU22IT8BNM1ujCaEvJfTtyCYVH38EMQ==", "dependencies": { - "@formatjs/intl-localematcher": "0.3.0", + "@formatjs/intl-localematcher": "0.4.0", "tslib": "^2.4.0" } }, "node_modules/@formatjs/intl-listformat": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.3.0.tgz", - "integrity": "sha512-HWSST1TBcKi5frneeDi9O6YYp9NWb7HNrDSbCgnBLmz/9rpGycdp9c5bTKJqYFN6apw3E/kIo+kZHjVeiFITRQ==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-7.4.0.tgz", + "integrity": "sha512-ifupb+balZUAF/Oh3QyGRqPRWGSKwWoMPR0cYZEG7r61SimD+m38oFQqVx/3Fp7LfQFF11m7IS+MlxOo2sKINA==", "dependencies": { - "@formatjs/ecma402-abstract": "1.16.0", - "@formatjs/intl-localematcher": "0.3.0", + "@formatjs/ecma402-abstract": "1.17.0", + "@formatjs/intl-localematcher": "0.4.0", "tslib": "^2.4.0" } }, "node_modules/@formatjs/intl-localematcher": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.3.0.tgz", - "integrity": "sha512-NFoxXX3dtZ6B53NlCErq181NxN/noMZOWKHfcEPQRNfV0a19THxyjxu2RTSNS3532wGm6fOdid5qsBQWg0Rhtw==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.4.0.tgz", + "integrity": "sha512-bRTd+rKomvfdS4QDlVJ6TA/Jx1F2h/TBVO5LjvhQ7QPPHp19oPNMIum7W2CMEReq/zPxpmCeB31F9+5gl/qtvw==", "dependencies": { "tslib": "^2.4.0" } @@ -3654,9 +3654,10 @@ } }, "node_modules/@rollup/plugin-commonjs": { - "version": "25.0.0", + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.1.tgz", + "integrity": "sha512-2DJ4kv4b1xfTJopWhu61ANdNRHvzQZ2fpaIrlgaP2jOfUv1wDJ0Ucqy8AZlbFmn/iUjiwKoqki9j55Y6L8kyNQ==", "dev": true, - "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", @@ -12583,9 +12584,10 @@ } }, "node_modules/core-js": { - "version": "3.30.2", + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.0.tgz", + "integrity": "sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==", "hasInstallScript": true, - "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/core-js" diff --git a/web/package.json b/web/package.json index 799a5d82400..a50e5e75d90 100644 --- a/web/package.json +++ b/web/package.json @@ -31,7 +31,7 @@ "@codemirror/lang-xml": "^6.0.2", "@codemirror/legacy-modes": "^6.3.2", "@codemirror/theme-one-dark": "^6.1.2", - "@formatjs/intl-listformat": "^7.3.0", + "@formatjs/intl-listformat": "^7.4.0", "@fortawesome/fontawesome-free": "^6.4.0", "@goauthentik/api": "^2023.5.3-1685646044", "@lit/localize": "^0.11.4", @@ -44,7 +44,7 @@ "chartjs-adapter-moment": "^1.0.1", "codemirror": "^6.0.1", "construct-style-sheets-polyfill": "^3.1.0", - "core-js": "^3.30.2", + "core-js": "^3.31.0", "country-flag-icons": "^1.5.7", "fuse.js": "^6.6.2", "lit": "^2.7.5", @@ -66,7 +66,7 @@ "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.6.9", "@rollup/plugin-babel": "^6.0.3", - "@rollup/plugin-commonjs": "^25.0.0", + "@rollup/plugin-commonjs": "^25.0.1", "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-replace": "^5.0.2", "@rollup/plugin-typescript": "^11.1.1", diff --git a/website/integrations/services/dokuwiki/index.md b/website/integrations/services/dokuwiki/index.md index 36750201a14..d3b9d988b23 100644 --- a/website/integrations/services/dokuwiki/index.md +++ b/website/integrations/services/dokuwiki/index.md @@ -4,7 +4,7 @@ title: DokuWiki Support level: Community -## What is Service Name +## What is DokuWiki From https://en.wikipedia.org/wiki/DokuWiki