Make it possible to use PluginLoader without store
[cascardo/ipsilon.git] / ipsilon / providers / openidp.py
1 # Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
2
3 from __future__ import absolute_import
4
5 from ipsilon.providers.common import ProviderBase, ProviderInstaller
6 from ipsilon.providers.openid.store import OpenIDStore
7 from ipsilon.providers.openid.auth import OpenID
8 from ipsilon.providers.openid.extensions.common import LoadExtensions
9 from ipsilon.util.plugin import PluginObject
10 from ipsilon.util import config as pconfig
11 from ipsilon.info.common import InfoMapping
12
13 from openid.server.server import Server
14
15
16 class IdpProvider(ProviderBase):
17
18     def __init__(self, *pargs):
19         super(IdpProvider, self).__init__('openid', 'openid', *pargs)
20         self.mapping = InfoMapping()
21         self.page = None
22         self.datastore = None
23         self.server = None
24         self.basepath = None
25         self.extensions = LoadExtensions()
26         self.description = """
27 Provides OpenID 2.0 authentication infrastructure. """
28
29         self.new_config(
30             self.name,
31             pconfig.String(
32                 'database url',
33                 'Database URL for OpenID temp storage',
34                 'openid.sqlite'),
35             pconfig.String(
36                 'default email domain',
37                 'Used for users missing the email property.',
38                 'example.com'),
39             pconfig.String(
40                 'endpoint url',
41                 'The Absolute URL of the OpenID provider',
42                 'http://localhost:8080/idp/openid/'),
43             pconfig.Template(
44                 'identity url template',
45                 'The templated URL where identities are exposed.',
46                 'http://localhost:8080/idp/openid/id/%(username)s'),
47             pconfig.List(
48                 'trusted roots',
49                 'List of trusted relying parties.'),
50             pconfig.List(
51                 'untrusted roots',
52                 'List of untrusted relying parties.'),
53             pconfig.Choice(
54                 'enabled extensions',
55                 'Choose the extensions to enable',
56                 self.extensions.available().keys()),
57             pconfig.MappingList(
58                 'default attribute mapping',
59                 'Defines how to map attributes before calling extensions',
60                 [['*', '*']]),
61             pconfig.ComplexList(
62                 'default allowed attributes',
63                 'Defines a list of allowed attributes, applied after mapping',
64                 ['*']),
65         )
66
67     @property
68     def endpoint_url(self):
69         url = self.get_config_value('endpoint url')
70         if url.endswith('/'):
71             return url
72         else:
73             return url+'/'
74
75     @property
76     def default_email_domain(self):
77         return self.get_config_value('default email domain')
78
79     @property
80     def identity_url_template(self):
81         url = self.get_config_value('identity url template')
82         if url.endswith('/'):
83             return url
84         else:
85             return url+'/'
86
87     @property
88     def trusted_roots(self):
89         return self.get_config_value('trusted roots')
90
91     @property
92     def untrusted_roots(self):
93         return self.get_config_value('untrusted roots')
94
95     @property
96     def enabled_extensions(self):
97         return self.get_config_value('enabled extensions')
98
99     @property
100     def default_attribute_mapping(self):
101         return self.get_config_value('default attribute mapping')
102
103     @property
104     def default_allowed_attributes(self):
105         return self.get_config_value('default allowed attributes')
106
107     def get_tree(self, site):
108         self.page = OpenID(site, self)
109         # self.admin = AdminPage(site, self)
110
111         return self.page
112
113     def used_datastores(self):
114         return [self.datastore]
115
116     def init_idp(self):
117         self.datastore = OpenIDStore(self.get_config_value('database url'))
118         self.server = Server(
119             self.datastore,
120             op_endpoint=self.endpoint_url)
121
122         # Expose OpenID presence in the root
123         headers = self._root.default_headers
124         headers['X-XRDS-Location'] = self.endpoint_url+'XRDS'
125
126         html_heads = self._root.html_heads
127         HEAD_LINK = '<link rel="%s" href="%s">'
128         openid_heads = [HEAD_LINK % ('openid2.provider', self.endpoint_url),
129                         HEAD_LINK % ('openid.server', self.endpoint_url)]
130         html_heads['openid'] = openid_heads
131
132     def on_enable(self):
133         super(IdpProvider, self).on_enable()
134         self.init_idp()
135         self.extensions.enable(self._config['enabled extensions'].get_value())
136
137
138 class Installer(ProviderInstaller):
139
140     def __init__(self, *pargs):
141         super(Installer, self).__init__()
142         self.name = 'openid'
143         self.pargs = pargs
144
145     def install_args(self, group):
146         group.add_argument('--openid', choices=['yes', 'no'], default='yes',
147                            help='Configure OpenID Provider')
148         group.add_argument('--openid-dburi',
149                            help='OpenID database URI')
150         group.add_argument('--openid-extensions', default='',
151                            help='List of OpenID Extensions to enable')
152
153     def configure(self, opts, changes):
154         if opts['openid'] != 'yes':
155             return
156
157         proto = 'https'
158         if opts['secure'].lower() == 'no':
159             proto = 'http'
160         url = '%s://%s/%s/openid/' % (
161             proto, opts['hostname'], opts['instance'])
162
163         # Add configuration data to database
164         po = PluginObject(*self.pargs)
165         po.name = 'openid'
166         po.wipe_data()
167         po.wipe_config_values()
168         config = {'endpoint url': url,
169                   'identity url template': '%sid/%%(username)s' % url,
170                   'database url': opts['openid_dburi'] or
171                   opts['database_url'] % {
172                       'datadir': opts['data_dir'], 'dbname': 'openid'},
173                   'enabled extensions': opts['openid_extensions']}
174         po.save_plugin_config(config)
175
176         # Update global config to add login plugin
177         po.is_enabled = True
178         po.save_enabled_state()