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
|
||||
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
|
||||
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";)
|
||||
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";)
|
||||
@ -403,7 +405,7 @@ aci: (targetattr = "audio || businesscategory || carlicense || departmentnumber
|
||||
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";)
|
||||
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
|
||||
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
|
||||
|
48
API.txt
48
API.txt
@ -5282,6 +5282,17 @@ option: Str('version?')
|
||||
output: Output('completed', type=[<type 'int'>])
|
||||
output: Output('failed', type=[<type 'dict'>])
|
||||
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
|
||||
args: 2,4,3
|
||||
arg: Str('uid', cli_name='login')
|
||||
@ -5465,6 +5476,17 @@ option: Str('version?')
|
||||
output: Output('completed', type=[<type 'int'>])
|
||||
output: Output('failed', type=[<type 'dict'>])
|
||||
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
|
||||
args: 2,4,3
|
||||
arg: Str('uid', cli_name='login')
|
||||
@ -6469,6 +6491,17 @@ option: Str('version?')
|
||||
output: Output('completed', type=[<type 'int'>])
|
||||
output: Output('failed', type=[<type 'dict'>])
|
||||
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
|
||||
args: 2,4,3
|
||||
arg: Str('uid', cli_name='login')
|
||||
@ -6671,6 +6704,17 @@ option: Str('version?')
|
||||
output: Output('completed', type=[<type 'int'>])
|
||||
output: Output('failed', type=[<type 'dict'>])
|
||||
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
|
||||
args: 2,4,3
|
||||
arg: Str('uid', cli_name='login')
|
||||
@ -7445,6 +7489,7 @@ default: stageuser_add/1
|
||||
default: stageuser_add_cert/1
|
||||
default: stageuser_add_certmapdata/1
|
||||
default: stageuser_add_manager/1
|
||||
default: stageuser_add_passkey/1
|
||||
default: stageuser_add_principal/1
|
||||
default: stageuser_del/1
|
||||
default: stageuser_find/1
|
||||
@ -7452,6 +7497,7 @@ default: stageuser_mod/1
|
||||
default: stageuser_remove_cert/1
|
||||
default: stageuser_remove_certmapdata/1
|
||||
default: stageuser_remove_manager/1
|
||||
default: stageuser_remove_passkey/1
|
||||
default: stageuser_remove_principal/1
|
||||
default: stageuser_show/1
|
||||
default: subid/1
|
||||
@ -7540,6 +7586,7 @@ default: user_add/1
|
||||
default: user_add_cert/1
|
||||
default: user_add_certmapdata/1
|
||||
default: user_add_manager/1
|
||||
default: user_add_passkey/1
|
||||
default: user_add_principal/1
|
||||
default: user_del/1
|
||||
default: user_disable/1
|
||||
@ -7549,6 +7596,7 @@ default: user_mod/1
|
||||
default: user_remove_cert/1
|
||||
default: user_remove_certmapdata/1
|
||||
default: user_remove_manager/1
|
||||
default: user_remove_passkey/1
|
||||
default: user_remove_principal/1
|
||||
default: user_show/1
|
||||
default: user_stage/1
|
||||
|
@ -382,6 +382,7 @@ IPA API Commands
|
||||
stageuser_add_cert.md
|
||||
stageuser_add_certmapdata.md
|
||||
stageuser_add_manager.md
|
||||
stageuser_add_passkey.md
|
||||
stageuser_add_principal.md
|
||||
stageuser_del.md
|
||||
stageuser_find.md
|
||||
@ -389,6 +390,7 @@ IPA API Commands
|
||||
stageuser_remove_cert.md
|
||||
stageuser_remove_certmapdata.md
|
||||
stageuser_remove_manager.md
|
||||
stageuser_remove_passkey.md
|
||||
stageuser_remove_principal.md
|
||||
stageuser_show.md
|
||||
subid_add.md
|
||||
@ -466,6 +468,7 @@ IPA API Commands
|
||||
user_add_cert.md
|
||||
user_add_certmapdata.md
|
||||
user_add_manager.md
|
||||
user_add_passkey.md
|
||||
user_add_principal.md
|
||||
user_del.md
|
||||
user_disable.md
|
||||
@ -475,6 +478,7 @@ IPA API Commands
|
||||
user_remove_cert.md
|
||||
user_remove_certmapdata.md
|
||||
user_remove_manager.md
|
||||
user_remove_passkey.md
|
||||
user_remove_principal.md
|
||||
user_show.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:cn: 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/>.
|
||||
|
||||
from ipaclient.frontend import MethodOverride
|
||||
from ipaclient.plugins.baseuser import baseuser_add_passkey
|
||||
from ipalib import errors
|
||||
from ipalib import Flag
|
||||
from ipalib import util
|
||||
@ -79,3 +80,8 @@ class user_show(MethodOverride):
|
||||
raise errors.NoCertificateError(entry=keys[-1])
|
||||
else:
|
||||
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"
|
||||
)
|
||||
PAM_CONFIG = None
|
||||
PASSKEY_CHILD = '/usr/libexec/sssd/passkey_child'
|
||||
|
||||
def check_paths(self):
|
||||
"""Check paths for missing files
|
||||
|
@ -17,6 +17,10 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# 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
|
||||
|
||||
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):
|
||||
"""
|
||||
baseuser object.
|
||||
@ -170,7 +203,7 @@ class baseuser(LDAPObject):
|
||||
possible_objectclasses = [
|
||||
'meporiginentry', 'ipauserauthtypeclass', 'ipauser',
|
||||
'ipatokenradiusproxyuser', 'ipacertmapobject',
|
||||
'ipantuserattrs', 'ipaidpuser',
|
||||
'ipantuserattrs', 'ipaidpuser', 'ipapasskeyuser',
|
||||
]
|
||||
disallow_object_classes = ['krbticketpolicyaux']
|
||||
permission_filter_objectclasses = ['posixaccount']
|
||||
@ -186,6 +219,7 @@ class baseuser(LDAPObject):
|
||||
'krbprincipalname', 'krbcanonicalname',
|
||||
'ipacertmapdata', 'ipantlogonscript', 'ipantprofilepath',
|
||||
'ipanthomedirectory', 'ipanthomedirectorydrive',
|
||||
'ipapasskey',
|
||||
]
|
||||
search_display_attributes = [
|
||||
'uid', 'givenname', 'sn', 'homedirectory', 'krbcanonicalname',
|
||||
@ -451,6 +485,12 @@ class baseuser(LDAPObject):
|
||||
'J:', 'K:', 'L:', 'M:', 'N:', 'O:', 'P:', 'Q:', 'R:',
|
||||
'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):
|
||||
@ -1011,3 +1051,30 @@ class baseuser_remove_certmapdata(ModCertMapData,
|
||||
LDAPRemoveAttribute):
|
||||
__doc__ = _("Remove one or more certificate mappings from the user entry.")
|
||||
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_remove_manager,
|
||||
baseuser_add_certmapdata,
|
||||
baseuser_remove_certmapdata)
|
||||
baseuser_remove_certmapdata,
|
||||
baseuser_add_passkey,
|
||||
baseuser_remove_passkey)
|
||||
from ipalib.request import context
|
||||
from ipalib.util import set_krbcanonicalname
|
||||
from ipalib import _, ngettext
|
||||
@ -819,3 +821,15 @@ class stageuser_add_certmapdata(baseuser_add_certmapdata):
|
||||
class stageuser_remove_certmapdata(baseuser_remove_certmapdata):
|
||||
__doc__ = _("Remove one or more certificate mappings from the stage user"
|
||||
" 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_add_certmapdata,
|
||||
baseuser_remove_certmapdata,
|
||||
baseuser_add_passkey,
|
||||
baseuser_remove_passkey,
|
||||
)
|
||||
from .idviews import remove_ipaobject_overrides
|
||||
from ipalib.plugable import Registry
|
||||
@ -210,6 +212,7 @@ class user(baseuser):
|
||||
'ipapermright': {'read', 'search', 'compare'},
|
||||
'ipapermdefaultattr': {
|
||||
'ipauniqueid', 'ipasshpubkey', 'ipauserauthtype', 'userclass',
|
||||
'ipapasskey',
|
||||
},
|
||||
'fixup_function': fix_addressbook_permission_bindrule,
|
||||
},
|
||||
@ -430,6 +433,14 @@ class user(baseuser):
|
||||
'Certificate Identity Mapping Administrators'
|
||||
},
|
||||
},
|
||||
'System: Manage Passkey Mappings': {
|
||||
'ipapermright': {'write'},
|
||||
'ipapermdefaultattr': {'ipapasskey', 'objectclass'},
|
||||
'default_privileges': {
|
||||
'Passkey Administrators'
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
takes_params = baseuser.takes_params + (
|
||||
@ -1019,13 +1030,15 @@ class user_stage(LDAPMultiQuery):
|
||||
# ipauniqueid, krbcanonicalname, sshpubkeyfp, krbextradata
|
||||
# are automatically generated
|
||||
# ipacertmapdata can only be provided with user_add_certmapdata
|
||||
# ipapasskey can only be provided with user_add_passkey
|
||||
ignore_attrs = [u'dn', u'uid',
|
||||
u'has_keytab', u'has_password', u'preserved',
|
||||
u'ipauniqueid', u'krbcanonicalname',
|
||||
u'sshpubkeyfp', u'krbextradata',
|
||||
u'ipacertmapdata',
|
||||
'ipantsecurityidentifier',
|
||||
u'nsaccountlock']
|
||||
u'nsaccountlock',
|
||||
u'ipapasskey']
|
||||
|
||||
def execute(self, *keys, **options):
|
||||
|
||||
@ -1079,6 +1092,12 @@ class user_stage(LDAPMultiQuery):
|
||||
self.api.Command.stageuser_add_certmapdata(
|
||||
*single_keys,
|
||||
ipacertmapdata=certmapdata)
|
||||
# special handling for passkey
|
||||
passkey = user.get(u'ipapasskey')
|
||||
if passkey:
|
||||
self.api.Command.stageuser_add_passkey(
|
||||
*single_keys,
|
||||
ipapasskey=passkey)
|
||||
try:
|
||||
self.api.Command.user_del(*multi_keys, preserve=False)
|
||||
except errors.ExecutionError:
|
||||
@ -1360,3 +1379,13 @@ class user_add_principal(baseuser_add_principal):
|
||||
class user_remove_principal(baseuser_remove_principal):
|
||||
__doc__ = _('Remove principal alias from the user entry')
|
||||
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