mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Extend IPA pwquality plugin to include libpwquality support
Add options to support maxrepeat, maxsequence, dictcheck and usercheck pwquality options. https://pagure.io/freeipa/issue/6964 https://pagure.io/freeipa/issue/5948 https://pagure.io/freeipa/issue/2445 https://pagure.io/freeipa/issue/298 Signed-off-by: Rob Crittenden <rcritten@redhat.com> Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com> Reviewed-By: Christian Heimes <cheimes@redhat.com>
This commit is contained in:
8
ACI.txt
8
ACI.txt
@@ -227,13 +227,13 @@ aci: (targetattr = "businesscategory || cn || createtimestamp || description ||
|
||||
dn: cn=privileges,cn=pbac,dc=ipa,dc=example
|
||||
aci: (targetfilter = "(objectclass=groupofnames)")(version 3.0;acl "permission:System: Remove Privileges";allow (delete) groupdn = "ldap:///cn=System: Remove Privileges,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=IPA.EXAMPLE,cn=kerberos,dc=ipa,dc=example
|
||||
aci: (targetfilter = "(objectclass=krbpwdpolicy)")(version 3.0;acl "permission:System: Add Group Password Policy";allow (add) groupdn = "ldap:///cn=System: Add Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
aci: (targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Add Group Password Policy";allow (add) groupdn = "ldap:///cn=System: Add Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=IPA.EXAMPLE,cn=kerberos,dc=ipa,dc=example
|
||||
aci: (targetfilter = "(objectclass=krbpwdpolicy)")(version 3.0;acl "permission:System: Delete Group Password Policy";allow (delete) groupdn = "ldap:///cn=System: Delete Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
aci: (targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Delete Group Password Policy";allow (delete) groupdn = "ldap:///cn=System: Delete Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=IPA.EXAMPLE,cn=kerberos,dc=ipa,dc=example
|
||||
aci: (targetattr = "krbmaxpwdlife || krbminpwdlife || krbpwdfailurecountinterval || krbpwdhistorylength || krbpwdlockoutduration || krbpwdmaxfailure || krbpwdmindiffchars || krbpwdminlength")(targetfilter = "(objectclass=krbpwdpolicy)")(version 3.0;acl "permission:System: Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=System: Modify Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
aci: (targetattr = "ipapwddictcheck || ipapwdmaxrepeat || ipapwdmaxsequence || ipapwdusercheck || krbmaxpwdlife || krbminpwdlife || krbpwdfailurecountinterval || krbpwdhistorylength || krbpwdlockoutduration || krbpwdmaxfailure || krbpwdmindiffchars || krbpwdminlength")(targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=System: Modify Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=IPA.EXAMPLE,cn=kerberos,dc=ipa,dc=example
|
||||
aci: (targetattr = "cn || cospriority || createtimestamp || entryusn || krbmaxpwdlife || krbminpwdlife || krbpwdfailurecountinterval || krbpwdhistorylength || krbpwdlockoutduration || krbpwdmaxfailure || krbpwdmindiffchars || krbpwdminlength || modifytimestamp || objectclass")(targetfilter = "(objectclass=krbpwdpolicy)")(version 3.0;acl "permission:System: Read Group Password Policy";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
aci: (targetattr = "cn || cospriority || createtimestamp || entryusn || ipapwddictcheck || ipapwdmaxrepeat || ipapwdmaxsequence || ipapwdusercheck || krbmaxpwdlife || krbminpwdlife || krbpwdfailurecountinterval || krbpwdhistorylength || krbpwdlockoutduration || krbpwdmaxfailure || krbpwdmindiffchars || krbpwdminlength || modifytimestamp || objectclass")(targetfilter = "(|(objectclass=ipapwdpolicy)(objectclass=krbpwdpolicy))")(version 3.0;acl "permission:System: Read Group Password Policy";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Group Password Policy,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=radiusproxy,dc=ipa,dc=example
|
||||
aci: (targetattr = "cn || createtimestamp || description || entryusn || ipatokenradiusretries || ipatokenradiusserver || ipatokenradiustimeout || ipatokenusermapattribute || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipatokenradiusconfiguration)")(version 3.0;acl "permission:System: Read Radius Servers";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Radius Servers,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=Realm Domains,cn=ipa,cn=etc,dc=ipa,dc=example
|
||||
|
||||
18
API.txt
18
API.txt
@@ -3960,11 +3960,15 @@ output: Entry('result')
|
||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||
output: PrimaryKey('value')
|
||||
command: pwpolicy_add/1
|
||||
args: 1,14,3
|
||||
args: 1,18,3
|
||||
arg: Str('cn', cli_name='group')
|
||||
option: Str('addattr*', cli_name='addattr')
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||
option: Int('cospriority', cli_name='priority')
|
||||
option: Bool('ipapwddictcheck?', cli_name='dictcheck', default=False)
|
||||
option: Int('ipapwdmaxrepeat?', cli_name='maxrepeat', default=0)
|
||||
option: Int('ipapwdmaxsequence?', cli_name='maxsequence', default=0)
|
||||
option: Bool('ipapwdusercheck?', cli_name='usercheck', default=False)
|
||||
option: Int('krbmaxpwdlife?', cli_name='maxlife')
|
||||
option: Int('krbminpwdlife?', cli_name='minlife')
|
||||
option: Int('krbpwdfailurecountinterval?', cli_name='failinterval')
|
||||
@@ -3988,11 +3992,15 @@ output: Output('result', type=[<type 'dict'>])
|
||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||
output: ListOfPrimaryKeys('value')
|
||||
command: pwpolicy_find/1
|
||||
args: 1,16,4
|
||||
args: 1,20,4
|
||||
arg: Str('criteria?')
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||
option: Str('cn?', autofill=False, cli_name='group')
|
||||
option: Int('cospriority?', autofill=False, cli_name='priority')
|
||||
option: Bool('ipapwddictcheck?', autofill=False, cli_name='dictcheck', default=False)
|
||||
option: Int('ipapwdmaxrepeat?', autofill=False, cli_name='maxrepeat', default=0)
|
||||
option: Int('ipapwdmaxsequence?', autofill=False, cli_name='maxsequence', default=0)
|
||||
option: Bool('ipapwdusercheck?', autofill=False, cli_name='usercheck', default=False)
|
||||
option: Int('krbmaxpwdlife?', autofill=False, cli_name='maxlife')
|
||||
option: Int('krbminpwdlife?', autofill=False, cli_name='minlife')
|
||||
option: Int('krbpwdfailurecountinterval?', autofill=False, cli_name='failinterval')
|
||||
@@ -4011,12 +4019,16 @@ output: ListOfEntries('result')
|
||||
output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
|
||||
output: Output('truncated', type=[<type 'bool'>])
|
||||
command: pwpolicy_mod/1
|
||||
args: 1,16,3
|
||||
args: 1,20,3
|
||||
arg: Str('cn?', cli_name='group')
|
||||
option: Str('addattr*', cli_name='addattr')
|
||||
option: Flag('all', autofill=True, cli_name='all', default=False)
|
||||
option: Int('cospriority?', autofill=False, cli_name='priority')
|
||||
option: Str('delattr*', cli_name='delattr')
|
||||
option: Bool('ipapwddictcheck?', autofill=False, cli_name='dictcheck', default=False)
|
||||
option: Int('ipapwdmaxrepeat?', autofill=False, cli_name='maxrepeat', default=0)
|
||||
option: Int('ipapwdmaxsequence?', autofill=False, cli_name='maxsequence', default=0)
|
||||
option: Bool('ipapwdusercheck?', autofill=False, cli_name='usercheck', default=False)
|
||||
option: Int('krbmaxpwdlife?', autofill=False, cli_name='maxlife')
|
||||
option: Int('krbminpwdlife?', autofill=False, cli_name='minlife')
|
||||
option: Int('krbpwdfailurecountinterval?', autofill=False, cli_name='failinterval')
|
||||
|
||||
@@ -86,8 +86,8 @@ define(IPA_DATA_VERSION, 20100614120000)
|
||||
# #
|
||||
########################################################
|
||||
define(IPA_API_VERSION_MAJOR, 2)
|
||||
define(IPA_API_VERSION_MINOR, 239)
|
||||
# Last change: allow ID overrides for users to be members of groups and roles
|
||||
define(IPA_API_VERSION_MINOR, 240)
|
||||
# Last change: add pwquality options to pwpolicy
|
||||
|
||||
|
||||
########################################################
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
import logging
|
||||
|
||||
from ipalib import api
|
||||
from ipalib import Int, Str, DNParam
|
||||
from ipalib import Int, Str, DNParam, Bool
|
||||
from ipalib import errors
|
||||
from .baseldap import (
|
||||
LDAPObject,
|
||||
@@ -236,13 +236,15 @@ class pwpolicy(LDAPObject):
|
||||
container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos'))
|
||||
object_name = _('password policy')
|
||||
object_name_plural = _('password policies')
|
||||
object_class = ['top', 'nscontainer', 'krbpwdpolicy']
|
||||
permission_filter_objectclasses = ['krbpwdpolicy']
|
||||
object_class = ['top', 'nscontainer', 'krbpwdpolicy', 'ipapwdpolicy']
|
||||
permission_filter_objectclasses = ['krbpwdpolicy', 'ipapwdpolicy']
|
||||
default_attributes = [
|
||||
'cn', 'cospriority', 'krbmaxpwdlife', 'krbminpwdlife',
|
||||
'krbpwdhistorylength', 'krbpwdmindiffchars', 'krbpwdminlength',
|
||||
'krbpwdmaxfailure', 'krbpwdfailurecountinterval',
|
||||
'krbpwdlockoutduration',
|
||||
'krbpwdlockoutduration', 'ipapwdmaxrepeat',
|
||||
'ipapwdmaxsequence', 'ipapwddictcheck',
|
||||
'ipapwdusercheck',
|
||||
]
|
||||
managed_permissions = {
|
||||
'System: Read Group Password Policy': {
|
||||
@@ -254,6 +256,8 @@ class pwpolicy(LDAPObject):
|
||||
'krbpwdfailurecountinterval', 'krbpwdhistorylength',
|
||||
'krbpwdlockoutduration', 'krbpwdmaxfailure',
|
||||
'krbpwdmindiffchars', 'krbpwdminlength', 'objectclass',
|
||||
'ipapwdmaxrepeat', 'ipapwdmaxsequence', 'ipapwddictcheck',
|
||||
'ipapwdusercheck',
|
||||
},
|
||||
'default_privileges': {
|
||||
'Password Policy Readers',
|
||||
@@ -279,7 +283,9 @@ class pwpolicy(LDAPObject):
|
||||
'ipapermdefaultattr': {
|
||||
'krbmaxpwdlife', 'krbminpwdlife', 'krbpwdfailurecountinterval',
|
||||
'krbpwdhistorylength', 'krbpwdlockoutduration',
|
||||
'krbpwdmaxfailure', 'krbpwdmindiffchars', 'krbpwdminlength'
|
||||
'krbpwdmaxfailure', 'krbpwdmindiffchars', 'krbpwdminlength',
|
||||
'ipapwdmaxrepeat', 'ipapwdmaxsequence', 'ipapwddictcheck',
|
||||
'ipapwdusercheck',
|
||||
},
|
||||
'replaces': [
|
||||
'(targetattr = "krbmaxpwdlife || krbminpwdlife || krbpwdhistorylength || krbpwdmindiffchars || krbpwdminlength || krbpwdmaxfailure || krbpwdfailurecountinterval || krbpwdlockoutduration")(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=Modify Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)',
|
||||
@@ -358,6 +364,38 @@ class pwpolicy(LDAPObject):
|
||||
doc=_('Period for which lockout is enforced (seconds)'),
|
||||
minvalue=0,
|
||||
),
|
||||
Int(
|
||||
'ipapwdmaxrepeat?',
|
||||
cli_name='maxrepeat',
|
||||
label=_('Max repeat'),
|
||||
doc=_('Maximum number of same consecutive characters'),
|
||||
minvalue=0,
|
||||
maxvalue=256,
|
||||
default=0,
|
||||
),
|
||||
Int(
|
||||
'ipapwdmaxsequence?',
|
||||
cli_name='maxsequence',
|
||||
label=_('Max sequence'),
|
||||
doc=_('The max. length of monotonic character sequences (abcd)'),
|
||||
minvalue=0,
|
||||
maxvalue=256,
|
||||
default=0,
|
||||
),
|
||||
Bool(
|
||||
'ipapwddictcheck?',
|
||||
cli_name='dictcheck',
|
||||
label=_('Dictionary check'),
|
||||
doc=_('Check if the password is a dictionary word'),
|
||||
default=False,
|
||||
),
|
||||
Bool(
|
||||
'ipapwdusercheck?',
|
||||
cli_name='usercheck',
|
||||
label=_('User check'),
|
||||
doc=_('Check if the password contains the username'),
|
||||
default=False,
|
||||
),
|
||||
)
|
||||
|
||||
def get_dn(self, *keys, **options):
|
||||
@@ -387,6 +425,51 @@ class pwpolicy(LDAPObject):
|
||||
if 'krbminpwdlife' in entry_attrs and entry_attrs['krbminpwdlife']:
|
||||
entry_attrs['krbminpwdlife'] = entry_attrs['krbminpwdlife'] * 3600
|
||||
|
||||
def validate_minlength(self, ldap, entry_attrs, add=False, *keys):
|
||||
"""
|
||||
If any of the libpwquality options are used then the minimum
|
||||
length must be >= 6 which is the built-in default of libpwquality.
|
||||
Allowing a lower value to be set will result in a failed policy
|
||||
check and a generic error message.
|
||||
"""
|
||||
def get_val(entry, attr):
|
||||
"""Get a single value from a list or a string"""
|
||||
val = entry.get(attr, 0)
|
||||
if isinstance(val, list):
|
||||
val = val[0]
|
||||
return val
|
||||
|
||||
def has_pwquality_set(entry):
|
||||
for attr in ['ipapwdmaxrepeat', 'ipapwdmaxsequence',
|
||||
'ipapwddictcheck', 'ipapwdusercheck']:
|
||||
val = get_val(entry, attr)
|
||||
if val not in ('FALSE', '0', 0, None):
|
||||
return True
|
||||
return False
|
||||
|
||||
has_pwquality_value = False
|
||||
if not add:
|
||||
if len(keys) > 0:
|
||||
existing_entry = self.api.Command.pwpolicy_show(
|
||||
keys[-1], all=True,)['result']
|
||||
else:
|
||||
existing_entry = self.api.Command.pwpolicy_show(
|
||||
all=True,)['result']
|
||||
existing_entry.update(entry_attrs)
|
||||
min_length = int(get_val(existing_entry, 'krbpwdminlength'))
|
||||
|
||||
has_pwquality_value = has_pwquality_set(existing_entry)
|
||||
else:
|
||||
min_length = int(get_val(entry_attrs, 'krbpwdminlength'))
|
||||
has_pwquality_value = has_pwquality_set(entry_attrs)
|
||||
|
||||
if min_length and min_length < 6 and has_pwquality_value:
|
||||
raise errors.ValidationError(
|
||||
name='minlength',
|
||||
error=_('Minimum length must be >= 6 if maxrepeat, '
|
||||
'maxsequence, dictcheck or usercheck are defined')
|
||||
)
|
||||
|
||||
def validate_lifetime(self, entry_attrs, add=False, *keys):
|
||||
"""
|
||||
Ensure that the maximum lifetime is greater than the minimum.
|
||||
@@ -435,6 +518,7 @@ class pwpolicy_add(LDAPCreate):
|
||||
assert isinstance(dn, DN)
|
||||
self.obj.convert_time_on_input(entry_attrs)
|
||||
self.obj.validate_lifetime(entry_attrs, True)
|
||||
self.obj.validate_minlength(ldap, entry_attrs, True)
|
||||
self.api.Command.cosentry_add(
|
||||
keys[-1], krbpwdpolicyreference=dn,
|
||||
cospriority=options.get('cospriority')
|
||||
@@ -486,7 +570,12 @@ class pwpolicy_mod(LDAPUpdate):
|
||||
|
||||
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
|
||||
assert isinstance(dn, DN)
|
||||
old_entry_attrs = ldap.get_entry(dn, ['objectclass'])
|
||||
if 'ipapwdpolicy' not in old_entry_attrs['objectclass']:
|
||||
old_entry_attrs['objectclass'].append('ipapwdpolicy')
|
||||
entry_attrs['objectclass'] = old_entry_attrs['objectclass']
|
||||
self.obj.convert_time_on_input(entry_attrs)
|
||||
self.obj.validate_minlength(ldap, entry_attrs, False, *keys)
|
||||
self.obj.validate_lifetime(entry_attrs, False, *keys)
|
||||
setattr(context, 'cosupdate', False)
|
||||
if options.get('cospriority') is not None:
|
||||
|
||||
Reference in New Issue
Block a user