merge ldap user and db user, cleanup, add password change
This commit is contained in:
parent
6334c993a9
commit
4150853588
14 changed files with 280 additions and 259 deletions
|
@ -11,7 +11,6 @@ import logging
|
|||
import requests
|
||||
|
||||
from ..model import User
|
||||
from ..model_db import User as DbUser
|
||||
from ..auth_providers import LdapAuthProvider
|
||||
|
||||
|
||||
|
@ -19,11 +18,15 @@ api_views = Blueprint('api', __name__, url_prefix='/api')
|
|||
|
||||
@api_views.route('/userinfo', methods=['GET', 'POST'])
|
||||
def userinfo():
|
||||
if 'authorization' not in request.headers:
|
||||
return 'not token found', 400
|
||||
token = request.headers['authorization'].replace('Bearer ', '')
|
||||
token_info = current_app.hydra_api.introspect_o_auth2_token(token=token)
|
||||
if not token_info.active:
|
||||
return 'token not valid', 403
|
||||
|
||||
user_db = DbUser.query.get(token_info.sub)
|
||||
user = User.query().by_username(user_db.username)
|
||||
user_db = User.query.get(token_info.sub)
|
||||
user = User.query_().by_username(user_db.username)
|
||||
|
||||
public_url = current_app.config.get('HYDRA_PUBLIC_URL')
|
||||
r = requests.get(
|
||||
|
@ -50,5 +53,6 @@ def user_list():
|
|||
if 'lc_i_userlist' not in token_info.scope.split(' '):
|
||||
return '', 403
|
||||
|
||||
return jsonify([{'username': str(user.username), 'email': str(user.email)}
|
||||
for user in User.query().all()])
|
||||
return jsonify([
|
||||
{'username': str(user.username), 'email': str(user.email)}
|
||||
for user in User.query_().all()])
|
||||
|
|
|
@ -14,8 +14,7 @@ from urllib.parse import urlparse
|
|||
from base64 import b64decode, b64encode
|
||||
import http
|
||||
|
||||
from ..model import User, SecurityUser
|
||||
from ..model_db import db, User as DbUser
|
||||
from ..model import db, User, SecurityUser
|
||||
from ..form.auth import ConsentForm, LoginForm
|
||||
from ..auth_providers import AUTH_PROVIDER_LIST
|
||||
|
||||
|
@ -29,7 +28,7 @@ def consent():
|
|||
# DUMMPY ONLY
|
||||
|
||||
form = ConsentForm()
|
||||
remember_for = 60*60*24*7 # remember for 7 days
|
||||
remember_for = 60*60*24*30 # remember for 7 days
|
||||
|
||||
consent_request = current_app.hydra_api.get_consent_request(
|
||||
request.args['consent_challenge'])
|
||||
|
@ -42,7 +41,7 @@ def consent():
|
|||
'grant_scope': requested_scope,
|
||||
'grant_access_token_audience': requested_audiences,
|
||||
'remember': form.data['remember'],
|
||||
# 'remember_for': remember_for,
|
||||
'remember_for': remember_for,
|
||||
})
|
||||
return redirect(resp.redirect_to)
|
||||
return render_template(
|
||||
|
@ -65,7 +64,7 @@ def login():
|
|||
return redirect(resp.redirect_to)
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
user = User.query().by_username(form.data['name'])
|
||||
user = User.query_().by_username(form.data['name'])
|
||||
if user:
|
||||
session['username'] = str(user.username)
|
||||
else:
|
||||
|
@ -83,7 +82,7 @@ def login_auth():
|
|||
if 'username' not in session:
|
||||
return redirect(url_for('auth.login'))
|
||||
auth_forms = {}
|
||||
user = User.query().by_username(session['username'])
|
||||
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\
|
||||
|
@ -95,31 +94,18 @@ def login_auth():
|
|||
|
||||
if len(session['auth_providers']) >= 2:
|
||||
remember_me = True
|
||||
db_user = DbUser.query.filter(DbUser.username == session['username']).one_or_none()
|
||||
if db_user is None:
|
||||
db_user = DbUser(username=session['username'])
|
||||
db.session.add(db_user)
|
||||
db.session.commit()
|
||||
# if db_user is None:
|
||||
# db_user = User(username=session['username'])
|
||||
# db.session.add(db_user)
|
||||
# db.session.commit()
|
||||
|
||||
subject = db_user.id
|
||||
subject = user.id
|
||||
|
||||
resp = current_app.hydra_api.accept_login_request(
|
||||
login_challenge, body={
|
||||
'subject': subject,
|
||||
'remember': remember_me})
|
||||
return redirect(resp.redirect_to)
|
||||
|
||||
login_user(SecurityUser(session['username']))
|
||||
# TODO use this var
|
||||
_next = None
|
||||
try:
|
||||
_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 TypeError:
|
||||
_next = None
|
||||
return redirect(_next or url_for('frontend.index'))
|
||||
return render_template('auth/login_auth.html.j2', forms=auth_forms)
|
||||
|
||||
|
||||
|
@ -128,7 +114,7 @@ def logout():
|
|||
logout_challenge = request.args.get('logout_challenge')
|
||||
logout_request = current_app.hydra_api.get_logout_request(logout_challenge)
|
||||
resp = current_app.hydra_api.accept_logout_request(logout_challenge)
|
||||
logout_user()
|
||||
# TODO confirm
|
||||
return redirect(resp.redirect_to)
|
||||
|
||||
|
||||
|
|
|
@ -1,46 +1,47 @@
|
|||
|
||||
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, flash
|
||||
from flask_login import login_required, login_user, logout_user, current_user
|
||||
from flask import current_app
|
||||
from flask import jsonify
|
||||
from flask import render_template, url_for, flash
|
||||
from flask_login import login_user, logout_user, current_user
|
||||
from werkzeug.utils import redirect
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
import pyotp
|
||||
from base64 import b64decode, b64encode
|
||||
from base64 import b64decode
|
||||
from flask_dance.consumer import oauth_authorized
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
from flask_dance.consumer import OAuth2ConsumerBlueprint
|
||||
from oauthlib.oauth2.rfc6749.errors import TokenExpiredError
|
||||
|
||||
from ..model import User, SecurityUser, Totp
|
||||
from ..model_db import OAuth, db, User as DbUser
|
||||
from ..form.frontend import ClientCertForm, TOTPForm, TOTPDeleteForm, PasswordChangeForm
|
||||
from ..auth_providers import AUTH_PROVIDER_LIST
|
||||
|
||||
from ..model import db, User, SecurityUser, Totp
|
||||
from ..form.frontend import ClientCertForm, TOTPForm, \
|
||||
TOTPDeleteForm, PasswordChangeForm
|
||||
from ..auth_providers import LdapAuthProvider
|
||||
|
||||
frontend_views = Blueprint('frontend', __name__, url_prefix='')
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def before_request():
|
||||
try:
|
||||
resp = current_app.oauth.session.get('/userinfo')
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(url_for('oauth.login'))
|
||||
except TokenExpiredError:
|
||||
return redirect(url_for('oauth.login'))
|
||||
|
||||
|
||||
frontend_views.before_request(before_request)
|
||||
|
||||
|
||||
def init_login_manager(app):
|
||||
@app.login_manager.user_loader
|
||||
def user_loader(username):
|
||||
return User.query().by_username(username)
|
||||
return User.query_().by_username(username)
|
||||
|
||||
@app.login_manager.request_loader
|
||||
def request_loader(request):
|
||||
def request_loader(_request):
|
||||
pass
|
||||
|
||||
@app.login_manager.unauthorized_handler
|
||||
|
@ -75,25 +76,9 @@ def init_login_manager(app):
|
|||
|
||||
oauth_info = resp.json()
|
||||
|
||||
db_user = DbUser.query.get(str(oauth_info["sub"]))
|
||||
oauth_username = db_user.username
|
||||
db_user = User.query.get(str(oauth_info["sub"]))
|
||||
|
||||
# Find this OAuth token in the database, or create it
|
||||
query = OAuth.query.filter_by(
|
||||
provider=blueprint.name,
|
||||
provider_username=oauth_username,
|
||||
)
|
||||
try:
|
||||
oauth = query.one()
|
||||
except NoResultFound:
|
||||
oauth = OAuth(
|
||||
provider=blueprint.name,
|
||||
provider_username=oauth_username,
|
||||
token=token,
|
||||
)
|
||||
|
||||
|
||||
login_user(SecurityUser(oauth.provider_username))
|
||||
login_user(SecurityUser(db_user.username))
|
||||
#flash("Successfully signed in with GitHub.")
|
||||
|
||||
# Since we're manually creating the OAuth model in the database,
|
||||
|
@ -106,27 +91,29 @@ def init_login_manager(app):
|
|||
@frontend_views.route('/logout')
|
||||
def logout():
|
||||
logout_user()
|
||||
return redirect(f'{current_app.config["HYDRA_PUBLIC_URL"]}/oauth2/sessions/logout')
|
||||
return redirect(
|
||||
f'{current_app.config["HYDRA_PUBLIC_URL"]}/oauth2/sessions/logout')
|
||||
|
||||
|
||||
@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)
|
||||
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)
|
||||
return render_template(
|
||||
'frontend/client_cert.html.j2',
|
||||
services=current_app.lenticular_services,
|
||||
client_certs=client_certs)
|
||||
|
||||
|
||||
@frontend_views.route('/client_cert/<service_name>/<serial_number>')
|
||||
@login_required
|
||||
def get_client_cert(service_name, serial_number):
|
||||
service = current_app.lenticular_services[service_name]
|
||||
cert = current_app.pki.get_client_cert(
|
||||
|
@ -137,8 +124,8 @@ def get_client_cert(service_name, serial_number):
|
|||
})
|
||||
|
||||
|
||||
@frontend_views.route('/client_cert/<service_name>/<serial_number>', methods=['DELETE'])
|
||||
@login_required
|
||||
@frontend_views.route(
|
||||
'/client_cert/<service_name>/<serial_number>', methods=['DELETE'])
|
||||
def revoke_client_cert(service_name, serial_number):
|
||||
service = current_app.lenticular_services[service_name]
|
||||
cert = current_app.pki.get_client_cert(
|
||||
|
@ -150,7 +137,6 @@ def revoke_client_cert(service_name, serial_number):
|
|||
@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()
|
||||
|
@ -180,23 +166,20 @@ def client_cert_new(service_name):
|
|||
|
||||
|
||||
@frontend_views.route('/totp')
|
||||
@login_required
|
||||
def totp():
|
||||
delete_form = TOTPDeleteForm()
|
||||
return render_template('frontend/totp.html.j2', delete_form=delete_form)
|
||||
|
||||
|
||||
@frontend_views.route('/totp/new', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def totp_new():
|
||||
form = TOTPForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
totp = Totp(name=form.data['name'], secret=form.data['secret'])
|
||||
if totp.verify(form.data['token']):
|
||||
current_user.make_writeable()
|
||||
current_user.totps.append(totp)
|
||||
current_user._ldap_object.entry_commit_changes()
|
||||
db.session.commit()
|
||||
return jsonify({
|
||||
'status': 'ok'})
|
||||
else:
|
||||
|
@ -208,47 +191,55 @@ def totp_new():
|
|||
return render_template('frontend/totp_new.html.j2', form=form)
|
||||
|
||||
|
||||
@frontend_views.route('/totp/<totp_name>/delete', methods=['GET','POST'])
|
||||
@login_required
|
||||
@frontend_views.route('/totp/<totp_name>/delete', methods=['GET', 'POST'])
|
||||
def totp_delete(totp_name):
|
||||
current_user.make_writeable()
|
||||
current_user.totps.delete(totp_name)
|
||||
current_user._ldap_object.entry_commit_changes()
|
||||
totp = Totp.query.filter(Totp.name == totp_name).first()
|
||||
db.session.delete(totp)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'status': 'ok'})
|
||||
|
||||
|
||||
|
||||
@frontend_views.route('/password_change')
|
||||
@login_required
|
||||
def password_change():
|
||||
|
||||
form = PasswordChangeForm()
|
||||
return render_template('frontend/password_change.html.j2', form=form)
|
||||
|
||||
|
||||
@frontend_views.route('/password_change', methods=['POST'])
|
||||
@login_required
|
||||
def password_change_post():
|
||||
form = PasswordChangeForm()
|
||||
if form.validate():
|
||||
return jsonify({})
|
||||
password_old = str(form.data['password_old'])
|
||||
password_new = str(form.data['password_new'])
|
||||
if not LdapAuthProvider.check_auth_internal(
|
||||
current_user, password_old):
|
||||
return jsonify(
|
||||
{'errors': {'password_old': 'Old Password is invalid'}})
|
||||
resp = current_user.change_password(password_new)
|
||||
if resp:
|
||||
print(current_user)
|
||||
return jsonify({})
|
||||
else:
|
||||
return jsonify({'errors': {'internal': 'internal server errror'}})
|
||||
return jsonify({'errors': form.errors})
|
||||
|
||||
|
||||
@frontend_views.route('/oauth2_token')
|
||||
@login_required
|
||||
def oauth2_tokens():
|
||||
|
||||
subject = current_app.oauth.session.get('/userinfo').json()['sub']
|
||||
consent_sessions = current_app.hydra_api.list_subject_consent_sessions(
|
||||
subject)
|
||||
|
||||
return render_template('frontend/oauth2_tokens.html.j2', consent_sessions=consent_sessions)
|
||||
print(consent_sessions)
|
||||
return render_template(
|
||||
'frontend/oauth2_tokens.html.j2',
|
||||
consent_sessions=consent_sessions)
|
||||
|
||||
|
||||
@frontend_views.route('/oauth2_token/<client_id>', methods=['DELETE'])
|
||||
@login_required
|
||||
def oauth2_token_revoke(client_id: str):
|
||||
subject = current_app.oauth.session.get('/userinfo').json()['sub']
|
||||
current_app.hydra_api.revoke_consent_sessions(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue