Skip to content

Commit

Permalink
Merge branch 'web/config-provider-2-tenant' into web/config-provider-…
Browse files Browse the repository at this point in the history
…2a-branded

* web/config-provider-2-tenant: (146 commits)
  web: abstract `rootInterface()?.config?.capabilities.includes()` into `.can()` (#7737)
  web: update some locale details (#8090)
  web: bump the eslint group in /web with 2 updates (#8082)
  web: bump rollup from 4.9.2 to 4.9.4 in /web (#8083)
  core: bump github.com/redis/go-redis/v9 from 9.3.1 to 9.4.0 (#8085)
  web: bump the eslint group in /tests/wdio with 2 updates (#8086)
  website: bump @types/react from 18.2.46 to 18.2.47 in /website (#8088)
  stages/user_login: only set last_ip in session if a binding is given (#8074)
  providers/oauth2: fix missing nonce in token endpoint not being saved (#8073)
  core: bump goauthentik.io/api/v3 from 3.2023105.3 to 3.2023105.5 (#8066)
  providers/oauth2: fix missing nonce in id_token (#8072)
  rbac: fix error when looking up permissions for now uninstalled apps (#8068)
  web/flows: fix device picker incorrect foreground color (#8067)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#8061)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#8062)
  website: bump postcss from 8.4.32 to 8.4.33 in /website (#8063)
  web: bump the sentry group in /web with 2 updates (#8064)
  core: bump golang.org/x/sync from 0.5.0 to 0.6.0 (#8065)
  website/docs: add link to our example flows (#8052)
  providers/oauth2: offline access (#8026)
  ...
  • Loading branch information
kensternberg-authentik committed Jan 8, 2024
2 parents 79601f6 + 0d30257 commit ce761c4
Show file tree
Hide file tree
Showing 389 changed files with 27,550 additions and 4,580 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.4
current_version = 2023.10.5
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
Expand Down
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ blueprints/local
.git
!gen-ts-api/node_modules
!gen-ts-api/dist/**
!gen-go-api/
1 change: 1 addition & 0 deletions .github/codespell-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ keypair
keypairs
hass
warmup
ontext
47 changes: 33 additions & 14 deletions .github/workflows/ci-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup authentik env
uses: ./.github/actions/setup
with:
postgresql_version: ${{ matrix.psql }}
- name: checkout stable
run: |
# Delete all poetry envs
Expand All @@ -76,7 +72,7 @@ jobs:
git checkout version/$(python -c "from authentik import __version__; print(__version__)")
rm -rf .github/ scripts/
mv ../.github ../scripts .
- name: Setup authentik env (ensure stable deps are installed)
- name: Setup authentik env (stable)
uses: ./.github/actions/setup
with:
postgresql_version: ${{ matrix.psql }}
Expand All @@ -90,14 +86,20 @@ jobs:
git clean -d -fx .
git checkout $GITHUB_SHA
# Delete previous poetry env
rm -rf $(poetry env info --path)
poetry install
rm -rf /home/runner/.cache/pypoetry/virtualenvs/*
- name: Setup authentik env (ensure latest deps are installed)
uses: ./.github/actions/setup
with:
postgresql_version: ${{ matrix.psql }}
- name: migrate to latest
run: poetry run python -m lifecycle.migrate
run: |
poetry run python -m lifecycle.migrate
- name: run tests
env:
# Test in the main database that we just migrated from the previous stable version
AUTHENTIK_POSTGRESQL__TEST__NAME: authentik
run: |
poetry run make test
test-unittest:
name: test-unittest - PostgreSQL ${{ matrix.psql }}
runs-on: ubuntu-latest
Expand Down Expand Up @@ -247,12 +249,6 @@ jobs:
VERSION_FAMILY=${{ steps.ev.outputs.versionFamily }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Comment on PR
if: github.event_name == 'pull_request'
continue-on-error: true
uses: ./.github/actions/comment-pr-instructions
with:
tag: gh-${{ steps.ev.outputs.branchNameContainer }}-${{ steps.ev.outputs.timestamp }}-${{ steps.ev.outputs.shortHash }}
build-arm64:
needs: ci-core-mark
runs-on: ubuntu-latest
Expand Down Expand Up @@ -301,3 +297,26 @@ jobs:
platforms: linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
pr-comment:
needs:
- build
- build-arm64
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
permissions:
# Needed to write comments on PRs
pull-requests: write
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
- name: Comment on PR
uses: ./.github/actions/comment-pr-instructions
with:
tag: gh-${{ steps.ev.outputs.branchNameContainer }}-${{ steps.ev.outputs.timestamp }}-${{ steps.ev.outputs.shortHash }}
2 changes: 2 additions & 0 deletions .github/workflows/ci-outpost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ jobs:
- proxy
- ldap
- radius
- rac
runs-on: ubuntu-latest
permissions:
# Needed to upload contianer images to ghcr.io
Expand Down Expand Up @@ -119,6 +120,7 @@ jobs:
- proxy
- ldap
- radius
- rac
goos: [linux]
goarch: [amd64, arm64]
steps:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ jobs:
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
1 change: 1 addition & 0 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ jobs:
- proxy
- ldap
- radius
- rac
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
# Stage 4: MaxMind GeoIP
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v6.0 as geoip

ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City"
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
ENV GEOIPUPDATE_VERBOSE="true"
ENV GEOIPUPDATE_ACCOUNT_ID_FILE="/run/secrets/GEOIPUPDATE_ACCOUNT_ID"
ENV GEOIPUPDATE_LICENSE_KEY_FILE="/run/secrets/GEOIPUPDATE_LICENSE_KEY"
Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ test: ## Run the server tests and produce a coverage report (locally)
lint-fix: ## Lint and automatically fix errors in the python source code. Reports spelling errors.
isort $(PY_SOURCES)
black $(PY_SOURCES)
ruff $(PY_SOURCES)
ruff --fix $(PY_SOURCES)
codespell -w $(CODESPELL_ARGS)

lint: ## Lint the python and golang sources
Expand Down Expand Up @@ -115,8 +115,9 @@ gen-diff: ## (Release) generate the changelog diff between the current schema a
npx prettier --write diff.md

gen-clean:
rm -rf web/api/src/
rm -rf api/
rm -rf gen-go-api/
rm -rf gen-ts-api/
rm -rf web/node_modules/@goauthentik/api/

gen-client-ts: ## Build and install the authentik API for Typescript into the authentik UI Application
docker run \
Expand Down
4 changes: 4 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
authentik takes security very seriously. We follow the rules of [responsible disclosure](https://en.wikipedia.org/wiki/Responsible_disclosure), and we urge our community to do so as well, instead of reporting vulnerabilities publicly. This allows us to patch the issue quickly, announce it's existence and release the fixed version.

## Independent audits and pentests

In May/June of 2023 [Cure53](https://cure53.de) conducted an audit and pentest. The [results](https://cure53.de/pentest-report_authentik.pdf) are published on the [Cure53 website](https://cure53.de/#publications-2023). For more details about authentik's response to the findings of the audit refer to [2023-06 Cure53 Code audit](https://goauthentik.io/docs/security/2023-06-cure53).

## What authentik classifies as a CVE

CVE (Common Vulnerability and Exposure) is a system designed to aggregate all vulnerabilities. As such, a CVE will be issued when there is a either vulnerability or exposure. Per NIST, A vulnerability is:
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.4"
__version__ = "2023.10.5"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"


Expand Down
8 changes: 7 additions & 1 deletion authentik/api/tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from authentik.core.models import Token, TokenIntents, User, UserTypes
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.lib.generators import generate_id
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.models import Outpost
from authentik.providers.oauth2.constants import SCOPE_AUTHENTIK_API
from authentik.providers.oauth2.models import AccessToken, OAuth2Provider

Expand Down Expand Up @@ -49,8 +51,12 @@ def test_bearer_valid_deactivated(self):
with self.assertRaises(AuthenticationFailed):
bearer_auth(f"Bearer {token.key}".encode())

def test_managed_outpost(self):
@reconcile_app("authentik_outposts")
def test_managed_outpost_fail(self):
"""Test managed outpost"""
outpost = Outpost.objects.filter(managed=MANAGED_OUTPOST).first()
outpost.user.delete()
outpost.delete()
with self.assertRaises(AuthenticationFailed):
bearer_auth(f"Bearer {settings.SECRET_KEY}".encode())

Expand Down
8 changes: 5 additions & 3 deletions authentik/api/v3/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from rest_framework.views import APIView

from authentik.core.api.utils import PassiveSerializer
from authentik.events.geo import GEOIP_READER
from authentik.events.context_processors.base import get_context_processors
from authentik.lib.config import CONFIG

capabilities = Signal()
Expand All @@ -30,6 +30,7 @@ class Capabilities(models.TextChoices):

CAN_SAVE_MEDIA = "can_save_media"
CAN_GEO_IP = "can_geo_ip"
CAN_ASN = "can_asn"
CAN_IMPERSONATE = "can_impersonate"
CAN_DEBUG = "can_debug"
IS_ENTERPRISE = "is_enterprise"
Expand Down Expand Up @@ -68,8 +69,9 @@ def get_capabilities(self) -> list[Capabilities]:
deb_test = settings.DEBUG or settings.TEST
if Path(settings.MEDIA_ROOT).is_mount() or deb_test:
caps.append(Capabilities.CAN_SAVE_MEDIA)
if GEOIP_READER.enabled:
caps.append(Capabilities.CAN_GEO_IP)
for processor in get_context_processors():
if cap := processor.capability():
caps.append(cap)
if CONFIG.get_bool("impersonation"):
caps.append(Capabilities.CAN_IMPERSONATE)
if settings.DEBUG: # pragma: no cover
Expand Down
6 changes: 3 additions & 3 deletions authentik/blueprints/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from drf_spectacular.utils import extend_schema, inline_serializer
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, DateTimeField, JSONField
from rest_framework.fields import CharField, DateTimeField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ListSerializer, ModelSerializer
Expand All @@ -15,7 +15,7 @@
from authentik.blueprints.v1.oci import OCI_PREFIX
from authentik.blueprints.v1.tasks import apply_blueprint, blueprints_find_dict
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer
from authentik.core.api.utils import JSONDictField, PassiveSerializer


class ManagedSerializer:
Expand All @@ -28,7 +28,7 @@ class MetadataSerializer(PassiveSerializer):
"""Serializer for blueprint metadata"""

name = CharField()
labels = JSONField()
labels = JSONDictField()


class BlueprintInstanceSerializer(ModelSerializer):
Expand Down
2 changes: 1 addition & 1 deletion authentik/blueprints/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def reconcile(self) -> None:
meth()
self._logger.debug("Successfully reconciled", name=name)
except (DatabaseError, ProgrammingError, InternalError) as exc:
self._logger.debug("Failed to run reconcile", name=name, exc=exc)
self._logger.warning("Failed to run reconcile", name=name, exc=exc)


class AuthentikBlueprintsConfig(ManagedAppConfig):
Expand Down
6 changes: 3 additions & 3 deletions authentik/blueprints/v1/meta/apply_blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
from typing import TYPE_CHECKING

from rest_framework.exceptions import ValidationError
from rest_framework.fields import BooleanField, JSONField
from rest_framework.fields import BooleanField
from structlog.stdlib import get_logger

from authentik.blueprints.v1.meta.registry import BaseMetaModel, MetaResult, registry
from authentik.core.api.utils import PassiveSerializer, is_dict
from authentik.core.api.utils import JSONDictField, PassiveSerializer

if TYPE_CHECKING:
from authentik.blueprints.models import BlueprintInstance
Expand All @@ -17,7 +17,7 @@
class ApplyBlueprintMetaSerializer(PassiveSerializer):
"""Serializer for meta apply blueprint model"""

identifiers = JSONField(validators=[is_dict])
identifiers = JSONDictField()
required = BooleanField(default=True)

# We cannot override `instance` as that will confuse rest_framework
Expand Down
13 changes: 10 additions & 3 deletions authentik/core/api/authenticated_sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
from authentik.api.authorization import OwnerSuperuserPermissions
from authentik.core.api.used_by import UsedByMixin
from authentik.core.models import AuthenticatedSession
from authentik.events.geo import GEOIP_READER, GeoIPDict
from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR, ASNDict
from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR, GeoIPDict


class UserAgentDeviceDict(TypedDict):
Expand Down Expand Up @@ -59,6 +60,7 @@ class AuthenticatedSessionSerializer(ModelSerializer):
current = SerializerMethodField()
user_agent = SerializerMethodField()
geo_ip = SerializerMethodField()
asn = SerializerMethodField()

def get_current(self, instance: AuthenticatedSession) -> bool:
"""Check if session is currently active session"""
Expand All @@ -70,8 +72,12 @@ def get_user_agent(self, instance: AuthenticatedSession) -> UserAgentDict:
return user_agent_parser.Parse(instance.last_user_agent)

def get_geo_ip(self, instance: AuthenticatedSession) -> Optional[GeoIPDict]: # pragma: no cover
"""Get parsed user agent"""
return GEOIP_READER.city_dict(instance.last_ip)
"""Get GeoIP Data"""
return GEOIP_CONTEXT_PROCESSOR.city_dict(instance.last_ip)

def get_asn(self, instance: AuthenticatedSession) -> Optional[ASNDict]: # pragma: no cover
"""Get ASN Data"""
return ASN_CONTEXT_PROCESSOR.asn_dict(instance.last_ip)

class Meta:
model = AuthenticatedSession
Expand All @@ -80,6 +86,7 @@ class Meta:
"current",
"user_agent",
"geo_ip",
"asn",
"user",
"last_ip",
"last_user_agent",
Expand Down
8 changes: 4 additions & 4 deletions authentik/core/api/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@
from drf_spectacular.utils import OpenApiResponse, extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action
from rest_framework.fields import CharField, IntegerField, JSONField
from rest_framework.fields import CharField, IntegerField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ListSerializer, ModelSerializer, ValidationError
from rest_framework.viewsets import ModelViewSet

from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer, is_dict
from authentik.core.api.utils import JSONDictField, PassiveSerializer
from authentik.core.models import Group, User
from authentik.rbac.api.roles import RoleSerializer


class GroupMemberSerializer(ModelSerializer):
"""Stripped down user serializer to show relevant users for groups"""

attributes = JSONField(validators=[is_dict], required=False)
attributes = JSONDictField(required=False)
uid = CharField(read_only=True)

class Meta:
Expand All @@ -44,7 +44,7 @@ class Meta:
class GroupSerializer(ModelSerializer):
"""Group Serializer"""

attributes = JSONField(validators=[is_dict], required=False)
attributes = JSONDictField(required=False)
users_obj = ListSerializer(
child=GroupMemberSerializer(), read_only=True, source="users", required=False
)
Expand Down
2 changes: 2 additions & 0 deletions authentik/core/api/propertymappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from authentik.core.api.utils import MetaNameSerializer, PassiveSerializer, TypeCreateSerializer
from authentik.core.expression.evaluator import PropertyMappingEvaluator
from authentik.core.models import PropertyMapping
from authentik.enterprise.apps import EnterpriseConfig
from authentik.events.utils import sanitize_item
from authentik.lib.utils.reflection import all_subclasses
from authentik.policies.api.exec import PolicyTestSerializer
Expand Down Expand Up @@ -95,6 +96,7 @@ def types(self, request: Request) -> Response:
"description": subclass.__doc__,
"component": subclass().component,
"model_name": subclass._meta.model_name,
"requires_enterprise": isinstance(subclass._meta.app_config, EnterpriseConfig),
}
)
return Response(TypeCreateSerializer(data, many=True).data)
Expand Down
Loading

0 comments on commit ce761c4

Please sign in to comment.