diff --git a/trurt/account/profiles.py b/trurt/account/profiles.py index b9725ef25a0630f598dc75921ee7ea1242168069..6eb8f0a9021d8e861bc3acaad0a810ea102c98bb 100644 --- a/trurt/account/profiles.py +++ b/trurt/account/profiles.py @@ -1,4 +1,5 @@ from trurt.account import blueprint +from trurt.sso import forms as sso_forms import flask_login import flask @@ -7,3 +8,18 @@ import flask @blueprint.route("/profiles") def profiles(): return flask.render_template("account_profiles.html") + + +@blueprint.route("/pick") +@flask_login.login_required +def pick(): + service_spn = flask.request.args.get("service_spn") or flask.abort(404) + service = models.Service.query.filter_by(spn=service_spn).first_or_404() + profiles = models.Profile.query.filter_by( + service_id=service.id, + user_id=flask_login.current_user.id + ) + form = sso_forms.SSOValidateForm() + return flask.render_template("sso_pick.html", + service=service, profiles=profiles, form=form, + action=utils.url_or_intent("account.status")) diff --git a/trurt/account/settings.py b/trurt/account/settings.py index 8d302e14de0545d8eb4458119f6b565c66e4a778..a16c1e892d61c8ef31cc915c5fcd3040e437b6a7 100644 --- a/trurt/account/settings.py +++ b/trurt/account/settings.py @@ -5,10 +5,12 @@ import flask @blueprint.route("/home") +@flask_login.login_required def home(): return flask.render_template("account_home.html") @blueprint.route("/password") +@flask_login.login_required def password(): return flask.render_template("account_password.html") diff --git a/trurt/account/templates/account_home.html b/trurt/account/templates/account_home.html index 94d9808cc760156cb7ab46e326c0267f3406125e..70c9b9628422e9cae97ae0e4493f1c24d7ba792c 100644 --- a/trurt/account/templates/account_home.html +++ b/trurt/account/templates/account_home.html @@ -1 +1,4 @@ {% extends "base.html" %} + +{% block title %}My account{% endblock %} +{% block subtitle %}overview of {{ current_user.username }}{% endblock %} diff --git a/trurt/sso/__init__.py b/trurt/sso/__init__.py index 77564400fe2272a327df32418d4c02ab0c744a04..43c4d023d65a7ba4da1d6d65a79ab9b66188fd4c 100644 --- a/trurt/sso/__init__.py +++ b/trurt/sso/__init__.py @@ -3,4 +3,4 @@ from flask import Blueprint blueprint = Blueprint("sso", __name__, template_folder="templates") -from trurt.sso import saml, oidc, profile +from trurt.sso import saml, oidc diff --git a/trurt/sso/profile.py b/trurt/sso/profile.py deleted file mode 100644 index c015812ff09b44909e1f80cf5d88352b7388ffe2..0000000000000000000000000000000000000000 --- a/trurt/sso/profile.py +++ /dev/null @@ -1,20 +0,0 @@ -from trurt.sso import blueprint, forms -from trurt import models, utils - -import flask_login -import flask - - -@blueprint.route("/pick") -@flask_login.login_required -def pick(): - service_spn = flask.request.args.get("service_spn") or flask.abort(404) - service = models.Service.query.filter_by(spn=service_spn).first_or_404() - profiles = models.Profile.query.filter_by( - service_id=service.id, - user_id=flask_login.current_user.id - ) - form = forms.SSOValidateForm() - return flask.render_template("sso_pick.html", - service=service, profiles=profiles, form=form, - action=utils.url_or_intent("account.status")) diff --git a/trurt/sso/saml.py b/trurt/sso/saml.py index 44f8b3c9a4fb00c9c0d145a5baa3f2f280d604d3..220d8b1e7f2ddd21af3a05ce6ffaaa3d0a86dd16 100644 --- a/trurt/sso/saml.py +++ b/trurt/sso/saml.py @@ -92,11 +92,11 @@ class SecurityContext(sigver.SecurityContext): return lxml.etree.tostring(xml) -@blueprint.route('/saml/<service_spn>/redirect') -def redirect(service_spn): - service = models.Service.query.filter_by(spn=service_spn).first_or_404() +@blueprint.route('/saml/<service_uuid>/redirect') +def redirect(service_uuid): + service = models.Service.query.get(service_uuid) or flask.abort(404) return flask.redirect(utils.url_for( - "sso.pick", intent="sso.reply", service_spn=service_spn, + "account.pick", intent="sso.reply", service_spn=service_spn, )) @@ -104,11 +104,10 @@ def redirect(service_spn): def reply(): # First check the service and picked profile form = forms.SSOValidateForm() - if not form.validate(): - return flask.abort(403) - service = models.Service.query.get(form.service_id.data) - profile = models.Profile.query.get(form.profile_id.data) - if not (profile.service_id == service.id and profile.user_id == flask_login.current_user.id): + form.validate() or flask.abort(403) + service = models.Service.query.get(service_uuid) or flask.abort(404) + profile = models.Profile.query.get(profile_uuid) or flask.abort(404) + if not (profile.user is flask_login.current_user and profile.service is service): return flask.abort(403) # Parse the authentication request idp = server.Server(config=(MetaData.get_config(service))) @@ -117,7 +116,7 @@ def reply(): if not service.config["acs"] == request.message.issuer.text: return flask.abort(403) # Provide a SAML response - response = idp.create_authn_response( + response = idp.cclass_refreate_authn_response( identity={ 'uid': profile.username, 'email': profile.email @@ -130,6 +129,6 @@ def reply(): sign_assertion=True ) return flask.render_template('sso_redirect.html', target=service.config["acs"], data={ - 'SAMLResponse':base64.b64encode(response).decode('ascii'), - 'RelayState':flask.request.args.get('RelayState', '') + 'SAMLResponse': base64.b64encode(response).decode('ascii'), + 'RelayState': flask.request.args.get('RelayState', '') }) diff --git a/trurt/utils.py b/trurt/utils.py index d96b817b3b0a924b7b25f80f9d6abdb14235f327..dc5cc549cbbe764be14d61de92137dfe943a0744 100644 --- a/trurt/utils.py +++ b/trurt/utils.py @@ -10,6 +10,7 @@ from werkzeug.contrib import fixers # Login configuration login = flask_login.LoginManager() login.login_view = "account.login" +INTENTS = "intents" @login.unauthorized_handler def handle_needs_login(): @@ -23,21 +24,25 @@ def url_for(endpoint, intent=None, *args, **kwargs): an intent """ query_string = dict(flask.request.args) - query_string.update(kwargs) - if "intents" in query_string and intent is not None: - query_string["intents"] += ":" + intent - elif "intents" not in query_string and intent is not None: - query_string["intents"] = intent + for key, value in kwargs.items(): + if value is None and key in query_string: + del query_string[key] + elif value is not None: + query_string[key] = value + if INTENTS in query_string and intent is not None: + query_string[INTENTS] += ":" + intent + elif INTENTS not in query_string and intent is not None: + query_string[INTENTS] = intent return flask.url_for(endpoint, *args, **query_string) def url_or_intent(endpoint): """ Return the latest intent, or the endpoint url if none """ - intents = flask.request.args.get("intents", "") + intents = flask.request.args.get(INTENTS, "") if intents: intents = intents.split(":") - return url_for(intents[-1], intents=":".join(intents[:-1])) + return url_for(intents.pop(0), intents=":".join(intents) or None) else: return flask.url_for(endpoint)