1
1
"""
2
- dash-enterprise auth
2
+ dash-enterprise- auth
3
3
4
- Methods to integrate dash apps with the authentication from the
5
- dash-deployment-server.
4
+ Methods to integrate dash apps with the authentication from Dash Enterprise.
6
5
"""
7
- from .version import __version__
8
6
import datetime as _dt
9
7
import os as _os
10
8
import platform as _platform
11
9
import base64 as _b64
12
10
import functools as _ft
13
11
import json as _json
14
- import jwt as _jwt
15
12
import urllib as _urllib
16
13
from typing import Any
17
14
15
+ import flask as _flask
16
+ import jwt as _jwt
18
17
import requests as _requests
19
18
19
+
20
20
import dash as _dash
21
21
if hasattr (_dash , "dcc" ):
22
22
_dcc = _dash .dcc
27
27
else :
28
28
import dash_html_components as _html
29
29
30
- import flask as _flask
30
+ from . version import __version__
31
31
32
- ua_string = 'Plotly/%s (Language=Python/%s; Platform=%s/%s)' % (__version__ , _platform .python_version (), _platform .system (), _platform .release ())
32
+ ua_string = (
33
+ f"Plotly/{ __version__ } (Language=Python/{ _platform .python_version ()} ;"
34
+ f" Platform={ _platform .system ()} /{ _platform .release ()} )"
35
+ )
33
36
34
37
35
38
class UaPyJWKClient (_jwt .PyJWKClient ):
36
39
def fetch_data (self ) -> Any :
37
- with _urllib .request .urlopen (_urllib .request .Request (self .uri , headers = {'User-Agent' : ua_string })) as response :
40
+ with _urllib .request .urlopen (
41
+ _urllib .request .Request (self .uri , headers = {"User-Agent" : ua_string })
42
+ ) as response :
38
43
return _json .load (response )
39
44
40
45
41
46
def _need_request_context (func ):
42
47
@_ft .wraps (func )
43
48
def _wrap (* args , ** kwargs ):
44
49
if not _flask .has_request_context ():
45
- raise RuntimeError ('`{0}` method needs a flask/dash request'
46
- ' context to run. Make sure to run '
47
- '`{0}` from a callback.' .format (func .__name__ ))
50
+ raise RuntimeError (
51
+ f"`{ func .__name__ } ` method needs a flask/dash request"
52
+ f" context to run. Make sure to run `{ func .__name__ } ` from a callback."
53
+ )
48
54
return func (* args , ** kwargs )
49
55
return _wrap
50
56
51
57
52
- def create_logout_button (label = ' Logout' , style = None ):
58
+ def create_logout_button (label = " Logout" , style = None ):
53
59
"""
54
- Create a dcc.LogoutButton with the dash-deployment-server logout url set
60
+ Create a dcc.LogoutButton with the Dash Enterprise logout url set
55
61
in the environment.
56
62
57
63
:param label: Text of the logout button.
@@ -60,31 +66,31 @@ def create_logout_button(label='Logout', style=None):
60
66
:type style: dict
61
67
:return:
62
68
"""
63
- logout_url = _os .getenv (' DASH_LOGOUT_URL' )
69
+ logout_url = _os .getenv (" DASH_LOGOUT_URL" )
64
70
if not logout_url :
65
- raise Exception (
66
- ' DASH_LOGOUT_URL was not set in the environment.'
71
+ raise RuntimeError (
72
+ " DASH_LOGOUT_URL was not set in the environment."
67
73
)
68
74
69
- if not _os .getenv (' DASH_JWKS_URL' ):
75
+ if not _os .getenv (" DASH_JWKS_URL" ):
70
76
return _dcc .LogoutButton (
71
77
logout_url = logout_url ,
72
78
label = label ,
73
79
style = style ,
74
80
)
75
81
76
- btn_style = {' display' : ' inline-block' }
82
+ btn_style = {" display" : " inline-block" }
77
83
if style :
78
84
btn_style .update (style )
79
85
80
86
return _html .Div (
81
87
_html .A (
82
88
label ,
83
89
href = logout_url ,
84
- className = ' dash-logout-btn' ,
85
- style = {' textDecoration' : ' none' }
90
+ className = " dash-logout-btn" ,
91
+ style = {" textDecoration" : " none" }
86
92
),
87
- className = ' dash-logout-frame' ,
93
+ className = " dash-logout-frame" ,
88
94
style = btn_style
89
95
)
90
96
@@ -96,40 +102,41 @@ def _get_decoded_token(name):
96
102
97
103
@_need_request_context
98
104
def get_user_data ():
99
- jwks_url = _os .getenv (' DASH_JWKS_URL' )
100
- info_url = _os .getenv (' DASH_USER_INFO_URL' )
105
+ jwks_url = _os .getenv (" DASH_JWKS_URL" )
106
+ info_url = _os .getenv (" DASH_USER_INFO_URL" )
101
107
if not jwks_url :
102
- return _json .loads (_flask .request .headers .get (' Plotly-User-Data' , "{}" ))
108
+ return _json .loads (_flask .request .headers .get (" Plotly-User-Data" , "{}" ))
103
109
try :
104
110
jwks_client = UaPyJWKClient (jwks_url )
105
111
106
- token = _get_decoded_token (' kcIdToken' )
112
+ token = _get_decoded_token (" kcIdToken" )
107
113
signing_key = jwks_client .get_signing_key_from_jwt (token )
108
114
109
115
info = _jwt .decode (
110
116
token ,
111
117
signing_key .key ,
112
- algorithms = [signing_key ._jwk_data .get (' alg' , ' RSA256' )],
113
- audience = _os .getenv (' DASH_AUD' , "dash" ),
114
- options = {' verify_exp' : True },
118
+ algorithms = [signing_key ._jwk_data .get (" alg" , " RSA256" )],
119
+ audience = _os .getenv (" DASH_AUD" , "dash" ),
120
+ options = {" verify_exp" : True },
115
121
)
116
122
if info_url :
117
- tok = _get_decoded_token (' kcToken' )
118
- authorization = f' Bearer { tok .decode ()} '
123
+ tok = _get_decoded_token (" kcToken" )
124
+ authorization = f" Bearer { tok .decode ()} "
119
125
response = _requests .get (
120
126
info_url ,
121
127
headers = {
122
- 'User-Agent' : ua_string ,
123
- 'Authorization' : authorization ,
124
- }
128
+ "User-Agent" : ua_string ,
129
+ "Authorization" : authorization ,
130
+ },
131
+ timeout = 10 ,
125
132
)
126
133
response .raise_for_status ()
127
134
data = response .json ()
128
135
info .update (data )
129
136
130
137
return info
131
138
except Exception as e :
132
- print (' JWT decode error: ' + repr (e ))
139
+ print (" JWT decode error: " + repr (e ))
133
140
return {}
134
141
135
142
@@ -142,9 +149,9 @@ def get_username():
142
149
:rtype: str
143
150
"""
144
151
data = get_user_data ()
145
- if not _os .getenv (' DASH_JWKS_URL' ):
146
- return data .get (' username' )
147
- return data .get (' preferred_username' )
152
+ if not _os .getenv (" DASH_JWKS_URL" ):
153
+ return data .get (" username" )
154
+ return data .get (" preferred_username" )
148
155
149
156
150
157
@_need_request_context
@@ -156,9 +163,9 @@ def get_kerberos_ticket_cache():
156
163
"""
157
164
data = get_user_data ()
158
165
159
- expiry_str = data [' kerberos_ticket_expiry' ]
160
- expiry = _dt .datetime .strptime (expiry_str , ' %Y-%m-%dT%H:%M:%SZ' )
166
+ expiry_str = data [" kerberos_ticket_expiry" ]
167
+ expiry = _dt .datetime .strptime (expiry_str , " %Y-%m-%dT%H:%M:%SZ" )
161
168
if expiry < _dt .datetime .utcnow ():
162
- raise Exception (' Kerberos ticket has expired.' )
169
+ raise Exception (" Kerberos ticket has expired." )
163
170
164
- return _b64 .b64decode (data [' kerberos_ticket_cache' ])
171
+ return _b64 .b64decode (data [" kerberos_ticket_cache" ])
0 commit comments