Change random passwords behaviour

Improved options checking so that host-mod operation is not changing
password for enrolled host when '--random' option is used.

Unit tests added.

https://fedorahosted.org/freeipa/ticket/2799

Updated set of characters that is used for generating random passwords
for ipa hosts. All characters that might need escaping were removed.

https://fedorahosted.org/freeipa/ticket/2800
This commit is contained in:
Ondrej Hamada
2012-06-26 15:23:55 +02:00
committed by Martin Kosek
parent 3c36fa8c0d
commit 8ce7330c53
2 changed files with 80 additions and 6 deletions

View File

@@ -24,6 +24,7 @@ import sys
from nss.error import NSPRError from nss.error import NSPRError
import nss.nss as nss import nss.nss as nss
import netaddr import netaddr
import string
from ipalib import api, errors, util from ipalib import api, errors, util
from ipalib import Str, Flag, Bytes from ipalib import Str, Flag, Bytes
@@ -99,6 +100,10 @@ EXAMPLES:
ipa host-add-managedby --hosts=test2 test ipa host-add-managedby --hosts=test2 test
""") """)
# Characters to be used by random password generator
# The set was chosen to avoid the need for escaping the characters by user
host_pwd_chars=string.digits + string.ascii_letters + '_,.@+-='
def remove_fwd_ptr(ipaddr, host, domain, recordtype): def remove_fwd_ptr(ipaddr, host, domain, recordtype):
api.log.debug('deleting ipaddr %s' % ipaddr) api.log.debug('deleting ipaddr %s' % ipaddr)
try: try:
@@ -404,7 +409,7 @@ class host_add(LDAPCreate):
if 'krbprincipal' in entry_attrs['objectclass']: if 'krbprincipal' in entry_attrs['objectclass']:
entry_attrs['objectclass'].remove('krbprincipal') entry_attrs['objectclass'].remove('krbprincipal')
if options.get('random'): if options.get('random'):
entry_attrs['userpassword'] = ipa_generate_password() entry_attrs['userpassword'] = ipa_generate_password(characters=host_pwd_chars)
# save the password so it can be displayed in post_callback # save the password so it can be displayed in post_callback
setattr(context, 'randompassword', entry_attrs['userpassword']) setattr(context, 'randompassword', entry_attrs['userpassword'])
cert = options.get('usercertificate') cert = options.get('usercertificate')
@@ -596,7 +601,7 @@ class host_mod(LDAPUpdate):
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
# Allow an existing OTP to be reset but don't allow a OTP to be # Allow an existing OTP to be reset but don't allow a OTP to be
# added to an enrolled host. # added to an enrolled host.
if 'userpassword' in options: if options.get('userpassword') or options.get('random'):
entry = {} entry = {}
self.obj.get_password_attributes(ldap, dn, entry) self.obj.get_password_attributes(ldap, dn, entry)
if not entry['has_password'] and entry['has_keytab']: if not entry['has_password'] and entry['has_keytab']:
@@ -649,7 +654,7 @@ class host_mod(LDAPUpdate):
entry_attrs['usercertificate'] = cert entry_attrs['usercertificate'] = cert
if options.get('random'): if options.get('random'):
entry_attrs['userpassword'] = ipa_generate_password() entry_attrs['userpassword'] = ipa_generate_password(characters=host_pwd_chars)
setattr(context, 'randompassword', entry_attrs['userpassword']) setattr(context, 'randompassword', entry_attrs['userpassword'])
if 'macaddress' in entry_attrs: if 'macaddress' in entry_attrs:
if 'objectclass' in entry_attrs: if 'objectclass' in entry_attrs:

View File

@@ -22,11 +22,15 @@
Test the `ipalib.plugins.host` module. Test the `ipalib.plugins.host` module.
""" """
import os
import tempfile
from ipapython import ipautil
from ipalib import api, errors, x509 from ipalib import api, errors, x509
from ipalib.dn import * from ipalib.dn import *
from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid, fuzzy_digits from nose.tools import raises, assert_raises
from tests.test_xmlrpc.xmlrpc_test import fuzzy_hash, fuzzy_date, fuzzy_issuer from tests.test_xmlrpc.xmlrpc_test import (Declarative, XMLRPC_test,
from tests.test_xmlrpc.xmlrpc_test import fuzzy_hex fuzzy_uuid, fuzzy_digits, fuzzy_hash, fuzzy_date, fuzzy_issuer,
fuzzy_hex)
from tests.test_xmlrpc import objectclasses from tests.test_xmlrpc import objectclasses
import base64 import base64
@@ -740,3 +744,68 @@ class test_host(Declarative):
), ),
] ]
class test_host_false_pwd_change(XMLRPC_test):
fqdn1 = u'testhost1.%s' % api.env.domain
short1 = u'testhost1'
new_pass = u'pass_123'
command = "ipa-client/ipa-join"
[keytabfd, keytabname] = tempfile.mkstemp()
os.close(keytabfd)
# auxiliary function for checking whether the join operation has set
# correct attributes
def host_joined(self):
ret = api.Command['host_show'](self.fqdn1, all=True)
assert (ret['result']['has_keytab'] == True)
assert (ret['result']['has_password'] == False)
def test_a_join_host(self):
"""
Create a test host and join him into IPA.
"""
# create a test host with bulk enrollment password
random_pass = api.Command['host_add'](self.fqdn1, random=True, force=True)['result']['randompassword']
# joint the host with the bulk password
new_args = [self.command,
"-s", api.env.host,
"-h", self.fqdn1,
"-k", self.keytabname,
"-w", random_pass,
"-q",
]
try:
# join operation may fail on 'adding key into keytab', but
# the keytab is not necessary for further tests
(out, err, rc) = ipautil.run(new_args, None)
except ipautil.CalledProcessError, e:
pass
finally:
self.host_joined()
@raises(errors.ValidationError)
def test_b_try_password(self):
"""
Try to change the password of enrolled host with specified password
"""
api.Command['host_mod'](self.fqdn1, userpassword=self.new_pass)
@raises(errors.ValidationError)
def test_c_try_random(self):
"""
Try to change the password of enrolled host with random password
"""
api.Command['host_mod'](self.fqdn1, random=True)
def test_d_cleanup(self):
"""
Clean up test data
"""
os.unlink(self.keytabname)
api.Command['host_del'](self.fqdn1)
# verify that it's gone
with assert_raises(errors.NotFound):
api.Command['host_show'](self.fqdn1)