refactor, implement next attribute, for forward, service need user approve berfore redirect

This commit is contained in:
TuxCoder 2020-05-13 17:04:22 +02:00
parent 77962edd15
commit 5037fe4def
8 changed files with 82 additions and 40 deletions

View file

@ -144,9 +144,9 @@ def oidc_provider_init_app(name=None):
app.babel = Babel(app) app.babel = Babel(app)
app.login_manager = LoginManager(app) app.login_manager = LoginManager(app)
init_login_manager(app)
from .views import oidc_provider_views, auth_views, frontend_views from .views import oidc_provider_views, auth_views, frontend_views, init_login_manager
init_login_manager(app)
app.register_blueprint(oidc_provider_views) app.register_blueprint(oidc_provider_views)
app.register_blueprint(auth_views) app.register_blueprint(auth_views)
app.register_blueprint(frontend_views) app.register_blueprint(frontend_views)
@ -171,16 +171,3 @@ def oidc_provider_init_app(name=None):
return app return app
def init_login_manager(app):
@app.login_manager.user_loader
def user_loader(username):
return model.User.query().by_username(username)
@app.login_manager.request_loader
def request_loader(request):
pass
@app.login_manager.unauthorized_handler
def unauthorized():
return redirect(url_for('auth.login'))

View file

@ -32,3 +32,7 @@ class TOTPForm(FlaskForm):
class TOTPDeleteForm(FlaskForm): class TOTPDeleteForm(FlaskForm):
submit = SubmitField(gettext('Delete')) submit = SubmitField(gettext('Delete'))
class OidcAuthenticationConfirm(FlaskForm):
submit = SubmitField(gettext('Continue'))

View file

@ -1,5 +1,5 @@
# pylint: disable=unused-import # pylint: disable=unused-import
from .oidc import oidc_provider_views from .oidc import oidc_provider_views
from .auth import auth_views from .auth import auth_views, init_login_manager
from .frontend import frontend_views from .frontend import frontend_views

View file

@ -18,7 +18,8 @@ from flask import Blueprint, render_template, request, url_for
from flask_login import login_required, login_user, logout_user from flask_login import login_required, login_user, logout_user
from werkzeug.utils import redirect from werkzeug.utils import redirect
import logging import logging
from urllib.parse import urlparse
from base64 import b64decode, b64encode
from ..model import User, SecurityUser from ..model import User, SecurityUser
from ..form.login import LoginForm from ..form.login import LoginForm
@ -29,6 +30,19 @@ from .oidc import do_logout
auth_views = Blueprint('auth', __name__, url_prefix='') auth_views = Blueprint('auth', __name__, url_prefix='')
def init_login_manager(app):
@app.login_manager.user_loader
def user_loader(username):
return User.query().by_username(username)
@app.login_manager.request_loader
def request_loader(request):
pass
@app.login_manager.unauthorized_handler
def unauthorized():
return redirect(url_for('auth.login', next=b64encode(request.url.encode())))
@auth_views.route('/login', methods=['GET', 'POST']) @auth_views.route('/login', methods=['GET', 'POST'])
def login(): def login():
form = LoginForm() form = LoginForm()
@ -36,7 +50,7 @@ def login():
user = User.query().by_username(form.data['name']) user = User.query().by_username(form.data['name'])
session['username'] = str(user.username) session['username'] = str(user.username)
session['auth_providers'] = [] session['auth_providers'] = []
return redirect(url_for('auth.login_auth')) return redirect(url_for('auth.login_auth', next=flask.request.args.get('next')))
return render_template('frontend/login.html.j2', form=form) return render_template('frontend/login.html.j2', form=form)
@ -44,7 +58,7 @@ def login():
def login_auth(): def login_auth():
if 'username' not in session: if 'username' not in session:
return redirect(url_for('auth.login')) return redirect(url_for('auth.login'))
auth_forms = [] auth_forms = {}
user = User.query().by_username(session['username']) user = User.query().by_username(session['username'])
for auth_provider in AUTH_PROVIDER_LIST: for auth_provider in AUTH_PROVIDER_LIST:
form = auth_provider.get_form() form = auth_provider.get_form()
@ -53,14 +67,20 @@ def login_auth():
session['auth_providers'].append(auth_provider.get_name()) session['auth_providers'].append(auth_provider.get_name())
if auth_provider.get_name() not in session['auth_providers']: if auth_provider.get_name() not in session['auth_providers']:
auth_forms.append(form) auth_forms[auth_provider.get_name()]=form
if len(session['auth_providers']) >= 2: if len(session['auth_providers']) >= 2:
login_user(SecurityUser(session['username'])) login_user(SecurityUser(session['username']))
# TODO use this var # TODO use this var
_next = request.args.get('next') _next = None
return redirect(url_for('frontend.index')) try:
print(auth_forms) _next_url = urlparse(b64decode(request.args.get('next')).decode())
_host_url = urlparse(request.url)
if _next_url.scheme == _host_url.scheme and _next_url.netloc == _host_url.netloc :
_next = _next_url.geturl()
except Exception as e:
raise e
return redirect(_next or url_for('frontend.index'))
return render_template('frontend/login_auth.html.j2', forms=auth_forms) return render_template('frontend/login_auth.html.j2', forms=auth_forms)

View file

@ -1,7 +1,7 @@
from urllib.parse import urlencode, parse_qs from urllib.parse import urlencode, parse_qs
import flask import flask
from flask import Blueprint, redirect from flask import Blueprint, redirect, request
from flask import current_app, session from flask import current_app, session
from flask import jsonify from flask import jsonify
from flask.helpers import make_response from flask.helpers import make_response
@ -14,6 +14,8 @@ from pyop.exceptions import InvalidAuthenticationRequest, InvalidAccessToken, In
InvalidSubjectIdentifier, InvalidClientRegistrationRequest InvalidSubjectIdentifier, InvalidClientRegistrationRequest
from pyop.util import should_fragment_encode from pyop.util import should_fragment_encode
from ..form.frontend import OidcAuthenticationConfirm
oidc_provider_views = Blueprint('oidc_provider', __name__, url_prefix='') oidc_provider_views = Blueprint('oidc_provider', __name__, url_prefix='')
@ -29,10 +31,17 @@ def registration_endpoint():
@oidc_provider_views.route('/authentication', methods=['GET']) @oidc_provider_views.route('/authentication', methods=['GET'])
@login_required @login_required
def authentication_endpoint_confirm():
form = OidcAuthenticationConfirm()
return render_template('frontend/oidc_authentication.html.j2', form=form)
@oidc_provider_views.route('/authentication', methods=['POST'])
@login_required
def authentication_endpoint(): def authentication_endpoint():
# parse authentication request # parse authentication request
print(flask.request) print(request)
print(flask.request.headers) print(request.headers)
try: try:
auth_req = current_app.provider.parse_authentication_request(urlencode(flask.request.args), auth_req = current_app.provider.parse_authentication_request(urlencode(flask.request.args),
flask.request.args) flask.request.args)
@ -45,7 +54,7 @@ def authentication_endpoint():
# show error to user # show error to user
return make_response('Something went wrong: {}'.format(str(e)), 400) return make_response('Something went wrong: {}'.format(str(e)), 400)
# automagic authentication # automatically authentication
authn_response = current_app.provider.authorize(auth_req, str(current_user.username)) authn_response = current_app.provider.authorize(auth_req, str(current_user.username))
response_url = authn_response.request(auth_req['redirect_uri'], should_fragment_encode(auth_req)) response_url = authn_response.request(auth_req['redirect_uri'], should_fragment_encode(auth_req))
return redirect(response_url, 303) return redirect(response_url, 303)

View file

@ -4,15 +4,8 @@
{% block content %} {% block content %}
<form method="POST" action="/login">
{{ form.csrf_token }} {{ render_form(form) }}
<div class="form-group row">
<label class="col-sm-2 col-form-label">{{ form.name.label }} </label>
<div class="col-sm-10">
{{ form.name(size=20) }}
</div>
</div>
{{ form.submit() }}
</form>
{% endblock %} {% endblock %}

View file

@ -4,9 +4,21 @@
{% block content %} {% block content %}
{% for form in forms %} <ul class="nav nav-tabs" id="myTab" role="tablist">
{{ render_form(form) }} {% for auth_name in forms.keys() %}
{% endfor %} <li class="nav-item">
<a class="nav-link{{' active' if loop.first else ''}}" id="home-tab" data-toggle="tab" href="#{{ auth_name }}" role="tab" aria-controls="home" aria-selected="true">{{ gettext(auth_name) }}</a>
</li>
{% endfor %}
</ul>
<div class="tab-content" id="myTabContent">
{% for auth_name, form in forms.items() %}
<div class="tab-pane fade{{ ' show active' if loop.first else '' }}" id="{{ auth_name }}" role="tabpanel" aria-labelledby="{{ auth_name }}-tab">
{{ render_form(form) }}
</div>
{% endfor %}
</div>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,17 @@
{% extends 'frontend/base.html.j2' %}
{% block title %}{{ gettext('Oauth2 Request') }}{% endblock %}
{% block content %}
<div class="container">
<p>
A service ask for access to your account data.<br>
You can confirm this pressing "Continue"
</p>
{{ render_form(form) }}
</div>
{% endblock %}