client-oidc/app.py

133 lines
4.3 KiB
Python
Raw Normal View History

2024-06-20 10:12:05 +00:00
import requests
import jwt
2024-06-20 10:12:05 +00:00
from authlib.integrations.base_client import OAuthError
2024-06-20 10:12:05 +00:00
from authlib.integrations.flask_client import OAuth
from flask import Flask, request, redirect, session, render_template, url_for, make_response
2024-06-18 21:37:30 +00:00
2024-06-18 21:37:30 +00:00
app = Flask(__name__)
app.config['SECRET_KEY'] = 'onelogindemopytoolkit'
2024-06-20 10:12:05 +00:00
issuer="https://id.vilanet.fr/realms/vilanet"
client_id="client-oidc"
client_secret="BqWWnuj5JkgZZWEaXuR8bprEx53lqGxC"
2024-06-20 10:12:05 +00:00
# To manage OIDC flow for UI client
2024-06-20 10:12:05 +00:00
oauth = OAuth(app=app)
oauth.register(
name="keycloak",
client_id=client_id,
client_secret=client_secret,
2024-06-20 10:12:05 +00:00
server_metadata_url=f'{issuer}/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid',
2024-06-20 10:12:05 +00:00
'code_challenge_method': 'S256',
}
)
@app.route("/api")
def api():
not_auth_warn = True
# is it OK to use access token to check API authorization on server side
# it is not OK to use ID token to check API authorization on server side
if 'accessToken' in request.args:
access_token = request.args['accessToken']
jwks_uri = f"{issuer}/protocol/openid-connect/certs"
jwks_client = jwt.PyJWKClient(jwks_uri)
key = jwks_client.get_signing_key_from_jwt(access_token)
data = jwt.decode(access_token, key.key, algorithms=["RS256"], audience='client-oidc', options={'verify_signature': True, 'verify_aud': True})
print(data)
not_auth_warn = False
# TODO verify token and check role
return render_template(
'api.html',
not_auth_warn=not_auth_warn,
)
2024-06-20 10:12:05 +00:00
@app.route("/auth")
def auth():
try:
token_response = oauth.keycloak.authorize_access_token()
except OAuthError as e:
return redirect('/?error=access_denied')
response = make_response(redirect('/'))
access_token = token_response['access_token']
if access_token:
response.set_cookie('accessToken', access_token, httponly=True)
refresh_token = token_response['refresh_token']
if refresh_token:
response.set_cookie('refreshToken', refresh_token, httponly=True)
id_token = token_response['id_token']
if id_token:
response.set_cookie('idToken', id_token, httponly=True)
if token_response['userinfo']:
session['name'] = token_response['userinfo']['name']
session['email'] = token_response['userinfo']['email']
return response
2024-06-20 10:12:05 +00:00
2024-06-18 21:37:30 +00:00
@app.route("/", methods=['GET', 'POST'])
def index():
attributes = False
access_token = False
2024-06-18 21:37:30 +00:00
paint_logout = False
not_auth_warn = False
user_name = False
user_email = False
2024-06-20 10:12:05 +00:00
if 'sso' in request.args:
redirect_uri = url_for('auth', _external=True)
return oauth.keycloak.authorize_redirect(redirect_uri)
elif 'slo' in request.args:
if 'refresh_token' in request.cookies:
2024-06-20 10:12:05 +00:00
# propagate logout to Keycloak
refresh_token = request.cookies['refresh_token']
requests.post(f'{issuer}/protocol/openid-connect/logout', data={
"client_id": client_id,
"client_secret": client_secret,
"refresh_token": refresh_token,
2024-06-20 10:12:05 +00:00
})
response = make_response(redirect('/'))
response.set_cookie('accessToken', '', expires=0)
response.set_cookie('refreshToken', '', expires=0)
response.set_cookie('idToken', '', expires=0)
if 'name' in session:
del session['name']
if 'email' in session:
del session['email']
return response
elif 'error' in request.args:
not_auth_warn = True
2024-06-20 10:12:05 +00:00
# it is OK to use ID token to display user info on client side
# is it not OK to use access token on client side
if 'idToken' in request.cookies:
2024-06-20 10:12:05 +00:00
paint_logout = True
attributes = {'idToken': [request.cookies['idToken']]}.items()
if 'name' in session:
user_name = session['name']
if 'email' in session:
user_email = session['email']
if 'accessToken' in request.cookies:
access_token = request.cookies['accessToken']
2024-06-20 10:12:05 +00:00
2024-06-18 21:37:30 +00:00
return render_template(
'index.html',
attributes=attributes,
access_token=access_token,
not_auth_warn=not_auth_warn,
paint_logout=paint_logout,
user_name=user_name,
user_email=user_email,
2024-06-18 21:37:30 +00:00
)
if __name__ == "__main__":
app.run(host='127.0.0.1', port=5001, debug=True)