Make SSSD Info enable the httpd_dbus_sssd boolean.
[cascardo/ipsilon.git] / ipsilon / login / authldap.py
1 # Copyright (C) 2014  Ipsilon Contributors, see COPYING for license
2
3 from ipsilon.login.common import LoginFormBase, LoginManagerBase, \
4     LoginManagerInstaller
5 from ipsilon.util.plugin import PluginObject
6 from ipsilon.util.log import Log
7 from ipsilon.util import config as pconfig
8 from ipsilon.info.infoldap import InfoProvider as LDAPInfo
9 import ldap
10
11
12 class LDAP(LoginFormBase, Log):
13
14     def __init__(self, site, mgr, page):
15         super(LDAP, self).__init__(site, mgr, page)
16         self.ldap_info = None
17
18     def _ldap_connect(self):
19
20         tls = self.lm.tls.lower()
21         tls_req_opt = None
22         if tls == "never":
23             tls_req_opt = ldap.OPT_X_TLS_NEVER
24         elif tls == "demand":
25             tls_req_opt = ldap.OPT_X_TLS_DEMAND
26         elif tls == "allow":
27             tls_req_opt = ldap.OPT_X_TLS_ALLOW
28         elif tls == "try":
29             tls_req_opt = ldap.OPT_X_TLS_TRY
30         if tls_req_opt is not None:
31             ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_opt)
32
33         conn = ldap.initialize(self.lm.server_url)
34
35         if tls != "notls":
36             if not self.lm.server_url.startswith("ldaps"):
37                 conn.start_tls_s()
38         return conn
39
40     def _authenticate(self, username, password):
41
42         conn = self._ldap_connect()
43         dn = self.lm.bind_dn_tmpl % {'username': username}
44         conn.simple_bind_s(dn, password)
45
46         # Bypass info plugins to optimize data retrieval
47         if self.lm.get_user_info:
48             self.lm.info = None
49
50             if not self.ldap_info:
51                 self.ldap_info = LDAPInfo(self._site)
52
53             return self.ldap_info.get_user_data_from_conn(conn, dn)
54
55         return None
56
57     def POST(self, *args, **kwargs):
58         username = kwargs.get("login_name")
59         password = kwargs.get("login_password")
60         userattrs = None
61         authed = False
62         errmsg = None
63
64         if username and password:
65             try:
66                 userattrs = self._authenticate(username, password)
67                 authed = True
68             except Exception, e:  # pylint: disable=broad-except
69                 errmsg = "Authentication failed"
70                 self.error("Exception raised: [%s]" % repr(e))
71         else:
72             errmsg = "Username or password is missing"
73             self.error(errmsg)
74
75         if authed:
76             return self.lm.auth_successful(self.trans, username, 'password',
77                                            userdata=userattrs)
78
79         context = self.create_tmpl_context(
80             username=username,
81             error=errmsg,
82             error_password=not password,
83             error_username=not username
84         )
85         # pylint: disable=star-args
86         return self._template('login/form.html', **context)
87
88
89 class LoginManager(LoginManagerBase):
90
91     def __init__(self, *args, **kwargs):
92         super(LoginManager, self).__init__(*args, **kwargs)
93         self.name = 'ldap'
94         self.path = 'ldap'
95         self.page = None
96         self.ldap_info = None
97         self.service_name = 'ldap'
98         self.description = """
99 Form based login Manager that uses a simple bind LDAP operation to perform
100 authentication. """
101         self.new_config(
102             self.name,
103             pconfig.String(
104                 'server url',
105                 'The LDAP server url.',
106                 'ldap://example.com'),
107             pconfig.Template(
108                 'bind dn template',
109                 'Template to turn username into DN.',
110                 'uid=%(username)s,ou=People,dc=example,dc=com'),
111             pconfig.Condition(
112                 'get user info',
113                 'Get user info via ldap using user credentials',
114                 True),
115             pconfig.Pick(
116                 'tls',
117                 'What TLS level show be required',
118                 ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
119                 'Demand'),
120             pconfig.String(
121                 'username text',
122                 'Text used to ask for the username at login time.',
123                 'Username'),
124             pconfig.String(
125                 'password text',
126                 'Text used to ask for the password at login time.',
127                 'Password'),
128             pconfig.String(
129                 'help text',
130                 'Text used to guide the user at login time.',
131                 'Provide your Username and Password')
132         )
133
134     @property
135     def help_text(self):
136         return self.get_config_value('help text')
137
138     @property
139     def username_text(self):
140         return self.get_config_value('username text')
141
142     @property
143     def password_text(self):
144         return self.get_config_value('password text')
145
146     @property
147     def server_url(self):
148         return self.get_config_value('server url')
149
150     @property
151     def tls(self):
152         return self.get_config_value('tls')
153
154     @property
155     def get_user_info(self):
156         return self.get_config_value('get user info')
157
158     @property
159     def bind_dn_tmpl(self):
160         return self.get_config_value('bind dn template')
161
162     def get_tree(self, site):
163         self.page = LDAP(site, self, 'login/ldap')
164         return self.page
165
166
167 class Installer(LoginManagerInstaller):
168
169     def __init__(self, *pargs):
170         super(Installer, self).__init__()
171         self.name = 'ldap'
172         self.pargs = pargs
173
174     def install_args(self, group):
175         group.add_argument('--ldap', choices=['yes', 'no'], default='no',
176                            help='Configure LDAP authentication')
177         group.add_argument('--ldap-server-url', action='store',
178                            help='LDAP Server Url')
179         group.add_argument('--ldap-bind-dn-template', action='store',
180                            help='LDAP Bind DN Template')
181
182     def configure(self, opts):
183         if opts['ldap'] != 'yes':
184             return
185
186         # Add configuration data to database
187         po = PluginObject(*self.pargs)
188         po.name = 'ldap'
189         po.wipe_data()
190         po.wipe_config_values()
191
192         config = dict()
193         if 'ldap_server_url' in opts:
194             config['server url'] = opts['ldap_server_url']
195         if 'ldap_bind_dn_template' in opts:
196             config['bind dn template'] = opts['ldap_bind_dn_template']
197         config['tls'] = 'Demand'
198         po.save_plugin_config(config)
199
200         # Update global config to add login plugin
201         po.is_enabled = True
202         po.save_enabled_state()