Simo Sorce wrote:
On Tue, 2012-02-21 at 15:57 -0500, Rob Crittenden wrote:
+                other_ldap = ldap2(shared_instance=False,
+                                   ldap_uri='ldap://%s' % host,
+                                   base_dn=self.api.env.basedn)
+                other_ldap.connect(ccache=os.environ['KRB5CCNAME'])

Nack,
if a server is not reachable this will give back a traceback as no
exception is trapped.
Also in general we should not fail, some servers may have whatever
issues. We should just return a "N/A" result for those servers that we
had problem reaching or requesting values from.

Simo.


fixed

rob

>From 2e54115d0162c0390cb6af1fc86740de09c03644 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Tue, 14 Feb 2012 09:41:25 -0500
Subject: [PATCH] Add status command to retrieve user lockout status

This information is not replicated so pull from all IPA masters
and display the status across all servers.

https://fedorahosted.org/freeipa/ticket/2162
---
 API.txt                |   10 ++++
 ipalib/plugins/user.py |  107 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 116 insertions(+), 1 deletions(-)

diff --git a/API.txt b/API.txt
index ba2248904829aa942545401318a51168163c02a3..a63d6fddd82faf311fcdf99ed2badfd057c9721a 100644
--- a/API.txt
+++ b/API.txt
@@ -3248,6 +3248,16 @@ option: Str('version?', exclude='webui')
 output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
 output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
 output: Output('value', <type 'unicode'>, None)
+command: user_status
+args: 1,3,4
+arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', pattern_errmsg='may only include letters, numbers, _, -, . and $', primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('version?', exclude='webui')
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None))
+output: Output('count', <type 'int'>, None)
+output: Output('truncated', <type 'bool'>, None)
 command: user_unlock
 args: 1,0,3
 arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', pattern_errmsg='may only include letters, numbers, _, -, . and $', primary_key=True, query=True, required=True)
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index ad9805bec5db0eee248c45022ee7810293a4109d..8193b43cc1bffd600571d984edf5739a940ca1dc 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -18,7 +18,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-from time import gmtime, strftime
+from time import gmtime, strftime, strptime
 import copy
 import string
 
@@ -27,9 +27,13 @@ from ipalib import Flag, Int, Password, Str, Bool, Bytes
 from ipalib.plugins.baseldap import *
 from ipalib.request import context
 from ipalib import _, ngettext
+from ipalib import output
 from ipapython.ipautil import ipa_generate_password
 import posixpath
 from ipalib.util import validate_sshpubkey, output_sshpubkey
+if api.env.in_server and api.env.context in ['lite', 'server']:
+    from ipaserver.plugins.ldap2 import ldap2
+    import os
 
 __doc__ = _("""
 Users
@@ -79,6 +83,21 @@ user_output_params = (
     ),
    )
 
+status_output_params = (
+    Str('server',
+        label=_('Server'),
+    ),
+    Str('krbloginfailedcount',
+        label=_('Failed logins'),
+    ),
+    Str('krblastsuccessfulauth',
+        label=_('Last successful authentication'),
+    ),
+    Str('krblastfailedauth',
+        label=_('Last failed authentication'),
+    ),
+   )
+
 # characters to be used for generating random user passwords
 user_pwdchars = string.digits + string.ascii_letters + '_,.@+-='
 
@@ -680,3 +699,89 @@ class user_unlock(LDAPQuery):
         )
 
 api.register(user_unlock)
+
+class user_status(LDAPQuery):
+    __doc__ = _("""
+    Lockout status of a user account
+
+    An account may become locked if the password is entered incorrectly too
+    many times within a specific time period as controlled by password
+    policy. A locked account is a temporary condition and may be unlocked by
+    an administrator.
+
+    This connects to each IPA master and displays the lockout status on
+    each one.""")
+
+    has_output = output.standard_list_of_entries
+    has_output_params = LDAPSearch.has_output_params + status_output_params
+
+    def execute(self, *keys, **options):
+        ldap = self.obj.backend
+        dn = self.obj.get_dn(*keys, **options)
+        attr_list = ['krbloginfailedcount', 'krblastsuccessfulauth', 'krblastfailedauth']
+
+        masters = []
+        # Get list of masters
+        try:
+            (masters, truncated) = ldap.find_entries(
+                None, ['*'], 'cn=masters,cn=ipa,cn=etc,%s' % api.env.basedn,
+                ldap.SCOPE_ONELEVEL
+            )
+        except errors.NotFound:
+            # If this happens we have some pretty serious problems
+            self.error('No IPA masters found!')
+            pass
+
+        entries = []
+        count = 0
+        for master in masters:
+            host = master[1]['cn'][0]
+            if host == api.env.host:
+                other_ldap = self.obj.backend
+            else:
+                try:
+                    other_ldap = ldap2(shared_instance=False,
+                                       ldap_uri='ldap://%s' % host,
+                                       base_dn=self.api.env.basedn)
+                    other_ldap.connect(ccache=os.environ['KRB5CCNAME'])
+                except Exception:
+                    newresult = dict()
+                    newresult['dn'] = dn
+                    newresult['server'] = _("%(host)s unreachable") % dict(host=host)
+                    entries.append(newresult)
+                    count += 1
+                    continue
+            try:
+                entry = other_ldap.get_entry(dn, attr_list)
+                newresult = dict()
+                for attr in attr_list:
+                    newresult[attr] = entry[1].get(attr, '')
+                if not options.get('raw', False):
+                    for attr in ['krblastsuccessfulauth', 'krblastfailedauth']:
+                        try:
+                            newtime = time.strptime(newresult[attr][0], '%Y%m%d%H%M%S%Z')
+                            newresult[attr][0] = unicode(time.strftime('%Y-%m-%dT%H:%M:%SZ', newtime))
+                        except Exception, e:
+                            self.debug("time conversion failed with %s" % str(e))
+                            pass
+                newresult['dn'] = dn
+                newresult['server'] = host
+                entries.append(newresult)
+                count += 1
+            except Exception, e:
+                self.error("Retrieving status for %s failed with %s" % (dn, str(e)))
+                newresult = dict()
+                newresult['dn'] = dn
+                newresult['server'] = _("%(host)s failed") % dict(host=host)
+                entries.append(newresult)
+                count += 1
+
+            if host != api.env.host:
+                other_ldap.destroy_connection()
+
+        return dict(result=entries,
+                    count=count,
+                    truncated=False,
+        )
+
+api.register(user_status)
-- 
1.7.6.5

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

Reply via email to