On 11.6.2014 15:19, Petr Vobornik wrote:
Patch set contains both API/server and Web UI parts.
[PATCH] 659 ldap2: add otp support to modify_password
[PATCH] 660 rpcserver: add otp support to change_password handler
[PATCH] 661 ipa-passwd: add OTP support
[PATCH] 662 webui: support password change with OTP in login screen
[PATCH] 663 webui: placeholder attribute support in textbox and textarea
[PATCH] 664 webui: add placeholders to login screen
[PATCH] 665 webui: rebase user password dialog on password dialog and
add otp support
[PATCH] 666 webui: support otp in reset_password.html
https://fedorahosted.org/freeipa/ticket/4262
attaching rebased patches (mainly because of VERSION conflict)
--
Petr Vobornik
From 7722d49fdc782d14e5bcc3fbefaee70e5fff62a4 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Thu, 22 May 2014 14:47:44 +0200
Subject: [PATCH] webui: placeholder attribute support in textbox and textarea
---
install/ui/src/freeipa/widget.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/install/ui/src/freeipa/widget.js b/install/ui/src/freeipa/widget.js
index cfa9417c5ddbaf94b45aa35498d6076a55fac493..9677a168eb2a137ed1c42b9b2b5d62f43c3a735d 100644
--- a/install/ui/src/freeipa/widget.js
+++ b/install/ui/src/freeipa/widget.js
@@ -269,6 +269,12 @@ IPA.input_widget = function(spec) {
var that = IPA.widget(spec);
/**
+ * Placeholder
+ * @property {string}
+ */
+ that.placeholder = text.get(spec.placeholder);
+
+ /**
* Widget's width.
* @deprecated
* @property {number}
@@ -709,6 +715,7 @@ IPA.text_widget = function(spec) {
'class': 'form-control',
size: that.size,
title: that.tooltip,
+ placeholder: that.placeholder,
keyup: function() {
that.on_value_changed();
}
@@ -1975,6 +1982,7 @@ IPA.textarea_widget = function (spec) {
'class': 'form-control',
readOnly: !!that.read_only,
title: that.tooltip,
+ placeholder: that.placeholder,
keyup: function() {
that.on_value_changed();
}
--
1.9.0
From 6b680e0092ca8518b6aebb974ee982139e85d266 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Thu, 22 May 2014 14:48:22 +0200
Subject: [PATCH] webui: add placeholders to login screen
---
install/ui/src/freeipa/widgets/LoginScreen.js | 8 +++++++-
install/ui/test/data/ipa_init.json | 3 +++
ipalib/plugins/internal.py | 3 +++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/install/ui/src/freeipa/widgets/LoginScreen.js b/install/ui/src/freeipa/widgets/LoginScreen.js
index 701c88cf12f07e7d7e4d4efc44d980f332656042..78991d0a93d6b9d3507d3afe31587ed1f3b55ed9 100644
--- a/install/ui/src/freeipa/widgets/LoginScreen.js
+++ b/install/ui/src/freeipa/widgets/LoginScreen.js
@@ -568,6 +568,7 @@ define(['dojo/_base/declare',
$type: 'text',
name: 'username',
label: text.get('@i18n:login.username', "Username"),
+ placeholder: text.get('@i18n:login.username', "Username"),
show_errors: false,
undo: false
},
@@ -575,6 +576,7 @@ define(['dojo/_base/declare',
$type: 'password',
name: 'password',
label: text.get('@i18n:login.password', "Password"),
+ placeholder: text.get('@i18n:login.password_and_otp', 'Password or Password+One-Time-Password'),
show_errors: false,
undo: false
},
@@ -589,13 +591,15 @@ define(['dojo/_base/declare',
name: 'current_password',
$type: 'password',
label: text.get('@i18n:login.current_password', "Current Password"),
+ placeholder: text.get('@i18n:login.current_password', "Current Password"),
show_errors: false,
undo: false
},
{
name: 'otp',
$type: 'password',
- label: text.get('@i18n:login.current_password', "OTP"),
+ label: text.get('@i18n:password.otp', "OTP"),
+ placeholder: text.get('@i18n:password.otp_long', 'One-Time-Password'),
show_errors: false,
undo: false
},
@@ -604,6 +608,7 @@ define(['dojo/_base/declare',
$type: 'password',
required: true,
label: text.get('@i18n:password.new_password)', "New Password"),
+ placeholder: text.get('@i18n:password.new_password)', "New Password"),
show_errors: false,
undo: false
},
@@ -612,6 +617,7 @@ define(['dojo/_base/declare',
$type: 'password',
required: true,
label: text.get('@i18n:password.verify_password', "Verify Password"),
+ placeholder: text.get('@i18n:password.new_password)', "New Password"),
validators: [{
$type: 'same_password',
other_field: 'new_password'
diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
index 8a96e23307de76624f94f2046d288181841b25ed..2ce5120e9042a3b4e4f20f3ae24c60880da813da 100644
--- a/install/ui/test/data/ipa_init.json
+++ b/install/ui/test/data/ipa_init.json
@@ -512,7 +512,10 @@
"invalid_password": "The password or username you entered is incorrect.",
"new_password": "New Password",
"new_password_required": "New password is required",
+ "otp": "OTP",
+ "otp_long": "One-Time-Password",
"password": "Password",
+ "password_and_otp": "Password or Password+One-Time-Password",
"password_change_complete": "Password change complete",
"password_must_match": "Passwords must match",
"reset_failure": "Password reset was not successful.",
diff --git a/ipalib/plugins/internal.py b/ipalib/plugins/internal.py
index e3c0faff13c86bec76c5f309a7bb43cdb59b4d97..4a3745ae7a28910e2089d7775ef4b0f40bb571da 100644
--- a/ipalib/plugins/internal.py
+++ b/ipalib/plugins/internal.py
@@ -652,7 +652,10 @@ class i18n_messages(Command):
"invalid_password": _("The password or username you entered is incorrect."),
"new_password": _("New Password"),
"new_password_required": _("New password is required"),
+ "otp": _("OTP"),
+ "otp_long": _("One-Time-Password"),
"password": _("Password"),
+ "password_and_otp": _("Password or Password+One-Time-Password"),
"password_change_complete": _("Password change complete"),
"password_must_match": _("Passwords must match"),
"reset_failure": _("Password reset was not successful."),
--
1.9.0
From cd04b0423723882ae4e0ccf121dbafac58b39516 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Thu, 22 May 2014 16:20:02 +0200
Subject: [PATCH] webui: rebase user password dialog on password dialog and add
otp support
https://fedorahosted.org/freeipa/ticket/4262
---
install/ui/src/freeipa/dialogs/password.js | 11 +-
install/ui/src/freeipa/ipa.js | 26 ++--
install/ui/src/freeipa/user.js | 193 ++++++++---------------------
ipatests/test_webui/test_user.py | 4 +-
4 files changed, 77 insertions(+), 157 deletions(-)
diff --git a/install/ui/src/freeipa/dialogs/password.js b/install/ui/src/freeipa/dialogs/password.js
index 35f96e4b79f32c56082c0f2874afd7869cd0848a..fa672901d589aaf7308ff7e2b6af545be544df4b 100644
--- a/install/ui/src/freeipa/dialogs/password.js
+++ b/install/ui/src/freeipa/dialogs/password.js
@@ -51,6 +51,7 @@ dialogs.password.default_fields_pre_op = function(spec) {
spec.width = spec.width || 400;
spec.sections = spec.sections || [
{
+ name: 'general',
fields: [
{
name: name,
@@ -193,7 +194,7 @@ dialogs.password.dialog = function(spec) {
for (var j=0; j<fields.length; j++) {
var field = fields[j];
var values = field.save();
- if (!values || values.length === 0) continue;
+ if (!values || values.length === 0 || !field.enabled) continue;
if (field.flags.indexOf('no_command') > -1) continue;
if (values.length === 1) {
@@ -212,10 +213,12 @@ dialogs.password.dialog = function(spec) {
that.create_command = function() {
var options = that.make_otions();
+ var entity = null;
+ if (that.entity) entity = that.entity.name;
var command = rpc.command({
- entity: that.entity.name,
+ entity: entity,
method: that.method,
- args: that.pkeys,
+ args: that.args,
options: options,
on_success: function(data) {
that.on_success();
@@ -301,7 +304,7 @@ dialogs.password.action = function(spec) {
ds.$type = 'password';
}
var dialog = builder.build('dialog', ds);
- dialog.pkeys = facet.get_pkeys();
+ dialog.args = facet.get_pkeys();
dialog.succeeded.attach(function() {
if (that.refresh) facet.refresh();
});
diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js
index 66d92b6e0726211f2a87bc25f84b26319756a9ee..be671d8f4246e769c019a544783314504f6977e2 100644
--- a/install/ui/src/freeipa/ipa.js
+++ b/install/ui/src/freeipa/ipa.js
@@ -619,20 +619,20 @@ IPA.update_password_expiration = function() {
* @member IPA
*/
IPA.password_selfservice = function() {
- var reset_dialog = IPA.user_password_dialog({
- pkey: IPA.whoami.uid[0],
- on_success: function() {
- var command = IPA.get_whoami_command();
- var orig_on_success = command.on_success;
- command.on_success = function(data, text_status, xhr) {
- orig_on_success.call(this, data, text_status, xhr);
- IPA.update_password_expiration();
- };
- command.execute();
+ var reset_dialog = builder.build('dialog', {
+ $type: 'user_password',
+ args: [IPA.whoami.uid[0]]
+ });
+ reset_dialog.succeeded.attach(function() {
+ var command = IPA.get_whoami_command();
+ var orig_on_success = command.on_success;
+ command.on_success = function(data, text_status, xhr) {
+ orig_on_success.call(this, data, text_status, xhr);
+ IPA.update_password_expiration();
+ };
+ command.execute();
- IPA.notify_success(text.get('@i18n:password.password_change_complete'));
- reset_dialog.close();
- }
+ IPA.notify_success(text.get('@i18n:password.password_change_complete'));
});
reset_dialog.open();
};
diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js
index 3685b116aad6708f88a437a4abebc68ff9df4474..73298093bd7a606cd9ee631056b7135880827d77 100644
--- a/install/ui/src/freeipa/user.js
+++ b/install/ui/src/freeipa/user.js
@@ -22,18 +22,20 @@
*/
define([
+ './builder',
'./ipa',
'./jquery',
'./phases',
'./reg',
'./rpc',
'./text',
+ './dialogs/password',
'./details',
'./search',
'./association',
'./entity',
'./certificate'],
- function(IPA, $, phases, reg, rpc, text) {
+ function(builder, IPA, $, phases, reg, rpc, text, password_dialog) {
/**
* User module
@@ -509,155 +511,57 @@ IPA.user_password_widget = function(spec) {
return that;
};
-IPA.user_password_dialog = function(spec) {
+IPA.user.password_dialog_pre_op0 = function(spec) {
- spec = spec || {};
+ spec.password_name = spec.password_name || 'password';
+ return spec;
+};
- spec.width = spec.width || 400;
- spec.title = spec.title || '@i18n:password.reset_password';
- spec.sections = spec.sections || [];
+IPA.user.password_dialog_pre_op = function(spec) {
- spec.sections.push(
- {
- name: 'input',
- fields: [
- {
- name: 'current_password',
- label: '@i18n:password.current_password',
- $type: 'password',
- required: true
- },
- {
- name: 'password1',
- label: '@i18n:password.new_password',
- $type: 'password',
- required: true
- },
- {
- name: 'password2',
- label: '@i18n:password.verify_password',
- $type: 'password',
- validators: [{
- $type: 'same_password',
- other_field: 'password1'
- }],
- required: true
- }
- ]
- });
+ spec.sections[0].fields.splice(0, 0, {
+ name: 'current_password',
+ label: '@i18n:password.current_password',
+ $type: 'password',
+ required: true
+ }, {
+ name: 'otp',
+ label: '@i18n:password.otp',
+ $type: 'password'
+ });
- var that = IPA.dialog(spec);
+ spec.method = spec.method || 'passwd';
- IPA.confirm_mixin().apply(that);
+ return spec;
+};
- that.success_handler = spec.on_success;
- that.error_handler = spec.on_error;
- that.pkey = spec.pkey;
+IPA.user.password_dialog = function(spec) {
+
+ var that = password_dialog.dialog(spec);
that.is_self_service = function() {
- var self_service = that.pkey === IPA.whoami.uid[0];
+ var self_service = that.args[0] === IPA.whoami.uid[0];
return self_service;
};
that.open = function() {
-
- var self_service = that.is_self_service();
- var section = that.widgets.get_widget('input');
- var current_password_f = that.fields.get_field('current_password');
-
that.dialog_open();
- section.set_row_visible('current_password', self_service);
- current_password_f.set_required(self_service);
+
+ var self_service = that.is_self_service();
+ var current_pw_f = that.fields.get_field('current_password');
+ var current_pw_w = that.widgets.get_widget('general.current_password');
+ var otp_f = that.fields.get_field('otp');
+ var otp_w = that.widgets.get_widget('general.otp');
+
+ current_pw_f.set_required(self_service);
+ current_pw_f.set_enabled(self_service);
+ current_pw_w.set_visible(self_service);
+ otp_f.set_enabled(self_service);
+ otp_w.set_visible(self_service);
+
that.focus_first_element();
};
- that.create_buttons = function() {
-
- that.create_button({
- name: 'reset_password',
- label: '@i18n:password.reset_password',
- click: that.on_reset_click
- });
-
- that.create_button({
- name: 'cancel',
- label: '@i18n:buttons.cancel',
- click: function() {
- that.close();
- }
- });
- };
-
- that.on_confirm = function() {
- that.on_reset_click();
- };
-
- that.on_reset_click = function() {
-
- if (!that.validate()) return;
-
- var self_service = that.is_self_service();
-
- var record = {};
- that.save(record);
-
- var current_password = self_service ? record.current_password[0] : undefined;
- var new_password = record.password1[0];
- var repeat_password = record.password2[0];
-
- that.set_password(
- that.pkey,
- current_password,
- new_password,
- that.on_reset_success,
- that.on_reset_error);
- };
-
- that.set_password = function(pkey, current_password, password, on_success, on_error) {
-
- var command = rpc.command({
- method: 'passwd',
- args: [ pkey ],
- options: {
- current_password: current_password,
- password: password
- },
- on_success: on_success,
- on_error: on_error
- });
-
- command.execute();
- };
-
- that.on_reset_success = function(data, text_status, xhr) {
-
- if (that.success_handler) {
- that.success_handler.call(this, data, text_status, xhr);
- } else {
- IPA.notify_success('@i18n:password.password_change_complete');
- that.close();
-
- // refresh password expiration field
- that.facet.refresh();
-
- if (that.is_self_service()) {
- var command = IPA.get_whoami_command();
- command.execute();
- }
- }
- };
-
- that.on_reset_error = function(xhr, text_status, error_thrown) {
-
- if (that.error_handler) {
- that.error_handler.call(this, xhr, text_status, error_thrown);
- } else {
- that.close();
- }
- };
-
- that.create_buttons();
-
return that;
};
@@ -672,10 +576,17 @@ IPA.user.reset_password_action = function(spec) {
that.execute_action = function(facet) {
- var dialog = IPA.user_password_dialog({
- entity: facet.entity,
- facet: facet,
- pkey: facet.get_pkey()
+ var dialog = builder.build('dialog', {
+ $type: 'user_password',
+ args: [facet.get_pkey()]
+ });
+
+ dialog.succeeded.attach(function() {
+ facet.refresh();
+ if (dialog.is_self_service()) {
+ var command = IPA.get_whoami_command();
+ command.execute();
+ }
});
dialog.open();
@@ -688,8 +599,14 @@ exp.entity_spec = make_spec();
exp.register = function() {
var e = reg.entity;
var a = reg.action;
+ var d = reg.dialog;
e.register({type: 'user', spec: exp.entity_spec});
a.register('reset_password', IPA.user.reset_password_action);
+ d.copy('password', 'user_password', {
+ factory: IPA.user.password_dialog,
+ pre_ops: [IPA.user.password_dialog_pre_op]
+ });
+ d.register_pre_op('user_password', IPA.user.password_dialog_pre_op0, true);
};
phases.on('registration', exp.register);
diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py
index 766fdafb4ee700fc2a4131dbf92d694be8d17188..4c189db89accd7fc0ac242007bbc2fde0ade89d2 100644
--- a/ipatests/test_webui/test_user.py
+++ b/ipatests/test_webui/test_user.py
@@ -246,7 +246,7 @@ class test_user(UI_driver):
self.assert_dialog()
fields = [
- ('password', 'password1', password),
+ ('password', 'password', password),
('password', 'password2', password),
]
@@ -254,6 +254,6 @@ class test_user(UI_driver):
fields.append(('password', 'current_password', current))
self.fill_fields(fields)
- self.dialog_button_click('reset_password')
+ self.dialog_button_click('confirm')
self.wait_for_request(n=3)
self.assert_no_error_dialog()
--
1.9.0
From 62a649f1dd6f2a84795f7be6494b003f02d2ba5f Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Fri, 23 May 2014 16:07:33 +0200
Subject: [PATCH] webui: support otp in reset_password.html
https://fedorahosted.org/freeipa/ticket/4262
---
install/ui/reset_password.html | 10 ++++++++++
install/ui/reset_password.js | 10 ++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/install/ui/reset_password.html b/install/ui/reset_password.html
index 2b758922615aacda46b9ddbdbf2a973cd2391830..598fe8f1e9cc440699ccfdd0000257dd6f569fc4 100644
--- a/install/ui/reset_password.html
+++ b/install/ui/reset_password.html
@@ -75,6 +75,16 @@
</div>
<div class="form-group">
<div class="col-sm-4 control-label">
+ <label for="otp">OTP</label>
+ </div>
+ <div class="col-sm-8 controls">
+ <div class="widget text-widget">
+ <input type="password" class="form-control" name="otp" id="otp" accesskey="o">
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-4 control-label">
<label for="new_password">New Password</label>
</div>
<div class="col-sm-8 controls">
diff --git a/install/ui/reset_password.js b/install/ui/reset_password.js
index 5555a17bc3334c60d4949e379c7374251453ec4e..bc08349876ea18d204ce4d6e8ae7724878967620 100644
--- a/install/ui/reset_password.js
+++ b/install/ui/reset_password.js
@@ -20,7 +20,7 @@
var RP = {}; //Reset Password Page
-RP.reset_password = function(username, old_password, new_password) {
+RP.reset_password = function(username, old_password, new_password, otp) {
//possible results: 'ok', 'invalid-password', 'policy-error'
@@ -55,6 +55,10 @@ RP.reset_password = function(username, old_password, new_password) {
new_password: new_password
};
+ if (otp) {
+ data.otp = otp;
+ }
+
request = {
url: '/ipa/session/change_password',
data: data,
@@ -89,6 +93,7 @@ RP.on_submit = function() {
var username = $('#user').val();
var current_password = $('#old_password').val();
+ var otp = $('#otp').val();
var new_password = $('#new_password').val();
var verify_password = $('#verify_password').val();
@@ -102,7 +107,7 @@ RP.on_submit = function() {
return;
}
- var result = RP.reset_password(username, current_password, new_password);
+ var result = RP.reset_password(username, current_password, new_password, otp);
if (result.status !== 'ok') {
RP.show_error(result.message);
@@ -116,6 +121,7 @@ RP.reset_form = function() {
$('.alert-danger').css('display', 'none');
$('.alert-success').css('display', 'none');
$('#old_password').val('');
+ $('#otp').val('');
$('#new_password').val('');
$('#verify_password').val('');
};
--
1.9.0
From dbb3e64a10476a91d5154e8f60e022742b2b5a0b Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Fri, 23 May 2014 15:53:54 +0200
Subject: [PATCH] ldap2: add otp support to modify_password
https://fedorahosted.org/freeipa/ticket/4262
---
ipaserver/plugins/ldap2.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index aa9a001c6c64d5e8e94316ab2f736993ce6903ee..74c9c1ec63ebb122c27a5e86e4a129af4cc9d49d 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -406,18 +406,21 @@ class ldap2(LDAPClient, CrudBackend):
return False
- def modify_password(self, dn, new_pass, old_pass=''):
+ def modify_password(self, dn, new_pass, old_pass='', otp='', skip_bind=False):
"""Set user password."""
assert isinstance(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 != '':
+ if not skip_bind and old_pass != '':
+ pw = old_pass
+ if (otp):
+ pw = old_pass+otp
with self.error_handler():
conn = IPASimpleLDAPObject(
self.ldap_uri, force_schema_updates=False)
- conn.simple_bind_s(dn, old_pass)
+ conn.simple_bind_s(dn, pw)
conn.unbind_s()
with self.error_handler():
--
1.9.0
From bad15be77084194d335c0441c77326c2e089450e Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Fri, 23 May 2014 15:54:18 +0200
Subject: [PATCH] rpcserver: add otp support to change_password handler
https://fedorahosted.org/freeipa/ticket/4262
---
ipaserver/rpcserver.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index ff1b7fe656b6655c68d5b5d4c576d001b1d266e2..30b9746397636128c0edc3fb4d2ad7f7bdc22495 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -1043,7 +1043,7 @@ class change_password(Backend, HTTP_Status):
return self.bad_request(environ, start_response, "cannot parse query data")
data = {}
- for field in ('user', 'old_password', 'new_password'):
+ for field in ('user', 'old_password', 'new_password', 'otp'):
value = query_dict.get(field, None)
if value is not None:
if len(value) == 1:
@@ -1051,7 +1051,7 @@ class change_password(Backend, HTTP_Status):
else:
return self.bad_request(environ, start_response, "more than one %s parameter"
% field)
- else:
+ elif field != 'otp': # otp is optional
return self.bad_request(environ, start_response, "no %s specified" % field)
# start building the response
@@ -1066,9 +1066,12 @@ class change_password(Backend, HTTP_Status):
self.api.env.container_user, self.api.env.basedn)
try:
+ pw = data['old_password']
+ if data.get('otp'):
+ pw = data['old_password'] + data['otp']
conn = ldap2(shared_instance=False,
ldap_uri=self.api.env.ldap_uri)
- conn.connect(bind_dn=bind_dn, bind_pw=data['old_password'])
+ conn.connect(bind_dn=bind_dn, bind_pw=pw)
except (NotFound, ACIError):
result = 'invalid-password'
message = 'The old password or username is not correct.'
@@ -1078,7 +1081,7 @@ class change_password(Backend, HTTP_Status):
data['user'], str(e))
else:
try:
- conn.modify_password(bind_dn, data['new_password'], data['old_password'])
+ conn.modify_password(bind_dn, data['new_password'], data['old_password'], skip_bind=True)
except ExecutionError, e:
result = 'policy-error'
policy_error = escape(str(e))
--
1.9.0
From d5dac2df4a8c190aa40ea33135b5dca4c3f9f29f Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Fri, 23 May 2014 09:36:49 +0200
Subject: [PATCH] ipa-passwd: add OTP support
https://fedorahosted.org/freeipa/ticket/4262
---
API.txt | 3 ++-
VERSION | 4 ++--
ipalib/plugins/passwd.py | 11 ++++++++++-
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/API.txt b/API.txt
index 0dd28068edbd37f021a58195941e102c25fa360f..98b61402822174f6ef20f79307c3158b4c8b5d05 100644
--- a/API.txt
+++ b/API.txt
@@ -2409,10 +2409,11 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: passwd
-args: 3,1,3
+args: 3,2,3
arg: Str('principal', autofill=True, cli_name='user', primary_key=True)
arg: Password('password')
arg: Password('current_password', autofill=True, confirm=False)
+option: Password('otp?', confirm=False)
option: Str('version?', exclude='webui')
output: Output('result', <type 'bool'>, None)
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
diff --git a/VERSION b/VERSION
index 65e52735079baf0e04f05d295e2b6dd8ad8515f4..a61848d62a88c02e756bc08c21fece037c16cd94 100644
--- a/VERSION
+++ b/VERSION
@@ -89,5 +89,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=93
-# Last change: mbasti - New record type added: DLV
+IPA_API_VERSION_MINOR=94
+# Last change: pvoborni - Add OTP option to passwd command
diff --git a/ipalib/plugins/passwd.py b/ipalib/plugins/passwd.py
index 95b9b6017b79260bb6fc17b4a369ef3517c9e202..f5fc14d510ea7eea1e16435fe11d982d4ca49d79 100644
--- a/ipalib/plugins/passwd.py
+++ b/ipalib/plugins/passwd.py
@@ -89,6 +89,14 @@ class passwd(Command):
),
)
+ takes_options = (
+ Password('otp?',
+ label=_('OTP'),
+ doc=_('One Time Password'),
+ confirm=False,
+ ),
+ )
+
has_output = output.standard_value
msg_summary = _('Changed password for "%(value)s"')
@@ -121,7 +129,8 @@ class passwd(Command):
if current_password == MAGIC_VALUE:
ldap.modify_password(entry_attrs.dn, password)
else:
- ldap.modify_password(entry_attrs.dn, password, current_password)
+ otp = options.get('otp')
+ ldap.modify_password(entry_attrs.dn, password, current_password, otp)
return dict(
result=True,
--
1.9.0
From 2a922a040236939f409743d161f2b602325413e9 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Fri, 23 May 2014 15:54:53 +0200
Subject: [PATCH] webui: support password change with OTP in login screen
https://fedorahosted.org/freeipa/ticket/4262
---
install/ui/src/freeipa/ipa.js | 6 +++-
install/ui/src/freeipa/widgets/LoginScreen.js | 51 +++++++++++++++++++++++----
2 files changed, 49 insertions(+), 8 deletions(-)
diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js
index 8a1ebaed76e1bd5bbecec7e80a35197191c55920..66d92b6e0726211f2a87bc25f84b26319756a9ee 100644
--- a/install/ui/src/freeipa/ipa.js
+++ b/install/ui/src/freeipa/ipa.js
@@ -516,7 +516,7 @@ IPA.login_password = function(username, password) {
* @return {string} result.status
* @return {string} result.message
*/
-IPA.reset_password = function(username, old_password, new_password) {
+IPA.reset_password = function(username, old_password, new_password, otp) {
//possible results: 'ok', 'invalid-password', 'policy-error'
@@ -553,6 +553,10 @@ IPA.reset_password = function(username, old_password, new_password) {
new_password: new_password
};
+ if (otp) {
+ data.otp = otp;
+ }
+
request = {
url: '/ipa/session/change_password',
data: data,
diff --git a/install/ui/src/freeipa/widgets/LoginScreen.js b/install/ui/src/freeipa/widgets/LoginScreen.js
index 349a3da1d9ed082df15083dd0d7feb0f242909b2..701c88cf12f07e7d7e4d4efc44d980f332656042 100644
--- a/install/ui/src/freeipa/widgets/LoginScreen.js
+++ b/install/ui/src/freeipa/widgets/LoginScreen.js
@@ -78,6 +78,8 @@ define(['dojo/_base/declare',
password_expired: "Your password has expired. Please enter a new password.",
+ password_change_complete: "Password change complete",
+
denied: "Sorry you are not allowed to access this service.",
caps_warning_msg: "Warning: CAPS LOCK key is on",
@@ -417,23 +419,36 @@ define(['dojo/_base/declare',
if (!this.validate()) return;
var psw_f = this.get_field('password');
+ var psw_f2 = this.get_field('current_password');
+ var otp_f = this.get_field('otp');
var new_f = this.get_field('new_password');
var ver_f = this.get_field('verify_password');
var username_f = this.get_field('username');
+ var psw = psw_f2.get_value()[0] || psw_f.get_value()[0];
+ var otp = otp_f.get_value()[0];
+
var result = IPA.reset_password(
username_f.get_value()[0],
- psw_f.get_value()[0],
- new_f.get_value()[0]);
+ psw,
+ new_f.get_value()[0],
+ otp);
if (result.status === 'ok') {
- psw_f.set_value(new_f.get_value());
- this.login();
+ val_summary.add_success('login', this.password_change_complete);
+ psw_f.set_value('');
+ psw_f2.set_value('');
+ // do not login if otp is used because it will fail (reuse of OTP)
+ if (!otp) {
+ psw_f.set_value(new_f.get_value());
+ this.login();
+ }
this.set('view', 'login');
} else {
val_summary.add_error('login', result.message);
}
+ otp_f.set_value('');
new_f.set_value('');
ver_f.set_value('');
},
@@ -456,7 +471,12 @@ define(['dojo/_base/declare',
}
if (this.password_enabled()) {
this.use_fields(['username', 'password']);
- this.get_widget('username').focus_input();
+ var username_f = this.get_field('username');
+ if (username_f.get_value()[0]) {
+ this.get_widget('password').focus_input();
+ } else {
+ this.get_widget('username').focus_input();
+ }
} else {
this.use_fields([]);
this.login_btn_node.focus();
@@ -469,14 +489,14 @@ define(['dojo/_base/declare',
if (this.buttons_node) {
construct.place(this.reset_btn_node, this.buttons_node);
}
- this.use_fields(['username_r', 'new_password', 'verify_password']);
+ this.use_fields(['username_r', 'current_password', 'otp', 'new_password', 'verify_password']);
var val_summary = this.get_widget('validation');
var u_f = this.fields.get('username');
var u_r_f = this.fields.get('username_r');
u_r_f.set_value(u_f.get_value());
- this.get_widget('new_password').focus_input();
+ this.get_widget('current_password').focus_input();
},
use_fields: function(names) {
@@ -536,6 +556,9 @@ define(['dojo/_base/declare',
this.kerberos_msg = this.kerberos_msg.replace('${host}', window.location.hostname);
+ this.password_change_complete = text.get(spec.password_change_complete ||
+ '@i18n:password.password_change_complete', this.password_change_complete);
+
this.krb_auth_failed = text.get(spec.krb_auth_failed, this.krb_auth_failed);
}
});
@@ -563,6 +586,20 @@ define(['dojo/_base/declare',
undo: false
},
{
+ name: 'current_password',
+ $type: 'password',
+ label: text.get('@i18n:login.current_password', "Current Password"),
+ show_errors: false,
+ undo: false
+ },
+ {
+ name: 'otp',
+ $type: 'password',
+ label: text.get('@i18n:login.current_password', "OTP"),
+ show_errors: false,
+ undo: false
+ },
+ {
name: 'new_password',
$type: 'password',
required: true,
--
1.9.0
_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel