sso/sso/views.py

143 lines
3.9 KiB
Python

from flask import (
Blueprint,
render_template,
abort,
redirect,
request,
url_for,
flash,
jsonify,
current_app,
)
from flask_login import login_required, current_user, login_user, logout_user
from sso.directory import LDAPUserProxy, check_credentials
from sso.models import db, Token
from sso.forms import LoginForm
from sso.oauth2 import authorization, require_oauth
from authlib.oauth2 import OAuth2Error
from authlib.integrations.flask_oauth2 import current_token
bp = Blueprint("sso", __name__)
@bp.route("/")
@bp.route("/profile")
@login_required
def profile():
return render_template(
"profile.html",
tokens=Token.query.filter(Token.user_id == current_user.username),
)
@bp.route("/token/<int:id>/revoke", methods=["POST"])
@login_required
def token_revoke(id):
token = Token.query.filter(
Token.user_id == current_user.username, Token.id == id
).first()
if not token:
abort(404)
db.session.delete(token)
db.session.commit()
return redirect("/")
@bp.route("/login", methods=["GET", "POST"])
def login():
form = LoginForm()
next = request.args.get("next")
if form.validate_on_submit():
username, password = form.data["username"], form.data["password"]
if not check_credentials(username, password):
flash("Invalid username or password")
return render_template("login_oauth.html", form=form, next=next)
login_user(LDAPUserProxy(username), form.data["remember"])
flash("Logged in successfully.")
return redirect(next or url_for("profile"))
return render_template("login_oauth.html", form=form, next=next)
@bp.route("/logout")
def logout():
logout_user()
return redirect("/")
@bp.route("/oauth/authorize", methods=["GET", "POST"])
@login_required
def authorize():
if request.method == "GET":
try:
grant = authorization.validate_consent_request(end_user=current_user)
except OAuth2Error as error:
return jsonify(dict(error.get_body()))
return render_template(
"oauthorize.html", user=current_user, grant=grant, client=grant.client
)
if request.form["confirm"]:
grant_user = current_user
else:
grant_user = None
return authorization.create_authorization_response(grant_user=grant_user)
@bp.route("/oauth/token", methods=["POST"])
def issue_token():
return authorization.create_token_response()
# HSWAW specific endpoint
@bp.route("/api/profile")
@bp.route("/api/1/profile")
@require_oauth("profile:read")
def api_profile():
user = current_token.user
print(user.email, user.username, user.gecos, user.phone, user.personal_email)
return jsonify(
email=user.email,
username=user.username,
gecos=user.gecos,
phone=user.phone,
personal_email=user.personal_email,
)
# OpenIDConnect userinfo
@bp.route("/api/1/userinfo")
# @require_oauth("profile:read")
@require_oauth("openid")
def api_userinfo():
user = current_token.user
# user = LDAPUserProxy(flask.request.oauth.user)
return jsonify(
sub=user.username,
name=user.gecos,
email=user.email,
preferred_username=user.username,
nickname=user.username,
)
@bp.route("/.well-known/openid-configuration")
def openid_configuration():
return jsonify(
{
"issuer": current_app.config['JWT_CONFIG']['iss'],
"authorization_endpoint": url_for(".authorize", _external=True),
"token_endpoint": url_for(".issue_token", _external=True),
"userinfo_endpoint": url_for(".api_userinfo", _external=True),
"response_types_supported": ["code", "id_token", "token id_token"],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post",
],
}
)