1
|
# -*- coding: utf-8 -*-
|
2
|
#
|
3
|
# UnivNautes
|
4
|
# Copyright (C) 2014 Entr'ouvert
|
5
|
#
|
6
|
# This program is free software: you can redistribute it and/or modify it under
|
7
|
# the terms of the GNU Affero General Public License as published by the Free
|
8
|
# Software Foundation, either version 3 of the License, or (at your option) any
|
9
|
# later version.
|
10
|
#
|
11
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
12
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
13
|
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
14
|
# details.
|
15
|
#
|
16
|
# You should have received a copy of the GNU Affero General Public License
|
17
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
|
19
|
from django.core.management.base import BaseCommand, CommandError
|
20
|
from django.core.management import call_command
|
21
|
|
22
|
import os
|
23
|
import sys
|
24
|
import subprocess
|
25
|
from sp import pfconfigxml
|
26
|
import urllib2
|
27
|
|
28
|
from authentic2.saml.models import LibertyProvider
|
29
|
from django.conf import settings
|
30
|
from sp import pfconfigxml
|
31
|
|
32
|
METADATAS_DIR = os.path.join('/', 'var', 'db', 'univnautes-sp-federations')
|
33
|
|
34
|
def metadata_filename(codename, suffix=None):
|
35
|
if not suffix:
|
36
|
return os.path.join(METADATAS_DIR, codename, 'metadata.xml')
|
37
|
else:
|
38
|
return os.path.join(METADATAS_DIR, codename, 'metadata.xml.%s' % suffix)
|
39
|
|
40
|
def store_metadata(codename, fp):
|
41
|
tempfilename = '/var/tmp/%s-metadata.xml-%s' % (codename, os.getpid())
|
42
|
f = open(tempfilename, 'wb')
|
43
|
f.write(fp.read())
|
44
|
f.close()
|
45
|
if not os.path.exists(METADATAS_DIR):
|
46
|
os.mkdir(METADATAS_DIR, 0770)
|
47
|
dir = os.path.join(METADATAS_DIR, codename)
|
48
|
if not os.path.exists(dir):
|
49
|
os.mkdir(dir, 0770)
|
50
|
os.rename(tempfilename, metadata_filename(codename, 'downloaded'))
|
51
|
|
52
|
# remove obsoletes files if they exist (just to be clean...)
|
53
|
for suffix in ('bad_signature', 'disabled'):
|
54
|
try:
|
55
|
os.remove(metadata_filename(codename, suffix))
|
56
|
except OSError:
|
57
|
pass
|
58
|
|
59
|
def verify_metadata(codename, signcert):
|
60
|
if not signcert:
|
61
|
print 'warn: do not verify %s metadata (no certificate provided)' % codename
|
62
|
ret = True
|
63
|
else:
|
64
|
metadata = metadata_filename(codename, 'downloaded')
|
65
|
signcert_pem = metadata_filename(codename, 'signcert.pem')
|
66
|
dir = os.path.join(METADATAS_DIR, codename)
|
67
|
f = open(signcert_pem, 'wb')
|
68
|
f.write(signcert)
|
69
|
f.close()
|
70
|
ret = 0 == subprocess.call(['xmlsec1', '--verify',
|
71
|
'--pubkey-cert-pem', signcert_pem,
|
72
|
'--id-attr:id', 'EntitiesDescriptor',
|
73
|
metadata])
|
74
|
if ret:
|
75
|
os.rename(metadata, metadata_filename(codename))
|
76
|
else:
|
77
|
print 'warn: bad signature for %s metadata' % codename
|
78
|
os.rename(metadata, metadata_filename(codename, 'bad_signature'))
|
79
|
return ret
|
80
|
|
81
|
def disable(codename):
|
82
|
print 'disable %s metadata' % str(codename)
|
83
|
LibertyProvider.objects.filter(federation_source=codename).delete()
|
84
|
dir = os.path.join(METADATAS_DIR, codename)
|
85
|
try:
|
86
|
os.rename(metadata_filename(codename), metadata_filename(codename, 'disabled'))
|
87
|
except OSError:
|
88
|
pass
|
89
|
|
90
|
|
91
|
class Command(BaseCommand):
|
92
|
help = 'update all metadatas in %s' % METADATAS_DIR
|
93
|
|
94
|
def handle(self, *args, **options):
|
95
|
actives = set()
|
96
|
|
97
|
federations = pfconfigxml.get_federations()
|
98
|
for federation in federations:
|
99
|
url = federation.get('url')
|
100
|
codename = federation.get('codename')
|
101
|
descr = federation.get('descr')
|
102
|
signcert = federation.get('signcert')
|
103
|
try:
|
104
|
print 'download federation %s metadata from %s' % (str(codename), str(url))
|
105
|
store_metadata(codename, urllib2.urlopen(url))
|
106
|
except urllib2.HTTPError as e:
|
107
|
print 'Error loading metadata (%s)' % str(e)
|
108
|
except urllib2.URLError as e:
|
109
|
print 'Error loading metadata (%s)' % str(e)
|
110
|
else:
|
111
|
if verify_metadata(codename, signcert):
|
112
|
actives.add(codename)
|
113
|
call_command('sync-metadata', metadata_filename(codename), source=codename, idp=True)
|
114
|
|
115
|
present_in_filesystem = set(os.listdir(METADATAS_DIR))
|
116
|
for codename in present_in_filesystem - actives:
|
117
|
disable(codename)
|
118
|
|
119
|
present_in_database = set([str(i['federation_source']) \
|
120
|
for i in LibertyProvider.objects.distinct().values('federation_source').order_by('federation_source')])
|
121
|
for codename in present_in_database - actives:
|
122
|
disable(codename)
|
123
|
|
124
|
|