In general I like simplifying the dialog so I took most of your suggestions and implemented them following way:

    Login
    -----------------------------------------------------

      Your session has expired. Please re-login.

      To login with Kerberos, please make sure you
      have valid tickets (obtainable via kinit) and
      [configured] the browser correctly.

      To login with username and password:

        Username:        [edewata                  ]
        Password:        [********                 ]

                                             [Login]


So I just changed the order and kept only one button. If username and password are filled it uses form-based auth otherwise it uses kerberos auth. I'm not sure if it is straightforward but it is easy to use.

I followed all suggestion in the reset part.

I have to place to the forms error box. I'm not sure about the position though.

Updated patch attached.


On 06/13/2012 07:18 PM, Endi Sukma Dewata wrote:
On 6/13/2012 8:15 AM, Petr Vobornik wrote:
I'll address all issues once we decide on the solution.

1. If you click 'form-based authentication the dialog title still shows
'Kerberos ticket no longer valid' which is not relevant for form-based
authentication. It might be better to use 'Login' as the title for all
pages in this dialog.

Agree

2. Instead of having to go to a separate page for form-based
authentication, would it be better to change the first page in the login
dialog to show the login form? Something like this:

Login
-----------------------------------------------------

Your session has expired. Please re-login.

To login with username and password:

Username: [edewata ]
Password: [******** ]

[Login]

To login with Kerberos, please make sure you
have valid tickets (obtainable via kinit) and
[configured] the browser correctly.

[Login with Kerberos]

The two login mechanisms can be shown at the same time like above or in
collapsible sections. If the user enters a password and it's expired,
the dialog will change into:

I like the idea but I'm not sure about the layout. Having one button
inside the dialog seems strange a also it will probably look weird.

You mean two buttons (Login & Login with Kerberos)? I agree it's kinda
strange.

Collapsible sections are worse because you have to click on them so it
slow things down.

That's also true. I'll leave this up to you. The current workflow still
makes sense if we consider form-based authentication a less preferred
method, so you'd have to go to another page to login with username &
password.

Current implementation has 'forms-based
authentication' link selected so user can in most cases hit enter and
immediately write username, password and complete login procedure only
by using keyboard.

Hmm... that's not very obvious though. I wouldn't have known that until
you told me :) I think intuitively people will think that if you hit
enter it will click the default button in the dialog, unless there's
input text field.

Also 'Login with Kerberos' is misleading. User login elsewhere (kinit).
So current button: 'retry' is more appropriate.

What I meant was 'Login with Kerberos mechanism' or 'Login with Kerberos
ticket', but it might be too long. I assume people in general isn't
going to be confused by that because the text also mentions that you'd
have to get the ticket from kinit.

My concern with 'Retry' is that if you open the UI for the first time
and you haven't done kinit yet, you'll see a message saying your
Kerberos ticket has expired and asking you to Retry. This is not quite
accurate because you never had a ticket before.

The 'expired ticket' and 'retry' message might make more sense if you
already had the UI open but left it for a while and come back to
continue. If you just open the UI for the first time I think the message
should only tell you what you need to do to login, not what went wrong
in the past.

I'll leave this up to you too. We might be able to keep the current
workflow, but display different message depending whether it's your
first visit or return visit.

Login
-----------------------------------------------------

Your password has expired. Please enter a new
password:

Username: edewata
New Password: [******** ]
Verify Password: [******** ]

[Reset Password and Login] [Cancel]

In this page the username is shown for info only, it's not editable. The
old password is not shown again, but kept in memory. I use Cancel
instead of Back to indicate that we are starting over. The Cancel button
will bring you back to the first page.

Little change, but can be probably more straightforward - will do.

If you keep the original workflow, the Cancel button probably should
bring you to the first page (expired ticket), not to the second page
(login) because if your password has expired you can't login without
reset anyway.

2a. The dialog uses headers in title (the one from #1) and a headers
inside (login, reset password). From your examples I'm not sure if you
would like to:
a) remove the inside headers
b) change them to 'login' everywhere
c) keep them unchanged

I think the inside header is not necessary, it's a duplicate of the
dialog title. This reset password operation is still part of login
operation because if you cancel reset you still aren't logged in yet.

3. I noticed that the password is kept in memory too long by the login
dialog so if you go back and forth between the pages the fields are
already populated. This might be a security risk. I think the username &
password should be cleaned up when you click Back/Cancel.

Agree

Also when you complete the login process, it should be cleaned up as well.

4. Is there a plan to provide password reset via email?

I don't think so. I'm not sure if it is even useful for Freeipa. One of
main purposes for Freeipa is SSO and I guess company mail would be
kerberized too. So if you forget the password, you can't login, reset
and even access mail. I guess using external mail is not the way to go.
Maybe it is useful if company uses additional authentication mechanism
like pin + token or other.

OK.



--
Petr Vobornik
From 992f450708ab8447a2d4d079c88d653ea3bc4ac8 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Fri, 8 Jun 2012 15:02:25 +0200
Subject: [PATCH] Added password reset capabilities to unauthorized dialog

Web UI was missing a way how to reset expired password for normal user. Recent server patch added API for such task. This patch is adding reset password form to unautorized dialog.

If user tries to login using form-based authentication and his password is expired login form transforms to reset password form. The username and password are used from previous login attempt. User have to enter new password and its verification. Then he can hit enter button on keyboard or click on reset button on dialog to perform the password reset. Error is displayed if some part of password reset fails. If it is successful new login with values entered for password reset is performed. It should login the user. In password reset form user can click on cancel button or hit escape on keyboard to go back to login form.

https://fedorahosted.org/freeipa/ticket/2755
---
 install/ui/ipa.js                  |  406 +++++++++++++++++++++++++++---------
 install/ui/test/data/ipa_init.json |   10 +-
 ipalib/plugins/internal.py         |   10 +-
 3 files changed, 317 insertions(+), 109 deletions(-)

diff --git a/install/ui/ipa.js b/install/ui/ipa.js
index 648fcfc31e1f017aeecd597189b5d4a9789194ae..94da06b7415bbad8613e7cab73fdd66415eb8483 100644
--- a/install/ui/ipa.js
+++ b/install/ui/ipa.js
@@ -4,6 +4,7 @@
  *    Adam Young <ayo...@redhat.com>
  *    Endi Dewata <edew...@redhat.com>
  *    John Dennis <jden...@redhat.com>
+ *    Petr Vobornik <pvobo...@redhat.com>
  *
  * Copyright (C) 2010 Red Hat
  * see file 'COPYING' for use and warranty information
@@ -402,6 +403,62 @@ IPA.login_password = function(username, password) {
     return result;
 };
 
+IPA.reset_password = function(username, old_password, new_password) {
+
+    //possible results: 'ok', 'invalid-password', 'policy-error'
+
+    var status, result, reason, invalid, failure, data, request;
+
+    status = 'invalid';
+    result = {
+        status: status,
+        message: IPA.get_message('password.reset_failure',
+                "Password reset was not successful.")
+    };
+
+    function success_handler(data, text_status, xhr) {
+
+        result.status = xhr.getResponseHeader("X-IPA-Pwchange-Result") || status;
+
+        if (result.status === 'policy-error') {
+            result.message = xhr.getResponseHeader("X-IPA-Pwchange-Policy-Error");
+        } else if (result.status === 'invalid-password') {
+            result.message = IPA.get_message('password.invalid_password',
+                          "The password or username you entered is incorrect.");
+        }
+
+        return result;
+    }
+
+    function error_handler(xhr, text_status, error_thrown) {
+        return result;
+    }
+
+    data = {
+        user: username,
+        old_password: old_password,
+        new_password: new_password
+    };
+
+    request = {
+        url: '/ipa/session/change_password',
+        data: data,
+        contentType: 'application/x-www-form-urlencoded',
+        processData: true,
+        dataType: 'html',
+        async: false,
+        type: 'POST',
+        success: success_handler,
+        error: error_handler
+    };
+
+    IPA.display_activity_icon();
+    $.ajax(request);
+    IPA.hide_activity_icon();
+
+    return result;
+};
+
 /**
  * Call an IPA command over JSON-RPC.
  *
@@ -1386,19 +1443,42 @@ IPA.unauthorized_dialog = function(spec) {
 
     spec.sections = [
         {
+            name: 'login',
+            label: 'Login',
             fields: [
                 {
                     name: 'username',
-                    required: true,
                     label: IPA.get_message('login.username', "Username")
                 },
                 {
                     name: 'password',
                     type: 'password',
-                    required: true,
                     label: IPA.get_message('login.password', "Password")
                 }
             ]
+        },
+        {
+            name: 'reset',
+            label: 'Reset',
+            fields: [
+                {
+                    name: 'username_r',
+                    read_only: true,
+                    label: IPA.get_message('login.username', "Username")
+                },
+                {
+                    name: 'new_password',
+                    type: 'password',
+                    required: true,
+                    label: IPA.get_message('password.new_password)', "New Password")
+                },
+                {
+                    name: 'verify_password',
+                    type: 'password',
+                    required: true,
+                    label: IPA.get_message('password.verify_password', "Verify Password")
+                }
+            ]
         }
     ];
 
@@ -1406,93 +1486,104 @@ IPA.unauthorized_dialog = function(spec) {
 
     var that = IPA.error_dialog(spec);
 
-    that.title = spec.title || IPA.get_message('ajax.401.title',
-                    'Kerberos ticket no longer valid.');
+    that.title = spec.title || IPA.get_message('login.login', "Login");
 
     that.message = spec.message || IPA.get_message('ajax.401.message',
-                    "Your kerberos ticket is no longer valid. "+
-                    "Please run kinit and then click 'Retry'. "+
-                    "If this is your first time running the IPA Web UI "+
-                    "<a href='/ipa/config/unauthorized.html'>"+
-                    "follow these directions</a> to configure your browser.");
+                    "Your session has expired. Please re-login.");
+
+    that.form_auth_msg = spec.form_auth_msg || IPA.get_message('login.form_auth',
+                    "To login with username and password:");
+
+    that.krb_auth_msg = spec.krb_auth_msg || IPA.get_message('login.krb_auth_msg',
+                    " To login with Kerberos, please make sure you" +
+                    " have valid tickets (obtainable via kinit) and " +
+                    "<a href='/ipa/config/unauthorized.html'>configured</a>" +
+                    " the browser correctly.");
 
     that.form_auth_failed = "<p><strong>Please re-enter your username or password</strong></p>" +
                 "<p>The password or username you entered is incorrect. " +
                 "Please try again (make sure your caps lock is off).</p>" +
                 "<p>If the problem persists, contact your administrator.</p>";
 
-    that.password_expired = "<p><strong>Password expired</strong></p>" +
-                "<p>Please run kinit to reset the password and then try to login again.</p>" +
-                "<p>If the problem persists, contact your administrator.</p>";
+    that.password_expired = "Your password has expired. Please enter a new password.";
 
     that.create = function() {
 
-        that.krb_message_contatiner = $('<div\>').appendTo(that.container);
-
-        $('<p/>', {
-            html: that.message
-        }).appendTo(that.krb_message_contatiner);
-
-        var text = IPA.get_message('login.use', "Or you can use ");
-        var fb_title = $('<p/>', {
-            text: text
-        }).appendTo(that.krb_message_contatiner);
-
-        text = IPA.get_message('login.form_auth', "form-based authentication");
-        that.form_auth_link = $('<a/>', {
-            text: text,
-            href: '#',
-            click: function() {
-                that.show_form();
-                return false;
-            },
-            keydown: function(event) {
-                if (event.keyCode === 13) { //enter
-                    that.show_form();
-                    return false;
-                }
-            }
-        }).appendTo(fb_title);
-
-        fb_title.append('.');
-
-        that.create_form();
+        that.session_expired_form();
+        that.create_reset_form();
     };
 
-    that.create_form = function() {
-
-        that.form = $('<div>', {
-            'class': 'auth-dialog',
-            style: 'display: none;',
-            keyup: that.on_form_keyup
+    that.session_expired_form = function() {
+        that.session_form = $('<div\>', {
+            keyup: that.on_login_keyup
         }).appendTo(that.container);
 
-        var text = IPA.get_message('login.login', "Login");
-        $('<h3/>', {
-            text: text
-        }).appendTo(that.form);
-
-        that.error_box = $('<div/>', {
+        that.login_error_box = $('<div/>', {
             'class': 'error-box',
             style: 'display:none',
             html: that.form_auth_failed
-        }).appendTo(that.form);
+        }).appendTo(that.session_form);
 
+        $('<p/>', {
+            html: that.message
+        }).appendTo(that.session_form);
 
-        var widgets = that.widgets.get_widgets();
-        for (var i=0; i<widgets.length; i++) {
-            var widget = widgets[i];
+        $('<p/>', {
+            html: that.krb_auth_msg
+        }).appendTo(that.session_form);
 
-            var div = $('<div/>', {
-                name: widget.name,
-                'class': 'dialog-section'
-            }).appendTo(that.form);
+        $('<p/>', {
+            html: that.form_auth_msg
+        }).appendTo(that.session_form);
 
-            widget.create(div);
-        }
+        $('<div>', {
+            'class': 'auth-dialog'
+        }).appendTo(that.session_form);
+
+
+        var section = that.widgets.get_widget('login');
+        var div = $('<div/>', {
+            name: 'login',
+            'class': 'dialog-section'
+        }).appendTo(that.session_form);
+        section.create(div);
+
+        that.username_widget = that.widgets.get_widget('login.username');
+        that.password_widget = that.widgets.get_widget('login.password');
+
+        that.username_widget.value_changed.attach(that.on_username_change);
+    };
+
+    that.create_reset_form = function() {
+
+        that.reset_form = $('<div\>', {
+            keyup: that.on_reset_keyup,
+            style: 'display:none'
+        }).appendTo(that.container);
+
+        that.reset_error_box =  $('<div/>', {
+            'class': 'error-box'
+        }).appendTo(that.reset_form);
+
+        $('<p/>', {
+            html: that.password_expired
+        }).appendTo(that.reset_form);
+
+        var section = that.widgets.get_widget('reset');
+        var div = $('<div/>', {
+            name: 'reset',
+            'class': 'dialog-section'
+        }).appendTo(that.reset_form);
+        section.create(div);
+
+        that.username_r_widget = that.widgets.get_widget('reset.username_r');
+        that.new_password_widget = that.widgets.get_widget('reset.new_password');
+        that.verify_password_widget = that.widgets.get_widget('reset.verify_password');
     };
 
-    that.create_login_buttons = function() {
+    that.create_buttons = function() {
+
+        that.buttons.empty();
 
         var visible = that.visible_buttons.indexOf('login') > -1;
         var label = IPA.get_message('login.login', "Login");
@@ -1505,24 +1596,75 @@ IPA.unauthorized_dialog = function(spec) {
             }
         });
 
-        visible = that.visible_buttons.indexOf('back') > -1;
-        label = IPA.get_message('buttons.back', "Back");
+        visible = that.visible_buttons.indexOf('reset') > -1;
+        label = IPA.get_message('buttons.reset_password_and_login', "Reset Password and Login");
         that.create_button({
-            name: 'back',
+            name: 'reset',
             label: label,
             visible: visible,
             click: function() {
-                that.on_back();
+                that.on_reset();
+            }
+        });
+
+        visible = that.visible_buttons.indexOf('cancel') > -1;
+        label = IPA.get_message('buttons.cancel', "Cancel");
+        that.create_button({
+            name: 'cancel',
+            label: label,
+            visible: visible,
+            click: function() {
+                that.on_cancel();
             }
         });
     };
 
     that.open = function() {
         that.dialog_open();
-        that.form_auth_link.focus();
+        that.show_session_form();
     };
 
-    that.on_form_keyup = function(event) {
+    that.on_username_change = function() {
+
+        var password_field = that.fields.get_field('password');
+        var user_specified = !IPA.is_empty(that.username_widget.save());
+        password_field.set_required(user_specified);
+        if (!user_specified) that.password_widget.clear();
+    };
+
+    that.enable_fields = function(field_names) {
+
+        var field, fields, i, enable;
+        fields = that.fields.get_fields();
+        for (i=0; i<fields.length; i++) {
+            field = fields[i];
+            enable = field_names.indexOf(field.name) > -1;
+            field.set_enabled(enable);
+        }
+    };
+
+    that.show_session_form = function() {
+
+        that.enable_fields(['username', 'password']);
+        that.session_form.css('display', 'block');
+        that.reset_form.css('display', 'none');
+        that.display_buttons(['login']);
+        that.username_widget.focus_input();
+    };
+
+    that.show_reset_form = function() {
+
+        that.enable_fields(['new_password', 'verify_password']);
+        that.session_form.css('display', 'none');
+        that.reset_form.css('display', 'block');
+        that.display_buttons(['reset', 'cancel']);
+
+        var username = that.username_widget.save();
+        that.username_r_widget.update(username);
+        that.new_password_widget.focus_input();
+    };
+
+    that.on_login_keyup = function(event) {
 
         if (that.switching) {
             that.switching = false;
@@ -1532,62 +1674,124 @@ IPA.unauthorized_dialog = function(spec) {
         if (event.keyCode === 13) { // enter
             that.on_login();
             event.preventDefault();
-        } else if (event.keyCode === 27) { // escape
-            that.on_back();
-            event.preventDefault();
         }
     };
 
-    that.show_form = function() {
+    that.on_cancel = function() {
 
-        that.switching = true;
+        that.username_r_widget.clear();
+        that.new_password_widget.clear();
+        that.verify_password_widget.clear();
 
-        that.krb_message_contatiner.css('display', 'none');
-        that.form.css('display', 'block');
-        that.display_buttons(['login', 'back']);
-
-        var user_field = that.fields.get_field('username');
-        user_field.widget.focus_input();
-    };
-
-    that.on_back = function() {
-
-        that.krb_message_contatiner.css('display', 'block');
-        that.form.css('display', 'none');
-        that.display_buttons(['retry']);
-        that.form_auth_link.focus();
+        that.show_session_form();
     };
 
     that.on_login = function() {
 
+        var username = that.username_widget.save();
+        var password = that.password_widget.save();
+
+        //if user doesn't specify username and password try kerberos auth
+        if (IPA.is_empty(username) && IPA.is_empty(password)) {
+            that.on_retry();
+            return;
+        }
+
         if (!that.validate()) return;
 
-        var record = {};
-        that.save(record);
-
         IPA.display_activity_icon();
 
-        var result = IPA.login_password(record.username[0], record.password[0]);
+        var result = IPA.login_password(username[0], password[0]);
 
         IPA.hide_activity_icon();
 
         if (result === 'success') {
             that.on_login_success();
         } else if (result === 'expired') {
-            that.error_box.html(that.password_expired);
-            that.error_box.css('display', 'block');
-        }else {
-            that.error_box.html(that.form_auth_failed);
-            that.error_box.css('display', 'block');
+            that.reset_error_box.css('display', 'none');
+            that.show_reset_form();
+        } else {
+            that.login_error_box.html(that.form_auth_failed);
+            that.login_error_box.css('display', 'block');
         }
     };
 
     that.on_login_success = function() {
-        that.error_box.css('display', 'none');
+        that.login_error_box.css('display', 'none');
+
+        that.username_widget.clear();
+        that.password_widget.clear();
+
         that.on_retry();
     };
 
-    that.create_login_buttons();
+    that.on_reset_keyup = function(event) {
+
+        if (that.switching) {
+            that.switching = false;
+            return;
+        }
+
+        if (event.keyCode === 13) { // enter
+            that.on_reset();
+            event.preventDefault();
+        } else if (event.keyCode === 27) { // escape
+            that.on_cancel();
+            event.preventDefault();
+        }
+    };
+
+    that.on_reset = function() {
+        if (!that.validate()) return;
+
+        var username = that.username_widget.save();
+        var password = that.password_widget.save();
+        var new_password = that.new_password_widget.save();
+        var verify_password = that.verify_password_widget.save();
+
+        if (new_password[0] !== verify_password[0]) {
+            var message = IPA.get_message('password.password_must_match',
+                            "Passwords must match");
+            that.reset_error_box.html(message);
+            that.reset_error_box.css('display', 'block');
+            return;
+        } else {
+            that.reset_error_box.css('display', 'none');
+        }
+
+        IPA.display_activity_icon();
+
+        var result = IPA.reset_password(username[0],
+                                        password[0],
+                                        new_password[0]);
+
+        IPA.hide_activity_icon();
+
+        if (result.status === 'ok') {
+            that.on_reset_success();
+        } else {
+            that.reset_error_box.html(result.message);
+            that.reset_error_box.css('display', 'block');
+        }
+    };
+
+    that.on_reset_success = function() {
+
+        that.login_error_box.css('display', 'none');
+        that.reset_error_box.css('display', 'none');
+
+        that.password_widget.update(that.new_password_widget.save());
+
+        that.new_password_widget.clear();
+        that.verify_password_widget.clear();
+
+        that.show_session_form();
+
+        //re-login
+        that.on_login();
+    };
+
+    that.create_buttons();
 
     return that;
 };
diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
index 09d5a545eb3facfce4377685cb3a4aa32916f2d6..1ca114bbc1372fbe4e8ca74f0fe70399e5b7931c 100644
--- a/install/ui/test/data/ipa_init.json
+++ b/install/ui/test/data/ipa_init.json
@@ -9,8 +9,7 @@
                 "messages": {
                     "ajax": {
                         "401": {
-                            "message": "Your Kerberos ticket is no longer valid. Please run kinit and then click 'Retry'. If this is your first time running the IPA Web UI <a href='/ipa/config/unauthorized.html'>follow these directions</a> to configure your browser.",
-                            "title": "Kerberos ticket no longer valid."
+                            "message": "Your session has expired. Please re-login."
                         }
                     },
                     "actions": {
@@ -67,6 +66,7 @@
                         "refresh": "Refresh",
                         "remove": "Delete",
                         "reset": "Reset",
+                        "reset_password_and_login": "Reset Password and Login",
                         "restore": "Restore",
                         "retry": "Retry",
                         "revoke": "Revoke",
@@ -129,13 +129,13 @@
                     },
                     "false": "False",
                     "login": {
-                        "form_auth": "form-based authentication",
+                        "form_auth": "To login with username and password:",
                         "header": "Logged In As",
+                        "krb_auth_msg": "To login with Kerberos, please make sure you have valid tickets (obtainable via kinit) and <a href='/ipa/config/unauthorized.html'>configured</a> the browser correctly.",
                         "login": "Login",
                         "logout": "Logout",
                         "logout_error": "Logout error",
                         "password": "Password",
-                        "use": "Or you can use ",
                         "username": "Username"
                     },
                     "objects": {
@@ -426,10 +426,12 @@
                     "password": {
                         "current_password": "Current Password",
                         "current_password_required": "Current password is required",
+                        "invalid_password": "The password or username you entered is incorrect.",
                         "new_password": "New Password",
                         "new_password_required": "New password is required",
                         "password_change_complete": "Password change complete",
                         "password_must_match": "Passwords must match",
+                        "reset_failure": "Password reset was not successful.",
                         "reset_password": "Reset Password",
                         "verify_password": "Verify Password"
                     },
diff --git a/ipalib/plugins/internal.py b/ipalib/plugins/internal.py
index d860baf4748deb42839f4ace7f9728736942de29..e96f2f186a57590aaafe3df72731191ba1d66da4 100644
--- a/ipalib/plugins/internal.py
+++ b/ipalib/plugins/internal.py
@@ -144,8 +144,7 @@ class i18n_messages(Command):
     messages = {
         "ajax": {
             "401": {
-                "message": _("Your Kerberos ticket is no longer valid. Please run kinit and then click 'Retry'. If this is your first time running the IPA Web UI <a href='/ipa/config/unauthorized.html'>follow these directions</a> to configure your browser."),
-                "title": _("Kerberos ticket no longer valid."),
+                "message": _("Your session has expired. Please re-login."),
             },
         },
         "actions": {
@@ -202,6 +201,7 @@ class i18n_messages(Command):
             "refresh": _("Refresh"),
             "remove": _("Delete"),
             "reset": _("Reset"),
+            "reset_password_and_login": _("Reset Password and Login"),
             "restore": _("Restore"),
             "retry": _("Retry"),
             "revoke": _("Revoke"),
@@ -264,13 +264,13 @@ class i18n_messages(Command):
         },
         "false": _("False"),
         "login": {
-            "form_auth": _("form-based authentication"),
+            "form_auth": _("To login with username and password:"),
             "header": _("Logged In As"),
+            "krb_auth_msg": _("To login with Kerberos, please make sure you have valid tickets (obtainable via kinit) and <a href='/ipa/config/unauthorized.html'>configured</a> the browser correctly."),
             "login": _("Login"),
             "logout": _("Logout"),
             "logout_error": _("Logout error"),
             "password": _("Password"),
-            "use": _("Or you can use "),
             "username": _("Username"),
         },
         "objects": {
@@ -565,10 +565,12 @@ class i18n_messages(Command):
         "password": {
             "current_password": _("Current Password"),
             "current_password_required": _("Current password is required"),
+            "invalid_password": _("The password or username you entered is incorrect."),
             "new_password": _("New Password"),
             "new_password_required": _("New password is required"),
             "password_change_complete": _("Password change complete"),
             "password_must_match": _("Passwords must match"),
+            "reset_failure": _("Password reset was not successful."),
             "reset_password": _("Reset Password"),
             "verify_password": _("Verify Password"),
         },
-- 
1.7.7.6

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to