sso.py 5.6 KB
Newer Older
marcus-tun's avatar
marcus-tun committed
1
2
3
4
5
6
7
8
#!/usr/bin/env python 

from mod_python import apache
from mod_python import util
import httplib2
import hashlib
from base64 import b64encode, b64decode

9
10
11
from Crypto.Cipher import Blowfish
from Crypto import Random
from struct import pack
marcus-tun's avatar
marcus-tun committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51


def handler(req):
    assertionLocation = str(req.subprocess_env['Shib-Assertion-01'])
    h1 = httplib2.HTTPSConnectionWithTimeout('saml-delegation.data.kit.edu')

    # get the path portion of the assertion link
    (i, assertionPath) = assertionLocation.split('https://saml-delegation.data.kit.edu')

    # get the assertion
    h1.request('GET', assertionPath)
    response = h1.getresponse()
    assertion = response.read()

    # remove newlines
    assertion = assertion.replace("\n", "")

    # find out at which url we were called
    (none, none, location) = req.uri.split('/')

    # sso
    if location == 'sso.py':
        req.content_type = 'text/html'
        req.write('''<!DOCTYPE html>
            <html>
            <head>
            <meta http-equiv="refresh" content="1
                  URL=https://saml-delegation.data.kit.edu/sd/ecp.py">

                  <!--   URI:     %s -->

            </head>
            <body>
            <br/>
            Save your assertion as "/tmp/samlup_uXXXX.tmp" where you replace
                  "XXXX" with your user id.<br>
            </body>
            </html>'''% req.uri)
        return apache.OK

52
    # js: sso via javascript
marcus-tun's avatar
marcus-tun committed
53
54
55
    if location == 'js.py':
        req.content_type = 'text/html'
        req.write('''<!DOCTYPE html>
56
              <meta charset="ASCII" />
marcus-tun's avatar
marcus-tun committed
57
58
            <html>
            <head>
59
60
            <script src="js/twofish/2-fish.js"> </script>
            <script src="js/seedrandom/seedrandom.min.js"> </script>
marcus-tun's avatar
marcus-tun committed
61
62
63
64
65
66
67
68
69
            </head>
            <body>
                <script type="text/javascript">''')
        req.sendfile(req.document_root() + "/sd/js.js")
        req.write(''' </script> </body> </html> ''')
        return apache.OK

    # ecp
    if location == 'ecp.py':
70
71
72
73
        # octet stream will force saving to disk, while
        # text will allow to open with a text editor
        #req.content_type='application/octet-stream'\
        req.content_type='application/text'\
marcus-tun's avatar
marcus-tun committed
74
75
76
77
                '\nContent-Disposition: attachment; filename=samlup_uXXXX.tmp'
        req.write(assertion)
        return apache.OK

78
79
80
    ############
    #  upload  #
    ############
81
    if location in ( 'upload.py', 'jsupload.py'):
marcus-tun's avatar
marcus-tun committed
82
83
84
85
        req.content_type = 'text/plain'
        # we expect the data via post in encrypted assertion.
        # we will return the url of where to collect the assertion
        # request.
marcus-tun's avatar
marcus-tun committed
86

marcus-tun's avatar
marcus-tun committed
87
88
89
90
        if req.method != 'POST':
            req.write("Error, i was expecting a post request")
            return apache.OK

marcus-tun's avatar
marcus-tun committed
91
92
93
94
95
        # This debug statement will destroy the whole processing
        #log_path=req.document_root() + '/assertions/' + 'js-log'
        #logfile=open(log_path, 'w')
        #logfile.write(req.read())
        #logfile.close()
96

marcus-tun's avatar
marcus-tun committed
97
        form = util.FieldStorage(req)
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
        if not form.has_key("encrypted_assertion"):
            req.write ("Error: did not obtain the encrypted_assertion")
            return apache.OK
        buf = form.get("encrypted_assertion", "ooops")
        client = form.get ("client", "oops")
        client_version = form.get ("client_verions", "oops")

        # decode assertion
        encrypted_assertion = b64decode(buf)

        # create hash
        assertion_hash = str(hashlib.md5(encrypted_assertion).hexdigest())
        assertion_path=req.document_root() + '/assertions/' + assertion_hash
        assertion_url ='https://' + req.hostname + '/assertions/' + assertion_hash

        # write to file
        try:
            file=open(assertion_path, 'w')
            if client == "perl":
                file.write(encrypted_assertion[16:]) # skip the 16 byte perl header
            else:
119
                file.write(encrypted_assertion)
120
121
122
            file.close()
        except:
            req.write("could not save assertion")
marcus-tun's avatar
marcus-tun committed
123

124
125
        if location == 'jsupload.py':
            req.write('You can use this url as a temporary password in all federation-enabled services:\n\n%s' % assertion_url);
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
        else:
            req.write("url=%s" % assertion_url)

        #########
        # debug #
        #########
        # decrypt assertion in case password is provided
        if form.has_key("key"):
            from binascii import hexlify, unhexlify

            key = unhexlify(form.get("key", "ooops"))
            perl_iv = form.get("perl_iv",   "ooops")
            iv =      form.get("iv",        "ooops")
            encryption_algorithm = form.get("encryption_algorithm", "ooops")

            log_path=req.document_root() + '/assertions/' + 'log'
            logfile=open(log_path, 'w')

            cipher = Blowfish.new(key, Blowfish.MODE_CBC, perl_iv)
            num_padding = ord(cipher.decrypt(encrypted_assertion[16:])[-1])

            cipher = Blowfish.new(key, Blowfish.MODE_CBC, perl_iv)
            plaintext = cipher.decrypt(encrypted_assertion[16:])[:(-1*num_padding)]

            logfile.write(plaintext)
            logfile.close()
marcus-tun's avatar
marcus-tun committed
153
154
155
156
157
158
159

        return apache.OK

    req.content_type = 'text/plain'
    req.write("Error: Your request was not understood")
    return apache.OK
    #return apache.HTTP_BAD_REQUEST
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174


# Some leftovers:

#bs = Blowfish.block_size
#iv = '12333123'
#cipher = Blowfish.new(key, Blowfish.MODE_ECB, iv)
#cipher = new Crypt::CBC (symmetric_key, 'Twofish');
#my plaintext = cipher->decrypt(encrypted_assertion);
#print ("\n".plaintext."\n");

##plaintext = b'docendo discimus '
##plen = bs - divmod(len(plaintext),bs)[1]
##padding = [plen]*plen
##padding = pack('b'*plen, *padding)