init commit
This commit is contained in:
commit
dfd166bd3b
55 changed files with 18538 additions and 0 deletions
5
lenticular_cloud/views/__init__.py
Normal file
5
lenticular_cloud/views/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
# pylint: disable=unused-import
|
||||
|
||||
from .oidc import oidc_provider_views
|
||||
from .auth import auth_views
|
||||
from .frontend import frontend_views
|
73
lenticular_cloud/views/auth.py
Normal file
73
lenticular_cloud/views/auth.py
Normal file
|
@ -0,0 +1,73 @@
|
|||
|
||||
from urllib.parse import urlencode, parse_qs
|
||||
|
||||
import flask
|
||||
from flask import Blueprint, redirect
|
||||
from flask import current_app, session
|
||||
from flask import jsonify
|
||||
from flask.helpers import make_response
|
||||
from flask.templating import render_template
|
||||
from oic.oic.message import TokenErrorResponse, UserInfoErrorResponse, EndSessionRequest
|
||||
|
||||
from pyop.access_token import AccessToken, BearerTokenError
|
||||
from pyop.exceptions import InvalidAuthenticationRequest, InvalidAccessToken, InvalidClientAuthentication, OAuthError, \
|
||||
InvalidSubjectIdentifier, InvalidClientRegistrationRequest
|
||||
from pyop.util import should_fragment_encode
|
||||
|
||||
from flask import Blueprint, render_template, request, url_for
|
||||
from flask_login import login_required, login_user, logout_user
|
||||
from werkzeug.utils import redirect
|
||||
import logging
|
||||
|
||||
|
||||
from ..model import User, SecurityUser
|
||||
from ..form.login import LoginForm
|
||||
from ..auth_providers import AUTH_PROVIDER_LIST
|
||||
from .oidc import do_logout
|
||||
|
||||
|
||||
auth_views = Blueprint('auth', __name__, url_prefix='')
|
||||
|
||||
|
||||
@auth_views.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
user = User.query().by_username(form.data['name'])
|
||||
session['username'] = str(user.username)
|
||||
session['auth_providers'] = []
|
||||
return redirect(url_for('auth.login_auth'))
|
||||
return render_template('frontend/login.html.j2', form=form)
|
||||
|
||||
|
||||
@auth_views.route('/login/auth', methods=['GET', 'POST'])
|
||||
def login_auth():
|
||||
if 'username' not in session:
|
||||
return redirect(url_for('auth.login'))
|
||||
auth_forms = []
|
||||
user = User.query().by_username(session['username'])
|
||||
for auth_provider in AUTH_PROVIDER_LIST:
|
||||
form = auth_provider.get_form()
|
||||
if auth_provider.get_name() not in session['auth_providers'] and\
|
||||
auth_provider.check_auth(user, form):
|
||||
session['auth_providers'].append(auth_provider.get_name())
|
||||
|
||||
if auth_provider.get_name() not in session['auth_providers']:
|
||||
auth_forms.append(form)
|
||||
|
||||
if len(session['auth_providers']) >= 2:
|
||||
login_user(SecurityUser(session['username']))
|
||||
# TODO use this var
|
||||
_next = request.args.get('next')
|
||||
return redirect(url_for('frontend.index'))
|
||||
print(auth_forms)
|
||||
return render_template('frontend/login_auth.html.j2', forms=auth_forms)
|
||||
|
||||
|
||||
@auth_views.route("/logout")
|
||||
@login_required
|
||||
def logout():
|
||||
logout_user()
|
||||
do_logout()
|
||||
return redirect(url_for('.login'))
|
||||
|
93
lenticular_cloud/views/frontend.py
Normal file
93
lenticular_cloud/views/frontend.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
|
||||
from urllib.parse import urlencode, parse_qs
|
||||
|
||||
import flask
|
||||
from flask import Blueprint, redirect
|
||||
from flask import current_app, session
|
||||
from flask import jsonify, send_file
|
||||
from flask.helpers import make_response
|
||||
from flask.templating import render_template
|
||||
from oic.oic.message import TokenErrorResponse, UserInfoErrorResponse, EndSessionRequest
|
||||
|
||||
from pyop.access_token import AccessToken, BearerTokenError
|
||||
from pyop.exceptions import InvalidAuthenticationRequest, InvalidAccessToken, InvalidClientAuthentication, OAuthError, \
|
||||
InvalidSubjectIdentifier, InvalidClientRegistrationRequest
|
||||
from pyop.util import should_fragment_encode
|
||||
|
||||
from flask import Blueprint, render_template, request, url_for
|
||||
from flask_login import login_required, login_user, logout_user, current_user
|
||||
from werkzeug.utils import redirect
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
from ..model import User, SecurityUser
|
||||
from ..form.login import LoginForm
|
||||
from ..form.frontend import ClientCertForm
|
||||
from ..auth_providers import AUTH_PROVIDER_LIST
|
||||
|
||||
|
||||
frontend_views = Blueprint('frontend', __name__, url_prefix='')
|
||||
|
||||
|
||||
@frontend_views.route('/', methods=['GET'])
|
||||
@login_required
|
||||
def index():
|
||||
return render_template('frontend/index.html.j2')
|
||||
|
||||
|
||||
@frontend_views.route('/client_cert')
|
||||
@login_required
|
||||
def client_cert():
|
||||
client_certs = {}
|
||||
for service in current_app.lenticular_services.values():
|
||||
client_certs[str(service.name)] = current_app.pki.get_client_certs(current_user, service)
|
||||
|
||||
return render_template('frontend/client_cert.html.j2', services=current_app.lenticular_services, client_certs=client_certs)
|
||||
|
||||
|
||||
@frontend_views.route('/client_cert/<service_name>/<fingerprint>')
|
||||
@login_required
|
||||
def get_client_cert(service_name, fingerprint):
|
||||
service = current_app.lenticular_services[service_name]
|
||||
current_app.pki.get_client_cert(current_user, service, fingerprint)
|
||||
pass
|
||||
|
||||
|
||||
@frontend_views.route(
|
||||
'/client_cert/<service_name>/new',
|
||||
methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def client_cert_new(service_name):
|
||||
service = current_app.lenticular_services[service_name]
|
||||
form = ClientCertForm()
|
||||
if form.validate_on_submit():
|
||||
valid_time = int(form.data['valid_time']) * timedelta(1, 0, 0)
|
||||
cert = current_app.pki.signing_publickey(
|
||||
current_user,
|
||||
service,
|
||||
form.data['publickey'],
|
||||
valid_time=valid_time)
|
||||
return jsonify( {
|
||||
'status': 'ok',
|
||||
'data': {
|
||||
'cert': cert.pem(),
|
||||
'ca_cert': current_app.pki.get_ca_cert_pem(service)
|
||||
}})
|
||||
elif form.is_submitted():
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'errors': form.errors
|
||||
})
|
||||
|
||||
return render_template('frontend/client_cert_new.html.j2',
|
||||
service=service,
|
||||
form=form)
|
||||
|
||||
|
||||
@frontend_views.route('/totp')
|
||||
@login_required
|
||||
def totp():
|
||||
return render_template('frontend/totp.html.j2')
|
||||
|
||||
|
113
lenticular_cloud/views/oidc.py
Normal file
113
lenticular_cloud/views/oidc.py
Normal file
|
@ -0,0 +1,113 @@
|
|||
from urllib.parse import urlencode, parse_qs
|
||||
|
||||
import flask
|
||||
from flask import Blueprint, redirect
|
||||
from flask import current_app, session
|
||||
from flask import jsonify
|
||||
from flask.helpers import make_response
|
||||
from flask.templating import render_template
|
||||
from oic.oic.message import TokenErrorResponse, UserInfoErrorResponse, EndSessionRequest
|
||||
from flask_login import current_user, login_required
|
||||
|
||||
from pyop.access_token import AccessToken, BearerTokenError
|
||||
from pyop.exceptions import InvalidAuthenticationRequest, InvalidAccessToken, InvalidClientAuthentication, OAuthError, \
|
||||
InvalidSubjectIdentifier, InvalidClientRegistrationRequest
|
||||
from pyop.util import should_fragment_encode
|
||||
|
||||
oidc_provider_views = Blueprint('oidc_provider', __name__, url_prefix='')
|
||||
|
||||
|
||||
@oidc_provider_views.route('/registration', methods=['POST'])
|
||||
def registration_endpoint():
|
||||
try:
|
||||
response = current_app.provider.handle_client_registration_request(flask.request.get_data().decode('utf-8'))
|
||||
return make_response(jsonify(response.to_dict()), 201)
|
||||
except InvalidClientRegistrationRequest as e:
|
||||
print(e)
|
||||
return make_response(jsonify(str(e)), 400)
|
||||
|
||||
|
||||
@oidc_provider_views.route('/authentication', methods=['GET'])
|
||||
@login_required
|
||||
def authentication_endpoint():
|
||||
# parse authentication request
|
||||
print(flask.request)
|
||||
print(flask.request.headers)
|
||||
try:
|
||||
auth_req = current_app.provider.parse_authentication_request(urlencode(flask.request.args),
|
||||
flask.request.args)
|
||||
except InvalidAuthenticationRequest as e:
|
||||
current_app.logger.debug('received invalid authn request', exc_info=True)
|
||||
error_url = e.to_error_url()
|
||||
if error_url:
|
||||
return redirect(error_url, 303)
|
||||
else:
|
||||
# show error to user
|
||||
return make_response('Something went wrong: {}'.format(str(e)), 400)
|
||||
|
||||
# automagic authentication
|
||||
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))
|
||||
return redirect(response_url, 303)
|
||||
|
||||
|
||||
@oidc_provider_views.route('/.well-known/openid-configuration')
|
||||
def provider_configuration():
|
||||
return jsonify(current_app.provider.provider_configuration.to_dict())
|
||||
|
||||
|
||||
@oidc_provider_views.route('/jwks')
|
||||
def jwks_uri():
|
||||
return jsonify(current_app.provider.jwks)
|
||||
|
||||
|
||||
@oidc_provider_views.route('/token', methods=['POST'])
|
||||
def token_endpoint():
|
||||
try:
|
||||
token_response = current_app.provider.handle_token_request(flask.request.get_data().decode('utf-8'),
|
||||
flask.request.headers)
|
||||
return jsonify(token_response.to_dict())
|
||||
except InvalidClientAuthentication as e:
|
||||
current_app.logger.debug('invalid client authentication at token endpoint', exc_info=True)
|
||||
error_resp = TokenErrorResponse(error='invalid_client', error_description=str(e))
|
||||
response = make_response(error_resp.to_json(), 401)
|
||||
response.headers['Content-Type'] = 'application/json'
|
||||
response.headers['WWW-Authenticate'] = 'Basic'
|
||||
return response
|
||||
except OAuthError as e:
|
||||
current_app.logger.debug('invalid request: %s', str(e), exc_info=True)
|
||||
error_resp = TokenErrorResponse(error=e.oauth_error, error_description=str(e))
|
||||
response = make_response(error_resp.to_json(), 400)
|
||||
response.headers['Content-Type'] = 'application/json'
|
||||
return response
|
||||
|
||||
|
||||
@oidc_provider_views.route('/userinfo', methods=['GET', 'POST'])
|
||||
def userinfo_endpoint():
|
||||
try:
|
||||
response = current_app.provider.handle_userinfo_request(flask.request.get_data().decode('utf-8'),
|
||||
flask.request.headers)
|
||||
return jsonify(response.to_dict())
|
||||
except (BearerTokenError, InvalidAccessToken) as e:
|
||||
error_resp = UserInfoErrorResponse(error='invalid_token', error_description=str(e))
|
||||
response = make_response(error_resp.to_json(), 401)
|
||||
response.headers['WWW-Authenticate'] = AccessToken.BEARER_TOKEN_TYPE
|
||||
response.headers['Content-Type'] = 'application/json'
|
||||
return response
|
||||
|
||||
|
||||
def do_logout():
|
||||
|
||||
end_session_request = EndSessionRequest().deserialize(urlencode(flask.request.args)).to_dict()
|
||||
try:
|
||||
current_app.provider.logout_user(end_session_request=end_session_request)
|
||||
except InvalidSubjectIdentifier as e:
|
||||
return make_response('Logout unsuccessful!', 400)
|
||||
|
||||
redirect_url = current_app.provider.do_post_logout_redirect(end_session_request)
|
||||
if redirect_url:
|
||||
return redirect(redirect_url, 303)
|
||||
|
||||
return make_response('Logout successful!')
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue