Projet

Général

Profil

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

organization_api / ckanext / ozwillo_organization_api / plugin.py @ cd3002be

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