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