diff --git a/authentik/core/migrations/0029_provider_backchannel_applications_and_more.py b/authentik/core/migrations/0029_provider_backchannel_applications_and_more.py index 07cb4f2df..f34c59ccb 100644 --- a/authentik/core/migrations/0029_provider_backchannel_applications_and_more.py +++ b/authentik/core/migrations/0029_provider_backchannel_applications_and_more.py @@ -11,7 +11,7 @@ def backport_is_backchannel(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) for model in BackchannelProvider.__subclasses__(): try: - for obj in model.objects.all(): + for obj in model.objects.only("is_backchannel"): obj.is_backchannel = True obj.save() except (DatabaseError, InternalError, ProgrammingError): diff --git a/authentik/providers/ldap/api.py b/authentik/providers/ldap/api.py index 870d66ee5..21438ef43 100644 --- a/authentik/providers/ldap/api.py +++ b/authentik/providers/ldap/api.py @@ -29,6 +29,7 @@ class LDAPProviderSerializer(ProviderSerializer): "outpost_set", "search_mode", "bind_mode", + "mfa_support", ] extra_kwargs = ProviderSerializer.Meta.extra_kwargs @@ -99,6 +100,7 @@ class LDAPOutpostConfigSerializer(ModelSerializer): "gid_start_number", "search_mode", "bind_mode", + "mfa_support", ] diff --git a/authentik/providers/ldap/migrations/0003_ldapprovider_mfa_support_and_more.py b/authentik/providers/ldap/migrations/0003_ldapprovider_mfa_support_and_more.py new file mode 100644 index 000000000..f5cd61cfa --- /dev/null +++ b/authentik/providers/ldap/migrations/0003_ldapprovider_mfa_support_and_more.py @@ -0,0 +1,37 @@ +# Generated by Django 4.1.7 on 2023-06-19 17:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_providers_ldap", "0002_ldapprovider_bind_mode"), + ] + + operations = [ + migrations.AddField( + model_name="ldapprovider", + name="mfa_support", + field=models.BooleanField( + default=True, + help_text="When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon.", + verbose_name="MFA Support", + ), + ), + migrations.AlterField( + model_name="ldapprovider", + name="gid_start_number", + field=models.IntegerField( + default=4000, + help_text="The start for gidNumbers, this number is added to a number generated from the group.pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber", + ), + ), + migrations.AlterField( + model_name="ldapprovider", + name="uid_start_number", + field=models.IntegerField( + default=2000, + help_text="The start for uidNumbers, this number is added to the user.pk to make sure that the numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't collide with local users uidNumber", + ), + ), + ] diff --git a/authentik/providers/ldap/models.py b/authentik/providers/ldap/models.py index 581d50230..d03f5e1f3 100644 --- a/authentik/providers/ldap/models.py +++ b/authentik/providers/ldap/models.py @@ -50,7 +50,7 @@ class LDAPProvider(OutpostModel, BackchannelProvider): uid_start_number = models.IntegerField( default=2000, help_text=_( - "The start for uidNumbers, this number is added to the user.Pk to make sure that the " + "The start for uidNumbers, this number is added to the user.pk to make sure that the " "numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't " "collide with local users uidNumber" ), @@ -60,7 +60,7 @@ class LDAPProvider(OutpostModel, BackchannelProvider): default=4000, help_text=_( "The start for gidNumbers, this number is added to a number generated from the " - "group.Pk to make sure that the numbers aren't too low for POSIX groups. Default " + "group.pk to make sure that the numbers aren't too low for POSIX groups. Default " "is 4000 to ensure that we don't collide with local groups or users " "primary groups gidNumber" ), @@ -69,6 +69,17 @@ class LDAPProvider(OutpostModel, BackchannelProvider): bind_mode = models.TextField(default=APIAccessMode.DIRECT, choices=APIAccessMode.choices) search_mode = models.TextField(default=APIAccessMode.DIRECT, choices=APIAccessMode.choices) + mfa_support = models.BooleanField( + default=True, + verbose_name="MFA Support", + help_text=_( + "When enabled, code-based multi-factor authentication can be used by appending a " + "semicolon and the TOTP code to the password. This should only be enabled if all " + "users that will bind to this provider have a TOTP device configured, as otherwise " + "a password may incorrectly be rejected if it contains a semicolon." + ), + ) + @property def launch_url(self) -> Optional[str]: """LDAP never has a launch URL""" diff --git a/blueprints/schema.json b/blueprints/schema.json index 8f41c9449..69c046195 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -3620,14 +3620,14 @@ "minimum": -2147483648, "maximum": 2147483647, "title": "Uid start number", - "description": "The start for uidNumbers, this number is added to the user.Pk to make sure that the numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't collide with local users uidNumber" + "description": "The start for uidNumbers, this number is added to the user.pk to make sure that the numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't collide with local users uidNumber" }, "gid_start_number": { "type": "integer", "minimum": -2147483648, "maximum": 2147483647, "title": "Gid start number", - "description": "The start for gidNumbers, this number is added to a number generated from the group.Pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber" + "description": "The start for gidNumbers, this number is added to a number generated from the group.pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber" }, "search_mode": { "type": "string", @@ -3644,6 +3644,11 @@ "cached" ], "title": "Bind mode" + }, + "mfa_support": { + "type": "boolean", + "title": "MFA Support", + "description": "When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon." } }, "required": [] diff --git a/internal/outpost/flow/const.go b/internal/outpost/flow/const.go index acecf3bd9..26fcb2f9b 100644 --- a/internal/outpost/flow/const.go +++ b/internal/outpost/flow/const.go @@ -14,5 +14,3 @@ const ( HeaderAuthentikRemoteIP = "X-authentik-remote-ip" HeaderAuthentikOutpostToken = "X-authentik-outpost-token" ) - -const CodePasswordSeparator = ";" diff --git a/internal/outpost/flow/solvers.go b/internal/outpost/flow/solvers.go index a809571a3..5006bbd75 100644 --- a/internal/outpost/flow/solvers.go +++ b/internal/outpost/flow/solvers.go @@ -3,21 +3,10 @@ package flow import ( "errors" "strconv" - "strings" "goauthentik.io/api/v3" ) -func (fe *FlowExecutor) checkPasswordMFA() { - password := fe.getAnswer(StagePassword) - if !strings.Contains(password, CodePasswordSeparator) || fe.Answers[StageAuthenticatorValidate] != "" { - return - } - idx := strings.LastIndex(password, CodePasswordSeparator) - fe.Answers[StagePassword] = password[:idx] - fe.Answers[StageAuthenticatorValidate] = password[idx+1:] -} - func (fe *FlowExecutor) solveChallenge_Identification(challenge *api.ChallengeTypes, req api.ApiFlowsExecutorSolveRequest) (api.FlowChallengeResponseRequest, error) { r := api.NewIdentificationChallengeResponseRequest(fe.getAnswer(StageIdentification)) r.SetPassword(fe.getAnswer(StagePassword)) @@ -25,7 +14,6 @@ func (fe *FlowExecutor) solveChallenge_Identification(challenge *api.ChallengeTy } func (fe *FlowExecutor) solveChallenge_Password(challenge *api.ChallengeTypes, req api.ApiFlowsExecutorSolveRequest) (api.FlowChallengeResponseRequest, error) { - fe.checkPasswordMFA() r := api.NewPasswordChallengeResponseRequest(fe.getAnswer(StagePassword)) return api.PasswordChallengeResponseRequestAsFlowChallengeResponseRequest(r), nil } @@ -52,7 +40,6 @@ func (fe *FlowExecutor) solveChallenge_AuthenticatorValidate(challenge *api.Chal } if devCh.DeviceClass == string(api.DEVICECLASSESENUM_STATIC) || devCh.DeviceClass == string(api.DEVICECLASSESENUM_TOTP) { - fe.checkPasswordMFA() // Only use code-based devices if we have a code in the entered password, // and we haven't selected a push device yet if deviceChallenge == nil && fe.getAnswer(StageAuthenticatorValidate) != "" { diff --git a/internal/outpost/ldap/bind/direct/bind.go b/internal/outpost/ldap/bind/direct/bind.go index 0ec9649bb..0806bff88 100644 --- a/internal/outpost/ldap/bind/direct/bind.go +++ b/internal/outpost/ldap/bind/direct/bind.go @@ -2,6 +2,9 @@ package direct import ( "context" + "regexp" + "strconv" + "strings" "beryju.io/ldap" "github.com/getsentry/sentry-go" @@ -13,6 +16,10 @@ import ( "goauthentik.io/internal/outpost/ldap/metrics" ) +const CodePasswordSeparator = ";" + +var alphaNum = regexp.MustCompile(`^[a-zA-Z0-9]*$`) + func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResultCode, error) { fe := flow.NewFlowExecutor(req.Context(), db.si.GetAuthenticationFlowSlug(), db.si.GetAPIClient().GetConfig(), log.Fields{ "bindDN": req.BindDN, @@ -24,6 +31,7 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul fe.Answers[flow.StageIdentification] = username fe.Answers[flow.StagePassword] = req.BindPW + db.CheckPasswordMFA(fe) passed, err := fe.Execute() flags := flags.UserFlags{ @@ -96,3 +104,41 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul uisp.Finish() return ldap.LDAPResultSuccess, nil } + +func (db *DirectBinder) CheckPasswordMFA(fe *flow.FlowExecutor) { + if !db.si.GetMFASupport() { + return + } + password := fe.Answers[flow.StagePassword] + // We already have an authenticator answer + if fe.Answers[flow.StageAuthenticatorValidate] != "" { + return + } + // password doesn't contain the separator + if !strings.Contains(password, CodePasswordSeparator) { + return + } + // password ends with the separator, so it won't contain an answer + if strings.HasSuffix(password, CodePasswordSeparator) { + return + } + idx := strings.LastIndex(password, CodePasswordSeparator) + authenticator := password[idx+1:] + // Authenticator is either 6 chars (totp code) or 8 chars (long totp or static) + if len(authenticator) == 6 { + // authenticator answer isn't purely numerical, so won't be value + if _, err := strconv.Atoi(authenticator); err != nil { + return + } + } else if len(authenticator) == 8 { + // 8 chars can be a long totp or static token, so it needs to be alphanumerical + if !alphaNum.MatchString(authenticator) { + return + } + } else { + // Any other length, doesn't contain an answer + return + } + fe.Answers[flow.StagePassword] = password[:idx] + fe.Answers[flow.StageAuthenticatorValidate] = authenticator +} diff --git a/internal/outpost/ldap/instance.go b/internal/outpost/ldap/instance.go index 23fbc9fb5..fe6ef7b71 100644 --- a/internal/outpost/ldap/instance.go +++ b/internal/outpost/ldap/instance.go @@ -42,6 +42,7 @@ type ProviderInstance struct { uidStartNumber int32 gidStartNumber int32 + mfaSupport bool } func (pi *ProviderInstance) GetAPIClient() *api.APIClient { @@ -68,6 +69,10 @@ func (pi *ProviderInstance) GetOutpostName() string { return pi.outpostName } +func (pi *ProviderInstance) GetMFASupport() bool { + return pi.mfaSupport +} + func (pi *ProviderInstance) GetFlags(dn string) *flags.UserFlags { pi.boundUsersMutex.RLock() defer pi.boundUsersMutex.RUnlock() diff --git a/internal/outpost/ldap/refresh.go b/internal/outpost/ldap/refresh.go index 0d121ad46..2ecd9a759 100644 --- a/internal/outpost/ldap/refresh.go +++ b/internal/outpost/ldap/refresh.go @@ -66,7 +66,7 @@ func (ls *LDAPServer) Refresh() error { } providers[idx] = &ProviderInstance{ - BaseDN: *provider.BaseDn, + BaseDN: provider.GetBaseDn(), VirtualGroupDN: virtualGroupDN, GroupDN: groupDN, UserDN: userDN, @@ -79,8 +79,9 @@ func (ls *LDAPServer) Refresh() error { s: ls, log: logger, tlsServerName: provider.TlsServerName, - uidStartNumber: *provider.UidStartNumber, - gidStartNumber: *provider.GidStartNumber, + uidStartNumber: provider.GetUidStartNumber(), + gidStartNumber: provider.GetGidStartNumber(), + mfaSupport: provider.GetMfaSupport(), outpostName: ls.ac.Outpost.Name, outpostPk: provider.Pk, } diff --git a/internal/outpost/ldap/server/base.go b/internal/outpost/ldap/server/base.go index d6227e77e..ff6649a03 100644 --- a/internal/outpost/ldap/server/base.go +++ b/internal/outpost/ldap/server/base.go @@ -22,6 +22,7 @@ type LDAPServerInstance interface { GetBaseGroupDN() string GetBaseVirtualGroupDN() string GetBaseUserDN() string + GetMFASupport() bool GetUserDN(string) string GetGroupDN(string) string diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 44b6ccb85..e588ad891 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-13 11:23+0000\n" +"POT-Creation-Date: 2023-06-19 17:34+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -861,7 +861,7 @@ msgstr "" #: authentik/providers/ldap/models.py:53 msgid "" -"The start for uidNumbers, this number is added to the user.Pk to make sure " +"The start for uidNumbers, this number is added to the user.pk to make sure " "that the numbers aren't too low for POSIX users. Default is 2000 to ensure " "that we don't collide with local users uidNumber" msgstr "" @@ -869,16 +869,25 @@ msgstr "" #: authentik/providers/ldap/models.py:62 msgid "" "The start for gidNumbers, this number is added to a number generated from " -"the group.Pk to make sure that the numbers aren't too low for POSIX groups. " +"the group.pk to make sure that the numbers aren't too low for POSIX groups. " "Default is 4000 to ensure that we don't collide with local groups or users " "primary groups gidNumber" msgstr "" -#: authentik/providers/ldap/models.py:97 +#: authentik/providers/ldap/models.py:76 +msgid "" +"When enabled, code-based multi-factor authentication can be used by " +"appending a semicolon and the TOTP code to the password. This should only be " +"enabled if all users that will bind to this provider have a TOTP device " +"configured, as otherwise a password may incorrectly be rejected if it " +"contains a semicolon." +msgstr "" + +#: authentik/providers/ldap/models.py:108 msgid "LDAP Provider" msgstr "" -#: authentik/providers/ldap/models.py:98 +#: authentik/providers/ldap/models.py:109 msgid "LDAP Providers" msgstr "" diff --git a/schema.yml b/schema.yml index 857e4d2a1..211e1e084 100644 --- a/schema.yml +++ b/schema.yml @@ -30796,7 +30796,7 @@ components: type: integer maximum: 2147483647 minimum: -2147483648 - description: The start for uidNumbers, this number is added to the user.Pk + description: The start for uidNumbers, this number is added to the user.pk to make sure that the numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't collide with local users uidNumber gid_start_number: @@ -30804,13 +30804,20 @@ components: maximum: 2147483647 minimum: -2147483648 description: The start for gidNumbers, this number is added to a number - generated from the group.Pk to make sure that the numbers aren't too low + generated from the group.pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber search_mode: $ref: '#/components/schemas/LDAPAPIAccessMode' bind_mode: $ref: '#/components/schemas/LDAPAPIAccessMode' + mfa_support: + type: boolean + description: When enabled, code-based multi-factor authentication can be + used by appending a semicolon and the TOTP code to the password. This + should only be enabled if all users that will bind to this provider have + a TOTP device configured, as otherwise a password may incorrectly be rejected + if it contains a semicolon. required: - application_slug - bind_flow_slug @@ -30966,7 +30973,7 @@ components: type: integer maximum: 2147483647 minimum: -2147483648 - description: The start for uidNumbers, this number is added to the user.Pk + description: The start for uidNumbers, this number is added to the user.pk to make sure that the numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't collide with local users uidNumber gid_start_number: @@ -30974,7 +30981,7 @@ components: maximum: 2147483647 minimum: -2147483648 description: The start for gidNumbers, this number is added to a number - generated from the group.Pk to make sure that the numbers aren't too low + generated from the group.pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber outpost_set: @@ -30986,6 +30993,13 @@ components: $ref: '#/components/schemas/LDAPAPIAccessMode' bind_mode: $ref: '#/components/schemas/LDAPAPIAccessMode' + mfa_support: + type: boolean + description: When enabled, code-based multi-factor authentication can be + used by appending a semicolon and the TOTP code to the password. This + should only be enabled if all users that will bind to this provider have + a TOTP device configured, as otherwise a password may incorrectly be rejected + if it contains a semicolon. required: - assigned_application_name - assigned_application_slug @@ -31041,7 +31055,7 @@ components: type: integer maximum: 2147483647 minimum: -2147483648 - description: The start for uidNumbers, this number is added to the user.Pk + description: The start for uidNumbers, this number is added to the user.pk to make sure that the numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't collide with local users uidNumber gid_start_number: @@ -31049,13 +31063,20 @@ components: maximum: 2147483647 minimum: -2147483648 description: The start for gidNumbers, this number is added to a number - generated from the group.Pk to make sure that the numbers aren't too low + generated from the group.pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber search_mode: $ref: '#/components/schemas/LDAPAPIAccessMode' bind_mode: $ref: '#/components/schemas/LDAPAPIAccessMode' + mfa_support: + type: boolean + description: When enabled, code-based multi-factor authentication can be + used by appending a semicolon and the TOTP code to the password. This + should only be enabled if all users that will bind to this provider have + a TOTP device configured, as otherwise a password may incorrectly be rejected + if it contains a semicolon. required: - authorization_flow - name @@ -36721,7 +36742,7 @@ components: type: integer maximum: 2147483647 minimum: -2147483648 - description: The start for uidNumbers, this number is added to the user.Pk + description: The start for uidNumbers, this number is added to the user.pk to make sure that the numbers aren't too low for POSIX users. Default is 2000 to ensure that we don't collide with local users uidNumber gid_start_number: @@ -36729,13 +36750,20 @@ components: maximum: 2147483647 minimum: -2147483648 description: The start for gidNumbers, this number is added to a number - generated from the group.Pk to make sure that the numbers aren't too low + generated from the group.pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber search_mode: $ref: '#/components/schemas/LDAPAPIAccessMode' bind_mode: $ref: '#/components/schemas/LDAPAPIAccessMode' + mfa_support: + type: boolean + description: When enabled, code-based multi-factor authentication can be + used by appending a semicolon and the TOTP code to the password. This + should only be enabled if all users that will bind to this provider have + a TOTP device configured, as otherwise a password may incorrectly be rejected + if it contains a semicolon. PatchedLDAPSourceRequest: type: object description: LDAP Source Serializer diff --git a/web/src/admin/providers/ldap/LDAPProviderForm.ts b/web/src/admin/providers/ldap/LDAPProviderForm.ts index 6c240b2c2..0a4df7ada 100644 --- a/web/src/admin/providers/ldap/LDAPProviderForm.ts +++ b/web/src/admin/providers/ldap/LDAPProviderForm.ts @@ -187,6 +187,27 @@ export class LDAPProviderFormPage extends ModelForm { ${msg("Configure how the outpost queries the core authentik server's users.")}

+ + +

+ ${msg( + "When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon.", + )} +

+
+ ${msg("Protocol settings")}
diff --git a/web/xliff/de.xlf b/web/xliff/de.xlf index a90848884..ec897f2f5 100644 --- a/web/xliff/de.xlf +++ b/web/xliff/de.xlf @@ -5741,6 +5741,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index f0df388df..8832f00fb 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -6057,6 +6057,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/web/xliff/es.xlf b/web/xliff/es.xlf index 081c8d4c3..972e7a147 100644 --- a/web/xliff/es.xlf +++ b/web/xliff/es.xlf @@ -5649,6 +5649,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/web/xliff/fr_FR.xlf b/web/xliff/fr_FR.xlf index 0d21fcd2e..f095b0459 100644 --- a/web/xliff/fr_FR.xlf +++ b/web/xliff/fr_FR.xlf @@ -5756,6 +5756,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/web/xliff/pl.xlf b/web/xliff/pl.xlf index 94eca296d..29646ec36 100644 --- a/web/xliff/pl.xlf +++ b/web/xliff/pl.xlf @@ -5888,6 +5888,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/web/xliff/pseudo-LOCALE.xlf b/web/xliff/pseudo-LOCALE.xlf index 8ca96535d..97bd3abef 100644 --- a/web/xliff/pseudo-LOCALE.xlf +++ b/web/xliff/pseudo-LOCALE.xlf @@ -5992,6 +5992,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/web/xliff/tr.xlf b/web/xliff/tr.xlf index eb51cbd78..15f95e098 100644 --- a/web/xliff/tr.xlf +++ b/web/xliff/tr.xlf @@ -5639,6 +5639,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 78ea7eb92..c4808491d 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -618,9 +618,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1072,8 +1072,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1819,8 +1819,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -3248,8 +3248,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -4046,8 +4046,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -4056,8 +4056,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -4253,10 +4253,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5372,7 +5372,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5712,10 +5712,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5764,7 +5764,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7572,7 +7572,13 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. 匹配选定模型创建的事件。如果留空,则匹配所有模型。 + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. - \ No newline at end of file + diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index d0f164b2f..d4deb9e1c 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -5694,6 +5694,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/web/xliff/zh_TW.xlf b/web/xliff/zh_TW.xlf index fd8c4ac91..1111b9d13 100644 --- a/web/xliff/zh_TW.xlf +++ b/web/xliff/zh_TW.xlf @@ -5693,6 +5693,12 @@ Bindings to groups/users are checked against the user of the event. Match events created by selected model. When left empty, all models are matched. + + + Code-based MFA Support + + + When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon. diff --git a/website/docs/providers/ldap/index.md b/website/docs/providers/ldap/index.md index f5714a9d4..7163bb2dd 100644 --- a/website/docs/providers/ldap/index.md +++ b/website/docs/providers/ldap/index.md @@ -80,6 +80,8 @@ The following stages are supported: Note: Authenticator validation currently only supports DUO, TOTP and static authenticators. + Starting with authentik 2023.6, code-based authenticators are only supported when _Code-based MFA Support_ is enabled in the provider. When enabled, all users that will bind to the LDAP provider should have a TOTP device configured, as otherwise a password might be incorrectly rejected when semicolons are used in the password. + For code-based authenticators, the code must be given as part of the bind password, separated by a semicolon. For example for the password `example-password` and the code `123456`, the input must be `example-password;123456`. SMS-based authenticators are not supported as they require a code to be sent from authentik, which is not possible during the bind.