better separation between api and frontend login
This commit is contained in:
@@ -5,12 +5,17 @@ Backend base module
|
|||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth
|
from flask_httpauth import HTTPTokenAuth, HTTPBasicAuth, MultiAuth
|
||||||
|
from flask_login import LoginManager
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_object('backend.config.Config')
|
app.config.from_object('backend.config.Config')
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
|
|
||||||
|
login_manager = LoginManager()
|
||||||
|
login_manager.init_app(app)
|
||||||
|
|
||||||
jwt_auth = HTTPTokenAuth()
|
jwt_auth = HTTPTokenAuth()
|
||||||
basic_auth = HTTPBasicAuth()
|
basic_auth = HTTPBasicAuth()
|
||||||
multi_auth = MultiAuth(basic_auth, jwt_auth)
|
multi_auth = MultiAuth(basic_auth, jwt_auth)
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
"""
|
"""
|
||||||
This module provides functions related to authentication through the API.
|
This module provides functions related to authentication through the API.
|
||||||
For example: listing of available auth providers or registration of users.
|
For example: listing of available auth providers or registration of users.
|
||||||
|
|
||||||
|
Login through API does not start a new session, but instead returns JWT.
|
||||||
"""
|
"""
|
||||||
|
import flask
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import jwt
|
import jwt
|
||||||
from flask import request, jsonify, current_app, url_for
|
from flask import request, jsonify, current_app, url_for
|
||||||
@@ -12,9 +15,9 @@ from random import randint
|
|||||||
from flask_login import logout_user, login_user
|
from flask_login import logout_user, login_user
|
||||||
from werkzeug.routing import BuildError
|
from werkzeug.routing import BuildError
|
||||||
|
|
||||||
from backend import db
|
from backend import db, app
|
||||||
from backend.api import auth_api_bp
|
from backend.api import auth_api_bp
|
||||||
from backend.auth import AUTH_PROVIDERS
|
from backend.auth import AUTH_PROVIDERS, oidc_auth
|
||||||
from backend.models.user_model import User
|
from backend.models.user_model import User
|
||||||
|
|
||||||
|
|
||||||
@@ -62,11 +65,39 @@ def login():
|
|||||||
return jsonify({'message': 'Invalid credentials', 'authenticated': False}), 401
|
return jsonify({'message': 'Invalid credentials', 'authenticated': False}), 401
|
||||||
|
|
||||||
token = create_jwt(user)
|
token = create_jwt(user)
|
||||||
#login_user(user)
|
|
||||||
return jsonify({'token': token.decode('UTF-8')})
|
return jsonify({'token': token.decode('UTF-8')})
|
||||||
|
|
||||||
|
|
||||||
@auth_api_bp.route('/logout', methods=('GET', ))
|
|
||||||
def logout():
|
def create_or_retrieve_user_from_userinfo(userinfo):
|
||||||
return jsonify({'message': 'Not yet implemented!', 'authenticated': False}), 401
|
try:
|
||||||
#logout_user()
|
email = userinfo["email"]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
user = User.get_by_identifier(email)
|
||||||
|
|
||||||
|
if user is not None:
|
||||||
|
app.logger.info("user found")
|
||||||
|
return user
|
||||||
|
|
||||||
|
user = User(email=email, first_name=userinfo.get("given_name", ""),
|
||||||
|
last_name=userinfo.get("family_name", ""))
|
||||||
|
|
||||||
|
app.logger.info("creating new user")
|
||||||
|
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
@auth_api_bp.route('/oidc', methods=['GET'])
|
||||||
|
@oidc_auth.oidc_auth()
|
||||||
|
def oidc():
|
||||||
|
user = create_or_retrieve_user_from_userinfo(flask.session['userinfo'])
|
||||||
|
if user is None:
|
||||||
|
return "Could not authenticate: could not find or create user.", 401
|
||||||
|
if current_app.config.get("AUTH_RETURN_EXTERNAL_JWT", False):
|
||||||
|
token = jwt.encode(flask.session['id_token'], current_app.config['SECRET_KEY'])
|
||||||
|
else:
|
||||||
|
token = create_jwt(user)
|
||||||
|
return token
|
||||||
|
|||||||
@@ -5,13 +5,16 @@ Base module for auth aspects.
|
|||||||
Also this module contains mainly code for login through HTML pages served by the backend.
|
Also this module contains mainly code for login through HTML pages served by the backend.
|
||||||
If frontend pages are build by frontend code (JS, etc.) authentication should consider using api functions.
|
If frontend pages are build by frontend code (JS, etc.) authentication should consider using api functions.
|
||||||
(For more info, see api.auth_api.py.)
|
(For more info, see api.auth_api.py.)
|
||||||
|
|
||||||
|
This code uses login_user and logout user (to start and end sessions) ... API code returns JWTs.
|
||||||
"""
|
"""
|
||||||
from flask import Blueprint
|
from flask import Blueprint, jsonify
|
||||||
|
from flask_login import logout_user, LoginManager
|
||||||
from werkzeug.routing import BuildError
|
from werkzeug.routing import BuildError
|
||||||
|
|
||||||
auth_bp = Blueprint('auth', __name__, url_prefix='/auth', template_folder='templates')
|
auth_bp = Blueprint('auth', __name__, url_prefix='/auth', template_folder='templates')
|
||||||
|
|
||||||
from backend.auth.config import AUTH_PROVIDERS, DEFAULT_PROVIDER
|
from backend.auth.config import AUTH_PROVIDERS, DEFAULT_FRONTEND_PROVIDER
|
||||||
from backend.auth.oidc_config import OIDC_PROVIDERS
|
from backend.auth.oidc_config import OIDC_PROVIDERS
|
||||||
|
|
||||||
from backend.auth.oidc import oidc_auth
|
from backend.auth.oidc import oidc_auth
|
||||||
@@ -26,7 +29,7 @@ def auth_decorator(): # custom decorator
|
|||||||
@auth_bp.route('/login', methods=['GET', 'POST'])
|
@auth_bp.route('/login', methods=['GET', 'POST'])
|
||||||
def login():
|
def login():
|
||||||
try:
|
try:
|
||||||
prov = AUTH_PROVIDERS[DEFAULT_PROVIDER]
|
prov = AUTH_PROVIDERS[DEFAULT_FRONTEND_PROVIDER]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return "No known default provider specified!"
|
return "No known default provider specified!"
|
||||||
url = prov["url"]
|
url = prov["url"]
|
||||||
@@ -41,3 +44,8 @@ def login():
|
|||||||
@auth_bp.route('/login_select', methods=['GET'])
|
@auth_bp.route('/login_select', methods=['GET'])
|
||||||
def login_select():
|
def login_select():
|
||||||
return render_template('login_select.html', providers=AUTH_PROVIDERS)
|
return render_template('login_select.html', providers=AUTH_PROVIDERS)
|
||||||
|
|
||||||
|
|
||||||
|
@auth_bp.route('/logout', methods=('GET', ))
|
||||||
|
def logout():
|
||||||
|
logout_user()
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
# Route for handling the login page logic
|
# Route for handling the login page logic
|
||||||
from flask import request, redirect, render_template, url_for
|
from flask import request, redirect, render_template, url_for
|
||||||
|
from flask_login import login_user
|
||||||
|
|
||||||
from backend.auth import auth_bp
|
from backend.auth import auth_bp
|
||||||
|
|
||||||
|
|
||||||
@@ -10,5 +12,9 @@ def base_login():
|
|||||||
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
|
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
|
||||||
error = 'Invalid Credentials. Please try again.'
|
error = 'Invalid Credentials. Please try again.'
|
||||||
else:
|
else:
|
||||||
|
login_user()
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
return render_template('login.html', error=error)
|
return render_template('login.html', error=error)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,19 @@ AUTH_PROVIDERS: Dict[str, Dict[str, str]] = {
|
|||||||
"type": "login_form",
|
"type": "login_form",
|
||||||
"url": "auth.base_login"
|
"url": "auth.base_login"
|
||||||
},
|
},
|
||||||
|
"KIT OIDC (API)":
|
||||||
|
{
|
||||||
|
"type": "api_oidc",
|
||||||
|
"url": "auth_api_bp.oidc"
|
||||||
|
},
|
||||||
|
"User-Password (API)":
|
||||||
|
{
|
||||||
|
"type": "api_login_form",
|
||||||
|
"url": "auth_api_bp.base_login"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_PROVIDER: str = "Base Login"
|
#DEFAULT_PROVIDER: str = "Base Login"
|
||||||
#DEFAULT_PROVIDER: str = "KIT OIDC"
|
DEFAULT_PROVIDER: str = "KIT OIDC (API)"
|
||||||
|
|
||||||
|
DEFAULT_FRONTEND_PROVIDER: str = "Base Login"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ OIDC login auth module
|
|||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
|
from flask_login import login_user
|
||||||
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
|
from flask_pyoidc.flask_pyoidc import OIDCAuthentication
|
||||||
from flask_pyoidc.user_session import UserSession
|
from flask_pyoidc.user_session import UserSession
|
||||||
|
|
||||||
@@ -50,8 +51,9 @@ def create_or_retrieve_user_from_userinfo(userinfo):
|
|||||||
@oidc_auth.oidc_auth()
|
@oidc_auth.oidc_auth()
|
||||||
def oidc():
|
def oidc():
|
||||||
user_session = UserSession(flask.session)
|
user_session = UserSession(flask.session)
|
||||||
create_or_retrieve_user_from_userinfo(user_session.userinfo)
|
app.logger.info(user_session.userinfo)
|
||||||
#login_user(user)
|
user = create_or_retrieve_user_from_userinfo(user_session.userinfo)
|
||||||
|
login_user(user)
|
||||||
return jsonify(id_token=user_session.id_token,
|
return jsonify(id_token=user_session.id_token,
|
||||||
access_token=flask.session['access_token'],
|
access_token=flask.session['access_token'],
|
||||||
userinfo=user_session.userinfo)
|
userinfo=user_session.userinfo)
|
||||||
|
|||||||
Reference in New Issue
Block a user