From 40eb1e1c9a1145911ea9130dfd9284a2f8025f21 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <sgallagh@redhat.com>
Date: Mon, 2 Nov 2009 15:14:44 -0500
Subject: [PATCH 3/4] Add support for option descriptions to SSSDConfig API

Addresses https://fedorahosted.org/sssd/ticket/242 related to
authconfig integration
---
 server/config/SSSDConfig.py     |  156 ++++++++++++++++++++++++++++++++++++---
 server/config/SSSDConfigTest.py |    6 +-
 2 files changed, 148 insertions(+), 14 deletions(-)

diff --git a/server/config/SSSDConfig.py b/server/config/SSSDConfig.py
index 578f292..7c04c25 100644
--- a/server/config/SSSDConfig.py
+++ b/server/config/SSSDConfig.py
@@ -5,6 +5,7 @@ Created on Sep 18, 2009
 '''
 
 import os
+import gettext
 import exceptions
 from ConfigParser import RawConfigParser, NoSectionError
 
@@ -25,6 +26,123 @@ class NoSuchProviderError(SSSDConfigException): pass
 class NoSuchProviderSubtypeError(SSSDConfigException): pass
 class ProviderSubtypeInUse(SSSDConfigException): pass
 
+PACKAGE = 'sss_daemon'
+LOCALEDIR = '/usr/share/locale'
+
+translation = gettext.translation(PACKAGE, LOCALEDIR, fallback=True)
+_ = translation.ugettext
+
+# TODO: This needs to be made external
+option_strings = {
+    # [service]
+    'debug_level' : _('Set the verbosity of the debug logging'),
+    'debug_timestamps' : _('Include timestamps in debug logs'),
+    'debug_to_files' : _('Write debug messages to logfiles'),
+    'timeout' : _('Ping timeout before restarting service'),
+    'command' : _('Command to start service'),
+    'reconnection_retries' : _('Number of times to attempt connection to Data Providers'),
+
+    # [sssd]
+    'services' : _('SSSD Services to start'),
+    'domains' : _('SSSD Domains to start'),
+    'sbus_timeout' : _('Timeout for messages sent over the SBUS'),
+    're_expression' : _('Regex to parse username and domain'),
+    'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'),
+
+    # [nss]
+    'enum_cache_timeout' : _('Enumeration cache timeout length (seconds)'),
+    'entry_cache_no_wait_timeout' : _('Entry cache background update timeout length (seconds)'),
+    'entry_negative_timeout' : _('Negative cache timeout length (seconds)'),
+    'filter_users' : _('Users that SSSD should explicitly ignore'),
+    'filter_groups' : _('Groups that SSSD should explicitly ignore'),
+    'filter_users_in_groups' : _('Should filtered users appear in groups'),
+
+    # [pam]
+    'offline_credentials_expiration' : _('How long to allow cached logins between online logins (days)'),
+
+    # [provider]
+    'id_provider' : _('Identity provider'),
+    'auth_provider' : _('Authentication provider'),
+    'access_provider' : _('Access control provider'),
+    'chpass_provider' : _('Password change provider'),
+
+    # [domain]
+    'min_id' : _('Minimum user ID'),
+    'max_id' : _('Maximum user ID'),
+    'timeout' : _('Ping timeout before restarting domain'),
+    'enumerate' : _('Enable enumerating all users/groups'),
+    'cache_credentials' : _('Cache credentials for offline login'),
+    'store_legacy_passwords' : _('Store password hashes'),
+    'use_fully_qualified_names' : _('Display users/groups in fully-qualified form'),
+    'entry_cache_timeout' : _('Entry cache timeout length (seconds)'),
+
+    # [provider/ipa]
+    'ipa_domain' : _('IPA domain'),
+    'ipa_server' : _('IPA server address'),
+    'ipa_hostname' : _('IPA client hostname'),
+
+    # [provider/krb5]
+    'krb5_kdcip' : _('Kerberos server address'),
+    'krb5_realm' : _('Kerberos realm'),
+    'krb5_auth_timeout' : _('Authentication timeout'),
+
+    # [provider/krb5/auth]
+    'krb5_ccachedir' : _('Directory to store credential caches'),
+    'krb5_ccname_template' : _("Location of the user's credential cache"),
+
+    # [provider/krb5/chpass]
+    'krb5_changepw_principal' : _('The principal of the change password service'),
+
+    # [provider/ldap]
+    'ldap_uri' : _('ldap_uri, The URI of the LDAP server'),
+    'ldap_search_base' : _('The default base DN'),
+    'ldap_schema' : _('The Schema Type in use on the LDAP server, rfc2307'),
+    'ldap_default_bind_dn' : _('The default bind DN'),
+    'ldap_default_authtok_type' : _('The type of the authentication token of the default bind DN'),
+    'ldap_default_authtok' : _('The authentication token of the default bind DN'),
+    'ldap_network_timeout' : _('Length of time to attempt connection'),
+    'ldap_opt_timeout' : _('Length of time to attempt synchronous LDAP operations'),
+    'ldap_offline_timeout' : _('Length of time between attempts to reconnect while offline'),
+    'ldap_tls_cacert' : _('file that contains CA certificates'),
+    'ldap_tls_reqcert' : _('Require TLS certificate verification'),
+    'ldap_sasl_mech' : _('Specify the sasl mechanism to use'),
+    'ldap_sasl_authid' : _('Specify the sasl authorization id to use'),
+    'krb5_kdcip' : _('Kerberos server address'),
+    'krb5_realm' : _('Kerberos realm'),
+    'ldap_krb5_keytab' : _('Kerberos service keytab'),
+    'ldap_krb5_init_creds' : _('Use Kerberos auth for LDAP connection'),
+
+    # [provider/ldap/id]
+    'ldap_search_timeout' : _('Length of time to wait for a search request'),
+    'ldap_enumeration_refresh_timeout' : _('Length of time between enumeration updates'),
+    'ldap_id_use_start_tls' : _('Require TLS for ID lookups, false'),
+    'ldap_user_search_base' : _('Base DN for user lookups'),
+    'ldap_user_search_scope' : _('Scope of user lookups'),
+    'ldap_user_search_filter' : _('Filter for user lookups'),
+    'ldap_user_object_class' : _('Objectclass for users'),
+    'ldap_user_name' : _('Username attribute'),
+    'ldap_user_uid_number' : _('UID attribute'),
+    'ldap_user_gid_number' : _('Primary GID attribute'),
+    'ldap_user_gecos' : _('GECOS attribute'),
+    'ldap_user_homedir' : _('Home directory attribute'),
+    'ldap_user_shell' : _('Shell attribute'),
+    'ldap_user_uuid' : _('UUID attribute'),
+    'ldap_user_principal' : _('User principal attribute (for Kerberos)'),
+    'ldap_user_fullname' : _('Full Name'),
+    'ldap_user_member_of' : _('memberOf attribute'),
+    'ldap_user_modify_timestamp' : _('Modification time attribute'),
+
+    # [provider/local/id]
+    'default_shell' : _('Default shell, /bin/bash'),
+    'base_directory' : _('Base for home directories'),
+
+    # [provider/proxy/id]
+    'proxy_lib_name' : _('The name of the NSS library to use'),
+
+    # [provider/proxy/auth]
+    'proxy_pam_target' : _('PAM stack to use')
+}
+
 class SSSDConfigSchema(RawConfigParser):
     def __init__(self, schemafile, schemaplugindir):
         #TODO: get these from a global setting
@@ -74,6 +192,11 @@ class SSSDConfigSchema(RawConfigParser):
             raise NoSectionError
         options = self.options(section)
 
+        # Indexes
+        PRIMARY_TYPE = 0
+        SUBTYPE = 1
+        DEFAULT = 2
+
         # Parse values
         parsed_options = {}
         for option in options:
@@ -81,33 +204,42 @@ class SSSDConfigSchema(RawConfigParser):
             split_option = self._striplist(unparsed_option.split(','))
             optionlen = len(split_option)
 
-            primarytype = self.type_lookup[split_option[0]]
-            subtype = self.type_lookup[split_option[1]]
+            primarytype = self.type_lookup[split_option[PRIMARY_TYPE]]
+            subtype = self.type_lookup[split_option[SUBTYPE]]
+
+            if option_strings.has_key(option):
+                desc = option_strings[option]
+            else:
+                desc = None
 
             if optionlen == 2:
                 # This option has no defaults
                 parsed_options[option] = \
                     (primarytype,
                      subtype,
+                     desc,
                      None)
             elif optionlen == 3:
-                if type(split_option[2]) == primarytype:
+                if type(split_option[DEFAULT]) == primarytype:
                     parsed_options[option] = \
                         (primarytype,
                          subtype,
-                         split_option[2])
+                         desc,
+                         split_option[DEFAULT])
                 elif primarytype == list:
-                    if (type(split_option[2]) == subtype):
+                    if (type(split_option[DEFAULT]) == subtype):
                         parsed_options[option] = \
                             (primarytype,
                              subtype,
-                             [split_option[2]])
+                             desc,
+                             [split_option[DEFAULT]])
                     else:
                         try:
                             parsed_options[option] = \
                                 (primarytype,
                                  subtype,
-                                 [subtype(split_option[2])])
+                                 desc,
+                                 [subtype(split_option[DEFAULT])])
                         except ValueError:
                             raise ParsingError
                 else:
@@ -115,7 +247,8 @@ class SSSDConfigSchema(RawConfigParser):
                         parsed_options[option] = \
                             (primarytype,
                              subtype,
-                             primarytype(split_option[2]))
+                             desc,
+                             primarytype(split_option[DEFAULT]))
                     except ValueError:
                         raise ParsingError
 
@@ -123,7 +256,7 @@ class SSSDConfigSchema(RawConfigParser):
                 if (primarytype != list):
                     raise ParsingError
                 fixed_options = []
-                for x in split_option[2:]:
+                for x in split_option[DEFAULT:]:
                     if type(x) != subtype:
                         try:
                             fixed_options.extend([subtype(x)])
@@ -134,6 +267,7 @@ class SSSDConfigSchema(RawConfigParser):
                 parsed_options[option] = \
                     (primarytype,
                      subtype,
+                     desc,
                      fixed_options)
             else:
                 # Bad config file
@@ -155,9 +289,9 @@ class SSSDConfigSchema(RawConfigParser):
             raise NoSectionError(section)
 
         schema_options = self.get_options(section)
-        defaults = dict([(x,schema_options[x][2])
+        defaults = dict([(x,schema_options[x][3])
                          for x in schema_options.keys()
-                         if schema_options[x][2] != None])
+                         if schema_options[x][3] != None])
 
         return defaults
 
diff --git a/server/config/SSSDConfigTest.py b/server/config/SSSDConfigTest.py
index 141773b..f99f672 100644
--- a/server/config/SSSDConfigTest.py
+++ b/server/config/SSSDConfigTest.py
@@ -239,7 +239,7 @@ class SSSDConfigTestSSSDService(unittest.TestCase):
         self.assertTrue(options['reconnection_retries'][0] == int,
                         "reconnection_retries should default to 2. " +
                         "list_options specifies %d" %
-                        options['reconnection_retries'][2])
+                        options['reconnection_retries'][3])
 
         self.assertTrue(type(options['services']) == tuple,
                         "Option values should be a tuple")
@@ -437,12 +437,12 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase):
                         "Option values should be a tuple")
 
         self.assertTrue(options['max_id'][0] == int,
-                        "config_file_version should require an int. " +
+                        "max_id should require an int. " +
                         "list_options is requiring a %s" %
                         options['max_id'][0])
 
         self.assertTrue(options['max_id'][1] == None,
-                        "config_file_version should not require a subtype. " +
+                        "max_id should not require a subtype. " +
                         "list_options is requiring a %s" %
                         options['max_id'][1])
 
-- 
1.6.2.5

