mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 07:33:27 -06:00
Add support for SSH public keys to user and host objects.
This patch adds a new multivalue param "sshpubkey" for specifying SSH public keys to both user and host objects. The accepted value is base64-encoded public key blob as specified in RFC4253, section 6.6. Additionaly, host commands automatically update DNS SSHFP records when requested by user. https://fedorahosted.org/freeipa/ticket/754
This commit is contained in:
parent
9b6baf9bee
commit
3c2b0fc28a
13
API.txt
13
API.txt
@ -1657,7 +1657,7 @@ output: Output('notmatched', (<type 'list'>, <type 'tuple'>, <type 'NoneType'>),
|
||||
output: Output('error', (<type 'list'>, <type 'tuple'>, <type 'NoneType'>), None)
|
||||
output: Output('value', <type 'bool'>, None)
|
||||
command: host_add
|
||||
args: 1,15,3
|
||||
args: 1,16,3
|
||||
arg: Str('fqdn', attribute=True, cli_name='hostname', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9][a-zA-Z0-9-\\.]{0,254}$', pattern_errmsg='may only include letters, numbers, and -', primary_key=True, required=True)
|
||||
option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False)
|
||||
option: Str('l', attribute=True, cli_name='locality', multivalue=False, required=False)
|
||||
@ -1668,6 +1668,7 @@ option: Str('userpassword', attribute=True, cli_name='password', multivalue=Fals
|
||||
option: Flag('random', attribute=False, autofill=True, cli_name='random', default=False, multivalue=False, required=False)
|
||||
option: Bytes('usercertificate', attribute=True, cli_name='certificate', multivalue=False, required=False)
|
||||
option: Str('macaddress', attribute=True, cli_name='macaddress', csv=True, multivalue=True, pattern='^([a-fA-F0-9]{2}[:|\\-]?){5}[a-fA-F0-9]{2}$', pattern_errmsg='Must be of the form HH:HH:HH:HH:HH:HH, where each H is a hexadecimal character.', required=False)
|
||||
option: Bytes('ipasshpubkey', attribute=True, cli_name='sshpubkey', multivalue=True, required=False)
|
||||
option: Flag('force', autofill=True, default=False)
|
||||
option: Flag('no_reverse', autofill=True, default=False)
|
||||
option: Str('ip_address?')
|
||||
@ -1739,7 +1740,7 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
|
||||
output: Output('count', <type 'int'>, None)
|
||||
output: Output('truncated', <type 'bool'>, None)
|
||||
command: host_mod
|
||||
args: 1,17,3
|
||||
args: 1,19,3
|
||||
arg: Str('fqdn', attribute=True, cli_name='hostname', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9][a-zA-Z0-9-\\.]{0,254}$', pattern_errmsg='may only include letters, numbers, and -', primary_key=True, query=True, required=True)
|
||||
option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, required=False)
|
||||
option: Str('l', attribute=True, autofill=False, cli_name='locality', multivalue=False, required=False)
|
||||
@ -1750,11 +1751,13 @@ option: Str('userpassword', attribute=True, autofill=False, cli_name='password',
|
||||
option: Flag('random', attribute=False, autofill=True, cli_name='random', default=False, multivalue=False, required=False)
|
||||
option: Bytes('usercertificate', attribute=True, autofill=False, cli_name='certificate', multivalue=False, required=False)
|
||||
option: Str('macaddress', attribute=True, autofill=False, cli_name='macaddress', csv=True, multivalue=True, pattern='^([a-fA-F0-9]{2}[:|\\-]?){5}[a-fA-F0-9]{2}$', pattern_errmsg='Must be of the form HH:HH:HH:HH:HH:HH, where each H is a hexadecimal character.', required=False)
|
||||
option: Bytes('ipasshpubkey', attribute=True, autofill=False, cli_name='sshpubkey', multivalue=True, required=False)
|
||||
option: Str('setattr*', cli_name='setattr', exclude='webui')
|
||||
option: Str('addattr*', cli_name='addattr', exclude='webui')
|
||||
option: Str('delattr*', cli_name='delattr', exclude='webui')
|
||||
option: Flag('rights', autofill=True, default=False)
|
||||
option: Str('krbprincipalname?', attribute=True, cli_name='principalname')
|
||||
option: Flag('updatedns?', autofill=True, default=False)
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
|
||||
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
|
||||
option: Str('version?', exclude='webui')
|
||||
@ -3087,7 +3090,7 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
|
||||
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
||||
output: Output('value', <type 'unicode'>, None)
|
||||
command: user_add
|
||||
args: 1,32,3
|
||||
args: 1,33,3
|
||||
arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', pattern_errmsg='may only include letters, numbers, _, -, . and $', primary_key=True, required=True)
|
||||
option: Str('givenname', attribute=True, cli_name='first', multivalue=False, required=True)
|
||||
option: Str('sn', attribute=True, cli_name='last', multivalue=False, required=True)
|
||||
@ -3115,6 +3118,7 @@ option: Str('ou', attribute=True, cli_name='orgunit', multivalue=False, required
|
||||
option: Str('title', attribute=True, cli_name='title', multivalue=False, required=False)
|
||||
option: Str('manager', attribute=True, cli_name='manager', multivalue=False, required=False)
|
||||
option: Str('carlicense', attribute=True, cli_name='carlicense', multivalue=False, required=False)
|
||||
option: Bytes('ipasshpubkey', attribute=True, cli_name='sshpubkey', multivalue=True, required=False)
|
||||
option: Str('setattr*', cli_name='setattr', exclude='webui')
|
||||
option: Str('addattr*', cli_name='addattr', exclude='webui')
|
||||
option: Flag('noprivate', autofill=True, cli_name='noprivate', default=False)
|
||||
@ -3194,7 +3198,7 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
|
||||
output: Output('count', <type 'int'>, None)
|
||||
output: Output('truncated', <type 'bool'>, None)
|
||||
command: user_mod
|
||||
args: 1,33,3
|
||||
args: 1,34,3
|
||||
arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', pattern_errmsg='may only include letters, numbers, _, -, . and $', primary_key=True, query=True, required=True)
|
||||
option: Str('givenname', attribute=True, autofill=False, cli_name='first', multivalue=False, required=False)
|
||||
option: Str('sn', attribute=True, autofill=False, cli_name='last', multivalue=False, required=False)
|
||||
@ -3221,6 +3225,7 @@ option: Str('ou', attribute=True, autofill=False, cli_name='orgunit', multivalue
|
||||
option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, required=False)
|
||||
option: Str('manager', attribute=True, autofill=False, cli_name='manager', multivalue=False, required=False)
|
||||
option: Str('carlicense', attribute=True, autofill=False, cli_name='carlicense', multivalue=False, required=False)
|
||||
option: Bytes('ipasshpubkey', attribute=True, autofill=False, cli_name='sshpubkey', multivalue=True, required=False)
|
||||
option: Str('setattr*', cli_name='setattr', exclude='webui')
|
||||
option: Str('addattr*', cli_name='addattr', exclude='webui')
|
||||
option: Str('delattr*', cli_name='delattr', exclude='webui')
|
||||
|
2
VERSION
2
VERSION
@ -79,4 +79,4 @@ IPA_DATA_VERSION=20100614120000
|
||||
# #
|
||||
########################################################
|
||||
IPA_API_VERSION_MAJOR=2
|
||||
IPA_API_VERSION_MINOR=25
|
||||
IPA_API_VERSION_MINOR=26
|
||||
|
@ -22,6 +22,8 @@ import platform
|
||||
import os
|
||||
import sys
|
||||
from nss.error import NSPRError
|
||||
import nss.nss as nss
|
||||
import netaddr
|
||||
|
||||
from ipalib import api, errors, util
|
||||
from ipalib import Str, Flag, Bytes
|
||||
@ -34,11 +36,9 @@ from ipalib.plugins.dns import add_forward_record
|
||||
from ipalib import _, ngettext
|
||||
from ipalib import x509
|
||||
from ipalib.dn import *
|
||||
from ipapython.ipautil import ipa_generate_password, CheckedIPAddress
|
||||
from ipalib.request import context
|
||||
import base64
|
||||
import nss.nss as nss
|
||||
import netaddr
|
||||
from ipalib.util import validate_sshpubkey, output_sshpubkey
|
||||
from ipapython.ipautil import ipa_generate_password, CheckedIPAddress, make_sshfp
|
||||
|
||||
__doc__ = _("""
|
||||
Hosts/Machines
|
||||
@ -87,6 +87,9 @@ EXAMPLES:
|
||||
Modify information about a host:
|
||||
ipa host-mod --os='Fedora 12' test.example.com
|
||||
|
||||
Remove SSH public keys of a host and update DNS to reflect this change:
|
||||
ipa host-mod --sshpubkey= --updatedns test.example.com
|
||||
|
||||
Disable the host Kerberos key, SSL certificate and all of its services:
|
||||
ipa host-disable test.example.com
|
||||
|
||||
@ -162,6 +165,22 @@ def remove_fwd_ptr(ipaddr, host, domain, recordtype):
|
||||
except errors.NotFound:
|
||||
pass
|
||||
|
||||
def update_sshfp_record(zone, record, entry_attrs):
|
||||
if 'ipasshpubkey' not in entry_attrs:
|
||||
return
|
||||
|
||||
pubkeys = entry_attrs['ipasshpubkey'] or ()
|
||||
sshfps=[]
|
||||
for pubkey in pubkeys:
|
||||
sshfp = unicode(make_sshfp(pubkey))
|
||||
if sshfp is not None:
|
||||
sshfps.append(sshfp)
|
||||
|
||||
try:
|
||||
api.Command['dnsrecord_mod'](zone, record, sshfprecord=sshfps)
|
||||
except errors.EmptyModlist:
|
||||
pass
|
||||
|
||||
host_output_params = (
|
||||
Flag('has_keytab',
|
||||
label=_('Keytab'),
|
||||
@ -226,6 +245,7 @@ class host(LDAPObject):
|
||||
'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname',
|
||||
'nshardwareplatform', 'nsosversion', 'usercertificate', 'memberof',
|
||||
'managedby', 'memberindirect', 'memberofindirect', 'macaddress',
|
||||
'sshpubkeyfp',
|
||||
]
|
||||
uuid_attribute = 'ipauniqueid'
|
||||
attribute_members = {
|
||||
@ -315,6 +335,15 @@ class host(LDAPObject):
|
||||
label=_('MAC address'),
|
||||
doc=_('Hardware MAC address(es) on this host'),
|
||||
),
|
||||
Bytes('ipasshpubkey*', validate_sshpubkey,
|
||||
cli_name='sshpubkey',
|
||||
label=_('Base-64 encoded SSH public key'),
|
||||
flags=['no_search'],
|
||||
),
|
||||
Str('sshpubkeyfp*',
|
||||
label=_('SSH public key fingerprint'),
|
||||
flags=['virtual_attribute', 'no_create', 'no_update', 'no_search'],
|
||||
),
|
||||
)
|
||||
|
||||
def get_dn(self, *keys, **options):
|
||||
@ -452,33 +481,37 @@ class host_add(LDAPCreate):
|
||||
entry_attrs['usercertificate'] = cert
|
||||
entry_attrs['managedby'] = dn
|
||||
entry_attrs['objectclass'].append('ieee802device')
|
||||
entry_attrs['objectclass'].append('ipasshhost')
|
||||
return dn
|
||||
|
||||
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
|
||||
exc = None
|
||||
try:
|
||||
if 'ip_address' in options and dns_container_exists(ldap):
|
||||
if dns_container_exists(ldap):
|
||||
try:
|
||||
parts = keys[-1].split('.')
|
||||
domain = unicode('.'.join(parts[1:]))
|
||||
|
||||
ip = CheckedIPAddress(options['ip_address'], match_local=False)
|
||||
add_forward_record(domain, parts[0], unicode(ip))
|
||||
if 'ip_address' in options:
|
||||
ip = CheckedIPAddress(options['ip_address'], match_local=False)
|
||||
add_forward_record(domain, parts[0], unicode(ip))
|
||||
|
||||
if not options.get('no_reverse', False):
|
||||
try:
|
||||
prefixlen = None
|
||||
if not ip.defaultnet:
|
||||
prefixlen = ip.prefixlen
|
||||
revzone, revname = get_reverse_zone(ip, prefixlen)
|
||||
addkw = { 'ptrrecord' : keys[-1]+'.' }
|
||||
api.Command['dnsrecord_add'](revzone, revname, **addkw)
|
||||
except errors.EmptyModlist:
|
||||
# the entry already exists and matches
|
||||
pass
|
||||
if not options.get('no_reverse', False):
|
||||
try:
|
||||
prefixlen = None
|
||||
if not ip.defaultnet:
|
||||
prefixlen = ip.prefixlen
|
||||
revzone, revname = get_reverse_zone(ip, prefixlen)
|
||||
addkw = { 'ptrrecord' : keys[-1]+'.' }
|
||||
api.Command['dnsrecord_add'](revzone, revname, **addkw)
|
||||
except errors.EmptyModlist:
|
||||
# the entry already exists and matches
|
||||
pass
|
||||
|
||||
del options['ip_address']
|
||||
except Exception, e:
|
||||
exc = e
|
||||
del options['ip_address']
|
||||
|
||||
update_sshfp_record(domain, unicode(parts[0]), entry_attrs)
|
||||
except Exception, e:
|
||||
exc = e
|
||||
if options.get('random', False):
|
||||
try:
|
||||
entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword'))
|
||||
@ -493,13 +526,15 @@ class host_add(LDAPCreate):
|
||||
set_certificate_attrs(entry_attrs)
|
||||
|
||||
if options.get('all', False):
|
||||
entry_attrs['managing'] = self.obj.get_managed_hosts(dn)
|
||||
entry_attrs['managing'] = self.obj.get_managed_hosts(dn)
|
||||
self.obj.get_password_attributes(ldap, dn, entry_attrs)
|
||||
if entry_attrs['has_password']:
|
||||
# If an OTP is set there is no keytab, at least not one
|
||||
# fetched anywhere.
|
||||
entry_attrs['has_keytab'] = False
|
||||
|
||||
output_sshpubkey(ldap, dn, entry_attrs)
|
||||
|
||||
return dn
|
||||
|
||||
api.register(host_add)
|
||||
@ -632,6 +667,10 @@ class host_mod(LDAPUpdate):
|
||||
doc=_('Kerberos principal name for this host'),
|
||||
attribute=True,
|
||||
),
|
||||
Flag('updatedns?',
|
||||
doc=_('Update DNS entries'),
|
||||
default=False,
|
||||
),
|
||||
)
|
||||
|
||||
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
|
||||
@ -688,6 +727,7 @@ class host_mod(LDAPUpdate):
|
||||
raise nsprerr
|
||||
|
||||
entry_attrs['usercertificate'] = cert
|
||||
|
||||
if options.get('random'):
|
||||
entry_attrs['userpassword'] = ipa_generate_password()
|
||||
setattr(context, 'randompassword', entry_attrs['userpassword'])
|
||||
@ -703,6 +743,30 @@ class host_mod(LDAPUpdate):
|
||||
obj_classes.append('ieee802device')
|
||||
entry_attrs['objectclass'] = obj_classes
|
||||
|
||||
if options.get('updatedns', False) and dns_container_exists(ldap):
|
||||
parts = keys[-1].split('.')
|
||||
domain = unicode('.'.join(parts[1:]))
|
||||
result = api.Command['dnszone_find']()['result']
|
||||
match = False
|
||||
for zone in result:
|
||||
if domain == zone['idnsname'][0]:
|
||||
match = True
|
||||
break
|
||||
if not match:
|
||||
raise errors.NotFound(
|
||||
reason=_('DNS zone %(zone)s not found') % dict(zone=domain)
|
||||
)
|
||||
update_sshfp_record(domain, unicode(parts[0]), entry_attrs)
|
||||
|
||||
if 'ipasshpubkey' in entry_attrs:
|
||||
if 'objectclass' in entry_attrs:
|
||||
obj_classes = entry_attrs['objectclass']
|
||||
else:
|
||||
(_dn, _entry_attrs) = ldap.get_entry(dn, ['objectclass'])
|
||||
obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass']
|
||||
if 'ipasshhost' not in obj_classes:
|
||||
obj_classes.append('ipasshhost')
|
||||
|
||||
return dn
|
||||
|
||||
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
|
||||
@ -720,6 +784,8 @@ class host_mod(LDAPUpdate):
|
||||
|
||||
self.obj.suppress_netgroup_memberof(entry_attrs)
|
||||
|
||||
output_sshpubkey(ldap, dn, entry_attrs)
|
||||
|
||||
return dn
|
||||
|
||||
api.register(host_mod)
|
||||
@ -802,6 +868,8 @@ class host_find(LDAPSearch):
|
||||
if options.get('all', False):
|
||||
entry_attrs['managing'] = self.obj.get_managed_hosts(entry[0])
|
||||
|
||||
output_sshpubkey(ldap, dn, entry_attrs)
|
||||
|
||||
api.register(host_find)
|
||||
|
||||
|
||||
@ -831,6 +899,8 @@ class host_show(LDAPRetrieve):
|
||||
|
||||
self.obj.suppress_netgroup_memberof(entry_attrs)
|
||||
|
||||
output_sshpubkey(ldap, dn, entry_attrs)
|
||||
|
||||
return dn
|
||||
|
||||
def forward(self, *keys, **options):
|
||||
|
@ -18,16 +18,18 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ipalib import api, errors
|
||||
from ipalib import Flag, Int, Password, Str, Bool
|
||||
from ipalib.plugins.baseldap import *
|
||||
from ipalib.request import context
|
||||
from time import gmtime, strftime
|
||||
import copy
|
||||
import string
|
||||
|
||||
from ipalib import api, errors
|
||||
from ipalib import Flag, Int, Password, Str, Bool, Bytes
|
||||
from ipalib.plugins.baseldap import *
|
||||
from ipalib.request import context
|
||||
from ipalib import _, ngettext
|
||||
from ipapython.ipautil import ipa_generate_password
|
||||
import string
|
||||
import posixpath
|
||||
from ipalib.util import validate_sshpubkey, output_sshpubkey
|
||||
|
||||
__doc__ = _("""
|
||||
Users
|
||||
@ -154,12 +156,12 @@ class user(LDAPObject):
|
||||
'uid', 'givenname', 'sn', 'homedirectory', 'loginshell',
|
||||
'uidnumber', 'gidnumber', 'mail', 'ou',
|
||||
'telephonenumber', 'title', 'memberof', 'nsaccountlock',
|
||||
'memberofindirect',
|
||||
'memberofindirect', 'sshpubkeyfp',
|
||||
]
|
||||
search_display_attributes = [
|
||||
'uid', 'givenname', 'sn', 'homedirectory', 'loginshell',
|
||||
'mail', 'telephonenumber', 'title', 'nsaccountlock',
|
||||
'uidnumber', 'gidnumber',
|
||||
'uidnumber', 'gidnumber', 'sshpubkeyfp',
|
||||
]
|
||||
uuid_attribute = 'ipauniqueid'
|
||||
attribute_members = {
|
||||
@ -310,6 +312,15 @@ class user(LDAPObject):
|
||||
label=_('Account disabled'),
|
||||
flags=['no_create', 'no_update', 'no_search'],
|
||||
),
|
||||
Bytes('ipasshpubkey*', validate_sshpubkey,
|
||||
cli_name='sshpubkey',
|
||||
label=_('Base-64 encoded SSH public key'),
|
||||
flags=['no_search'],
|
||||
),
|
||||
Str('sshpubkeyfp*',
|
||||
label=_('SSH public key fingerprint'),
|
||||
flags=['virtual_attribute', 'no_create', 'no_update', 'no_search'],
|
||||
),
|
||||
)
|
||||
|
||||
def _normalize_email(self, email, config=None):
|
||||
@ -489,6 +500,9 @@ class user_add(LDAPCreate):
|
||||
pass
|
||||
|
||||
self.obj.get_password_attributes(ldap, dn, entry_attrs)
|
||||
|
||||
output_sshpubkey(ldap, dn, entry_attrs)
|
||||
|
||||
return dn
|
||||
|
||||
api.register(user_add)
|
||||
@ -522,6 +536,14 @@ class user_mod(LDAPUpdate):
|
||||
entry_attrs['userpassword'] = ipa_generate_password(user_pwdchars)
|
||||
# save the password so it can be displayed in post_callback
|
||||
setattr(context, 'randompassword', entry_attrs['userpassword'])
|
||||
if 'ipasshpubkey' in entry_attrs:
|
||||
if 'objectclass' in entry_attrs:
|
||||
obj_classes = entry_attrs['objectclass']
|
||||
else:
|
||||
(_dn, _entry_attrs) = ldap.get_entry(dn, ['objectclass'])
|
||||
obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass']
|
||||
if 'ipasshuser' not in obj_classes:
|
||||
obj_classes.append('ipasshuser')
|
||||
return dn
|
||||
|
||||
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
|
||||
@ -534,6 +556,7 @@ class user_mod(LDAPUpdate):
|
||||
convert_nsaccountlock(entry_attrs)
|
||||
self.obj._convert_manager(entry_attrs, **options)
|
||||
self.obj.get_password_attributes(ldap, dn, entry_attrs)
|
||||
output_sshpubkey(ldap, dn, entry_attrs)
|
||||
return dn
|
||||
|
||||
api.register(user_mod)
|
||||
@ -567,6 +590,7 @@ class user_find(LDAPSearch):
|
||||
self.obj._convert_manager(attrs, **options)
|
||||
self.obj.get_password_attributes(ldap, dn, attrs)
|
||||
convert_nsaccountlock(attrs)
|
||||
output_sshpubkey(ldap, dn, attrs)
|
||||
|
||||
msg_summary = ngettext(
|
||||
'%(count)d user matched', '%(count)d users matched', 0
|
||||
@ -584,6 +608,7 @@ class user_show(LDAPRetrieve):
|
||||
convert_nsaccountlock(entry_attrs)
|
||||
self.obj._convert_manager(entry_attrs, **options)
|
||||
self.obj.get_password_attributes(ldap, dn, entry_attrs)
|
||||
output_sshpubkey(ldap, dn, entry_attrs)
|
||||
return dn
|
||||
|
||||
api.register(user_show)
|
||||
|
@ -32,6 +32,7 @@ from weakref import WeakKeyDictionary
|
||||
from ipalib import errors
|
||||
from ipalib.text import _
|
||||
from ipapython import dnsclient
|
||||
from ipapython.ipautil import decode_ssh_pubkey
|
||||
|
||||
|
||||
def json_serialize(obj):
|
||||
@ -278,6 +279,37 @@ def validate_hostname(hostname, check_fqdn=True):
|
||||
raise ValueError(_('only letters, numbers, and - are allowed. ' \
|
||||
'- must not be the last name character'))
|
||||
|
||||
def validate_sshpubkey(ugettext, pubkey):
|
||||
try:
|
||||
algo, data, fp = decode_ssh_pubkey(pubkey)
|
||||
except ValueError:
|
||||
return _('invalid SSH public key')
|
||||
|
||||
def output_sshpubkey(ldap, dn, entry_attrs):
|
||||
if 'ipasshpubkey' in entry_attrs:
|
||||
pubkeys = entry_attrs.get('ipasshpubkey')
|
||||
else:
|
||||
entry = ldap.get_entry(dn, ['ipasshpubkey'])
|
||||
pubkeys = entry[1].get('ipasshpubkey')
|
||||
if pubkeys is None:
|
||||
return
|
||||
|
||||
fingerprints = []
|
||||
for pubkey in pubkeys:
|
||||
try:
|
||||
algo, data, fp = decode_ssh_pubkey(pubkey)
|
||||
fp = u':'.join([fp[j:j+2] for j in range(0, len(fp), 2)])
|
||||
fingerprints.append(u'%s (%s)' % (fp, algo))
|
||||
except ValueError:
|
||||
pass
|
||||
if fingerprints:
|
||||
entry_attrs['sshpubkeyfp'] = fingerprints
|
||||
|
||||
def normalize_sshpubkeyfp(value):
|
||||
value = value.split()[0]
|
||||
value = unicode(c for c in value if c in '0123456789ABCDEFabcdef')
|
||||
return value
|
||||
|
||||
class cachedproperty(object):
|
||||
"""
|
||||
A property-like attribute that caches the return value of a method call.
|
||||
|
@ -36,6 +36,7 @@ import shutil
|
||||
import urllib2
|
||||
import socket
|
||||
import ldap
|
||||
import struct
|
||||
|
||||
from ipapython import ipavalidate
|
||||
from types import *
|
||||
@ -58,6 +59,7 @@ except ImportError:
|
||||
self.cmd = cmd
|
||||
def __str__(self):
|
||||
return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
|
||||
from ipapython.compat import sha1, md5
|
||||
|
||||
def get_domain_name():
|
||||
try:
|
||||
@ -1395,3 +1397,22 @@ def backup_config_and_replace_variables(fstore, filepath, replacevars=dict(), ap
|
||||
old_values = config_replace_variables(filepath, replacevars, appendvars)
|
||||
|
||||
return old_values
|
||||
|
||||
def decode_ssh_pubkey(data, fptype=md5):
|
||||
try:
|
||||
(algolen,) = struct.unpack('>I', data[:4])
|
||||
if algolen > 0 and algolen <= len(data) - 4:
|
||||
return (data[4:algolen+4], data[algolen+4:], fptype(data).hexdigest().upper())
|
||||
except struct.error:
|
||||
pass
|
||||
raise ValueError('not a SSH public key')
|
||||
|
||||
def make_sshfp(key):
|
||||
algo, data, fp = decode_ssh_pubkey(key, fptype=sha1)
|
||||
if algo == 'ssh-rsa':
|
||||
algo = 1
|
||||
elif algo == 'ssh-dss':
|
||||
algo = 2
|
||||
else:
|
||||
return
|
||||
return '%d 1 %s' % (algo, fp)
|
||||
|
@ -110,7 +110,7 @@ class KrbInstance(service.Service):
|
||||
# Create a host entry for this master
|
||||
host_dn = "fqdn=%s,cn=computers,cn=accounts,%s" % (self.fqdn, self.suffix)
|
||||
host_entry = ipaldap.Entry(host_dn)
|
||||
host_entry.setValues('objectclass', ['top', 'ipaobject', 'nshost', 'ipahost', 'ipaservice', 'pkiuser', 'krbprincipalaux', 'krbprincipal', 'krbticketpolicyaux'])
|
||||
host_entry.setValues('objectclass', ['top', 'ipaobject', 'nshost', 'ipahost', 'ipaservice', 'pkiuser', 'krbprincipalaux', 'krbprincipal', 'krbticketpolicyaux', 'ipasshhost'])
|
||||
host_entry.setValues('krbextradata', service_entry.getValues('krbextradata'))
|
||||
host_entry.setValue('krblastpwdchange', service_entry.getValue('krblastpwdchange'))
|
||||
if 'krbpasswordexpiration' in service_entry.toDict():
|
||||
|
@ -31,6 +31,8 @@ user_base = [
|
||||
u'krbprincipalaux',
|
||||
u'krbticketpolicyaux',
|
||||
u'ipaobject',
|
||||
u'ipasshuser',
|
||||
u'ipaSshGroupOfPubKeys',
|
||||
]
|
||||
|
||||
user = user_base + [u'mepOriginEntry']
|
||||
@ -44,6 +46,8 @@ group = [
|
||||
]
|
||||
|
||||
host = [
|
||||
u'ipasshhost',
|
||||
u'ipaSshGroupOfPubKeys',
|
||||
u'ieee802device',
|
||||
u'ipaobject',
|
||||
u'nshost',
|
||||
|
Loading…
Reference in New Issue
Block a user