-
Notifications
You must be signed in to change notification settings - Fork 10
/
app.py
186 lines (147 loc) · 5.05 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""
Created on 20 feb 2020
@author: Alessandro Ogier <alessandro.ogier@gmail.com>
A sample demo application you can invoke with:
JWT_ALG=RS256 uvicorn sample_app.app:app
default alg is HS256
You can then check it via curl using a cookie-jar
1. "check" endpoint returns a 401
oggei@cane ~ curl -Lv -c /tmp/cookiejar localhost:8000/
[...]
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.67.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< date: Fri, 21 Feb 2020 15:24:54 GMT
< server: uvicorn
< transfer-encoding: chunked
<
* Connection #0 to host localhost left intact
2. "login" endpoint correctly put you in session, and now / return http/200
oggei@cane ~ curl -Lv -c /tmp/cookiejar localhost:8000/login
[...]
> GET /login HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.67.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 307 Temporary Redirect
< date: Fri, 21 Feb 2020 15:25:44 GMT
< server: uvicorn
< location: http://localhost:8000/
* Added cookie session="eyJhb[...]xHtOQ" for domain localhost, path /, expire 1583508344
< set-cookie: session=eyJhb[...]xHtOQ; path=/; Max-Age=1209600; httponly; samesite=lax
[...]
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.67.0
> Accept: */*
> Cookie: session=eyJhb[...]xHtOQ
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Fri, 21 Feb 2020 15:25:44 GMT
< server: uvicorn
* Replaced cookie session="eyJhb[...]xHtOQ" for domain localhost, path /, expire 1583508344
< set-cookie: session=eyJhb[...]xHtOQ; path=/; Max-Age=1209600; httponly; samesite=lax
< transfer-encoding: chunked
<
* Connection #0 to host localhost left intact
"""
import os
from starlette.applications import Starlette
from starlette.config import Config
from starlette.datastructures import Secret
from starlette.responses import RedirectResponse, Response
from starlette.routing import Route
if os.environ.get("VANILLA"):
print("using vanilla")
from starlette.middleware.sessions import SessionMiddleware
else:
from starlette_authlib.middleware import (
AuthlibMiddleware as SessionMiddleware,
SecretKey,
)
config = Config(".env") # pylint: disable=invalid-name
KEYS_DIR = os.path.join(os.path.dirname(__file__), "keys")
# Override this via command line env vars eg.
# JWT_ALG=RS256 uvicorn sample_app.app:app
JWT_ALG = config("JWT_ALG", cast=str, default="HS256")
async def check(request):
"""
Check if we are in session.
"""
content = """
<html>
<title>starlette authlib demo</title>
<body>
your status is: %(status)s, click here to <a href="/%(action)s">%(action)s</a>
</body></html>
"""
if not request.session.get("user"):
return Response(
content % {"status": "logged out", "action": "login"},
headers={"content-type": "text/html"},
status_code=401,
)
return Response(content % {"status": "logged in", "action": "logout"})
async def login(request):
"""
A login endpoint that creates a session.
"""
request.session.update(
{
"iss": "myself",
"user": "username",
}
)
return RedirectResponse(url=request.url_for("check"))
async def logout(request):
"""
A login endpoint that creates a session.
"""
request.session.clear()
return RedirectResponse(url=request.url_for("check"))
routes = [ # pylint: disable=invalid-name
Route("/", endpoint=check, name="check"),
Route("/login", endpoint=login),
Route("/logout", endpoint=logout),
]
app = Starlette(debug=True, routes=routes) # pylint: disable=invalid-name
if JWT_ALG.startswith("HS"):
secret_key = config( # pylint: disable=invalid-name
"JWT_SECRET", cast=Secret, default="secret"
)
else:
if JWT_ALG.startswith("RS"):
private_key = open( # pylint: disable=invalid-name
os.path.join(KEYS_DIR, "rsa.key")
).read()
public_key = open( # pylint: disable=invalid-name
os.path.join(KEYS_DIR, "rsa.pub")
).read()
elif JWT_ALG.startswith("ES"):
private_key = open( # pylint: disable=invalid-name
os.path.join(KEYS_DIR, "ec.key")
).read()
public_key = open( # pylint: disable=invalid-name
os.path.join(KEYS_DIR, "ec.pub")
).read()
## WIP: can't find a proper way to generate them
# elif JWT_ALG.startswith("PS"):
#
# private_key = open( # pylint: disable=invalid-name
# os.path.join(KEYS_DIR, "ps.key")
# ).read()
#
# public_key = open( # pylint: disable=invalid-name
# os.path.join(KEYS_DIR, "ps.pub")
# ).read()
secret_key = SecretKey( # pylint: disable=invalid-name
Secret(private_key), Secret(public_key)
)
app.add_middleware(SessionMiddleware, secret_key=secret_key)