Client unit tests

This commit is contained in:
Éloi Rivard 2020-08-26 15:37:15 +02:00
parent c42c139205
commit d94f7a4988
8 changed files with 127 additions and 22 deletions

View file

@ -4,5 +4,5 @@
- User "Manage my permissions" screen
- Admin tokens screen
- Admin codes screen
- Admin client screen unit tests
- Limit login attempts by time interval
- Cleanup LDAP connections

View file

@ -87,6 +87,7 @@ def app(slapd_server):
"BIND_DN": slapd_server.root_dn,
"BIND_PW": slapd_server.root_pw,
"USER_FILTER": "(|(uid={login})(cn={login}))",
"ADMIN_FILTER": "uid=admin",
},
"JWT": {
"KEY": "secret-key",
@ -155,6 +156,18 @@ def user(app, slapd_connection):
return u
@pytest.fixture
def admin(app, slapd_connection):
u = User(
cn="Jane Doe",
sn="Doe",
uid="admin",
userpassword="{SSHA}Vmgh2jkD0idX3eZHf8RzGos31oerjGiU",
)
u.save(slapd_connection)
return u
@pytest.fixture
def token(slapd_connection, client, user):
t = Token(
@ -176,3 +189,10 @@ def logged_user(user, testclient):
with testclient.session_transaction() as sess:
sess["user_dn"] = user.dn
return user
@pytest.fixture
def logged_admin(admin, testclient):
with testclient.session_transaction() as sess:
sess["user_dn"] = admin.dn
return admin

84
tests/test_admin.py Normal file
View file

@ -0,0 +1,84 @@
from web.models import Client
def test_no_logged_no_access(testclient):
testclient.get("/client", status=403)
def test_no_admin_no_access(testclient, logged_user):
testclient.get("/client", status=403)
def test_client_list(testclient, client, logged_admin):
res = testclient.get("/client")
assert client.oauthClientName in res.text
def test_client_add(testclient, logged_admin, slapd_connection):
res = testclient.get("/client/add")
data = {
"oauthClientName": "foobar",
"oauthClientContact": "foo@bar.com",
"oauthClientURI": "https://foo.bar",
"oauthRedirectURIs": ["https:/foo.bar/callback"],
"oauthGrantType": ["password", "authorization_code"],
"oauthScope": "openid profile",
"oauthResponseType": ["code", "token"],
"oauthTokenEndpointAuthMethod": "none",
"oauthLogoURI": "https://foo.bar/logo.png",
"oauthTermsOfServiceURI": "https://foo.bar/tos",
"oauthPolicyURI": "https://foo.bar/policy",
"oauthSoftwareID": "software",
"oauthSoftwareVersion": "1",
"oauthJWK": "jwk",
"oauthJWKURI": "https://foo.bar/jwks.json",
}
for k, v in data.items():
res.form[k] = v
res = res.form.submit()
assert 302 == res.status_code
res = res.follow()
assert 200 == res.status_code
client_id = res.forms["readonly"]["oauthClientID"].value
client = Client.get(client_id, conn=slapd_connection)
for k, v in data.items():
client_value = getattr(client, k)
if k == "oauthScope":
assert v == " ".join(client_value)
else:
assert v == client_value
def test_client_edit(testclient, client, logged_admin, slapd_connection):
res = testclient.get("/client/edit/" + client.oauthClientID)
data = {
"oauthClientName": "foobar",
"oauthClientContact": "foo@bar.com",
"oauthClientURI": "https://foo.bar",
"oauthRedirectURIs": ["https:/foo.bar/callback"],
"oauthGrantType": ["password", "authorization_code"],
"oauthScope": "openid profile",
"oauthResponseType": ["code", "token"],
"oauthTokenEndpointAuthMethod": "none",
"oauthLogoURI": "https://foo.bar/logo.png",
"oauthTermsOfServiceURI": "https://foo.bar/tos",
"oauthPolicyURI": "https://foo.bar/policy",
"oauthSoftwareID": "software",
"oauthSoftwareVersion": "1",
"oauthJWK": "jwk",
"oauthJWKURI": "https://foo.bar/jwks.json",
}
for k, v in data.items():
res.forms["clientadd"][k] = v
res = res.forms["clientadd"].submit()
assert 200 == res.status_code
client.reload(conn=slapd_connection)
for k, v in data.items():
client_value = getattr(client, k)
if k == "oauthScope":
assert v == " ".join(client_value)
else:
assert v == client_value

View file

@ -20,7 +20,7 @@ def index():
class ClientAdd(FlaskForm):
oauthClientName = wtforms.TextField(
oauthClientName = wtforms.StringField(
gettext("Name"),
validators=[wtforms.validators.DataRequired()],
render_kw={"placeholder": "Client Name"},
@ -52,7 +52,7 @@ class ClientAdd(FlaskForm):
],
default=["authorization_code", "refresh_token"],
)
oauthScope = wtforms.TextField(
oauthScope = wtforms.StringField(
gettext("Scope"),
validators=[wtforms.validators.Optional()],
default="openid profile",
@ -89,17 +89,17 @@ class ClientAdd(FlaskForm):
validators=[wtforms.validators.Optional()],
render_kw={"placeholder": "https://mydomain.tld/policy.html"},
)
oauthSoftwareID = wtforms.TextField(
oauthSoftwareID = wtforms.StringField(
gettext("Software ID"),
validators=[wtforms.validators.Optional()],
render_kw={"placeholder": "xyz"},
)
oauthSoftwareVersion = wtforms.TextField(
oauthSoftwareVersion = wtforms.StringField(
gettext("Software Version"),
validators=[wtforms.validators.Optional()],
render_kw={"placeholder": "1.0"},
)
oauthJWK = wtforms.TextField(
oauthJWK = wtforms.StringField(
gettext("JWK"),
validators=[wtforms.validators.Optional()],
render_kw={"placeholder": ""},

View file

@ -27,10 +27,8 @@ def admin_needed():
@wraps(view_function)
def decorator(*args, **kwargs):
user = current_user()
if not user:
if not user or not user.admin:
abort(403)
if not user.admin:
abort(404)
return view_function(*args, **kwargs)
return decorator

View file

@ -26,6 +26,7 @@ class User(LDAPObjectHelper):
if (
admin_filter
and user
and user.dn
and conn.search_s(user.dn, ldap.SCOPE_SUBTREE, admin_filter)
):

View file

@ -15,18 +15,20 @@
{% endwith %}
<div class="ui attached clearing segment">
<div class="ui form">
<form id="readonly">
<div class="field">
<label>{% trans %}ID{% endtrans %}</label>
<input type="text" value="{{ client.oauthClientID }}" readonly>
<input type="text" value="{{ client.oauthClientID }}" readonly name="oauthClientID">
</div>
<div class="field">
<label>{% trans %}Secret{% endtrans %}</label>
<input type="text" value="{{ client.oauthClientSecret }}" readonly>
<input type="text" value="{{ client.oauthClientSecret }}" readonly name="oauthClientSecret">
</div>
<div class="field">
<label>{% trans %}Issued at{% endtrans %}</label>
<input type="text" value="{{ client.issue_date }}" readonly>
<input type="text" value="{{ client.issue_date }}" readonly name="oauthIssueDate">
</div>
</form>
</div>
{{ sui.render_form(form, _("Confirm")) }}