Skip to content

Commit

Permalink
Merge branch 'main' into web/issue-4880-multi-select-limitations
Browse files Browse the repository at this point in the history
* main: (82 commits)
  translate: Updates for file web/xliff/en.xlf in fr (#8212)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#8211)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#8210)
  web/flows: update flow background (#8209)
  web: clear "blanked" placeholder when present (#15) (#5948)
  web: bump prettier from 3.2.3 to 3.2.4 in /web (#8207)
  web: bump prettier from 3.2.2 to 3.2.3 in /tests/wdio (#8200)
  web: bump the wdio group in /tests/wdio with 4 updates (#8199)
  web: bump @formatjs/intl-listformat from 7.5.4 to 7.5.5 in /web (#8203)
  core: bump uvicorn from 0.25.0 to 0.26.0 (#8198)
  web: bump prettier from 3.2.2 to 3.2.3 in /web (#8201)
  web: bump vite-tsconfig-paths from 4.2.3 to 4.3.1 in /web (#8202)
  website: bump prettier from 3.2.2 to 3.2.3 in /website (#8204)
  website: fix styling on pricing page on firefox
  website: update pricing page (#8197)
  website: bump @types/react from 18.2.47 to 18.2.48 in /website (#8184)
  website: bump react-tooltip from 5.25.1 to 5.25.2 in /website (#8185)
  web: bump the eslint group in /tests/wdio with 2 updates (#8186)
  web: bump the eslint group in /web with 2 updates (#8187)
  web: bump mermaid from 10.6.1 to 10.7.0 in /web (#8189)
  ...
  • Loading branch information
kensternberg-authentik committed Jan 17, 2024
2 parents 529b2b0 + 245d8b7 commit a80f4fa
Show file tree
Hide file tree
Showing 86 changed files with 8,852 additions and 3,908 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 2023.10.5
current_version = 2023.10.6
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: "Setup authentik testing environment"
inputs:
postgresql_version:
description: "Optional postgresql image tag"
default: "12"
default: "16"

runs:
using: "composite"
Expand All @@ -18,7 +18,7 @@ runs:
- name: Setup python and restore poetry
uses: actions/setup-python@v4
with:
python-version-file: 'pyproject.toml'
python-version-file: "pyproject.toml"
cache: "poetry"
- name: Setup node
uses: actions/setup-node@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/setup/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: "3.7"

services:
postgresql:
image: docker.io/library/postgres:${PSQL_TAG:-12}
image: docker.io/library/postgres:${PSQL_TAG:-16}
volumes:
- db-data:/var/lib/postgresql/data
environment:
Expand Down
2 changes: 2 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ updates:
sentry:
patterns:
- "@sentry/*"
- "@spotlightjs/*"
babel:
patterns:
- "@babel/*"
Expand Down Expand Up @@ -66,6 +67,7 @@ updates:
sentry:
patterns:
- "@sentry/*"
- "@spotlightjs/*"
babel:
patterns:
- "@babel/*"
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
RUN npm run build

# Stage 3: Build go proxy
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.5-bookworm AS go-builder
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.6-bookworm AS go-builder

ARG TARGETOS
ARG TARGETARCH
Expand Down Expand Up @@ -69,7 +69,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
GOARM="${TARGETVARIANT#v}" go build -o /go/authentik ./cmd/server

# Stage 4: MaxMind GeoIP
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.0 as geoip
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.1 as geoip

ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
ENV GEOIPUPDATE_VERBOSE="true"
Expand Down
2 changes: 1 addition & 1 deletion authentik/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from os import environ
from typing import Optional

__version__ = "2023.10.5"
__version__ = "2023.10.6"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"


Expand Down
8 changes: 6 additions & 2 deletions authentik/blueprints/v1/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
Source,
UserSourceConnection,
)
from authentik.enterprise.models import LicenseUsage
from authentik.enterprise.models import LicenseKey, LicenseUsage
from authentik.events.utils import cleanse_dict
from authentik.flows.models import FlowToken, Stage
from authentik.lib.models import SerializerModel
Expand Down Expand Up @@ -108,12 +108,16 @@ def __init__(self, blueprint: Blueprint, context: Optional[dict] = None):
self.__pk_map: dict[Any, Model] = {}
self._import = blueprint
self.logger = get_logger()
ctx = {}
ctx = self.default_context()
always_merger.merge(ctx, self._import.context)
if context:
always_merger.merge(ctx, context)
self._import.context = ctx

def default_context(self):
"""Default context"""
return {"goauthentik.io/enterprise/licensed": LicenseKey.get_total().is_valid()}

@staticmethod
def from_string(yaml_input: str, context: dict | None = None) -> "Importer":
"""Parse YAML string and create blueprint importer from it"""
Expand Down
19 changes: 16 additions & 3 deletions authentik/enterprise/providers/rac/api/property_mappings.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
"""RAC Provider API Views"""
from django_filters.filters import AllValuesMultipleFilter
from django_filters.filterset import FilterSet
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from rest_framework.fields import CharField
from rest_framework.viewsets import ModelViewSet

from authentik.core.api.propertymappings import PropertyMappingSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import JSONDictField
from authentik.enterprise.api import EnterpriseRequiredMixin
from authentik.enterprise.providers.rac.models import RACPropertyMapping


class RACPropertyMappingSerializer(EnterpriseRequiredMixin, PropertyMappingSerializer):
class RACPropertyMappingSerializer(PropertyMappingSerializer):
"""RACPropertyMapping Serializer"""

static_settings = JSONDictField()
Expand All @@ -26,11 +29,21 @@ class Meta:
fields = PropertyMappingSerializer.Meta.fields + ["static_settings"]


class RACPropertyMappingFilter(FilterSet):
"""Filter for RACPropertyMapping"""

managed = extend_schema_field(OpenApiTypes.STR)(AllValuesMultipleFilter(field_name="managed"))

class Meta:
model = RACPropertyMapping
fields = ["name", "managed"]


class RACPropertyMappingViewSet(UsedByMixin, ModelViewSet):
"""RACPropertyMapping Viewset"""

queryset = RACPropertyMapping.objects.all()
serializer_class = RACPropertyMappingSerializer
search_fields = ["name"]
ordering = ["name"]
filterset_fields = ["name", "managed"]
filterset_class = RACPropertyMappingFilter
9 changes: 7 additions & 2 deletions authentik/enterprise/providers/rac/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from authentik.flows.challenge import RedirectChallenge
from authentik.flows.exceptions import FlowNonApplicableException
from authentik.flows.models import in_memory_stage
from authentik.flows.planner import FlowPlanner
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, FlowPlanner
from authentik.flows.stage import RedirectStage
from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.lib.utils.time import timedelta_from_string
Expand All @@ -39,7 +39,12 @@ def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
planner = FlowPlanner(self.provider.authorization_flow)
planner.allow_empty_flows = True
try:
plan = planner.plan(self.request)
plan = planner.plan(
self.request,
{
PLAN_CONTEXT_APPLICATION: self.application,
},
)
except FlowNonApplicableException:
raise Http404
plan.insert_stage(
Expand Down
3 changes: 0 additions & 3 deletions authentik/events/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@

def should_log_model(model: Model) -> bool:
"""Return true if operation on `model` should be logged"""
# Check for silk by string so this comparison doesn't fail when silk isn't installed
if model.__module__.startswith("silk"):
return False
return model.__class__ not in IGNORED_MODELS


Expand Down
1 change: 0 additions & 1 deletion authentik/lib/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ def get_logger_config():
"kubernetes": "INFO",
"asyncio": "WARNING",
"redis": "WARNING",
"silk": "INFO",
"fsevents": "WARNING",
"uvicorn": "WARNING",
"gunicorn": "INFO",
Expand Down
2 changes: 2 additions & 0 deletions authentik/lib/sentry.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ def sentry_init(**sentry_init_kwargs):
},
}
kwargs.update(**sentry_init_kwargs)
if settings.DEBUG:
kwargs["spotlight"] = True
# pylint: disable=abstract-class-instantiated
sentry_sdk_init(
dsn=CONFIG.get("error_reporting.sentry_dsn"),
Expand Down
19 changes: 19 additions & 0 deletions authentik/providers/oauth2/tests/test_authorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,25 @@ def test_invalid_redirect_uri(self):
)
OAuthAuthorizationParams.from_request(request)

def test_blocked_redirect_uri(self):
"""test missing/invalid redirect URI"""
OAuth2Provider.objects.create(
name=generate_id(),
client_id="test",
authorization_flow=create_test_flow(),
redirect_uris="data:local.invalid",
)
with self.assertRaises(RedirectUriError):
request = self.factory.get(
"/",
data={
"response_type": "code",
"client_id": "test",
"redirect_uri": "data:localhost",
},
)
OAuthAuthorizationParams.from_request(request)

def test_invalid_redirect_uri_empty(self):
"""test missing/invalid redirect URI"""
provider = OAuth2Provider.objects.create(
Expand Down
12 changes: 8 additions & 4 deletions authentik/providers/oauth2/views/authorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
SESSION_KEY_LAST_LOGIN_UID = "authentik/providers/oauth2/last_login_uid"

ALLOWED_PROMPT_PARAMS = {PROMPT_NONE, PROMPT_CONSENT, PROMPT_LOGIN}
FORBIDDEN_URI_SCHEMES = {"javascript", "data", "vbscript"}


@dataclass(slots=True)
Expand Down Expand Up @@ -179,6 +180,10 @@ def __post_init__(self, github_compat=False):
self.check_scope(github_compat)
self.check_nonce()
self.check_code_challenge()
if self.request:
raise AuthorizeError(
self.redirect_uri, "request_not_supported", self.grant_type, self.state
)

def check_redirect_uri(self):
"""Redirect URI validation."""
Expand Down Expand Up @@ -216,10 +221,9 @@ def check_redirect_uri(self):
redirect_uri_expected=allowed_redirect_urls,
)
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
if self.request:
raise AuthorizeError(
self.redirect_uri, "request_not_supported", self.grant_type, self.state
)
# Check against forbidden schemes
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)

def check_scope(self, github_compat=False):
"""Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
Expand Down
6 changes: 6 additions & 0 deletions authentik/providers/oauth2/views/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from re import error as RegexError
from re import fullmatch
from typing import Any, Optional
from urllib.parse import urlparse

from django.http import HttpRequest, HttpResponse
from django.utils import timezone
Expand Down Expand Up @@ -55,6 +56,7 @@
RefreshToken,
)
from authentik.providers.oauth2.utils import TokenResponse, cors_allow, extract_client_auth
from authentik.providers.oauth2.views.authorize import FORBIDDEN_URI_SCHEMES
from authentik.sources.oauth.models import OAuthSource
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS

Expand Down Expand Up @@ -206,6 +208,10 @@ def __post_init_code(self, raw_code: str, request: HttpRequest):
).from_http(request)
raise TokenError("invalid_client")

# Check against forbidden schemes
if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
raise TokenError("invalid_request")

self.authorization_code = AuthorizationCode.objects.filter(code=raw_code).first()
if not self.authorization_code:
LOGGER.warning("Code does not exist", code=raw_code)
Expand Down
2 changes: 0 additions & 2 deletions authentik/root/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,6 @@ def _update_settings(app_path: str):
if DEBUG:
CELERY["task_always_eager"] = True
os.environ[ENV_GIT_HASH_KEY] = "dev"
INSTALLED_APPS.append("silk")
MIDDLEWARE = ["silk.middleware.SilkyMiddleware"] + MIDDLEWARE
REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append(
"rest_framework.renderers.BrowsableAPIRenderer"
)
Expand Down
6 changes: 0 additions & 6 deletions authentik/root/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""authentik URL Configuration"""
from django.conf import settings
from django.urls import include, path
from structlog.stdlib import get_logger

Expand Down Expand Up @@ -48,8 +47,3 @@
path("-/health/live/", LiveView.as_view(), name="health-live"),
path("-/health/ready/", ReadyView.as_view(), name="health-ready"),
]

if settings.DEBUG:
urlpatterns += [
path("debug/silk/", include("silk.urls", namespace="silk")),
]
17 changes: 13 additions & 4 deletions authentik/sources/oauth/api/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class SourceTypeSerializer(PassiveSerializer):
"""Serializer for SourceType"""

name = CharField(required=True)
slug = CharField(required=True)
verbose_name = CharField(required=True)
urls_customizable = BooleanField()
request_token_url = CharField(read_only=True, allow_null=True)
authorization_url = CharField(read_only=True, allow_null=True)
Expand Down Expand Up @@ -56,6 +56,7 @@ def get_type(self, instance: OAuthSource) -> SourceTypeSerializer:
"""Get source's type configuration"""
return SourceTypeSerializer(instance.source_type).data

# pylint: disable=too-many-locals
def validate(self, attrs: dict) -> dict:
session = get_http_session()
source_type = registry.find_type(attrs["provider_type"])
Expand All @@ -73,9 +74,17 @@ def validate(self, attrs: dict) -> dict:
config = well_known_config.json()
if "issuer" not in config:
raise ValidationError({"oidc_well_known_url": "Invalid well-known configuration"})
attrs["authorization_url"] = config.get("authorization_endpoint", "")
attrs["access_token_url"] = config.get("token_endpoint", "")
attrs["profile_url"] = config.get("userinfo_endpoint", "")
field_map = {
# authentik field to oidc field
"authorization_url": "authorization_endpoint",
"access_token_url": "token_endpoint",
"profile_url": "userinfo_endpoint",
}
for ak_key, oidc_key in field_map.items():
# Don't overwrite user-set values
if ak_key in attrs and attrs[ak_key]:
continue
attrs[ak_key] = config.get(oidc_key, "")
inferred_oidc_jwks_url = config.get("jwks_uri", "")

# Prefer user-entered URL to inferred URL to default URL
Expand Down
4 changes: 4 additions & 0 deletions authentik/sources/oauth/tests/test_type_azure_ad.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ def test_enroll_context(self):
self.assertEqual(ak_context["username"], AAD_USER["userPrincipalName"])
self.assertEqual(ak_context["email"], AAD_USER["mail"])
self.assertEqual(ak_context["name"], AAD_USER["displayName"])

def test_user_id(self):
"""Test azure AD user ID"""
self.assertEqual(AzureADOAuthCallback().get_user_id(AAD_USER), AAD_USER["id"])
Loading

0 comments on commit a80f4fa

Please sign in to comment.