mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
API: add new commands for passkey mappings
- ipa user-add-passkey - ipa user-remove-passkey - ipa stageuser-add-passkey - ipa stageuser-remove-passkey Fixes: https://pagure.io/freeipa/issue/9261 Signed-off-by: Florence Blanc-Renaud <flo@redhat.com> Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
parent
4bd1be9e90
commit
a21214cb9e
4
ACI.txt
4
ACI.txt
@ -387,6 +387,8 @@ aci: (targetattr = "krbpasswordexpiration || krbprincipalkey || passwordhistory
|
|||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "krbpasswordexpiration || krbprincipalkey || passwordhistory || sambalmpassword || sambantpassword || userpassword")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Change User password";allow (write) groupdn = "ldap:///cn=System: Change User password,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "krbpasswordexpiration || krbprincipalkey || passwordhistory || sambalmpassword || sambantpassword || userpassword")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Change User password";allow (write) groupdn = "ldap:///cn=System: Change User password,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
|
aci: (targetattr = "ipapasskey || objectclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage Passkey Mappings";allow (write) groupdn = "ldap:///cn=System: Manage Passkey Mappings,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "ipacertmapdata || objectclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User Certificate Mappings";allow (write) groupdn = "ldap:///cn=System: Manage User Certificate Mappings,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "ipacertmapdata || objectclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User Certificate Mappings";allow (write) groupdn = "ldap:///cn=System: Manage User Certificate Mappings,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "usercertificate")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Manage User Certificates";allow (write) groupdn = "ldap:///cn=System: Manage User Certificates,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
aci: (targetattr = "usercertificate")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Manage User Certificates";allow (write) groupdn = "ldap:///cn=System: Manage User Certificates,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||||
@ -403,7 +405,7 @@ aci: (targetattr = "audio || businesscategory || carlicense || departmentnumber
|
|||||||
dn: dc=ipa,dc=example
|
dn: dc=ipa,dc=example
|
||||||
aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || loginshell || modifytimestamp || objectclass || uid || uidnumber")(target = "ldap:///cn=users,cn=compat,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read User Compat Tree";allow (compare,read,search) userdn = "ldap:///anyone";)
|
aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || loginshell || modifytimestamp || objectclass || uid || uidnumber")(target = "ldap:///cn=users,cn=compat,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read User Compat Tree";allow (compare,read,search) userdn = "ldap:///anyone";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "ipasshpubkey || ipauniqueid || ipauserauthtype || userclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User IPA Attributes";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "ipapasskey || ipasshpubkey || ipauniqueid || ipauserauthtype || userclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User IPA Attributes";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
aci: (targetattr = "krbcanonicalname || krblastpwdchange || krbpasswordexpiration || krbprincipalaliases || krbprincipalexpiration || krbprincipalname || krbprincipaltype || nsaccountlock")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Kerberos Attributes";allow (compare,read,search) userdn = "ldap:///all";)
|
aci: (targetattr = "krbcanonicalname || krblastpwdchange || krbpasswordexpiration || krbprincipalaliases || krbprincipalexpiration || krbprincipalname || krbprincipaltype || nsaccountlock")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Kerberos Attributes";allow (compare,read,search) userdn = "ldap:///all";)
|
||||||
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
dn: cn=users,cn=accounts,dc=ipa,dc=example
|
||||||
|
48
API.txt
48
API.txt
@ -5282,6 +5282,17 @@ option: Str('version?')
|
|||||||
output: Output('completed', type=[<type 'int'>])
|
output: Output('completed', type=[<type 'int'>])
|
||||||
output: Output('failed', type=[<type 'dict'>])
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
|
command: stageuser_add_passkey/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('uid', cli_name='login')
|
||||||
|
arg: Str('ipapasskey+', alwaysask=True, cli_name='passkey')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: stageuser_add_principal/1
|
command: stageuser_add_principal/1
|
||||||
args: 2,4,3
|
args: 2,4,3
|
||||||
arg: Str('uid', cli_name='login')
|
arg: Str('uid', cli_name='login')
|
||||||
@ -5465,6 +5476,17 @@ option: Str('version?')
|
|||||||
output: Output('completed', type=[<type 'int'>])
|
output: Output('completed', type=[<type 'int'>])
|
||||||
output: Output('failed', type=[<type 'dict'>])
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
|
command: stageuser_remove_passkey/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('uid', cli_name='login')
|
||||||
|
arg: Str('ipapasskey+', alwaysask=True, cli_name='passkey')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: stageuser_remove_principal/1
|
command: stageuser_remove_principal/1
|
||||||
args: 2,4,3
|
args: 2,4,3
|
||||||
arg: Str('uid', cli_name='login')
|
arg: Str('uid', cli_name='login')
|
||||||
@ -6469,6 +6491,17 @@ option: Str('version?')
|
|||||||
output: Output('completed', type=[<type 'int'>])
|
output: Output('completed', type=[<type 'int'>])
|
||||||
output: Output('failed', type=[<type 'dict'>])
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
|
command: user_add_passkey/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('uid', cli_name='login')
|
||||||
|
arg: Str('ipapasskey+', alwaysask=True, cli_name='passkey')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: user_add_principal/1
|
command: user_add_principal/1
|
||||||
args: 2,4,3
|
args: 2,4,3
|
||||||
arg: Str('uid', cli_name='login')
|
arg: Str('uid', cli_name='login')
|
||||||
@ -6671,6 +6704,17 @@ option: Str('version?')
|
|||||||
output: Output('completed', type=[<type 'int'>])
|
output: Output('completed', type=[<type 'int'>])
|
||||||
output: Output('failed', type=[<type 'dict'>])
|
output: Output('failed', type=[<type 'dict'>])
|
||||||
output: Entry('result')
|
output: Entry('result')
|
||||||
|
command: user_remove_passkey/1
|
||||||
|
args: 2,4,3
|
||||||
|
arg: Str('uid', cli_name='login')
|
||||||
|
arg: Str('ipapasskey+', alwaysask=True, cli_name='passkey')
|
||||||
|
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||||
|
option: Flag('no_members', autofill=True, default=False)
|
||||||
|
option: Flag('raw', autofill=True, cli_name='raw', default=False)
|
||||||
|
option: Str('version?')
|
||||||
|
output: Entry('result')
|
||||||
|
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||||
|
output: PrimaryKey('value')
|
||||||
command: user_remove_principal/1
|
command: user_remove_principal/1
|
||||||
args: 2,4,3
|
args: 2,4,3
|
||||||
arg: Str('uid', cli_name='login')
|
arg: Str('uid', cli_name='login')
|
||||||
@ -7445,6 +7489,7 @@ default: stageuser_add/1
|
|||||||
default: stageuser_add_cert/1
|
default: stageuser_add_cert/1
|
||||||
default: stageuser_add_certmapdata/1
|
default: stageuser_add_certmapdata/1
|
||||||
default: stageuser_add_manager/1
|
default: stageuser_add_manager/1
|
||||||
|
default: stageuser_add_passkey/1
|
||||||
default: stageuser_add_principal/1
|
default: stageuser_add_principal/1
|
||||||
default: stageuser_del/1
|
default: stageuser_del/1
|
||||||
default: stageuser_find/1
|
default: stageuser_find/1
|
||||||
@ -7452,6 +7497,7 @@ default: stageuser_mod/1
|
|||||||
default: stageuser_remove_cert/1
|
default: stageuser_remove_cert/1
|
||||||
default: stageuser_remove_certmapdata/1
|
default: stageuser_remove_certmapdata/1
|
||||||
default: stageuser_remove_manager/1
|
default: stageuser_remove_manager/1
|
||||||
|
default: stageuser_remove_passkey/1
|
||||||
default: stageuser_remove_principal/1
|
default: stageuser_remove_principal/1
|
||||||
default: stageuser_show/1
|
default: stageuser_show/1
|
||||||
default: subid/1
|
default: subid/1
|
||||||
@ -7540,6 +7586,7 @@ default: user_add/1
|
|||||||
default: user_add_cert/1
|
default: user_add_cert/1
|
||||||
default: user_add_certmapdata/1
|
default: user_add_certmapdata/1
|
||||||
default: user_add_manager/1
|
default: user_add_manager/1
|
||||||
|
default: user_add_passkey/1
|
||||||
default: user_add_principal/1
|
default: user_add_principal/1
|
||||||
default: user_del/1
|
default: user_del/1
|
||||||
default: user_disable/1
|
default: user_disable/1
|
||||||
@ -7549,6 +7596,7 @@ default: user_mod/1
|
|||||||
default: user_remove_cert/1
|
default: user_remove_cert/1
|
||||||
default: user_remove_certmapdata/1
|
default: user_remove_certmapdata/1
|
||||||
default: user_remove_manager/1
|
default: user_remove_manager/1
|
||||||
|
default: user_remove_passkey/1
|
||||||
default: user_remove_principal/1
|
default: user_remove_principal/1
|
||||||
default: user_show/1
|
default: user_show/1
|
||||||
default: user_stage/1
|
default: user_stage/1
|
||||||
|
@ -382,6 +382,7 @@ IPA API Commands
|
|||||||
stageuser_add_cert.md
|
stageuser_add_cert.md
|
||||||
stageuser_add_certmapdata.md
|
stageuser_add_certmapdata.md
|
||||||
stageuser_add_manager.md
|
stageuser_add_manager.md
|
||||||
|
stageuser_add_passkey.md
|
||||||
stageuser_add_principal.md
|
stageuser_add_principal.md
|
||||||
stageuser_del.md
|
stageuser_del.md
|
||||||
stageuser_find.md
|
stageuser_find.md
|
||||||
@ -389,6 +390,7 @@ IPA API Commands
|
|||||||
stageuser_remove_cert.md
|
stageuser_remove_cert.md
|
||||||
stageuser_remove_certmapdata.md
|
stageuser_remove_certmapdata.md
|
||||||
stageuser_remove_manager.md
|
stageuser_remove_manager.md
|
||||||
|
stageuser_remove_passkey.md
|
||||||
stageuser_remove_principal.md
|
stageuser_remove_principal.md
|
||||||
stageuser_show.md
|
stageuser_show.md
|
||||||
subid_add.md
|
subid_add.md
|
||||||
@ -466,6 +468,7 @@ IPA API Commands
|
|||||||
user_add_cert.md
|
user_add_cert.md
|
||||||
user_add_certmapdata.md
|
user_add_certmapdata.md
|
||||||
user_add_manager.md
|
user_add_manager.md
|
||||||
|
user_add_passkey.md
|
||||||
user_add_principal.md
|
user_add_principal.md
|
||||||
user_del.md
|
user_del.md
|
||||||
user_disable.md
|
user_disable.md
|
||||||
@ -475,6 +478,7 @@ IPA API Commands
|
|||||||
user_remove_cert.md
|
user_remove_cert.md
|
||||||
user_remove_certmapdata.md
|
user_remove_certmapdata.md
|
||||||
user_remove_manager.md
|
user_remove_manager.md
|
||||||
|
user_remove_passkey.md
|
||||||
user_remove_principal.md
|
user_remove_principal.md
|
||||||
user_show.md
|
user_show.md
|
||||||
user_stage.md
|
user_stage.md
|
||||||
|
32
doc/api/stageuser_add_passkey.md
Normal file
32
doc/api/stageuser_add_passkey.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
# stageuser_add_passkey
|
||||||
|
Add one or more passkey mappings to the stage user entry.
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|Name|Type|Required
|
||||||
|
|-|-|-
|
||||||
|
|uid|:ref:`Str<Str>`|True
|
||||||
|
|ipapasskey|:ref:`Str<Str>`|True
|
||||||
|
|
||||||
|
### Options
|
||||||
|
* all : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* raw : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* no_members : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* version : :ref:`Str<Str>`
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|Name|Type
|
||||||
|
|-|-
|
||||||
|
|result|Entry
|
||||||
|
|summary|Output
|
||||||
|
|value|PrimaryKey
|
||||||
|
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
### Semantics
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
### Version differences
|
32
doc/api/stageuser_remove_passkey.md
Normal file
32
doc/api/stageuser_remove_passkey.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
# stageuser_remove_passkey
|
||||||
|
Remove one or more passkey mappings from the stage user entry.
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|Name|Type|Required
|
||||||
|
|-|-|-
|
||||||
|
|uid|:ref:`Str<Str>`|True
|
||||||
|
|ipapasskey|:ref:`Str<Str>`|True
|
||||||
|
|
||||||
|
### Options
|
||||||
|
* all : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* raw : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* no_members : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* version : :ref:`Str<Str>`
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|Name|Type
|
||||||
|
|-|-
|
||||||
|
|result|Entry
|
||||||
|
|summary|Output
|
||||||
|
|value|PrimaryKey
|
||||||
|
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
### Semantics
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
### Version differences
|
32
doc/api/user_add_passkey.md
Normal file
32
doc/api/user_add_passkey.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
# user_add_passkey
|
||||||
|
Add one or more passkey mappings to the user entry.
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|Name|Type|Required
|
||||||
|
|-|-|-
|
||||||
|
|uid|:ref:`Str<Str>`|True
|
||||||
|
|ipapasskey|:ref:`Str<Str>`|True
|
||||||
|
|
||||||
|
### Options
|
||||||
|
* all : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* raw : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* no_members : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* version : :ref:`Str<Str>`
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|Name|Type
|
||||||
|
|-|-
|
||||||
|
|result|Entry
|
||||||
|
|summary|Output
|
||||||
|
|value|PrimaryKey
|
||||||
|
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
### Semantics
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
### Version differences
|
32
doc/api/user_remove_passkey.md
Normal file
32
doc/api/user_remove_passkey.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[//]: # (THE CONTENT BELOW IS GENERATED. DO NOT EDIT.)
|
||||||
|
# user_remove_passkey
|
||||||
|
Remove one or more passkey mappings from the user entry.
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
|Name|Type|Required
|
||||||
|
|-|-|-
|
||||||
|
|uid|:ref:`Str<Str>`|True
|
||||||
|
|ipapasskey|:ref:`Str<Str>`|True
|
||||||
|
|
||||||
|
### Options
|
||||||
|
* all : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* raw : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* no_members : :ref:`Flag<Flag>` **(Required)**
|
||||||
|
* Default: False
|
||||||
|
* version : :ref:`Str<Str>`
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|Name|Type
|
||||||
|
|-|-
|
||||||
|
|result|Entry
|
||||||
|
|summary|Output
|
||||||
|
|value|PrimaryKey
|
||||||
|
|
||||||
|
[//]: # (ADD YOUR NOTES BELOW. THESE WILL BE PICKED EVERY TIME THE DOCS ARE REGENERATED. //end)
|
||||||
|
### Semantics
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
### Version differences
|
@ -12,3 +12,6 @@ default:objectClass: groupofnames
|
|||||||
default:objectClass: nestedgroup
|
default:objectClass: nestedgroup
|
||||||
default:cn: Passkey Administrators
|
default:cn: Passkey Administrators
|
||||||
default:description: Passkey Administrators
|
default:description: Passkey Administrators
|
||||||
|
|
||||||
|
dn: $SUFFIX
|
||||||
|
add:aci: (targetattr = "ipapasskey")(targattrfilters="add=objectclass:(objectclass=ipapasskeyuser)")(version 3.0;acl "selfservice:Users can manage their own passkey mappings";allow (write) userdn = "ldap:///self";)
|
93
ipaclient/plugins/baseuser.py
Normal file
93
ipaclient/plugins/baseuser.py
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2022 FreeIPA Contributors see COPYING for license
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import locale
|
||||||
|
import logging
|
||||||
|
import subprocess
|
||||||
|
from ipaclient.frontend import MethodOverride
|
||||||
|
from ipalib import errors
|
||||||
|
from ipalib import Bool, Flag, StrEnum
|
||||||
|
from ipalib.text import _
|
||||||
|
from ipaplatform.paths import paths
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class baseuser_add_passkey(MethodOverride):
|
||||||
|
takes_options = (
|
||||||
|
Flag(
|
||||||
|
'register',
|
||||||
|
cli_name='register',
|
||||||
|
doc=_('Register the passkey'),
|
||||||
|
),
|
||||||
|
Bool(
|
||||||
|
'require_user_verification?',
|
||||||
|
cli_name='require_user_verification',
|
||||||
|
doc=_('Require user verification during authentication with '
|
||||||
|
'the passkey')
|
||||||
|
),
|
||||||
|
StrEnum(
|
||||||
|
'cosetype?',
|
||||||
|
cli_name='cose_type',
|
||||||
|
doc=_('COSE type to use for registration'),
|
||||||
|
values=('es256', 'rs256', 'eddsa'),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_args(self):
|
||||||
|
# ipapasskey is not mandatory as it can be built
|
||||||
|
# from the registration step
|
||||||
|
for arg in super(baseuser_add_passkey, self).get_args():
|
||||||
|
if arg.name == 'ipapasskey':
|
||||||
|
yield arg.clone(required=False, alwaysask=False)
|
||||||
|
else:
|
||||||
|
yield arg.clone()
|
||||||
|
|
||||||
|
def forward(self, *args, **options):
|
||||||
|
if self.api.env.context == 'cli':
|
||||||
|
# 2 formats are possible for ipa user-add-passkey:
|
||||||
|
# --register [--require-user-verification] [--cose-type ...]
|
||||||
|
# or
|
||||||
|
# passkey:<key id>,<pub key>
|
||||||
|
for option in super(baseuser_add_passkey, self).get_options():
|
||||||
|
if args and option in options:
|
||||||
|
raise errors.MutuallyExclusiveError(
|
||||||
|
reason=_("cannot specify both %s and "
|
||||||
|
"passkey mapping").format(option))
|
||||||
|
# if the first format is used, need to register the key first
|
||||||
|
# and obtained the data
|
||||||
|
if 'register' in options:
|
||||||
|
# Ensure the executable exists
|
||||||
|
if not os.path.exists(paths.PASSKEY_CHILD):
|
||||||
|
raise errors.ValidationError(name="register", error=_(
|
||||||
|
"Missing executable %s, use the command with "
|
||||||
|
"LOGIN PASSKEY instead of LOGIN --register")
|
||||||
|
% paths.PASSKEY_CHILD)
|
||||||
|
|
||||||
|
options.pop('register')
|
||||||
|
cosetype = options.pop('cosetype', None)
|
||||||
|
require_verif = options.pop('require_user_verification', None)
|
||||||
|
cmd = [paths.PASSKEY_CHILD, "--register",
|
||||||
|
"--domain", self.api.env.domain,
|
||||||
|
"--username", args[0]]
|
||||||
|
if cosetype:
|
||||||
|
cmd.append("--type")
|
||||||
|
cmd.append(cosetype)
|
||||||
|
if require_verif is not None:
|
||||||
|
cmd.append("--user-verification")
|
||||||
|
cmd.append(str(require_verif).lower())
|
||||||
|
|
||||||
|
logger.debug("Executing command: %s", cmd)
|
||||||
|
subp = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||||
|
stdout, _stderr = subp.communicate(None)
|
||||||
|
|
||||||
|
if subp.returncode != 0:
|
||||||
|
raise errors.NotFound(reason="Failed to generate passkey")
|
||||||
|
|
||||||
|
passkey = stdout.decode(locale.getpreferredencoding(),
|
||||||
|
errors='replace').strip()
|
||||||
|
args = (args[0], [passkey])
|
||||||
|
|
||||||
|
return super(baseuser_add_passkey, self).forward(*args, **options)
|
14
ipaclient/plugins/stageuser.py
Normal file
14
ipaclient/plugins/stageuser.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2022 FreeIPA Contributors see COPYING for license
|
||||||
|
#
|
||||||
|
from ipaclient.plugins.baseuser import baseuser_add_passkey
|
||||||
|
from ipalib.plugable import Registry
|
||||||
|
from ipalib import _
|
||||||
|
|
||||||
|
|
||||||
|
register = Registry()
|
||||||
|
|
||||||
|
|
||||||
|
@register(override=True, no_fail=True)
|
||||||
|
class stageuser_add_passkey(baseuser_add_passkey):
|
||||||
|
__doc__ = _("Add one or more passkey mappings to the user entry.")
|
@ -19,6 +19,7 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from ipaclient.frontend import MethodOverride
|
from ipaclient.frontend import MethodOverride
|
||||||
|
from ipaclient.plugins.baseuser import baseuser_add_passkey
|
||||||
from ipalib import errors
|
from ipalib import errors
|
||||||
from ipalib import Flag
|
from ipalib import Flag
|
||||||
from ipalib import util
|
from ipalib import util
|
||||||
@ -79,3 +80,8 @@ class user_show(MethodOverride):
|
|||||||
raise errors.NoCertificateError(entry=keys[-1])
|
raise errors.NoCertificateError(entry=keys[-1])
|
||||||
else:
|
else:
|
||||||
return super(user_show, self).forward(*keys, **options)
|
return super(user_show, self).forward(*keys, **options)
|
||||||
|
|
||||||
|
|
||||||
|
@register(override=True, no_fail=True)
|
||||||
|
class user_add_passkey(baseuser_add_passkey):
|
||||||
|
__doc__ = _("Add one or more passkey mappings to the user entry.")
|
||||||
|
@ -463,6 +463,7 @@ class BasePathNamespace:
|
|||||||
"/var/lib/gssproxy/ipa_ccache_sweeper.sock"
|
"/var/lib/gssproxy/ipa_ccache_sweeper.sock"
|
||||||
)
|
)
|
||||||
PAM_CONFIG = None
|
PAM_CONFIG = None
|
||||||
|
PASSKEY_CHILD = '/usr/libexec/sssd/passkey_child'
|
||||||
|
|
||||||
def check_paths(self):
|
def check_paths(self):
|
||||||
"""Check paths for missing files
|
"""Check paths for missing files
|
||||||
|
@ -17,6 +17,10 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import base64
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives.serialization import load_pem_public_key
|
||||||
|
import re
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from ipalib import api, errors, constants
|
from ipalib import api, errors, constants
|
||||||
@ -157,6 +161,35 @@ def update_samba_attrs(ldap, dn, entry_attrs, **options):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_passkey(ugettext, key):
|
||||||
|
"""
|
||||||
|
Validate the format for passkey mappings.
|
||||||
|
|
||||||
|
The expected format is passkey:<key id>,<pubkey>
|
||||||
|
"""
|
||||||
|
pattern = re.compile(r'passkey:(?P<id>.*),(?P<pkey>.*)')
|
||||||
|
result = re.match(pattern, key)
|
||||||
|
if result is None:
|
||||||
|
return '"%s" is not a valid passkey mapping' % key
|
||||||
|
|
||||||
|
# Validate the id part
|
||||||
|
try:
|
||||||
|
base64.b64decode(result.group('id'))
|
||||||
|
except Exception:
|
||||||
|
return '"%s" is not a valid passkey mapping, invalid id' % key
|
||||||
|
|
||||||
|
# Validate the pkey part
|
||||||
|
try:
|
||||||
|
pem = "-----BEGIN PUBLIC KEY-----\n" + \
|
||||||
|
result.group('pkey') + \
|
||||||
|
"\n-----END PUBLIC KEY-----"
|
||||||
|
load_pem_public_key(data=pem.encode('utf-8'),
|
||||||
|
backend=default_backend())
|
||||||
|
except ValueError:
|
||||||
|
return '"%s" is not a valid passkey mapping, invalid key' % key
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class baseuser(LDAPObject):
|
class baseuser(LDAPObject):
|
||||||
"""
|
"""
|
||||||
baseuser object.
|
baseuser object.
|
||||||
@ -170,7 +203,7 @@ class baseuser(LDAPObject):
|
|||||||
possible_objectclasses = [
|
possible_objectclasses = [
|
||||||
'meporiginentry', 'ipauserauthtypeclass', 'ipauser',
|
'meporiginentry', 'ipauserauthtypeclass', 'ipauser',
|
||||||
'ipatokenradiusproxyuser', 'ipacertmapobject',
|
'ipatokenradiusproxyuser', 'ipacertmapobject',
|
||||||
'ipantuserattrs', 'ipaidpuser',
|
'ipantuserattrs', 'ipaidpuser', 'ipapasskeyuser',
|
||||||
]
|
]
|
||||||
disallow_object_classes = ['krbticketpolicyaux']
|
disallow_object_classes = ['krbticketpolicyaux']
|
||||||
permission_filter_objectclasses = ['posixaccount']
|
permission_filter_objectclasses = ['posixaccount']
|
||||||
@ -186,6 +219,7 @@ class baseuser(LDAPObject):
|
|||||||
'krbprincipalname', 'krbcanonicalname',
|
'krbprincipalname', 'krbcanonicalname',
|
||||||
'ipacertmapdata', 'ipantlogonscript', 'ipantprofilepath',
|
'ipacertmapdata', 'ipantlogonscript', 'ipantprofilepath',
|
||||||
'ipanthomedirectory', 'ipanthomedirectorydrive',
|
'ipanthomedirectory', 'ipanthomedirectorydrive',
|
||||||
|
'ipapasskey',
|
||||||
]
|
]
|
||||||
search_display_attributes = [
|
search_display_attributes = [
|
||||||
'uid', 'givenname', 'sn', 'homedirectory', 'krbcanonicalname',
|
'uid', 'givenname', 'sn', 'homedirectory', 'krbcanonicalname',
|
||||||
@ -451,6 +485,12 @@ class baseuser(LDAPObject):
|
|||||||
'J:', 'K:', 'L:', 'M:', 'N:', 'O:', 'P:', 'Q:', 'R:',
|
'J:', 'K:', 'L:', 'M:', 'N:', 'O:', 'P:', 'Q:', 'R:',
|
||||||
'S:', 'T:', 'U:', 'V:', 'W:', 'X:', 'Y:', 'Z:'),
|
'S:', 'T:', 'U:', 'V:', 'W:', 'X:', 'Y:', 'Z:'),
|
||||||
),
|
),
|
||||||
|
Str('ipapasskey*', validate_passkey,
|
||||||
|
cli_name='passkey',
|
||||||
|
label=_('Passkey mapping'),
|
||||||
|
doc=_('Passkey mapping'),
|
||||||
|
flags=['no_create', 'no_update', 'no_search'],
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def normalize_and_validate_email(self, email, config=None):
|
def normalize_and_validate_email(self, email, config=None):
|
||||||
@ -1011,3 +1051,30 @@ class baseuser_remove_certmapdata(ModCertMapData,
|
|||||||
LDAPRemoveAttribute):
|
LDAPRemoveAttribute):
|
||||||
__doc__ = _("Remove one or more certificate mappings from the user entry.")
|
__doc__ = _("Remove one or more certificate mappings from the user entry.")
|
||||||
msg_summary = _('Removed certificate mappings from user "%(value)s"')
|
msg_summary = _('Removed certificate mappings from user "%(value)s"')
|
||||||
|
|
||||||
|
|
||||||
|
class ModPassKey(LDAPModAttribute):
|
||||||
|
attribute = 'ipapasskey'
|
||||||
|
|
||||||
|
|
||||||
|
class baseuser_add_passkey(ModPassKey, LDAPAddAttribute):
|
||||||
|
__doc__ = _("Add one or more passkey mappings to the user entry.")
|
||||||
|
msg_summary = _('Added passkey mappings to user "%(value)s"')
|
||||||
|
|
||||||
|
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
|
||||||
|
**options):
|
||||||
|
|
||||||
|
dn = super(baseuser_add_passkey, self).pre_callback(
|
||||||
|
ldap, dn, entry_attrs, attrs_list, *keys, **options)
|
||||||
|
|
||||||
|
# The objectclass ipafpasskeyuser may not be present on
|
||||||
|
# existing user entries. We need to add it if we define a new
|
||||||
|
# value for ipapasskey
|
||||||
|
add_missing_object_class(ldap, u'ipapasskeyuser', dn)
|
||||||
|
|
||||||
|
return dn
|
||||||
|
|
||||||
|
|
||||||
|
class baseuser_remove_passkey(ModPassKey, LDAPRemoveAttribute):
|
||||||
|
__doc__ = _("Remove one or more passkey mappings from the user entry.")
|
||||||
|
msg_summary = _('Removed passkey mappings from user "%(value)s"')
|
||||||
|
@ -49,7 +49,9 @@ from .baseuser import (
|
|||||||
baseuser_add_manager,
|
baseuser_add_manager,
|
||||||
baseuser_remove_manager,
|
baseuser_remove_manager,
|
||||||
baseuser_add_certmapdata,
|
baseuser_add_certmapdata,
|
||||||
baseuser_remove_certmapdata)
|
baseuser_remove_certmapdata,
|
||||||
|
baseuser_add_passkey,
|
||||||
|
baseuser_remove_passkey)
|
||||||
from ipalib.request import context
|
from ipalib.request import context
|
||||||
from ipalib.util import set_krbcanonicalname
|
from ipalib.util import set_krbcanonicalname
|
||||||
from ipalib import _, ngettext
|
from ipalib import _, ngettext
|
||||||
@ -819,3 +821,15 @@ class stageuser_add_certmapdata(baseuser_add_certmapdata):
|
|||||||
class stageuser_remove_certmapdata(baseuser_remove_certmapdata):
|
class stageuser_remove_certmapdata(baseuser_remove_certmapdata):
|
||||||
__doc__ = _("Remove one or more certificate mappings from the stage user"
|
__doc__ = _("Remove one or more certificate mappings from the stage user"
|
||||||
" entry.")
|
" entry.")
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
class stageuser_add_passkey(baseuser_add_passkey):
|
||||||
|
__doc__ = _("Add one or more passkey mappings to the stage user"
|
||||||
|
" entry.")
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
class stageuser_remove_passkey(baseuser_remove_passkey):
|
||||||
|
__doc__ = _("Remove one or more passkey mappings from the stage user"
|
||||||
|
" entry.")
|
||||||
|
@ -51,6 +51,8 @@ from .baseuser import (
|
|||||||
baseuser_remove_principal,
|
baseuser_remove_principal,
|
||||||
baseuser_add_certmapdata,
|
baseuser_add_certmapdata,
|
||||||
baseuser_remove_certmapdata,
|
baseuser_remove_certmapdata,
|
||||||
|
baseuser_add_passkey,
|
||||||
|
baseuser_remove_passkey,
|
||||||
)
|
)
|
||||||
from .idviews import remove_ipaobject_overrides
|
from .idviews import remove_ipaobject_overrides
|
||||||
from ipalib.plugable import Registry
|
from ipalib.plugable import Registry
|
||||||
@ -210,6 +212,7 @@ class user(baseuser):
|
|||||||
'ipapermright': {'read', 'search', 'compare'},
|
'ipapermright': {'read', 'search', 'compare'},
|
||||||
'ipapermdefaultattr': {
|
'ipapermdefaultattr': {
|
||||||
'ipauniqueid', 'ipasshpubkey', 'ipauserauthtype', 'userclass',
|
'ipauniqueid', 'ipasshpubkey', 'ipauserauthtype', 'userclass',
|
||||||
|
'ipapasskey',
|
||||||
},
|
},
|
||||||
'fixup_function': fix_addressbook_permission_bindrule,
|
'fixup_function': fix_addressbook_permission_bindrule,
|
||||||
},
|
},
|
||||||
@ -430,6 +433,14 @@ class user(baseuser):
|
|||||||
'Certificate Identity Mapping Administrators'
|
'Certificate Identity Mapping Administrators'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'System: Manage Passkey Mappings': {
|
||||||
|
'ipapermright': {'write'},
|
||||||
|
'ipapermdefaultattr': {'ipapasskey', 'objectclass'},
|
||||||
|
'default_privileges': {
|
||||||
|
'Passkey Administrators'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
takes_params = baseuser.takes_params + (
|
takes_params = baseuser.takes_params + (
|
||||||
@ -1019,13 +1030,15 @@ class user_stage(LDAPMultiQuery):
|
|||||||
# ipauniqueid, krbcanonicalname, sshpubkeyfp, krbextradata
|
# ipauniqueid, krbcanonicalname, sshpubkeyfp, krbextradata
|
||||||
# are automatically generated
|
# are automatically generated
|
||||||
# ipacertmapdata can only be provided with user_add_certmapdata
|
# ipacertmapdata can only be provided with user_add_certmapdata
|
||||||
|
# ipapasskey can only be provided with user_add_passkey
|
||||||
ignore_attrs = [u'dn', u'uid',
|
ignore_attrs = [u'dn', u'uid',
|
||||||
u'has_keytab', u'has_password', u'preserved',
|
u'has_keytab', u'has_password', u'preserved',
|
||||||
u'ipauniqueid', u'krbcanonicalname',
|
u'ipauniqueid', u'krbcanonicalname',
|
||||||
u'sshpubkeyfp', u'krbextradata',
|
u'sshpubkeyfp', u'krbextradata',
|
||||||
u'ipacertmapdata',
|
u'ipacertmapdata',
|
||||||
'ipantsecurityidentifier',
|
'ipantsecurityidentifier',
|
||||||
u'nsaccountlock']
|
u'nsaccountlock',
|
||||||
|
u'ipapasskey']
|
||||||
|
|
||||||
def execute(self, *keys, **options):
|
def execute(self, *keys, **options):
|
||||||
|
|
||||||
@ -1079,6 +1092,12 @@ class user_stage(LDAPMultiQuery):
|
|||||||
self.api.Command.stageuser_add_certmapdata(
|
self.api.Command.stageuser_add_certmapdata(
|
||||||
*single_keys,
|
*single_keys,
|
||||||
ipacertmapdata=certmapdata)
|
ipacertmapdata=certmapdata)
|
||||||
|
# special handling for passkey
|
||||||
|
passkey = user.get(u'ipapasskey')
|
||||||
|
if passkey:
|
||||||
|
self.api.Command.stageuser_add_passkey(
|
||||||
|
*single_keys,
|
||||||
|
ipapasskey=passkey)
|
||||||
try:
|
try:
|
||||||
self.api.Command.user_del(*multi_keys, preserve=False)
|
self.api.Command.user_del(*multi_keys, preserve=False)
|
||||||
except errors.ExecutionError:
|
except errors.ExecutionError:
|
||||||
@ -1360,3 +1379,13 @@ class user_add_principal(baseuser_add_principal):
|
|||||||
class user_remove_principal(baseuser_remove_principal):
|
class user_remove_principal(baseuser_remove_principal):
|
||||||
__doc__ = _('Remove principal alias from the user entry')
|
__doc__ = _('Remove principal alias from the user entry')
|
||||||
msg_summary = _('Removed aliases from user "%(value)s"')
|
msg_summary = _('Removed aliases from user "%(value)s"')
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
class user_add_passkey(baseuser_add_passkey):
|
||||||
|
__doc__ = _("Add one or more passkey mappings to the user entry.")
|
||||||
|
|
||||||
|
|
||||||
|
@register()
|
||||||
|
class user_remove_passkey(baseuser_remove_passkey):
|
||||||
|
__doc__ = _("Remove one or more passkey mappings from the user entry.")
|
||||||
|
Loading…
Reference in New Issue
Block a user