Compare commits
	
		
			4 Commits
		
	
	
		
			version-20
			...
			version/20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 72d67f65e5 | |||
| ea75741ec2 | |||
| aaa9b398f4 | |||
| d54d01b118 | 
| @ -1,5 +1,5 @@ | ||||
| [bumpversion] | ||||
| current_version = 2023.8.3 | ||||
| current_version = 2023.8.4 | ||||
| tag = True | ||||
| commit = True | ||||
| parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+) | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| from os import environ | ||||
| from typing import Optional | ||||
|  | ||||
| __version__ = "2023.8.3" | ||||
| __version__ = "2023.8.4" | ||||
| ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										25
									
								
								authentik/flows/migrations/0026_alter_flow_options.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								authentik/flows/migrations/0026_alter_flow_options.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| # Generated by Django 4.2.6 on 2023-10-10 17:18 | ||||
|  | ||||
| from django.db import migrations | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|     dependencies = [ | ||||
|         ("authentik_flows", "0025_alter_flowstagebinding_evaluate_on_plan_and_more"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.AlterModelOptions( | ||||
|             name="flow", | ||||
|             options={ | ||||
|                 "permissions": [ | ||||
|                     ("export_flow", "Can export a Flow"), | ||||
|                     ("inspect_flow", "Can inspect a Flow's execution"), | ||||
|                     ("view_flow_cache", "View Flow's cache metrics"), | ||||
|                     ("clear_flow_cache", "Clear Flow's cache metrics"), | ||||
|                 ], | ||||
|                 "verbose_name": "Flow", | ||||
|                 "verbose_name_plural": "Flows", | ||||
|             }, | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										34
									
								
								authentik/flows/migrations/0027_auto_20231028_1424.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								authentik/flows/migrations/0027_auto_20231028_1424.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| # Generated by Django 4.2.6 on 2023-10-28 14:24 | ||||
|  | ||||
| from django.apps.registry import Apps | ||||
| from django.db import migrations | ||||
| from django.db.backends.base.schema import BaseDatabaseSchemaEditor | ||||
|  | ||||
|  | ||||
| def set_oobe_flow_authentication(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): | ||||
|     from guardian.shortcuts import get_anonymous_user | ||||
|  | ||||
|     Flow = apps.get_model("authentik_flows", "Flow") | ||||
|     User = apps.get_model("authentik_core", "User") | ||||
|  | ||||
|     db_alias = schema_editor.connection.alias | ||||
|  | ||||
|     users = User.objects.using(db_alias).exclude(username="akadmin") | ||||
|     try: | ||||
|         users = users.exclude(pk=get_anonymous_user().pk) | ||||
|     # pylint: disable=broad-except | ||||
|     except Exception:  # nosec | ||||
|         pass | ||||
|  | ||||
|     if users.exists(): | ||||
|         Flow.objects.filter(slug="initial-setup").update(authentication="require_superuser") | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|     dependencies = [ | ||||
|         ("authentik_flows", "0026_alter_flow_options"), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.RunPython(set_oobe_flow_authentication), | ||||
|     ] | ||||
| @ -171,6 +171,8 @@ class MetadataProcessor: | ||||
|             entity_descriptor, f"{{{NS_SAML_METADATA}}}IDPSSODescriptor" | ||||
|         ) | ||||
|         idp_sso_descriptor.attrib["protocolSupportEnumeration"] = NS_SAML_PROTOCOL | ||||
|         if self.provider.verification_kp: | ||||
|             idp_sso_descriptor.attrib["WantAuthnRequestsSigned"] = "true" | ||||
|  | ||||
|         signing_descriptor = self.get_signing_key_descriptor() | ||||
|         if signing_descriptor is not None: | ||||
|  | ||||
| @ -12,7 +12,7 @@ from authentik.lib.xml import lxml_from_string | ||||
| from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider | ||||
| from authentik.providers.saml.processors.metadata import MetadataProcessor | ||||
| from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser | ||||
| from authentik.sources.saml.processors.constants import NS_MAP | ||||
| from authentik.sources.saml.processors.constants import NS_MAP, NS_SAML_METADATA | ||||
|  | ||||
|  | ||||
| class TestServiceProviderMetadataParser(TestCase): | ||||
| @ -55,6 +55,24 @@ class TestServiceProviderMetadataParser(TestCase): | ||||
|         schema = etree.XMLSchema(etree.parse("schemas/saml-schema-metadata-2.0.xsd"))  # nosec | ||||
|         self.assertTrue(schema.validate(metadata)) | ||||
|  | ||||
|     def test_schema_want_authn_requests_signed(self): | ||||
|         """Test metadata generation with WantAuthnRequestsSigned""" | ||||
|         cert = create_test_cert() | ||||
|         provider = SAMLProvider.objects.create( | ||||
|             name=generate_id(), | ||||
|             authorization_flow=self.flow, | ||||
|             verification_kp=cert, | ||||
|         ) | ||||
|         Application.objects.create( | ||||
|             name=generate_id(), | ||||
|             slug=generate_id(), | ||||
|             provider=provider, | ||||
|         ) | ||||
|         request = self.factory.get("/") | ||||
|         metadata = lxml_from_string(MetadataProcessor(provider, request).build_entity_descriptor()) | ||||
|         idp_sso_descriptor = metadata.findall(f"{{{NS_SAML_METADATA}}}IDPSSODescriptor")[0] | ||||
|         self.assertEqual(idp_sso_descriptor.attrib["WantAuthnRequestsSigned"], "true") | ||||
|  | ||||
|     def test_simple(self): | ||||
|         """Test simple metadata without Signing""" | ||||
|         metadata = ServiceProviderMetadataParser().parse(load_fixture("fixtures/simple.xml")) | ||||
|  | ||||
| @ -47,9 +47,11 @@ class FreeIPA(BaseLDAPSynchronizer): | ||||
|             return | ||||
|         # For some reason, nsaccountlock is not defined properly in the schema as bool | ||||
|         # hence we get it as a list of strings | ||||
|         _is_active = str(self._flatten(attributes.get("nsaccountlock", ["FALSE"]))) | ||||
|         _is_locked = str(self._flatten(attributes.get("nsaccountlock", ["FALSE"]))) | ||||
|         # So we have to attempt to convert it to a bool | ||||
|         is_active = _is_active.lower() == "true" | ||||
|         is_locked = _is_locked.lower() == "true" | ||||
|         # And then invert it since freeipa saves locked and we save active | ||||
|         is_active = not is_locked | ||||
|         if is_active != user.is_active: | ||||
|             user.is_active = is_active | ||||
|             user.save() | ||||
|  | ||||
| @ -137,6 +137,7 @@ class LDAPSyncTests(TestCase): | ||||
|             user_sync.sync_full() | ||||
|             self.assertTrue(User.objects.filter(username="user0_sn").exists()) | ||||
|             self.assertFalse(User.objects.filter(username="user1_sn").exists()) | ||||
|             self.assertFalse(User.objects.get(username="user-nsaccountlock").is_active) | ||||
|  | ||||
|     def test_sync_groups_ad(self): | ||||
|         """Test group sync""" | ||||
|  | ||||
| @ -85,6 +85,19 @@ entries: | ||||
|   identifiers: | ||||
|     name: default-oobe-password-usable | ||||
|   model: authentik_policies_expression.expressionpolicy | ||||
| - attrs: | ||||
|     expression: | | ||||
|       # This policy ensures that the setup flow can only be | ||||
|       # used one time | ||||
|       from authentik.flows.models import Flow, FlowAuthenticationRequirement | ||||
|       Flow.objects.filter(slug="initial-setup").update( | ||||
|           authentication=FlowAuthenticationRequirement.REQUIRE_SUPERUSER, | ||||
|       ) | ||||
|       return True | ||||
|   id: policy-default-oobe-flow-set-authentication | ||||
|   identifiers: | ||||
|     name: default-oobe-flow-set-authentication | ||||
|   model: authentik_policies_expression.expressionpolicy | ||||
| - attrs: | ||||
|     fields: | ||||
|     - !KeyOf prompt-field-header | ||||
| @ -129,6 +142,7 @@ entries: | ||||
|     evaluate_on_plan: true | ||||
|     invalid_response_action: retry | ||||
|     re_evaluate_policies: false | ||||
|   id: binding-login | ||||
|   identifiers: | ||||
|     order: 100 | ||||
|     stage: !KeyOf stage-default-authentication-login | ||||
| @ -144,3 +158,8 @@ entries: | ||||
|     policy: !KeyOf policy-default-oobe-prefill-user | ||||
|     target: !KeyOf binding-password-write | ||||
|   model: authentik_policies.policybinding | ||||
| - identifiers: | ||||
|     order: 0 | ||||
|     policy: !KeyOf policy-default-oobe-flow-set-authentication | ||||
|     target: !KeyOf binding-login | ||||
|   model: authentik_policies.policybinding | ||||
|  | ||||
| @ -42,9 +42,3 @@ entries: | ||||
|       user: !KeyOf admin-user | ||||
|     attrs: | ||||
|       key: !Context token | ||||
|   - model: authentik_blueprints.blueprintinstance | ||||
|     identifiers: | ||||
|       metadata: | ||||
|         labels: | ||||
|           blueprints.goauthentik.io/system-bootstrap: "true" | ||||
|     state: absent | ||||
|  | ||||
| @ -32,7 +32,7 @@ services: | ||||
|     volumes: | ||||
|       - redis:/data | ||||
|   server: | ||||
|     image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.3} | ||||
|     image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.4} | ||||
|     restart: unless-stopped | ||||
|     command: server | ||||
|     environment: | ||||
| @ -53,7 +53,7 @@ services: | ||||
|       - postgresql | ||||
|       - redis | ||||
|   worker: | ||||
|     image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.3} | ||||
|     image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.4} | ||||
|     restart: unless-stopped | ||||
|     command: worker | ||||
|     environment: | ||||
|  | ||||
| @ -29,4 +29,4 @@ func UserAgent() string { | ||||
| 	return fmt.Sprintf("authentik@%s", FullVersion()) | ||||
| } | ||||
|  | ||||
| const VERSION = "2023.8.3" | ||||
| const VERSION = "2023.8.4" | ||||
|  | ||||
| @ -113,7 +113,7 @@ filterwarnings = [ | ||||
|  | ||||
| [tool.poetry] | ||||
| name = "authentik" | ||||
| version = "2023.8.3" | ||||
| version = "2023.8.4" | ||||
| description = "" | ||||
| authors = ["authentik Team <hello@goauthentik.io>"] | ||||
|  | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| openapi: 3.0.3 | ||||
| info: | ||||
|   title: authentik | ||||
|   version: 2023.8.3 | ||||
|   version: 2023.8.4 | ||||
|   description: Making authentication simple. | ||||
|   contact: | ||||
|     email: hello@goauthentik.io | ||||
|  | ||||
| @ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success"; | ||||
| export const ERROR_CLASS = "pf-m-danger"; | ||||
| export const PROGRESS_CLASS = "pf-m-in-progress"; | ||||
| export const CURRENT_CLASS = "pf-m-current"; | ||||
| export const VERSION = "2023.8.3"; | ||||
| export const VERSION = "2023.8.4"; | ||||
| export const TITLE_DEFAULT = "authentik"; | ||||
| export const ROUTE_SEPARATOR = ";"; | ||||
|  | ||||
|  | ||||
| @ -155,6 +155,10 @@ image: | ||||
| -   web: don't import entire SourceViewPage in flow and user interface (#6761) | ||||
| -   web: replace ampersand (#6737) | ||||
|  | ||||
| ## Fixed in 2023.8.4 | ||||
|  | ||||
| -   \*: fix [GHSA-rjvp-29xq-f62w](../security/GHSA-rjvp-29xq-f62w), Reported by [@devSparkle](https://github.com/devSparkle) | ||||
|  | ||||
| ## API Changes | ||||
|  | ||||
| #### What's New | ||||
|  | ||||
							
								
								
									
										27
									
								
								website/docs/security/GHSA-rjvp-29xq-f62w.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								website/docs/security/GHSA-rjvp-29xq-f62w.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| # GHSA-rjvp-29xq-f62w | ||||
|  | ||||
| _Reported by [@devSparkle](https://github.com/devSparkle)_ | ||||
|  | ||||
| ## Potential Installation takeover when default admin user is deleted | ||||
|  | ||||
| ### Summary | ||||
|  | ||||
| In the affected versions, when the default admin user has been deleted, it is potentially possible for an attacker to set the password of the default admin user without any authentication. | ||||
|  | ||||
| ### Patches | ||||
|  | ||||
| authentik 2023.8.4 and 2023.10.2 fix this issue, for other versions the workaround can be used. | ||||
|  | ||||
| ### Impact | ||||
|  | ||||
| authentik uses a blueprint to create the default admin user, which can also optionally set the default admin users' password from an environment variable. When the user is deleted, the `initial-setup` flow used to configure authentik after the first installation becomes available again. | ||||
|  | ||||
| ### Workarounds | ||||
|  | ||||
| Ensure the default admin user (Username `akadmin`) exists and has a password set. It is recommended to use a very strong password for this user, and store it in a secure location like a password manager. It is also possible to deactivate the user to prevent any logins as akadmin. | ||||
|  | ||||
| ### For more information | ||||
|  | ||||
| If you have any questions or comments about this advisory: | ||||
|  | ||||
| -   Email us at [security@goauthentik.io](mailto:security@goauthentik.io) | ||||
| @ -362,6 +362,7 @@ const docsSidebar = { | ||||
|             }, | ||||
|             items: [ | ||||
|                 "security/policy", | ||||
|                 "security/GHSA-rjvp-29xq-f62w", | ||||
|                 "security/CVE-2023-39522", | ||||
|                 "security/CVE-2023-36456", | ||||
|                 "security/2023-06-cure53", | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	