1616 Flask ,
1717 Response ,
1818 abort ,
19- redirect ,
2019 render_template ,
2120 request ,
2221 send_from_directory ,
23- session ,
2422)
2523
26- from flask_oauthlib .client import OAuth
27- from functools import wraps
2824from gevent import sleep , spawn
2925from gevent .pywsgi import WSGIServer
3026from jq import jq
3430from re import X , compile
3531from requests .exceptions import RequestException
3632from signal import SIGTERM , signal
37- from urllib .parse import urljoin
3833
3934from . import __version__
4035from .cluster_discovery import DEFAULT_CLUSTERS , StaticClusterDiscoverer
41- from .oauth import OAuthRemoteAppWithRefresh
4236
4337from .spiloutils import (
4438 apply_postgresql ,
7165SERVER_STATUS = {'shutdown' : False }
7266
7367APP_URL = getenv ('APP_URL' )
74- AUTHORIZE_URL = getenv ('AUTHORIZE_URL' )
7568SPILO_S3_BACKUP_BUCKET = getenv ('SPILO_S3_BACKUP_BUCKET' )
7669TEAM_SERVICE_URL = getenv ('TEAM_SERVICE_URL' )
77- ACCESS_TOKEN_URL = getenv ('ACCESS_TOKEN_URL' )
78- TOKENINFO_URL = getenv ('OAUTH2_TOKEN_INFO_URL' )
7970
8071OPERATOR_API_URL = getenv ('OPERATOR_API_URL' , 'http://postgres-operator' )
8172OPERATOR_CLUSTER_NAME_LABEL = getenv ('OPERATOR_CLUSTER_NAME_LABEL' , 'cluster-name' )
@@ -184,38 +175,6 @@ def __call__(self, environ, start_response):
184175 return self .app (environ , start_response )
185176
186177
187- oauth = OAuth (app )
188-
189- auth = OAuthRemoteAppWithRefresh (
190- oauth ,
191- 'auth' ,
192- request_token_url = None ,
193- access_token_method = 'POST' ,
194- access_token_url = ACCESS_TOKEN_URL ,
195- authorize_url = AUTHORIZE_URL ,
196- )
197- oauth .remote_apps ['auth' ] = auth
198-
199-
200- def verify_token (token ):
201- if not token :
202- return False
203-
204- r = requests .get (TOKENINFO_URL , headers = {'Authorization' : token })
205-
206- return r .status_code == 200
207-
208-
209- def authorize (f ):
210- @wraps (f )
211- def wrapper (* args , ** kwargs ):
212- if AUTHORIZE_URL and 'auth_token' not in session :
213- return redirect (urljoin (APP_URL , '/login' ))
214- return f (* args , ** kwargs )
215-
216- return wrapper
217-
218-
219178def ok (body = {}, status = 200 ):
220179 return (
221180 Response (
@@ -297,19 +256,16 @@ def health():
297256
298257
299258@app .route ('/css/<path:path>' )
300- @authorize
301259def send_css (path ):
302260 return send_from_directory ('static/' , path ), 200 , STATIC_HEADERS
303261
304262
305263@app .route ('/js/<path:path>' )
306- @authorize
307264def send_js (path ):
308265 return send_from_directory ('static/' , path ), 200 , STATIC_HEADERS
309266
310267
311268@app .route ('/' )
312- @authorize
313269def index ():
314270 return render_template ('index.html' , google_analytics = GOOGLE_ANALYTICS )
315271
@@ -345,7 +301,6 @@ def index():
345301
346302
347303@app .route ('/config' )
348- @authorize
349304def get_config ():
350305 config = DEFAULT_UI_CONFIG .copy ()
351306 config .update (OPERATOR_UI_CONFIG )
@@ -407,17 +362,15 @@ def get_teams_for_user(user_name):
407362
408363
409364@app .route ('/teams' )
410- @authorize
411365def get_teams ():
412366 return ok (
413367 get_teams_for_user (
414- session . get ('user_name ' , '' ),
368+ request . headers . get ('X-Uid ' , '' ),
415369 )
416370 )
417371
418372
419373@app .route ('/services/<namespace>/<cluster>' )
420- @authorize
421374def get_service (namespace : str , cluster : str ):
422375
423376 if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -433,7 +386,6 @@ def get_service(namespace: str, cluster: str):
433386
434387
435388@app .route ('/pooler/<namespace>/<cluster>' )
436- @authorize
437389def get_list_poolers (namespace : str , cluster : str ):
438390
439391 if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -449,7 +401,6 @@ def get_list_poolers(namespace: str, cluster: str):
449401
450402
451403@app .route ('/statefulsets/<namespace>/<cluster>' )
452- @authorize
453404def get_list_clusters (namespace : str , cluster : str ):
454405
455406 if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -465,7 +416,6 @@ def get_list_clusters(namespace: str, cluster: str):
465416
466417
467418@app .route ('/statefulsets/<namespace>/<cluster>/pods' )
468- @authorize
469419def get_list_members (namespace : str , cluster : str ):
470420
471421 if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -485,7 +435,6 @@ def get_list_members(namespace: str, cluster: str):
485435
486436
487437@app .route ('/namespaces' )
488- @authorize
489438def get_namespaces ():
490439
491440 if TARGET_NAMESPACE not in ['' , '*' ]:
@@ -503,7 +452,6 @@ def get_namespaces():
503452
504453
505454@app .route ('/postgresqls' )
506- @authorize
507455def get_postgresqls ():
508456 postgresqls = [
509457 {
@@ -602,7 +550,6 @@ def run(*args, **kwargs):
602550
603551
604552@app .route ('/postgresqls/<namespace>/<cluster>' , methods = ['POST' ])
605- @authorize
606553@namespaced
607554def update_postgresql (namespace : str , cluster : str ):
608555 if READ_ONLY_MODE :
@@ -614,8 +561,8 @@ def update_postgresql(namespace: str, cluster: str):
614561
615562 postgresql = request .get_json (force = True )
616563
617- teams = get_teams_for_user (session . get ('user_name ' , '' ))
618- logger .info (f'Changes to: { cluster } by { session . get ("user_name " , "local-user" )} /{ teams } { postgresql } ' ) # noqa
564+ teams = get_teams_for_user (request . headers . get ('X-Uid ' , '' ))
565+ logger .info (f'Changes to: { cluster } by { request . headers . get ("X-Uid " , "local-user" )} /{ teams } { postgresql } ' ) # noqa
619566
620567 if SUPERUSER_TEAM and SUPERUSER_TEAM in teams :
621568 logger .info (f'Allowing edit due to membership in superuser team { SUPERUSER_TEAM } ' ) # noqa
@@ -810,7 +757,6 @@ def update_postgresql(namespace: str, cluster: str):
810757
811758
812759@app .route ('/postgresqls/<namespace>/<cluster>' , methods = ['GET' ])
813- @authorize
814760def get_postgresql (namespace : str , cluster : str ):
815761
816762 if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
@@ -826,7 +772,6 @@ def get_postgresql(namespace: str, cluster: str):
826772
827773
828774@app .route ('/stored_clusters' )
829- @authorize
830775def get_stored_clusters ():
831776 return respond (
832777 read_stored_clusters (
@@ -837,7 +782,6 @@ def get_stored_clusters():
837782
838783
839784@app .route ('/stored_clusters/<pg_cluster>' , methods = ['GET' ])
840- @authorize
841785def get_versions (pg_cluster : str ):
842786 return respond (
843787 read_versions (
@@ -850,9 +794,7 @@ def get_versions(pg_cluster: str):
850794 )
851795
852796
853-
854797@app .route ('/stored_clusters/<pg_cluster>/<uid>' , methods = ['GET' ])
855- @authorize
856798def get_basebackups (pg_cluster : str , uid : str ):
857799 return respond (
858800 read_basebackups (
@@ -867,7 +809,6 @@ def get_basebackups(pg_cluster: str, uid: str):
867809
868810
869811@app .route ('/create-cluster' , methods = ['POST' ])
870- @authorize
871812def create_new_cluster ():
872813
873814 if READ_ONLY_MODE :
@@ -885,8 +826,8 @@ def create_new_cluster():
885826 if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
886827 return wrong_namespace ()
887828
888- teams = get_teams_for_user (session . get ('user_name ' , '' ))
889- logger .info (f'Create cluster by { session . get ("user_name " , "local-user" )} /{ teams } { postgresql } ' ) # noqa
829+ teams = get_teams_for_user (request . headers . get ('X-Uid ' , '' ))
830+ logger .info (f'Create cluster by { request . headers . get ("X-Uid " , "local-user" )} /{ teams } { postgresql } ' ) # noqa
890831
891832 if SUPERUSER_TEAM and SUPERUSER_TEAM in teams :
892833 logger .info (f'Allowing create due to membership in superuser team { SUPERUSER_TEAM } ' ) # noqa
@@ -898,7 +839,6 @@ def create_new_cluster():
898839
899840
900841@app .route ('/postgresqls/<namespace>/<cluster>' , methods = ['DELETE' ])
901- @authorize
902842def delete_postgresql (namespace : str , cluster : str ):
903843 if TARGET_NAMESPACE not in ['' , '*' , namespace ]:
904844 return wrong_namespace ()
@@ -910,9 +850,9 @@ def delete_postgresql(namespace: str, cluster: str):
910850 if postgresql is None :
911851 return not_found ()
912852
913- teams = get_teams_for_user (session . get ('user_name ' , '' ))
853+ teams = get_teams_for_user (request . headers . get ('X-Uid ' , '' ))
914854
915- logger .info (f'Delete cluster: { cluster } by { session . get ("user_name " , "local-user" )} /{ teams } ' ) # noqa
855+ logger .info (f'Delete cluster: { cluster } by { request . headers . get ("X-Uid " , "local-user" )} /{ teams } ' ) # noqa
916856
917857 if SUPERUSER_TEAM and SUPERUSER_TEAM in teams :
918858 logger .info (f'Allowing delete due to membership in superuser team { SUPERUSER_TEAM } ' ) # noqa
@@ -936,78 +876,30 @@ def proxy_operator(url: str):
936876
937877
938878@app .route ('/operator/status' )
939- @authorize
940879def get_operator_status ():
941880 return proxy_operator ('/status/' )
942881
943882
944883@app .route ('/operator/workers/<worker>/queue' )
945- @authorize
946884def get_operator_get_queue (worker : int ):
947885 return proxy_operator (f'/workers/{ worker } /queue' )
948886
949887
950888@app .route ('/operator/workers/<worker>/logs' )
951- @authorize
952889def get_operator_get_logs (worker : int ):
953890 return proxy_operator (f'/workers/{ worker } /logs' )
954891
955892
956893@app .route ('/operator/clusters/<namespace>/<cluster>/logs' )
957- @authorize
958894def get_operator_get_logs_per_cluster (namespace : str , cluster : str ):
959895 return proxy_operator (f'/clusters/{ namespace } /{ cluster } /logs/' )
960896
961897
962- @app .route ('/login' )
963- def login ():
964- redirect = request .args .get ('redirect' , False )
965- if not redirect :
966- return render_template ('login-deeplink.html' )
967-
968- redirect_uri = urljoin (APP_URL , '/login/authorized' )
969- return auth .authorize (callback = redirect_uri )
970-
971-
972- @app .route ('/logout' )
973- def logout ():
974- session .pop ('auth_token' , None )
975- return redirect (urljoin (APP_URL , '/' ))
976-
977-
978898@app .route ('/favicon.png' )
979899def favicon ():
980900 return send_from_directory ('static/' , 'favicon-96x96.png' ), 200
981901
982902
983- @app .route ('/login/authorized' )
984- def authorized ():
985- resp = auth .authorized_response ()
986- if resp is None :
987- return 'Access denied: reason=%s error=%s' % (
988- request .args ['error' ],
989- request .args ['error_description' ]
990- )
991-
992- if not isinstance (resp , dict ):
993- return 'Invalid auth response'
994-
995- session ['auth_token' ] = (resp ['access_token' ], '' )
996-
997- r = requests .get (
998- TOKENINFO_URL ,
999- headers = {
1000- 'Authorization' : f'Bearer { session ["auth_token" ][0 ]} ' ,
1001- },
1002- )
1003- session ['user_name' ] = r .json ().get ('uid' )
1004-
1005- logger .info (f'Login from: { session ["user_name" ]} ' )
1006-
1007- # return redirect(urljoin(APP_URL, '/'))
1008- return render_template ('login-resolve-deeplink.html' )
1009-
1010-
1011903def shutdown ():
1012904 # just wait some time to give Kubernetes time to update endpoints
1013905 # this requires changing the readinessProbe's
@@ -1083,28 +975,20 @@ def init_cluster():
1083975 help = 'Verbose logging' ,
1084976 is_flag = True ,
1085977)
1086- @option (
1087- '--secret-key' ,
1088- default = 'development' ,
1089- envvar = 'SECRET_KEY' ,
1090- help = 'Secret key for session cookies' ,
1091- )
1092978@option (
1093979 '--clusters' ,
1094980 envvar = 'CLUSTERS' ,
1095981 help = f'Comma separated list of Kubernetes API server URLs (default: { DEFAULT_CLUSTERS } )' , # noqa
1096982 type = CommaSeparatedValues (),
1097983)
1098- def main (port , secret_key , debug , clusters : list ):
984+ def main (port , debug , clusters : list ):
1099985 global TARGET_NAMESPACE
1100986
1101987 basicConfig (stream = sys .stdout , level = (DEBUG if debug else INFO ), format = '%(asctime)s %(levelname)s: %(message)s' ,)
1102988
1103989 init_cluster ()
1104990
1105- logger .info (f'Access token URL: { ACCESS_TOKEN_URL } ' )
1106991 logger .info (f'App URL: { APP_URL } ' )
1107- logger .info (f'Authorize URL: { AUTHORIZE_URL } ' )
1108992 logger .info (f'Operator API URL: { OPERATOR_API_URL } ' )
1109993 logger .info (f'Operator cluster name label: { OPERATOR_CLUSTER_NAME_LABEL } ' )
1110994 logger .info (f'Readonly mode: { "enabled" if READ_ONLY_MODE else "disabled" } ' ) # noqa
@@ -1113,7 +997,6 @@ def main(port, secret_key, debug, clusters: list):
1113997 logger .info (f'Superuser team: { SUPERUSER_TEAM } ' )
1114998 logger .info (f'Target namespace: { TARGET_NAMESPACE } ' )
1115999 logger .info (f'Teamservice URL: { TEAM_SERVICE_URL } ' )
1116- logger .info (f'Tokeninfo URL: { TOKENINFO_URL } ' )
11171000 logger .info (f'Use AWS instance_profile: { USE_AWS_INSTANCE_PROFILE } ' )
11181001 logger .info (f'WAL-E S3 endpoint: { WALE_S3_ENDPOINT } ' )
11191002 logger .info (f'AWS S3 endpoint: { AWS_ENDPOINT } ' )
@@ -1136,7 +1019,6 @@ def get_target_namespace():
11361019 logger .info (f'Target namespace set to: { TARGET_NAMESPACE or "*" } ' )
11371020
11381021 app .debug = debug
1139- app .secret_key = secret_key
11401022
11411023 signal (SIGTERM , exit_gracefully )
11421024
0 commit comments