[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Freeipa-devel] [PATCH] 1006 detect expired passwords in forms login



When doing a forms-based login there is no notification that a password needs to be reset. We don't currently provide a facility for that but we should at least tell users what is going on.

This patch adds an LDAP bind to test the password to see if it is expired and returns the string "Password Expired" along with the 401 if it is. I'm told this is all the UI will need to be able to identify this condition.

rob
>From 1d45cb950b1fadac06596c3a9f1ab2ebcfc1a1e3 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcritten redhat com>
Date: Fri, 13 Apr 2012 15:19:32 -0400
Subject: [PATCH] Return consistent expiration message for forms-based login

We need to inform users when a forms-based login fails due to the
password needing to be reset. Currently there is no way to distinguish
a reset case vs an incorrect password.

This will bind the user using a simple LDAP bind over ldapi (by default)
and if that is successful, check the expiration date against the current
time.

The UI portion of this that uses this message will come later.

https://fedorahosted.org/freeipa/ticket/2608
---
 ipaserver/rpcserver.py |   34 ++++++++++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 2fbd79f208320664ec3acb6c8c6004cff683650d..dddbab906919f436dd834019323ecbb658d8f300 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -32,6 +32,8 @@ from ipalib.errors import PublicError, InternalError, CommandError, JSONError, C
 from ipalib.request import context, Connection, destroy_context
 from ipalib.rpc import xml_dumps, xml_loads
 from ipalib.util import make_repr, parse_time_duration
+from ipalib.dn import DN
+from ipaserver.plugins.ldap2 import ldap2
 from ipapython.compat import json
 from ipalib.session import session_mgr, AuthManager, get_ipa_ccache_name, load_ccache_data, bind_ipa_ccache, release_ipa_ccache, fmt_time, default_max_session_duration
 from ipalib.backend import Backend
@@ -45,6 +47,7 @@ import string
 import datetime
 from decimal import Decimal
 import urlparse
+import time
 
 HTTP_STATUS_SUCCESS = '200 Success'
 HTTP_STATUS_SERVER_ERROR = '500 Internal Server Error'
@@ -938,6 +941,37 @@ class login_password(Backend, KerberosSession, HTTP_Status):
         try:
             self.kinit(user, self.api.env.realm, password, ipa_ccache_name)
         except InvalidSessionPassword, e:
+            # Ok, now why is this bad. Is the password simply bad or is the
+            # password expired?
+            try:
+                dn = str(DN(('uid', user),
+                            self.api.env.container_user,
+                            self.api.env.basedn))
+                conn = ldap2(shared_instance=False,
+                             ldap_uri=self.api.env.ldap_uri)
+                conn.connect(bind_dn=dn, bind_pw=password)
+
+                # password is ok, must be expired, lets double-check
+                (userdn, entry_attrs) = conn.get_entry(dn,
+                    ['krbpasswordexpiration'])
+                if 'krbpasswordexpiration' in entry_attrs:
+                    expiration = entry_attrs['krbpasswordexpiration'][0]
+                    try:
+                        exp = time.strptime(expiration, '%Y%m%d%H%M%SZ')
+                        if exp <= time.gmtime():
+                            # Return a fixed value so the UI can
+                            # identify the problem.
+                            e = "Password Expired"
+                    except ValueError, v:
+                        self.error('Unable to convert %s to a time string'
+                            % expiration)
+
+                conn.destroy_connection()
+            except Exception:
+                # It doesn't really matter how we got here but the user's
+                # password is not accepted or the user is unknown.
+                pass
+
             return self.unauthorized(environ, start_response, str(e))
 
         return self.finalize_kerberos_acquisition('login_password', ipa_ccache_name, environ, start_response)
-- 
1.7.6


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]