Skip to content

Commit 56e9c91

Browse files
committed
Sanitised on the oidc integration
1 parent bf01486 commit 56e9c91

File tree

3 files changed

+108
-30
lines changed

3 files changed

+108
-30
lines changed

mrmat_python_api_flask/__init__.py

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import pkg_resources
2929
from logging.config import dictConfig
3030

31-
from flask import Flask
31+
from flask import Flask, render_template
3232
from flask_sqlalchemy import SQLAlchemy
3333
from flask_migrate import Migrate
3434
from flask_marshmallow import Marshmallow
@@ -105,9 +105,10 @@ def create_app(config_override=None, instance_path=None):
105105
app.config.setdefault('OPENAPI_REDOC_URL', 'https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js')
106106
app.config.setdefault('OPENAPI_RAPIDOC_PATH', 'rapidoc')
107107
app.config.setdefault('OPENAPI_RAPIDOC_URL', 'https://unpkg.com/rapidoc/dist/rapidoc-min.js')
108-
#app.config.setdefault('OPENAPI_SWAGGER_UI_CONFIG', {
109-
# 'oauth2RedirectUrl': 'http://localhost:5000/apidoc/swagger/oauth2-redirect'
110-
#})
108+
app.config.setdefault('OPENAPI_SWAGGER_UI_CONFIG', {
109+
'oauth2RedirectUrl': 'http://localhost:5000/apidoc/swagger/oauth2-redirect'
110+
})
111+
app.config.setdefault('OPENAPI_SWAGGER_UI_ENABLE_OAUTH', True)
111112
if 'FLASK_CONFIG' in os.environ and os.path.exists(os.path.expanduser(os.environ['FLASK_CONFIG'])):
112113
app.config.from_json(os.path.expanduser(os.environ['FLASK_CONFIG']))
113114
if config_override is not None:
@@ -156,31 +157,39 @@ def create_app(config_override=None, instance_path=None):
156157
#
157158
# If OAuth2 is in use, register our usage
158159

159-
api.spec.components.security_scheme('mrmat_keycloak',
160-
{'type': 'oauth2',
161-
'description': 'This API uses OAuth 2',
162-
'flows': {
163-
'clientCredentials': {
164-
'tokenUrl': 'https://keycloak.mrmat.org/auth/realms/master/protocol/openid-connect/token',
165-
'scopes': {
166-
'mrmat-python-api-flask-resource-read': 'Allows reading objects '
167-
'in the Resource API',
168-
'mrmat-python-api-flask-resource-write': 'Allows creating/modifying'
169-
' and deleting objects '
170-
'in the Resource API'
171-
}
172-
},
173-
'authorizationCode': {
174-
'authorizationUrl': 'https://keycloak.mrmat.org/auth/realms/master/protocol/openid-connect/auth',
175-
'tokenUrl': 'https://keycloak.mrmat.org/auth/realms/master/protocol/openid-connect/token',
176-
'scopes': {
177-
'mrmat-python-api-flask-resource-read': 'Allows reading objects '
178-
'in the Resource API',
179-
'mrmat-python-api-flask-resource-write': 'Allows creating/modifying'
180-
' and deleting objects '
181-
'in the Resource API'
182-
}
183-
}
184-
}})
160+
api.spec.components.security_scheme('mrmat_keycloak', {
161+
'type': 'oauth2',
162+
'flows': {
163+
'authorizationCode': {
164+
'authorizationUrl': 'https://keycloak.mrmat.org/auth/realms/master/protocol/openid-connect/auth',
165+
'tokenUrl': 'https://keycloak.mrmat.org/auth/realms/master/protocol/openid-connect/token',
166+
'scopes': {
167+
'openid': 'Basic token without extra authorisation',
168+
'mrmat-python-api-flask-resource-read': 'Allows reading objects '
169+
'in the Resource API',
170+
'mrmat-python-api-flask-resource-write': 'Allows creating/modifying'
171+
' and deleting objects '
172+
'in the Resource API'
173+
}
174+
}
175+
}})
176+
# api.spec.components.security_scheme('mrmat_keycloak', {
177+
# 'type': 'openIdConnect',
178+
# 'openIdConnectUrl': 'https://keycloak.mrmat.org/auth/realms/master/.well-known/openid-configuration'
179+
# })
180+
# api.spec.security('mrmat_keycloak', [
181+
# 'profile',
182+
# 'mrmat-python-api-flask-resource-write',
183+
# 'mrmat-python-api-flask-resource-read'
184+
# ])
185+
186+
@app.route('/apidoc/swagger/oauth2-redirect')
187+
def oauth2_redirect():
188+
return render_template('swagger-ui-redirect.html')
189+
# state = request.args.get('state')
190+
# code = request.args.get('code')
191+
# session_state = request.args.get('session_state')
192+
# return {'state': state, 'code': code, 'session_state': session_state}, 200
193+
185194

186195
return app

mrmat_python_api_flask/apis/greeting/v3/api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
class GreetingV3(MethodView):
3939

4040
@oidc.accept_token(require_token=True)
41+
@bp.doc(security=[{'mrmat_keycloak': ['profile']}])
4142
@bp.response(200, GreetingV3Output)
4243
def get(self):
4344
"""Get a greeting for your asserted name from a JWT token
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<!doctype html>
2+
<!-- Taken from a PR to flask-smorest at https://github.com/marshmallow-code/flask-smorest/pull/89 -->
3+
<html lang="en-US">
4+
<body onload="run()">
5+
</body>
6+
</html>
7+
<script>
8+
'use strict';
9+
function run () {
10+
var oauth2 = window.opener.swaggerUIRedirectOauth2;
11+
var sentState = oauth2.state;
12+
var redirectUrl = oauth2.redirectUrl;
13+
var isValid, qp, arr;
14+
15+
if (/code|token|error/.test(window.location.hash)) {
16+
qp = window.location.hash.substring(1);
17+
} else {
18+
qp = location.search.substring(1);
19+
}
20+
21+
arr = qp.split("&")
22+
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
23+
qp = qp ? JSON.parse('{' + arr.join() + '}',
24+
function (key, value) {
25+
return key === "" ? value : decodeURIComponent(value)
26+
}
27+
) : {}
28+
29+
isValid = qp.state === sentState
30+
31+
if ((
32+
oauth2.auth.schema.get("flow") === "accessCode"||
33+
oauth2.auth.schema.get("flow") === "authorizationCode"
34+
) && !oauth2.auth.code) {
35+
if (!isValid) {
36+
oauth2.errCb({
37+
authId: oauth2.auth.name,
38+
source: "auth",
39+
level: "warning",
40+
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
41+
});
42+
}
43+
44+
if (qp.code) {
45+
delete oauth2.state;
46+
oauth2.auth.code = qp.code;
47+
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
48+
} else {
49+
let oauthErrorMsg
50+
if (qp.error) {
51+
oauthErrorMsg = "["+qp.error+"]: " +
52+
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
53+
(qp.error_uri ? "More info: "+qp.error_uri : "");
54+
}
55+
56+
oauth2.errCb({
57+
authId: oauth2.auth.name,
58+
source: "auth",
59+
level: "error",
60+
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
61+
});
62+
}
63+
} else {
64+
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
65+
}
66+
window.close();
67+
}
68+
</script>

0 commit comments

Comments
 (0)