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