forked from Github-Mirrors/canaille
Client unit tests
This commit is contained in:
parent
c42c139205
commit
d94f7a4988
8 changed files with 127 additions and 22 deletions
2
TODO.md
2
TODO.md
|
@ -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
|
||||
|
|
|
@ -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
84
tests/test_admin.py
Normal 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
|
|
@ -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": ""},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
):
|
||||
|
||||
|
|
|
@ -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")) }}
|
||||
|
|
Loading…
Reference in a new issue