Projet

Général

Profil

« Précédent | Suivant » 

Révision 5af7a362

Ajouté par Thomas Noël il y a plus de 9 ans

add update-metadatas command and script

Voir les différences:

usr/local/univnautes/sp/sp/management/commands/update-metadatas.py
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

  
usr/local/univnautes/sp/update-metadatas.sh
1
#!/bin/sh
2

  
3
COMMAND=$(basename $0 .sh)
4

  
5
# lock to avoid concurrent updates
6
LOCK=/var/run/univnautes-sp-$COMMAND.lock
7
if [ -r $LOCK ]
8
then
9
	PID=`cat $LOCK`
10
	echo "$COMMAND locked by $LOCK"
11
	ps waux | grep "$PID" | grep $COMMAND | grep -vq grep && exit
12
	echo "... but PID $PID is not a $COMMAND, continue"
13
fi
14
unlock() {
15
	rm -f $LOCK
16
	exit
17
}
18
trap unlock INT TERM EXIT
19
echo $$ > $LOCK
20

  
21
cd /usr/local/univnautes/sp
22
./manage.py $COMMAND
23

  

Formats disponibles : Unified diff