0001-agent-authentic2-add-new-command-import-wcs-roles.patch
hobo/agent/authentic2/management/commands/import-wcs-roles.py | ||
---|---|---|
1 |
from optparse import make_option |
|
2 |
from django.core.management.base import BaseCommand |
|
3 | ||
4 |
from .. import role_extractors |
|
5 | ||
6 |
class Command(BaseCommand): |
|
7 |
option_list = BaseCommand.option_list + ( |
|
8 |
make_option('--slug', action='store', dest='slug'), |
|
9 |
make_option('--key', action='store', dest='key'), |
|
10 |
make_option('--orig', action='store', dest='orig'), |
|
11 |
make_option('--delete', action='store_true', dest='delete'), |
|
12 |
) |
|
13 |
help = "Import W.C.S. roles" |
|
14 | ||
15 |
requires_system_checks = False |
|
16 | ||
17 |
def handle(self, *args, **options): |
|
18 |
role_extractor = role_extractors.WcsRoleExtractor( |
|
19 |
slug=options['slug'], |
|
20 |
key=options['key'], |
|
21 |
orig=options['orig'], |
|
22 |
delete=options.get('delete', False), |
|
23 |
) |
|
24 |
role_extractor.extract() |
hobo/agent/authentic2/management/role_extractors.py | ||
---|---|---|
1 |
import logging |
|
2 |
import requests |
|
3 |
import urllib |
|
4 | ||
5 |
from django.utils.text import slugify |
|
6 | ||
7 |
from authentic2.saml.models import LibertyProvider |
|
8 |
from authentic2.model import ServiceRole, ServiceRoleAttribute |
|
9 | ||
10 |
from . import signature |
|
11 | ||
12 |
class RoleExtractor(object): |
|
13 |
def __init__(self, slug, delete=False): |
|
14 |
self.slug = slug |
|
15 |
self.logger = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__)) |
|
16 |
self.delete = delete |
|
17 | ||
18 |
def extract_impl(self): |
|
19 |
pass |
|
20 | ||
21 |
def extract(self): |
|
22 |
seen_ids = set() |
|
23 |
for role_tpl in self.extract_impl(): |
|
24 |
defaults = { |
|
25 |
'name': role_tpl['name'], |
|
26 |
'slug': role_tpl.get('slug', slugify(role_tpl['name'])), |
|
27 |
} |
|
28 |
seen_ids.add(role_tpl['seen_ids']) |
|
29 |
role, created = ServiceRole.objects.get_or_create( |
|
30 |
service=self.service, |
|
31 |
external_id=role_tpl['external_id'], |
|
32 |
defaults=defaults) |
|
33 |
ServiceRoleAttribute.objects.get_or_create( |
|
34 |
service_role=role, |
|
35 |
name=role_tpl['attribute_name'], |
|
36 |
kind='string', |
|
37 |
value=role_tpl['external_id']) |
|
38 |
if created: |
|
39 |
self.logger.info('imported new role %r(%r) from service ' |
|
40 |
'%s', role_tpl['external_id'], role_tpl['name'], |
|
41 |
self.slug) |
|
42 |
self.logger |
|
43 |
if not created: |
|
44 |
# Update name if it has changed |
|
45 |
if role.name != role_tpl['name']: |
|
46 |
role.name = role_tpl['name'] |
|
47 |
role.save() |
|
48 |
if self.delete: |
|
49 |
qs = ServiceRole.objects.filter(service=self.service) \ |
|
50 |
.exclude(external_id__in=list(seen_ids)) |
|
51 |
for role in qs: |
|
52 |
self.logger.info('deleted dead role %r(%r) from service ' |
|
53 |
'%s', role.external_id, role.slug, self.slug) |
|
54 |
qs.delete() |
|
55 | ||
56 |
class WcsRoleExtractor(RoleExtractor): |
|
57 |
def __init__(self, *args, **kwargs): |
|
58 |
self.key = kwargs.pop('key') |
|
59 |
self.orig = kwargs.pop('orig') |
|
60 |
self.attribute_name = kwargs.pop('attribute_name', 'role_id') |
|
61 |
super(WcsRoleExtractor, self).__init__(*args, **kwargs) |
|
62 |
self.service = LibertyProvider.objects.get(slug=self.slug) |
|
63 |
assert 'saml/metadata' in self.liberty_provider.entity_id |
|
64 |
self.wcs_url = self.liberty_provider.entity_id.split('saml/metadata')[0] |
|
65 | ||
66 |
def extract_impl(self): |
|
67 |
url = self.wcs_url + 'roles?%s' % urllib.urlencode({'orig': self.orig}) |
|
68 |
signed_url = signature.sign_url(url, self.key) |
|
69 |
response = requests.get(signed_url) |
|
70 |
for role in response.json()['data']: |
|
71 |
yield { |
|
72 |
'attribute_name': self.attribute_name, |
|
73 |
'external_id': str(role['id']), |
|
74 |
'name': role['text'], |
|
75 |
} |
hobo/agent/authentic2/management/signature.py | ||
---|---|---|
1 |
import base64 |
|
2 |
import hmac |
|
3 |
import hashlib |
|
4 |
import datetime |
|
5 |
import urllib |
|
6 |
import urllib2 |
|
7 |
import urlparse |
|
8 |
import random |
|
9 | ||
10 |
def sign_url(url, key, algo='sha256', timestamp=None, nonce=None): |
|
11 |
parsed = urlparse.urlparse(url) |
|
12 |
new_query = sign_query(parsed.query, key, algo, timestamp, nonce) |
|
13 |
return urlparse.urlunparse(parsed[:4] + (new_query,) + parsed[5:]) |
|
14 | ||
15 |
def sign_query(query, key, algo='sha256', timestamp=None, nonce=None): |
|
16 |
if timestamp is None: |
|
17 |
timestamp = datetime.datetime.utcnow() |
|
18 |
timestamp = timestamp.strftime('%Y-%m-%dT%H:%M:%SZ') |
|
19 |
if nonce is None: |
|
20 |
nonce = hex(random.getrandbits(128))[2:-1] |
|
21 |
new_query = query |
|
22 |
if new_query: |
|
23 |
new_query += '&' |
|
24 |
new_query += urllib.urlencode(( |
|
25 |
('algo', algo), |
|
26 |
('timestamp', timestamp), |
|
27 |
('nonce', nonce))) |
|
28 |
signature = base64.b64encode(sign_string(new_query, key, algo=algo)) |
|
29 |
new_query += '&signature=' + urllib.quote(signature) |
|
30 |
return new_query |
|
31 | ||
32 |
def sign_string(s, key, algo='sha256', timedelta=30): |
|
33 |
digestmod = getattr(hashlib, algo) |
|
34 |
hash = hmac.HMAC(key, digestmod=digestmod, msg=s) |
|
35 |
return hash.digest() |
|
36 | ||
37 | ||
0 |
- |