Use python logging in install / log cherrypy at right severity
[cascardo/ipsilon.git] / ipsilon / login / authfas.py
1 # Copyright (C) 2014 Ipsilon contributors, see COPYING file for license
2
3
4 from ipsilon.login.common import LoginFormBase, LoginManagerBase, \
5     LoginManagerInstaller
6 from ipsilon.util.plugin import PluginObject
7 from ipsilon.util.policy import Policy
8 from ipsilon.util import config as pconfig
9 import cherrypy
10 import logging
11
12 from fedora.client.fasproxy import FasProxyClient
13 from fedora.client import AuthError
14
15
16 try:
17     import openid_cla.cla as cla
18
19     CLA_GROUPS = {
20         'cla_click': cla.CLA_URI_FEDORA_CLICK,
21         'cla_dell': cla.CLA_URI_FEDORA_DELL,
22         'cla_done': cla.CLA_URI_FEDORA_DONE,
23         'cla_fedora': cla.CLA_URI_FEDORA_FEDORA,
24         'cla_fpca': cla.CLA_URI_FEDORA_FPCA,
25         'cla_ibm': cla.CLA_URI_FEDORA_IBM,
26         'cla_intel': cla.CLA_URI_FEDORA_INTEL,
27         'cla_redhat': cla.CLA_URI_FEDORA_REDHAT,
28     }
29 except ImportError:
30     CLA_GROUPS = dict()
31
32 fas_mapping = [
33     ['username', 'nickname'],
34     ['telephone', 'phone'],
35     ['country_code', 'country'],
36     ['human_name', 'fullname'],
37     ['email', 'email'],
38     ['timezone', 'timezone'],
39 ]
40
41
42 class FAS(LoginFormBase):
43
44     def __init__(self, site, mgr, page):
45         super(FAS, self).__init__(site, mgr, page)
46         self.mapper = Policy(fas_mapping)
47
48     def POST(self, *args, **kwargs):
49         username = kwargs.get("login_name")
50         password = kwargs.get("login_password")
51         error = None
52
53         if username and password:
54             data = None
55             try:
56                 _, data = self.lm.fpc.login(username, password)
57             except AuthError, e:
58                 cherrypy.log.error("Authentication error [%s]" % str(e),
59                                    severity=logging.ERROR)
60             except Exception, e:  # pylint: disable=broad-except
61                 cherrypy.log.error("Unknown Error [%s]" % str(e),
62                                    severity=logging.ERROR)
63
64             if data and data.user:
65                 userdata = self.make_userdata(data.user)
66                 return self.lm.auth_successful(self.trans,
67                                                data.user['username'],
68                                                userdata=userdata)
69             else:
70                 error = "Authentication failed"
71                 cherrypy.log.error(error, severity=logging.ERROR)
72         else:
73             error = "Username or password is missing"
74             cherrypy.log.error("Error: " + error, severity=logging.ERROR)
75
76         context = self.create_tmpl_context(
77             username=username,
78             error=error,
79             error_password=not password,
80             error_username=not username
81         )
82         self.lm.set_auth_error()
83         # pylint: disable=star-args
84         return self._template(self.formtemplate, **context)
85
86     def make_userdata(self, fas_data):
87         userdata, fas_extra = self.mapper.map_attributes(fas_data)
88
89         # compute and store groups and cla groups
90         userdata['_groups'] = []
91         userdata['_extras'] = {'fas': fas_extra, 'cla': []}
92         for group in fas_data.get('approved_memberships', {}):
93             if 'name' not in group:
94                 continue
95             if group.get('group_type') == 'cla':
96                 if group['name'] in CLA_GROUPS:
97                     group_name = CLA_GROUPS[group['name']]
98                 else:
99                     group_name = group['name']
100                 userdata['_extras']['cla'].append(group_name)
101             else:
102                 userdata['_groups'].append(group['name'])
103
104         return userdata
105
106
107 class LoginManager(LoginManagerBase):
108
109     def __init__(self, *args, **kwargs):
110         super(LoginManager, self).__init__(*args, **kwargs)
111         self.name = 'fas'
112         self.path = 'fas'
113         self.service_name = 'fas'
114         self.page = None
115         self.fpc = None
116         self.description = """
117 Form based login Manager that uses the Fedora Authentication Server
118 """
119         self.new_config(
120             self.name,
121             pconfig.String(
122                 'FAS url',
123                 'The FAS Url.',
124                 'https://admin.fedoraproject.org/accounts/'),
125             pconfig.String(
126                 'FAS Proxy client user Agent',
127                 'The User Agent presented to the FAS Server.',
128                 'Ipsilon v1.0'),
129             pconfig.Condition(
130                 'FAS Insecure Auth',
131                 'If checked skips FAS server cert verification.',
132                 False),
133             pconfig.String(
134                 'username text',
135                 'Text used to ask for the username at login time.',
136                 'FAS Username'),
137             pconfig.String(
138                 'password text',
139                 'Text used to ask for the password at login time.',
140                 'Password'),
141             pconfig.String(
142                 'help text',
143                 'Text used to guide the user at login time.',
144                 'Login with your FAS credentials')
145         )
146
147     @property
148     def help_text(self):
149         return self.get_config_value('help text')
150
151     @property
152     def username_text(self):
153         return self.get_config_value('username text')
154
155     @property
156     def password_text(self):
157         return self.get_config_value('password text')
158
159     @property
160     def fas_url(self):
161         return self.get_config_value('FAS url')
162
163     @property
164     def user_agent(self):
165         return self.get_config_value('FAS Proxy client user Agent')
166
167     @property
168     def insecure(self):
169         return self.get_config_value('FAS Insecure Auth')
170
171     def get_tree(self, site):
172         self.fpc = FasProxyClient(base_url=self.fas_url,
173                                   useragent=self.user_agent,
174                                   insecure=(self.insecure == 'YES'))
175         self.page = FAS(site, self, 'login/fas')
176         return self.page
177
178
179 class Installer(LoginManagerInstaller):
180
181     def __init__(self, *pargs):
182         super(Installer, self).__init__()
183         self.name = 'fas'
184         self.pargs = pargs
185
186     def install_args(self, group):
187         group.add_argument('--fas', choices=['yes', 'no'], default='no',
188                            help='Configure FAS authentication')
189
190     def configure(self, opts):
191         if opts['fas'] != 'yes':
192             return
193
194         # Add configuration data to database
195         po = PluginObject(*self.pargs)
196         po.name = 'fas'
197         po.wipe_data()
198         po.wipe_config_values()
199
200         # Update global config to add login plugin
201         po.is_enabled = True
202         po.save_enabled_state()