forked from Github-Mirrors/canaille
Token list and auth code list views
This commit is contained in:
parent
d94f7a4988
commit
f2da1e87db
13 changed files with 227 additions and 3 deletions
|
@ -144,6 +144,26 @@ def client(app, slapd_connection):
|
|||
return c
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def authorization(app, slapd_connection):
|
||||
a = AuthorizationCode(
|
||||
oauthCode="my-code",
|
||||
oauthClientID="client-id",
|
||||
oauthSubject="user-id",
|
||||
oauthRedirectURI="https://foo.bar/callback",
|
||||
oauthResponseType="code",
|
||||
oauthScope="openid profile",
|
||||
oauthNonce="nonce",
|
||||
oauthAuthorizationDate="20200101000000Z",
|
||||
oauthAuthorizationLifetime="3600",
|
||||
oauthCodeChallenge="challenge",
|
||||
oauthCodeChallengeMethod="method",
|
||||
oauthRevoked="FALSE",
|
||||
)
|
||||
a.save(slapd_connection)
|
||||
return a
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def user(app, slapd_connection):
|
||||
u = User(
|
||||
|
|
17
tests/test_code_admin.py
Normal file
17
tests/test_code_admin.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
def test_no_logged_no_access(testclient):
|
||||
testclient.get("/authorization", status=403)
|
||||
|
||||
|
||||
def test_no_admin_no_access(testclient, logged_user):
|
||||
testclient.get("/authorization", status=403)
|
||||
|
||||
|
||||
def test_authorizaton_list(testclient, authorization, logged_admin):
|
||||
res = testclient.get("/authorization")
|
||||
assert authorization.oauthCode in res.text
|
||||
|
||||
|
||||
def test_authorizaton_view(testclient, authorization, logged_admin):
|
||||
res = testclient.get("/authorization/" + authorization.oauthCode)
|
||||
for attr in authorization.may + authorization.must:
|
||||
assert attr in res.text
|
17
tests/test_token_admin.py
Normal file
17
tests/test_token_admin.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
def test_no_logged_no_access(testclient):
|
||||
testclient.get("/token", status=403)
|
||||
|
||||
|
||||
def test_no_admin_no_access(testclient, logged_user):
|
||||
testclient.get("/token", status=403)
|
||||
|
||||
|
||||
def test_token_list(testclient, token, logged_admin):
|
||||
res = testclient.get("/token")
|
||||
assert token.oauthAccessToken in res.text
|
||||
|
||||
|
||||
def test_token_view(testclient, token, logged_admin):
|
||||
res = testclient.get("/token/" + token.oauthAccessToken)
|
||||
for attr in token.may + token.must:
|
||||
assert attr in res.text
|
|
@ -1,7 +1,7 @@
|
|||
import ldap
|
||||
import os
|
||||
import toml
|
||||
from . import routes, clients, oauth
|
||||
from . import routes, clients, oauth, tokens, authorizations
|
||||
|
||||
from flask import Flask, g, request, render_template
|
||||
from flask_babel import Babel
|
||||
|
@ -38,6 +38,8 @@ def setup_app(app):
|
|||
app.register_blueprint(routes.bp)
|
||||
app.register_blueprint(oauth.bp, url_prefix="/oauth")
|
||||
app.register_blueprint(clients.bp, url_prefix="/client")
|
||||
app.register_blueprint(tokens.bp, url_prefix="/token")
|
||||
app.register_blueprint(authorizations.bp, url_prefix="/authorization")
|
||||
|
||||
babel = Babel(app)
|
||||
|
||||
|
|
20
web/authorizations.py
Normal file
20
web/authorizations.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from flask import Blueprint, render_template
|
||||
from .models import AuthorizationCode
|
||||
from .flaskutils import admin_needed
|
||||
|
||||
|
||||
bp = Blueprint(__name__, "authorizations")
|
||||
|
||||
|
||||
@bp.route("/")
|
||||
@admin_needed()
|
||||
def index():
|
||||
authorizations = AuthorizationCode.filter()
|
||||
return render_template("authorization_list.html", authorizations=authorizations)
|
||||
|
||||
|
||||
@bp.route("/<authorization_id>", methods=["GET", "POST"])
|
||||
@admin_needed()
|
||||
def view(authorization_id):
|
||||
authorization = AuthorizationCode.get(authorization_id)
|
||||
return render_template("authorization_view.html", authorization=authorization)
|
|
@ -143,6 +143,10 @@ class AuthorizationCode(LDAPObjectHelper, AuthorizationCodeMixin):
|
|||
base = "ou=authorizations"
|
||||
id = "oauthCode"
|
||||
|
||||
@property
|
||||
def issue_date(self):
|
||||
return datetime.datetime.strptime(self.oauthIssueDate, "%Y%m%d%H%M%SZ")
|
||||
|
||||
def get_redirect_uri(self):
|
||||
return self.oauthRedirectURI
|
||||
|
||||
|
@ -175,6 +179,10 @@ class Token(LDAPObjectHelper, TokenMixin):
|
|||
base = "ou=tokens"
|
||||
id = "oauthAccessToken"
|
||||
|
||||
@property
|
||||
def issue_date(self):
|
||||
return datetime.datetime.strptime(self.oauthIssueDate, "%Y%m%d%H%M%SZ")
|
||||
|
||||
@property
|
||||
def revoked(self):
|
||||
return self.oauthRevoked in ("yes", "YES", 1, "on", "ON", "TRUE", "true")
|
||||
|
|
33
web/templates/authorization_list.html
Normal file
33
web/templates/authorization_list.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block style %}
|
||||
<link href="/static/datatables/jquery.dataTables.min.css" rel="stylesheet">
|
||||
<link href="/static/datatables/dataTables.semanticui.min.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script src="/static/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="/static/datatables/dataTables.semanticui.min.js"></script>
|
||||
<script src="/static/js/users.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
<th>{% trans %}Token{% endtrans %}</th>
|
||||
<th>{% trans %}Client{% endtrans %}</th>
|
||||
<th>{% trans %}Subject{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
</thead>
|
||||
{% for authorization in authorizations %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('web.authorizations.view', authorization_id=authorization.oauthCode) }}">{{ authorization.oauthCode }}</a></td>
|
||||
<td><a href="{{ url_for('web.clients.edit', client_id=authorization.oauthClientID) }}">{{ authorization.oauthClientID }}</a></td>
|
||||
<td>{{ authorization.oauthSubject }}</td>
|
||||
<td>{{ authorization.issue_date }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
27
web/templates/authorization_view.html
Normal file
27
web/templates/authorization_view.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends 'base.html' %}
|
||||
{% import 'fomanticui.j2' as sui %}
|
||||
|
||||
{% block content %}
|
||||
<div class="loginform">
|
||||
<h3 class="ui top attached header">
|
||||
{% trans %}View a authorization{% endtrans %}
|
||||
</h3>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% for category, message in messages %}
|
||||
<div class="ui attached message {{ category }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
<div class="ui attached clearing segment">
|
||||
<ul>
|
||||
{% for attr in authorization.may %}
|
||||
<li>{{ attr }}: {{ authorization[attr] }}</li>
|
||||
{% endfor %}
|
||||
{% for attr in authorization.must %}
|
||||
<li>{{ attr }}: {{ authorization[attr] }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -37,11 +37,11 @@
|
|||
<i class="plug icon"></i>
|
||||
{% trans %}Clients{% endtrans %}
|
||||
</a>
|
||||
<a class="item" href="/">
|
||||
<a class="item" href="{{ url_for('web.tokens.index') }}">
|
||||
<i class="key icon"></i>
|
||||
{% trans %}Tokens{% endtrans %}
|
||||
</a>
|
||||
<a class="item" href="/">
|
||||
<a class="item" href="{{ url_for('web.authorizations.index') }}">
|
||||
<i class="user secret icon"></i>
|
||||
{% trans %}Codes{% endtrans %}
|
||||
</a>
|
||||
|
|
33
web/templates/token_list.html
Normal file
33
web/templates/token_list.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block style %}
|
||||
<link href="/static/datatables/jquery.dataTables.min.css" rel="stylesheet">
|
||||
<link href="/static/datatables/dataTables.semanticui.min.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script src="/static/datatables/jquery.dataTables.min.js"></script>
|
||||
<script src="/static/datatables/dataTables.semanticui.min.js"></script>
|
||||
<script src="/static/js/users.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<table class="ui table">
|
||||
<thead>
|
||||
<th>{% trans %}Token{% endtrans %}</th>
|
||||
<th>{% trans %}Client{% endtrans %}</th>
|
||||
<th>{% trans %}Subject{% endtrans %}</th>
|
||||
<th>{% trans %}Created{% endtrans %}</th>
|
||||
</thead>
|
||||
{% for token in tokens %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('web.tokens.view', token_id=token.oauthAccessToken) }}">{{ token.oauthAccessToken }}</a></td>
|
||||
<td><a href="{{ url_for('web.clients.edit', client_id=token.oauthClientID) }}">{{ token.oauthClientID }}</a></td>
|
||||
<td>{{ token.oauthSubject }}</td>
|
||||
<td>{{ token.issue_date }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
27
web/templates/token_view.html
Normal file
27
web/templates/token_view.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
{% extends 'base.html' %}
|
||||
{% import 'fomanticui.j2' as sui %}
|
||||
|
||||
{% block content %}
|
||||
<div class="loginform">
|
||||
<h3 class="ui top attached header">
|
||||
{% trans %}View a token{% endtrans %}
|
||||
</h3>
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% for category, message in messages %}
|
||||
<div class="ui attached message {{ category }}">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
<div class="ui attached clearing segment">
|
||||
<ul>
|
||||
{% for attr in token.may %}
|
||||
<li>{{ attr }}: {{ token[attr] }}</li>
|
||||
{% endfor %}
|
||||
{% for attr in token.must %}
|
||||
<li>{{ attr }}: {{ token[attr] }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
20
web/tokens.py
Normal file
20
web/tokens.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from flask import Blueprint, render_template
|
||||
from .models import Token
|
||||
from .flaskutils import admin_needed
|
||||
|
||||
|
||||
bp = Blueprint(__name__, "tokens")
|
||||
|
||||
|
||||
@bp.route("/")
|
||||
@admin_needed()
|
||||
def index():
|
||||
tokens = Token.filter()
|
||||
return render_template("token_list.html", tokens=tokens)
|
||||
|
||||
|
||||
@bp.route("/<token_id>", methods=["GET", "POST"])
|
||||
@admin_needed()
|
||||
def view(token_id):
|
||||
token = Token.get(token_id)
|
||||
return render_template("token_view.html", token=token)
|
Loading…
Reference in a new issue