Skip to content

Commit 10bb5fc

Browse files
committed
Added unit tests and updated requirements and docs
1 parent baaebd4 commit 10bb5fc

File tree

4 files changed

+110
-0
lines changed

4 files changed

+110
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77
## [Unreleased]
88
### Changed
99
- Uses flask `before_request` to protect all endpoints rather than protecting routes present at instantiation time
10+
- Allows user to use user-defined authorization python function instead of a dictionary/list of usernames and passwords
1011

1112
## [2.0.0] - 2023-03-10
1213
### Removed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,20 @@ USER_PWD = {
4141
}
4242
BasicAuth(app, USER_PWD)
4343
```
44+
45+
One can also use an authorization python function instead of a dictionary/list of usernames and passwords:
46+
47+
```python
48+
from dash import Dash
49+
from dash_auth import BasicAuth
50+
51+
def authorization_function(username, password):
52+
if (username == "hello") and (password == "world"):
53+
return True
54+
else:
55+
return False
56+
57+
58+
app = Dash(__name__)
59+
BasicAuth(app, auth_func = authorization_function)
60+
```

dev-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ dash[testing]>=2
22
requests[security]
33
flake8
44
flask
5+
pytest
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
from dash import Dash, Input, Output, dcc, html
2+
import requests
3+
import pytest
4+
5+
from dash_auth import basic_auth
6+
7+
TEST_USERS = {
8+
"valid": [
9+
["hello", "world"],
10+
["hello2", "wo:rld"]
11+
],
12+
"invalid": [
13+
["hello", "password"]
14+
],
15+
}
16+
17+
18+
# Test using auth_func instead of TEST_USERS directly
19+
def auth_function(username, password):
20+
if [username, password] in TEST_USERS["valid"]:
21+
return True
22+
else:
23+
return False
24+
25+
26+
def test_ba002_basic_auth_login_flow(dash_br, dash_thread_server):
27+
app = Dash(__name__)
28+
app.layout = html.Div([
29+
dcc.Input(id="input", value="initial value"),
30+
html.Div(id="output")
31+
])
32+
33+
@app.callback(Output("output", "children"), Input("input", "value"))
34+
def update_output(new_value):
35+
return new_value
36+
37+
basic_auth.BasicAuth(app, auth_func=auth_function)
38+
39+
dash_thread_server(app)
40+
base_url = dash_thread_server.url
41+
42+
def test_failed_views(url):
43+
assert requests.get(url).status_code == 401
44+
assert requests.get(url.strip("/") + "/_dash-layout").status_code == 401
45+
46+
test_failed_views(base_url)
47+
48+
for user, password in TEST_USERS["invalid"]:
49+
test_failed_views(base_url.replace("//", f"//{user}:{password}@"))
50+
51+
# Test login for each user:
52+
for user, password in TEST_USERS["valid"]:
53+
# login using the URL instead of the alert popup
54+
# selenium has no way of accessing the alert popup
55+
dash_br.driver.get(base_url.replace("//", f"//{user}:{password}@"))
56+
57+
# the username:password@host url doesn"t work right now for dash
58+
# routes, but it saves the credentials as part of the browser.
59+
# visiting the page again will use the saved credentials
60+
dash_br.driver.get(base_url)
61+
dash_br.wait_for_text_to_equal("#output", "initial value")
62+
63+
64+
# Test incorrect initialization of BasicAuth
65+
def both_dict_and_func(dash_br, dash_thread_server):
66+
app = Dash(__name__)
67+
app.layout = html.Div([
68+
dcc.Input(id="input", value="initial value"),
69+
html.Div(id="output")
70+
])
71+
72+
basic_auth.BasicAuth(app, TEST_USERS["valid"], auth_func=auth_function)
73+
return True
74+
75+
76+
def both_no_auth_func_or_dict(dash_br, dash_thread_server):
77+
app = Dash(__name__)
78+
app.layout = html.Div([
79+
dcc.Input(id="input", value="initial value"),
80+
html.Div(id="output")
81+
])
82+
basic_auth.BasicAuth(app)
83+
return True
84+
85+
86+
def test_ba003_basic_auth_login_flow(dash_br, dash_thread_server):
87+
with pytest.raises(ValueError):
88+
both_dict_and_func(dash_br, dash_thread_server)
89+
with pytest.raises(ValueError):
90+
both_no_auth_func_or_dict(dash_br, dash_thread_server)
91+
return

0 commit comments

Comments
 (0)