om@3
|
1 |
"""openid.py: an openid library for web.py
|
om@3
|
2 |
|
om@3
|
3 |
Notes:
|
om@3
|
4 |
|
om@3
|
5 |
- This will create a file called .openid_secret_key in the
|
om@3
|
6 |
current directory with your secret key in it. If someone
|
om@3
|
7 |
has access to this file they can log in as any user. And
|
om@3
|
8 |
if the app can't find this file for any reason (e.g. you
|
om@3
|
9 |
moved the app somewhere else) then each currently logged
|
om@3
|
10 |
in user will get logged out.
|
om@3
|
11 |
|
om@3
|
12 |
- State must be maintained through the entire auth process
|
om@3
|
13 |
-- this means that if you have multiple web.py processes
|
om@3
|
14 |
serving one set of URLs or if you restart your app often
|
om@3
|
15 |
then log ins will fail. You have to replace sessions and
|
om@3
|
16 |
store for things to work.
|
om@3
|
17 |
|
om@3
|
18 |
- We set cookies starting with "openid_".
|
om@3
|
19 |
|
om@3
|
20 |
"""
|
om@3
|
21 |
|
om@3
|
22 |
import os
|
om@3
|
23 |
import random
|
om@3
|
24 |
import hmac
|
om@3
|
25 |
import __init__ as web
|
om@3
|
26 |
import openid.consumer.consumer
|
om@3
|
27 |
import openid.store.memstore
|
om@3
|
28 |
|
om@3
|
29 |
sessions = {}
|
om@3
|
30 |
store = openid.store.memstore.MemoryStore()
|
om@3
|
31 |
|
om@3
|
32 |
def _secret():
|
om@3
|
33 |
try:
|
om@3
|
34 |
secret = file('.openid_secret_key').read()
|
om@3
|
35 |
except IOError:
|
om@3
|
36 |
# file doesn't exist
|
om@3
|
37 |
secret = os.urandom(20)
|
om@3
|
38 |
file('.openid_secret_key', 'w').write(secret)
|
om@3
|
39 |
return secret
|
om@3
|
40 |
|
om@3
|
41 |
def _hmac(identity_url):
|
om@3
|
42 |
return hmac.new(_secret(), identity_url).hexdigest()
|
om@3
|
43 |
|
om@3
|
44 |
def _random_session():
|
om@3
|
45 |
n = random.random()
|
om@3
|
46 |
while n in sessions:
|
om@3
|
47 |
n = random.random()
|
om@3
|
48 |
n = str(n)
|
om@3
|
49 |
return n
|
om@3
|
50 |
|
om@3
|
51 |
def status():
|
om@3
|
52 |
oid_hash = web.cookies().get('openid_identity_hash', '').split(',', 1)
|
om@3
|
53 |
if len(oid_hash) > 1:
|
om@3
|
54 |
oid_hash, identity_url = oid_hash
|
om@3
|
55 |
if oid_hash == _hmac(identity_url):
|
om@3
|
56 |
return identity_url
|
om@3
|
57 |
return None
|
om@3
|
58 |
|
om@3
|
59 |
def form(openid_loc):
|
om@3
|
60 |
oid = status()
|
om@3
|
61 |
if oid:
|
om@3
|
62 |
return '''
|
om@3
|
63 |
<form method="post" action="%s">
|
om@3
|
64 |
<img src="http://openid.net/login-bg.gif" alt="OpenID" />
|
om@3
|
65 |
<strong>%s</strong>
|
om@3
|
66 |
<input type="hidden" name="action" value="logout" />
|
om@3
|
67 |
<input type="hidden" name="return_to" value="%s" />
|
om@3
|
68 |
<button type="submit">log out</button>
|
om@3
|
69 |
</form>''' % (openid_loc, oid, web.ctx.fullpath)
|
om@3
|
70 |
else:
|
om@3
|
71 |
return '''
|
om@3
|
72 |
<form method="post" action="%s">
|
om@3
|
73 |
<input type="text" name="openid" value=""
|
om@3
|
74 |
style="background: url(http://openid.net/login-bg.gif) no-repeat; padding-left: 18px; background-position: 0 50%%;" />
|
om@3
|
75 |
<input type="hidden" name="return_to" value="%s" />
|
om@3
|
76 |
<button type="submit">log in</button>
|
om@3
|
77 |
</form>''' % (openid_loc, web.ctx.fullpath)
|
om@3
|
78 |
|
om@3
|
79 |
def logout():
|
om@3
|
80 |
web.setcookie('openid_identity_hash', '', expires=-1)
|
om@3
|
81 |
|
om@3
|
82 |
class host:
|
om@3
|
83 |
def POST(self):
|
om@3
|
84 |
# unlike the usual scheme of things, the POST is actually called
|
om@3
|
85 |
# first here
|
om@3
|
86 |
i = web.input(return_to='/')
|
om@3
|
87 |
if i.get('action') == 'logout':
|
om@3
|
88 |
logout()
|
om@3
|
89 |
return web.redirect(i.return_to)
|
om@3
|
90 |
|
om@3
|
91 |
i = web.input('openid', return_to='/')
|
om@3
|
92 |
|
om@3
|
93 |
n = _random_session()
|
om@3
|
94 |
sessions[n] = {'webpy_return_to': i.return_to}
|
om@3
|
95 |
|
om@3
|
96 |
c = openid.consumer.consumer.Consumer(sessions[n], store)
|
om@3
|
97 |
a = c.begin(i.openid)
|
om@3
|
98 |
f = a.redirectURL(web.ctx.home, web.ctx.home + web.ctx.fullpath)
|
om@3
|
99 |
|
om@3
|
100 |
web.setcookie('openid_session_id', n)
|
om@3
|
101 |
return web.redirect(f)
|
om@3
|
102 |
|
om@3
|
103 |
def GET(self):
|
om@3
|
104 |
n = web.cookies('openid_session_id').openid_session_id
|
om@3
|
105 |
web.setcookie('openid_session_id', '', expires=-1)
|
om@3
|
106 |
return_to = sessions[n]['webpy_return_to']
|
om@3
|
107 |
|
om@3
|
108 |
c = openid.consumer.consumer.Consumer(sessions[n], store)
|
om@3
|
109 |
a = c.complete(web.input(), web.ctx.home + web.ctx.fullpath)
|
om@3
|
110 |
|
om@3
|
111 |
if a.status.lower() == 'success':
|
om@3
|
112 |
web.setcookie('openid_identity_hash', _hmac(a.identity_url) + ',' + a.identity_url)
|
om@3
|
113 |
|
om@3
|
114 |
del sessions[n]
|
om@3
|
115 |
return web.redirect(return_to)
|