mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Require current password when using passwd to change your own password.
Add a new required parameter, current_password. In order to ask this first I added a new parameter option, sortorder. The lower the value the earlier it will be prompted for. I also changed the way autofill works. It will attempt to get the default and if it doesn't get anything will continue prompting interactively. Since current_password is required I'm passing a magic value that means changing someone else's password. We need to pass something since current_password is required. The python-ldap passwd command doesn't seem to use the old password at all so I do a simple bind to validate it. https://fedorahosted.org/freeipa/ticket/1808
This commit is contained in:
parent
651534087c
commit
844d4ff8bf
5
API.txt
5
API.txt
@ -1829,9 +1829,10 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly
|
|||||||
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
|
||||||
output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
|
output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
|
||||||
command: passwd
|
command: passwd
|
||||||
args: 2,0,3
|
args: 3,0,3
|
||||||
arg: Str('principal', validate_principal, autofill=True, cli_name='user', create_default=<lambda>, label=Gettext('User name', domain='ipa', localedir=None), normalizer=<lambda>, primary_key=True)
|
arg: Str('principal', validate_principal, autofill=True, cli_name='user', create_default=<lambda>, label=Gettext('User name', domain='ipa', localedir=None), normalizer=<lambda>, primary_key=True)
|
||||||
arg: Password('password', label=Gettext('Password', domain='ipa', localedir=None))
|
arg: Password('password', label=Gettext('New Password', domain='ipa', localedir=None))
|
||||||
|
arg: Password('current_password', autofill=True, confirm=False, default_from=<lambda>, label=Gettext('Current Password', domain='ipa', localedir=None), sortorder=-1)
|
||||||
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
|
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
|
||||||
output: Output('result', <type 'bool'>, 'True means the operation was successful')
|
output: Output('result', <type 'bool'>, 'True means the operation was successful')
|
||||||
output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
|
output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
|
||||||
|
2
VERSION
2
VERSION
@ -79,4 +79,4 @@ IPA_DATA_VERSION=20100614120000
|
|||||||
# #
|
# #
|
||||||
########################################################
|
########################################################
|
||||||
IPA_API_VERSION_MAJOR=2
|
IPA_API_VERSION_MAJOR=2
|
||||||
IPA_API_VERSION_MINOR=11
|
IPA_API_VERSION_MINOR=12
|
||||||
|
@ -1048,12 +1048,14 @@ class cli(backend.Executioner):
|
|||||||
for param in cmd.params():
|
for param in cmd.params():
|
||||||
if (param.required and param.name not in kw) or \
|
if (param.required and param.name not in kw) or \
|
||||||
(param.alwaysask and honor_alwaysask) or self.env.prompt_all:
|
(param.alwaysask and honor_alwaysask) or self.env.prompt_all:
|
||||||
|
if param.autofill:
|
||||||
|
kw[param.name] = param.get_default(**kw)
|
||||||
|
if param.name in kw and kw[param.name] is not None:
|
||||||
|
continue
|
||||||
if param.password:
|
if param.password:
|
||||||
kw[param.name] = self.Backend.textui.prompt_password(
|
kw[param.name] = self.Backend.textui.prompt_password(
|
||||||
param.label, param.confirm
|
param.label, param.confirm
|
||||||
)
|
)
|
||||||
elif param.autofill:
|
|
||||||
kw[param.name] = param.get_default(**kw)
|
|
||||||
else:
|
else:
|
||||||
default = param.get_default(**kw)
|
default = param.get_default(**kw)
|
||||||
error = None
|
error = None
|
||||||
|
@ -777,6 +777,8 @@ class Command(HasParam):
|
|||||||
self._create_param_namespace('options')
|
self._create_param_namespace('options')
|
||||||
def get_key(p):
|
def get_key(p):
|
||||||
if p.required:
|
if p.required:
|
||||||
|
if p.sortorder < 0:
|
||||||
|
return p.sortorder
|
||||||
if p.default_from is None:
|
if p.default_from is None:
|
||||||
return 0
|
return 0
|
||||||
return 1
|
return 1
|
||||||
|
@ -317,6 +317,7 @@ class Param(ReadOnly):
|
|||||||
('flags', frozenset, frozenset()),
|
('flags', frozenset, frozenset()),
|
||||||
('hint', (str, Gettext), None),
|
('hint', (str, Gettext), None),
|
||||||
('alwaysask', bool, False),
|
('alwaysask', bool, False),
|
||||||
|
('sortorder', int, 2), # see finalize()
|
||||||
|
|
||||||
# The 'default' kwarg gets appended in Param.__init__():
|
# The 'default' kwarg gets appended in Param.__init__():
|
||||||
# ('default', self.type, None),
|
# ('default', self.type, None),
|
||||||
|
@ -23,6 +23,7 @@ from ipalib import Str, Password
|
|||||||
from ipalib import _
|
from ipalib import _
|
||||||
from ipalib import output
|
from ipalib import output
|
||||||
from ipalib.plugins.user import split_principal, validate_principal, normalize_principal
|
from ipalib.plugins.user import split_principal, validate_principal, normalize_principal
|
||||||
|
from ipalib.request import context
|
||||||
|
|
||||||
__doc__ = _("""
|
__doc__ = _("""
|
||||||
Set a user's password
|
Set a user's password
|
||||||
@ -43,6 +44,22 @@ EXAMPLES:
|
|||||||
ipa passwd tuser1
|
ipa passwd tuser1
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
# We only need to prompt for the current password when changing a password
|
||||||
|
# for yourself, but the parameter is still required
|
||||||
|
MAGIC_VALUE = u'CHANGING_PASSWORD_FOR_ANOTHER_USER'
|
||||||
|
|
||||||
|
def get_current_password(principal):
|
||||||
|
"""
|
||||||
|
If the user is changing their own password then return None so the
|
||||||
|
current password is prompted for, otherwise return a fixed value to
|
||||||
|
be ignored later.
|
||||||
|
"""
|
||||||
|
current_principal = util.get_current_principal()
|
||||||
|
if current_principal == normalize_principal(principal):
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return MAGIC_VALUE
|
||||||
|
|
||||||
class passwd(Command):
|
class passwd(Command):
|
||||||
__doc__ = _("Set a user's password.")
|
__doc__ = _("Set a user's password.")
|
||||||
|
|
||||||
@ -56,14 +73,21 @@ class passwd(Command):
|
|||||||
normalizer=lambda value: normalize_principal(value),
|
normalizer=lambda value: normalize_principal(value),
|
||||||
),
|
),
|
||||||
Password('password',
|
Password('password',
|
||||||
label=_('Password'),
|
label=_('New Password'),
|
||||||
|
),
|
||||||
|
Password('current_password',
|
||||||
|
label=_('Current Password'),
|
||||||
|
confirm=False,
|
||||||
|
default_from=lambda principal: get_current_password(principal),
|
||||||
|
autofill=True,
|
||||||
|
sortorder=-1,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
has_output = output.standard_value
|
has_output = output.standard_value
|
||||||
msg_summary = _('Changed password for "%(value)s"')
|
msg_summary = _('Changed password for "%(value)s"')
|
||||||
|
|
||||||
def execute(self, principal, password):
|
def execute(self, principal, password, current_password):
|
||||||
"""
|
"""
|
||||||
Execute the passwd operation.
|
Execute the passwd operation.
|
||||||
|
|
||||||
@ -74,6 +98,7 @@ class passwd(Command):
|
|||||||
|
|
||||||
:param principal: The login name or principal of the user
|
:param principal: The login name or principal of the user
|
||||||
:param password: the new password
|
:param password: the new password
|
||||||
|
:param current_password: the existing password, if applicable
|
||||||
"""
|
"""
|
||||||
ldap = self.api.Backend.ldap2
|
ldap = self.api.Backend.ldap2
|
||||||
|
|
||||||
@ -82,7 +107,16 @@ class passwd(Command):
|
|||||||
",".join([api.env.container_user, api.env.basedn])
|
",".join([api.env.container_user, api.env.basedn])
|
||||||
)
|
)
|
||||||
|
|
||||||
ldap.modify_password(dn, password)
|
if principal == getattr(context, 'principal') and \
|
||||||
|
current_password == MAGIC_VALUE:
|
||||||
|
# No cheating
|
||||||
|
self.log.warn('User attempted to change password using magic value')
|
||||||
|
raise errors.ACIError(info='Invalid credentials')
|
||||||
|
|
||||||
|
if current_password == MAGIC_VALUE:
|
||||||
|
ldap.modify_password(dn, password)
|
||||||
|
else:
|
||||||
|
ldap.modify_password(dn, password, current_password)
|
||||||
|
|
||||||
return dict(
|
return dict(
|
||||||
result=True,
|
result=True,
|
||||||
|
@ -899,6 +899,17 @@ class ldap2(CrudBackend, Encoder):
|
|||||||
def modify_password(self, dn, new_pass, old_pass=''):
|
def modify_password(self, dn, new_pass, old_pass=''):
|
||||||
"""Set user password."""
|
"""Set user password."""
|
||||||
dn = self.normalize_dn(dn)
|
dn = self.normalize_dn(dn)
|
||||||
|
|
||||||
|
# The python-ldap passwd command doesn't verify the old password
|
||||||
|
# so we'll do a simple bind to validate it.
|
||||||
|
if old_pass != '':
|
||||||
|
try:
|
||||||
|
conn = _ldap.initialize(self.ldap_uri)
|
||||||
|
conn.simple_bind_s(dn, old_pass)
|
||||||
|
conn.unbind()
|
||||||
|
except _ldap.LDAPError, e:
|
||||||
|
_handle_errors(e, **{})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.conn.passwd_s(dn, old_pass, new_pass)
|
self.conn.passwd_s(dn, old_pass, new_pass)
|
||||||
except _ldap.LDAPError, e:
|
except _ldap.LDAPError, e:
|
||||||
|
Loading…
Reference in New Issue
Block a user