1+ import html
2+ import json
13import os
24import random
35import string
4- import html
56import urllib .parse
67
7- import requests as requests
88from flask import Flask , redirect , request
9+ import requests
910
1011CLIENT_PORT = 8001
1112CLIENT_ID = os .environ .get ("CLIENT_ID" , "test" )
1213CLIENT_SECRET = os .environ .get ("CLIENT_SECRET" , "CHANGE ME" )
1314
14- ZAUTH_BASE_URL = "http://zauth.localhost:8000"
15+ ZAUTH_BASE_URI = "http://localhost:8000"
16+ CLIENT_BASE_URI = f"http://localhost:{ CLIENT_PORT } "
17+ CLIENT_CALLBACK_URI = f"{ CLIENT_BASE_URI } /callback"
1518
1619app = Flask (__name__ )
1720
@@ -24,95 +27,133 @@ def authenticate_params():
2427 return {
2528 "client_id" : CLIENT_ID ,
2629 "response_type" : "code" ,
27- "redirect_uri" : f"http://client.localhost:{ CLIENT_PORT } /callback" ,
28- "state" : state
30+ "redirect_uri" : CLIENT_CALLBACK_URI ,
31+ "state" : state ,
32+ "scope" : "roles"
2933 }
3034
3135
32- @app .route ('/' )
33- def homepage ():
34- return f"""
35- <h1>Zauth test client</h1>
36- <p><b>Client ID:</b> { CLIENT_ID }
37- <form action="/secret" method="post">
38- <label for="secret"><b>Client secret: </b></label>
39- <input type="text" value="{ CLIENT_SECRET } "
40- name="secret" id="secret">
41- <input type="submit" value="submit">
42- </form>
43- <p><b>Client redirect URI:</b> http://localhost:{ CLIENT_PORT } /callback
44- <p><a href="/authenticate">Start authentication flow</a>
45-
46- """
47-
48-
49- @app .route ('/secret' , methods = ['POST' ])
50- def change_secret ():
51- global CLIENT_SECRET
52- CLIENT_SECRET = request .form ['secret' ]
53- return redirect ("/" )
54-
55-
56- @app .route ('/authenticate' )
57- def authenticate ():
58- params = urllib .parse .urlencode (authenticate_params ())
59- return redirect (f"{ ZAUTH_BASE_URL } /oauth/authorize?{ params } " )
60-
61-
6236def fetch_token (code ):
6337 auth = (CLIENT_ID , CLIENT_SECRET )
6438 data = {
6539 "grant_type" : "authorization_code" ,
6640 "code" : code ,
67- "redirect_uri" : f"http://client.localhost: { CLIENT_PORT } /callback" ,
41+ "redirect_uri" : CLIENT_CALLBACK_URI
6842 }
69- return requests .post (f"{ ZAUTH_BASE_URL } /oauth/token" , auth = auth , data = data )
43+ return requests .post (f"{ ZAUTH_BASE_URI } /oauth/token" , auth = auth , data = data )
7044
7145
7246def fetch_user (access_token ):
7347 return requests .get (
74- f"{ ZAUTH_BASE_URL } /current_user" ,
48+ f"{ ZAUTH_BASE_URI } /current_user" ,
7549 headers = {
7650 "Authorization" : "Bearer " + access_token ,
7751 "Accept" : "application/json"
7852 }
7953 )
8054
8155
56+ @app .route ('/' )
57+ def homepage ():
58+ return f"""\
59+ <!DOCTYPE html>
60+ <html lang="en">
61+ <head>
62+ <meta charset="utf-8">
63+ <title>Zauth test client</title>
64+ </head>
65+ <body>
66+ <h1>Zauth test client</h1>
67+ <p><b>Client ID:</b> { CLIENT_ID } </p>
68+ <form action="/secret" method="post">
69+ <label for="secret"><b>Client secret: </b></label>
70+ <input type="text" name="secret" value="{ CLIENT_SECRET } " />
71+ <input type="submit" value="submit" />
72+ </form>
73+ <p><b>ZAuth base URI:</b> { ZAUTH_BASE_URI } </p>
74+ <p><b>Client base URI:</b> { CLIENT_BASE_URI } </p>
75+ <p><b>Client redirect URI:</b> { CLIENT_CALLBACK_URI } </p>
76+ <p><a href="/authenticate">Start authentication flow</a></p>
77+ </body>
78+ </html>
79+ """
80+
81+
82+ @app .route ('/secret' , methods = ['POST' ])
83+ def change_secret ():
84+ global CLIENT_SECRET
85+ CLIENT_SECRET = request .form ['secret' ]
86+ return redirect ("/" )
87+
88+
89+ @app .route ('/authenticate' )
90+ def authenticate ():
91+ params = urllib .parse .urlencode (authenticate_params ())
92+ return redirect (f"{ ZAUTH_BASE_URI } /oauth/authorize?{ params } " )
93+
94+
8295@app .route ('/callback' )
8396def callback ():
8497 global state
85- response = [
86- "<h1> Callback received </h1>"
87- ]
88- code = request .args ['code' ]
89- response .append (f"<p><b>Code</b>: { html .escape (code ) } " )
98+
99+ callback_code = request .args ['code' ]
100+ html_callback_code = html .escape (callback_code )
101+
90102 callback_state = request .args ['state' ]
91- response .append (f"<p><b>State</b>: { html .escape (callback_state ) } " )
92- if state == callback_state :
93- response .append ("<b>OK</b>" )
103+ if callback_state == state :
104+ html_callback_state = f'{ callback_state } <b>OK</b>'
94105 else :
95- response . append ( f" <b>NOT OK </b> (should be { state } )" )
96-
97- token_response = fetch_token (code )
98- if token_response .ok :
99- token_json = token_response .json ()
100- access_token = token_json [ "access_token" ]
101- response . append (
102- f"<p>OK fetching access token: { html . escape ( access_token ) } " )
103-
104- user_response = fetch_user ( access_token )
105- if user_response . ok :
106- user_json = user_response . json ()
107- response . append ( f"<p>OK fetching current user:" )
108- response . append ( str ( user_json ))
106+ html_callback_state = f' { callback_state } <b>ERROR </b> (should be { state } )'
107+
108+ token_res = fetch_token (callback_code )
109+ if token_res .ok :
110+ token_res_json = token_res .json ()
111+ html_token_res = f'<b>OK</b>:<br /><pre> { html . escape ( json . dumps ( token_res_json , indent = 4 )) } </pre>'
112+
113+ access_token = token_res_json [ " access_token" ]
114+ html_access_token = html . escape ( access_token )
115+
116+ user_res = fetch_user ( access_token )
117+ if user_res . ok :
118+ user_res_json = user_res . json ( )
119+ html_user_res = f'<b>OK</b>:<br /><pre> { html . escape ( json . dumps ( user_res_json , indent = 4 )) } </pre>'
109120 else :
110- response .append (f"<p>ERROR fetching current user:" )
111- response .append (html .escape (str (user_response .content )))
121+ html_user_res = f'<b>ERROR ({ user_res .status_code } )</b><br /><pre>{ html .escape (str (user_res .content .decode ()))} </pre>'
112122 else :
113- response .append (f"<p>ERROR fetching token: " )
114- response .append (html .escape (str (token_response .content )))
115- return "" .join (response )
123+ html_token_res = f'<b>ERROR ({ token_res .status_code } )</b><br /><pre>{ html .escape (str (token_res .content .decode ()))} </pre>'
124+ html_access_token = '<b>SKIP</b>'
125+ html_user_res = '<b>SKIP</b>'
126+ return f"""\
127+ <!DOCTYPE html>
128+ <html lang="en">
129+ <head>
130+ <meta charset="utf-8">
131+ <title>Zauth test client</title>
132+ </head>
133+ <body>
134+ <h1>Received callback from browser:</h1>
135+ <p>
136+ <b>Code</b>: { html_callback_code }
137+ </p>
138+ <p>
139+ <b>State</b>: { html_callback_state }
140+ </p>
141+
142+ <h1>Getting token from <code>{ html .escape (f'{ ZAUTH_BASE_URI } /oauth/token' )} </code>:</h1>
143+ <p>
144+ <b>Response</b>: { html_token_res }
145+ </p>
146+ <p>
147+ <b>Access token</b>: { html_access_token }
148+ </p>
149+
150+ <h1>Fetching user info from <code>{ html .escape (f'{ ZAUTH_BASE_URI } /current_user' )} </code>:</h1>
151+ <p>
152+ <b>Response</b>: { html_user_res }
153+ </p>
154+ </body>
155+ </html>
156+ """
116157
117158
118159if __name__ == "__main__" :
0 commit comments