From 7911b2466d892386721952991d5150412530fb6e Mon Sep 17 00:00:00 2001 From: Florence Blanc-Renaud Date: Jun 01 2023 06:20:37 +0000 Subject: CLI: add support for passkey authentication type Add a new authentication type for Passkey in the following commands: ipa user-add --user-auth-type=AUTHTYPE ipa user-mod --user-auth-type=AUTHTYPE ipa config-mod --user-auth-type=AUTHTYPE ipa service-add --auth-ind=AUTHTYPE ipa service-mod --auth-ind=AUTHTYPE ipa host-add --auth-ind=AUTHTYPE ipa host-mod --auth-ind=AUTHTYPE ipa krbtpolicy-mod --passkey-maxlife=INT --passkey-maxrenew=INT Fixes: https://pagure.io/freeipa/issue/9262 Signed-off-by: Florence Blanc-Renaud Reviewed-By: Alexander Bokovoy --- diff --git a/API.txt b/API.txt index e0c4847..8dc7711 100644 --- a/API.txt +++ b/API.txt @@ -1099,7 +1099,7 @@ option: Int('ipasearchrecordslimit?', autofill=False, cli_name='searchrecordslim option: Int('ipasearchtimelimit?', autofill=False, cli_name='searchtimelimit') option: Str('ipaselinuxusermapdefault?', autofill=False) option: Str('ipaselinuxusermaporder?', autofill=False) -option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'disabled']) +option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey', u'disabled']) option: Bool('ipauserdefaultsubordinateid?', autofill=False, cli_name='user_default_subid') option: Str('ipauserobjectclasses*', autofill=False, cli_name='userobjectclasses') option: IA5Str('ipausersearchfields?', autofill=False, cli_name='usersearch') @@ -2478,7 +2478,7 @@ option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate') option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate') option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth') option: Str('ipasshpubkey*', cli_name='sshpubkey') -option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: Str('l?', cli_name='locality') option: Str('macaddress*') option: Flag('no_members', autofill=True, default=False) @@ -2653,7 +2653,7 @@ option: Str('in_netgroup*', cli_name='in_netgroups') option: Str('in_role*', cli_name='in_roles') option: Str('in_sudorule*', cli_name='in_sudorules') option: Str('ipaassignedidview?', autofill=False) -option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: Str('l?', autofill=False, cli_name='locality') option: Str('macaddress*', autofill=False) option: Str('man_by_host*', cli_name='man_by_hosts') @@ -2693,7 +2693,7 @@ option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate') option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate') option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth') option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey') -option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: Principal('krbprincipalname*', autofill=False) option: Str('l?', autofill=False, cli_name='locality') option: Str('macaddress*', autofill=False) @@ -3377,7 +3377,7 @@ output: Output('result', type=[]) output: Output('summary', type=[, ]) output: PrimaryKey('value') command: krbtpolicy_mod/1 -args: 1,19,3 +args: 1,21,3 arg: Str('uid?', cli_name='user') option: Str('addattr*', cli_name='addattr') option: Flag('all', autofill=True, cli_name='all', default=False) @@ -3385,11 +3385,13 @@ option: Str('delattr*', cli_name='delattr') option: Int('krbauthindmaxrenewableage_hardened?', autofill=False, cli_name='hardened_maxrenew') option: Int('krbauthindmaxrenewableage_idp?', autofill=False, cli_name='idp_maxrenew') option: Int('krbauthindmaxrenewableage_otp?', autofill=False, cli_name='otp_maxrenew') +option: Int('krbauthindmaxrenewableage_passkey?', autofill=False, cli_name='passkey_maxrenew') option: Int('krbauthindmaxrenewableage_pkinit?', autofill=False, cli_name='pkinit_maxrenew') option: Int('krbauthindmaxrenewableage_radius?', autofill=False, cli_name='radius_maxrenew') option: Int('krbauthindmaxticketlife_hardened?', autofill=False, cli_name='hardened_maxlife') option: Int('krbauthindmaxticketlife_idp?', autofill=False, cli_name='idp_maxlife') option: Int('krbauthindmaxticketlife_otp?', autofill=False, cli_name='otp_maxlife') +option: Int('krbauthindmaxticketlife_passkey?', autofill=False, cli_name='passkey_maxlife') option: Int('krbauthindmaxticketlife_pkinit?', autofill=False, cli_name='pkinit_maxlife') option: Int('krbauthindmaxticketlife_radius?', autofill=False, cli_name='radius_maxlife') option: Int('krbmaxrenewableage?', autofill=False, cli_name='maxrenew') @@ -4756,7 +4758,7 @@ option: StrEnum('ipakrbauthzdata*', cli_name='pac_type', values=[u'MS-PAC', u'PA option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate') option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate') option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth') -option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('krbprincipalauthind*', cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: Flag('no_members', autofill=True, default=False) option: Flag('raw', autofill=True, cli_name='raw', default=False) option: Str('setattr*', cli_name='setattr') @@ -4931,7 +4933,7 @@ arg: Str('criteria?') option: Flag('all', autofill=True, cli_name='all', default=False) option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=[u'MS-PAC', u'PAD', u'NONE']) option: Principal('krbcanonicalname?', autofill=False, cli_name='canonical_principal') -option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: Principal('krbprincipalname*', autofill=False, cli_name='principal') option: Str('man_by_host*', cli_name='man_by_hosts') option: Flag('no_members', autofill=True, default=True) @@ -4955,7 +4957,7 @@ option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values= option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate') option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate') option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth') -option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('krbprincipalauthind*', autofill=False, cli_name='auth_ind', values=[u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: Principal('krbprincipalname*', autofill=False, cli_name='principal') option: Flag('no_members', autofill=True, default=False) option: Flag('raw', autofill=True, cli_name='raw', default=False) @@ -5216,7 +5218,7 @@ option: Str('ipaidpsub?', cli_name='idp_user_id') option: Str('ipasshpubkey*', cli_name='sshpubkey') option: Str('ipatokenradiusconfiglink?', cli_name='radius') option: Str('ipatokenradiususername?', cli_name='radius_username') -option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: DateTime('krbpasswordexpiration?', cli_name='password_expiration') option: DateTime('krbprincipalexpiration?', cli_name='principal_expiration') option: Principal('krbprincipalname*', autofill=True, cli_name='principal') @@ -5342,7 +5344,7 @@ option: Str('ipantlogonscript?', autofill=False, cli_name='smb_logon_script') option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path') option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius') option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username') -option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration') option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration') option: Principal('krbprincipalname*', autofill=False, cli_name='principal') @@ -5408,7 +5410,7 @@ option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path') option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey') option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius') option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username') -option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration') option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration') option: Principal('krbprincipalname*', autofill=False, cli_name='principal') @@ -6423,7 +6425,7 @@ option: Str('ipaidpsub?', cli_name='idp_user_id') option: Str('ipasshpubkey*', cli_name='sshpubkey') option: Str('ipatokenradiusconfiglink?', cli_name='radius') option: Str('ipatokenradiususername?', cli_name='radius_username') -option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('ipauserauthtype*', cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: DateTime('krbpasswordexpiration?', cli_name='password_expiration') option: DateTime('krbprincipalexpiration?', cli_name='principal_expiration') option: Principal('krbprincipalname*', autofill=True, cli_name='principal') @@ -6566,7 +6568,7 @@ option: Str('ipantlogonscript?', autofill=False, cli_name='smb_logon_script') option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path') option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius') option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username') -option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration') option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration') option: Principal('krbprincipalname*', autofill=False, cli_name='principal') @@ -6635,7 +6637,7 @@ option: Str('ipantprofilepath?', autofill=False, cli_name='smb_profile_path') option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey') option: Str('ipatokenradiusconfiglink?', autofill=False, cli_name='radius') option: Str('ipatokenradiususername?', autofill=False, cli_name='radius_username') -option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp']) +option: StrEnum('ipauserauthtype*', autofill=False, cli_name='user_auth_type', values=[u'password', u'radius', u'otp', u'pkinit', u'hardened', u'idp', u'passkey']) option: DateTime('krbpasswordexpiration?', autofill=False, cli_name='password_expiration') option: DateTime('krbprincipalexpiration?', autofill=False, cli_name='principal_expiration') option: Principal('krbprincipalname*', autofill=False, cli_name='principal') diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py index b5ac8be..8d44580 100644 --- a/ipaserver/plugins/baseuser.py +++ b/ipaserver/plugins/baseuser.py @@ -405,7 +405,7 @@ class baseuser(LDAPObject): label=_('User authentication types'), doc=_('Types of supported user authentication'), values=(u'password', u'radius', u'otp', u'pkinit', u'hardened', - u'idp'), + u'idp', u'passkey'), ), Str('userclass*', cli_name='class', diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py index 4035f7e..eface54 100644 --- a/ipaserver/plugins/config.py +++ b/ipaserver/plugins/config.py @@ -269,7 +269,7 @@ class config(LDAPObject): label=_('Default user authentication types'), doc=_('Default types of supported user authentication'), values=(u'password', u'radius', u'otp', - u'pkinit', u'hardened', u'idp', u'disabled'), + u'pkinit', u'hardened', u'idp', u'passkey', u'disabled'), ), Bool('ipauserdefaultsubordinateid?', cli_name='user_default_subid', diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py index e3eb7ae..b8d97d3 100644 --- a/ipaserver/plugins/host.py +++ b/ipaserver/plugins/host.py @@ -630,9 +630,11 @@ class host(LDAPObject): " authentication by SPAKE or FAST." " Use 'idp' to allow External Identity Provider" " authentications." + " Use 'passkey' to allow passkey-based 2FA authentications." " With no indicator specified," " all authentication mechanisms are allowed."), - values=(u'radius', u'otp', u'pkinit', u'hardened', u'idp'), + values=(u'radius', u'otp', u'pkinit', u'hardened', u'idp', + u'passkey'), ), ) + ticket_flags_params diff --git a/ipaserver/plugins/internal.py b/ipaserver/plugins/internal.py index e1e920f..b8f68f1 100644 --- a/ipaserver/plugins/internal.py +++ b/ipaserver/plugins/internal.py @@ -196,6 +196,7 @@ class i18n_messages(Command): "type_pkinit": _("PKINIT"), "type_hardened": _("Hardened Password (by SPAKE or FAST)"), "type_idp": _("External Identity Provider"), + "type_passkey": _("Passkey"), "type_disabled": _("Disable per-user override"), "user_tooltip": _("

Per-user setting, overwrites the global setting if any option is checked.

Password + Two-factor: LDAP and Kerberos allow authentication with either one of the authentication types but Kerberos uses pre-authentication method which requires to use armor ccache.

RADIUS with another type: Kerberos always use RADIUS, but LDAP never does. LDAP only recognize the password and two-factor authentication options.

"), }, diff --git a/ipaserver/plugins/krbtpolicy.py b/ipaserver/plugins/krbtpolicy.py index 610e1ca..ba13602 100644 --- a/ipaserver/plugins/krbtpolicy.py +++ b/ipaserver/plugins/krbtpolicy.py @@ -75,7 +75,7 @@ _default_values = { # These attributes never have non-optional values, so they should be # ignored in post callbacks _option_based_attrs = ('krbauthindmaxticketlife', 'krbauthindmaxrenewableage') -_supported_options = ('otp', 'radius', 'pkinit', 'hardened', 'idp') +_supported_options = ('otp', 'radius', 'pkinit', 'hardened', 'idp', 'passkey') @register() class krbtpolicy(baseldap.LDAPObject): @@ -199,6 +199,16 @@ class krbtpolicy(baseldap.LDAPObject): doc=_('External Identity Provider ticket maximum renewable ' 'age (seconds)'), minvalue=1), + Int('krbauthindmaxticketlife_passkey?', + cli_name='passkey_maxlife', + label=_('Passkey max life'), + doc=_('Passkey ticket maximum ticket life (seconds)'), + minvalue=1), + Int('krbauthindmaxrenewableage_passkey?', + cli_name='passkey_maxrenew', + label=_('Passkey max renew'), + doc=_('Passkey ticket maximum renewable age (seconds)'), + minvalue=1), ) def get_dn(self, *keys, **kwargs): diff --git a/ipaserver/plugins/service.py b/ipaserver/plugins/service.py index d3b6cd2..f4b1072 100644 --- a/ipaserver/plugins/service.py +++ b/ipaserver/plugins/service.py @@ -614,9 +614,11 @@ class service(LDAPObject): " Use 'idp' to allow authentication against an external" " Identity Provider supporting OAuth 2.0 Device" " Authorization Flow (RFC 8628)." + " Use 'passkey' to allow passkey-based 2FA authentications." " With no indicator specified," " all authentication mechanisms are allowed."), - values=(u'radius', u'otp', u'pkinit', u'hardened', u'idp'), + values=(u'radius', u'otp', u'pkinit', u'hardened', u'idp', + u'passkey'), ), ) + ticket_flags_params