Projet

Général

Profil

Télécharger (7,65 ko) Statistiques
| Branche: | Tag: | Révision:

organization_api / ckanext / ozwillo_organization_api / plugin.py @ 5c4e0677

1 5c8cfd17 Serghei MIHAI
from hashlib import sha1
2
import hmac
3 74d08116 Serghei MIHAI
import requests
4
import logging
5 d443ceb7 Serghei MIHAI
import json
6 5c8cfd17 Serghei MIHAI
7
import ckan.plugins as plugins
8 cb821f25 Serghei MIHAI
import ckan.plugins.toolkit as toolkit
9
10 5c8cfd17 Serghei MIHAI
import ckan.logic as logic
11 5c4e0677 Serghei MIHAI
import ckan.lib.base as base
12 5c8cfd17 Serghei MIHAI
13
from pylons import config
14
from ckan.common import request, _
15
from ckan.logic.action.create import _group_or_org_create as group_or_org_create
16 74d08116 Serghei MIHAI
from ckan.logic.action.create import user_create
17 7d5492a9 Serghei MIHAI
from ckan.logic.action.delete import _group_or_org_purge
18 3c33f2ff Serghei MIHAI
from ckan.lib.plugins import DefaultOrganizationForm
19 5c8cfd17 Serghei MIHAI
20 cb821f25 Serghei MIHAI
plugin_config_prefix = 'ckanext.ozwillo_organization_api.'
21
22 74d08116 Serghei MIHAI
log = logging.getLogger(__name__)
23
24 5c8cfd17 Serghei MIHAI
def valid_signature_required(func):
25 cb821f25 Serghei MIHAI
26 5c8cfd17 Serghei MIHAI
    signature_header_name = config.get(plugin_config_prefix + 'signature_header_name',
27
                                       'X-Hub-Signature')
28 458a2c0b Serghei MIHAI
    instantiated_secret = config.get(plugin_config_prefix + 'instantiation_secret',
29 5c8cfd17 Serghei MIHAI
                                     'secret')
30
31
    def wrapper(context, data):
32
        if signature_header_name in request.headers:
33
            if request.headers[signature_header_name].startswith('sha1='):
34 cb821f25 Serghei MIHAI
                algo, received_hmac = request.headers[signature_header_name].rsplit('=')
35 74d08116 Serghei MIHAI
                computed_hmac = hmac.new(instantiated_secret, request.body, sha1).hexdigest()
36 cb821f25 Serghei MIHAI
                # the received hmac is uppercase according to
37
                # http://doc.ozwillo.com/#ref-3-2-1
38
                if received_hmac != computed_hmac.upper():
39 5c8cfd17 Serghei MIHAI
                    raise logic.NotAuthorized(_('Invalid HMAC'))
40
            else:
41
                raise logic.ValidationError(_('Invalid HMAC algo'))
42
        else:
43
            raise logic.NotAuthorized(_("No HMAC in the header"))
44
        return func(context, data)
45
    return wrapper
46
47
@valid_signature_required
48
def create_organization(context, data_dict):
49 74d08116 Serghei MIHAI
    context['ignore_auth'] = True
50
    model = context['model']
51 55fa9cda Serghei MIHAI
    session = context['session']
52 cb821f25 Serghei MIHAI
53
    destruction_secret = config.get(plugin_config_prefix + 'destruction_secret',
54
                                       'changeme')
55
56
    client_id = data_dict.pop('client_id')
57
    client_secret = data_dict.pop('client_secret')
58
    instance_id = data_dict.pop('instance_id')
59
60
    # re-mapping received dict
61
    registration_uri = data_dict.pop('instance_registration_uri')
62
    organization = data_dict['organization']
63 74d08116 Serghei MIHAI
    user = data_dict['user']
64 270f763c Serghei MIHAI
    user_dict = {
65 19d8afdf Serghei MIHAI
        'id': user['id'],
66 b08bb39f Serghei MIHAI
        'name': user['name'].lower().replace(' ', '').replace('.', ''),
67 270f763c Serghei MIHAI
        'email': user['email_address'],
68
        'password': user['id']
69
    }
70
    user_obj = model.User.get(user_dict['name'])
71
72 cb821f25 Serghei MIHAI
    org_dict = {
73
        'type': 'organization',
74 270f763c Serghei MIHAI
        'name': organization['name'].lower().replace(' ', '-'),
75 0225110e Serghei MIHAI
        'id': instance_id,
76 74d08116 Serghei MIHAI
        'title': organization['name'],
77 270f763c Serghei MIHAI
        'user': user_dict['name']
78 74d08116 Serghei MIHAI
    }
79
80
    if not user_obj:
81
        user_create(context, user_dict)
82
    context['user'] = user_dict['name']
83
84 cb821f25 Serghei MIHAI
    try:
85 c314bc51 Serghei MIHAI
        delete_uri = toolkit.url_for(host=request.host,
86
                                     controller='api', action='action',
87 55388392 Serghei MIHAI
                                     logic_function="delete-ozwillo-organization",
88 cb821f25 Serghei MIHAI
                                     ver=context['api_version'],
89
                                     qualified=True)
90 74d08116 Serghei MIHAI
        organization_uri = toolkit.url_for(host=request.host,
91
                                           controller='organization',
92
                                           action='read',
93
                                           id=org_dict['name'],
94
                                           qualified=True)
95 d443ceb7 Serghei MIHAI
        default_icon_url = toolkit.url_for(host=request.host,
96
                                           qualified=True,
97
                                           controller='home',
98
                                           action='index') + 'organization_icon.png'
99 74d08116 Serghei MIHAI
100 cb821f25 Serghei MIHAI
        group_or_org_create(context, org_dict, is_org=True)
101
102 74d08116 Serghei MIHAI
        # setting organization as active explicitely
103
        group = model.Group.get(org_dict['name'])
104
        group.state = 'active'
105 d443ceb7 Serghei MIHAI
        group.image_url = default_icon_url
106 74d08116 Serghei MIHAI
        group.save()
107 55fa9cda Serghei MIHAI
        model.repo.new_revision()
108
        model.GroupExtra(group_id=group.id, key='client_id',
109
                         value=client_id).save()
110
        model.GroupExtra(group_id=group.id, key='client_secret',
111
                         value=client_secret).save()
112
        session.flush()
113 74d08116 Serghei MIHAI
114 cb821f25 Serghei MIHAI
        # notify about organization creation
115
        services = {'services': [{
116
            'local_id': 'organization',
117 dca00d04 Serghei MIHAI
            'name': 'Open Data',
118 472417ae Serghei MIHAI
            'service_uri': organization_uri + '/sso',
119 d443ceb7 Serghei MIHAI
            'description': 'Organization ' + org_dict['name'] + ' on CKAN',
120
            'tos_uri': organization_uri,
121
            'policy_uri': organization_uri,
122
            'icon': group.image_url,
123
            'payment_option': 'FREE',
124
            'target_audience': ['PUBLIC_BODIES'],
125
            'contacts': [organization_uri],
126 a5322fb2 Serghei MIHAI
            'redirect_uris': [organization_uri + '/callback'],
127 eecd60db Serghei MIHAI
            'post_logout_redirect_uris': [organization_uri + '/logout'],
128 00985cc5 Serghei MIHAI
            'visible': False}],
129 cb821f25 Serghei MIHAI
            'instance_id': instance_id,
130
            'destruction_uri': delete_uri,
131
            'destruction_secret': destruction_secret,
132
            'needed_scopes': [{
133
                'scope_id': 'profile',
134
                'motivation': 'Used to link user to the organization'
135
            }]
136
        }
137 606ae999 Serghei MIHAI
        headers = {'Content-type': 'application/json',
138
                   'Accept': 'application/json'}
139 cb821f25 Serghei MIHAI
        requests.post(registration_uri,
140 d443ceb7 Serghei MIHAI
                      data=json.dumps(services),
141 606ae999 Serghei MIHAI
                      auth=(client_id, client_secret),
142
                      headers=headers
143 cb821f25 Serghei MIHAI
                  )
144 d2732e9e Serghei MIHAI
    except logic.ValidationError, e:
145
        log.debug('Validation error "%s" occured while creating organization' % e)
146
        raise
147 5c8cfd17 Serghei MIHAI
148
@valid_signature_required
149
def delete_organization(context, data_dict):
150 7d5492a9 Serghei MIHAI
    data_dict['id'] = data_dict.pop('instance_id')
151
    context['ignore_auth'] = True
152
    _group_or_org_purge(context, data_dict, is_org=True)
153 5c8cfd17 Serghei MIHAI
154
155 3c33f2ff Serghei MIHAI
class OrganizationForm(plugins.SingletonPlugin, DefaultOrganizationForm):
156
    """
157
    Custom form ignoring 'title' and 'name' organization fields
158
    """
159
    plugins.implements(plugins.IGroupForm)
160
161
    def is_fallback(self):
162
        return True
163
164
    def group_types(self):
165
        return ('organization',)
166
167
    def form_to_db_schema(self):
168
        schema = super(OrganizationForm, self).form_to_db_schema()
169
        del schema['name']
170
        del schema['title']
171
        return schema
172
173
174 5c4e0677 Serghei MIHAI
class ErrorController(base.BaseController):
175
    def error403(self):
176
        return base.abort(403, '')
177
178
179 5c8cfd17 Serghei MIHAI
class OzwilloOrganizationApiPlugin(plugins.SingletonPlugin):
180
    """
181
    API for OASIS to create and delete an organization
182
    """
183
    plugins.implements(plugins.IActions)
184 d443ceb7 Serghei MIHAI
    plugins.implements(plugins.IConfigurer)
185 5c4e0677 Serghei MIHAI
    plugins.implements(plugins.IRoutes)
186
187
    def before_map(self, map):
188
        # disable organization and members api
189
        for action in ('member_create', 'member_delete',
190
                       'organization_member_delete',
191
                       'organization_member_create',
192
                       'organization_create',
193
                       'organization_update',
194
                       'organization_delete'):
195
            map.connect('/api/{ver:.*}/action/%s' % action,
196
                        controller=__name__ + ':ErrorController',
197
                        action='error403')
198
        return map
199
200
    def after_map(self, map):
201
        return map
202 d443ceb7 Serghei MIHAI
203
    def update_config(self, config):
204 9afd103f Serghei MIHAI
        toolkit.add_template_directory(config, 'templates')
205 d443ceb7 Serghei MIHAI
        toolkit.add_public_directory(config, 'public')
206 5c8cfd17 Serghei MIHAI
207
    def get_actions(self):
208
        return {
209 f81cd06f Serghei MIHAI
            'create-ozwillo-organization': create_organization,
210
            'delete-ozwillo-organization': delete_organization
211 5c8cfd17 Serghei MIHAI
        }