Update saml auth patch
This commit is contained in:
parent
26ca1342d0
commit
a67a7e01b4
|
@ -1,264 +1,178 @@
|
||||||
diff -crB src.orig/webfaf/config.py src/webfaf/config.py
|
diff -aruN faf-2.6.1/src/webfaf/config.py faf-2.6.1.alma/src/webfaf/config.py
|
||||||
*** src.orig/webfaf/config.py 2021-02-11 11:31:10.000000000 +0200
|
--- faf-2.6.1/src/webfaf/config.py 2023-01-11 17:35:16
|
||||||
--- src/webfaf/config.py 2021-02-11 11:43:27.000000000 +0200
|
+++ faf-2.6.1.alma/src/webfaf/config.py 2023-05-23 09:47:50
|
||||||
***************
|
@@ -13,6 +13,7 @@
|
||||||
*** 10,15 ****
|
|
||||||
--- 10,16 ----
|
|
||||||
|
class Config:
|
||||||
|
+ SAML_CONFIG_DIR = '/etc/faf/saml'
|
||||||
class Config(object):
|
DEBUG = False
|
||||||
+ SAML_CONFIG_DIR = '/etc/faf/saml'
|
TESTING = False
|
||||||
DEBUG = False
|
SECRET_KEY = "NOT_A_RANDOM_STRING"
|
||||||
TESTING = False
|
diff -aruN faf-2.6.1/src/webfaf/login.py faf-2.6.1.alma/src/webfaf/login.py
|
||||||
SECRET_KEY = 'NOT_A_RANDOM_STRING'
|
--- faf-2.6.1/src/webfaf/login.py 2023-01-11 17:35:16
|
||||||
diff -crB src.orig/webfaf/login.py src/webfaf/login.py
|
+++ faf-2.6.1.alma/src/webfaf/login.py 2023-05-23 09:50:08
|
||||||
*** src.orig/webfaf/login.py 2021-02-11 11:31:10.000000000 +0200
|
@@ -1,58 +1,112 @@
|
||||||
--- src/webfaf/login.py 2021-02-11 11:44:30.000000000 +0200
|
import flask
|
||||||
***************
|
from openid_teams import teams
|
||||||
*** 1,56 ****
|
from werkzeug.wrappers import Response
|
||||||
import flask
|
+from urllib.parse import urlparse, urljoin
|
||||||
from openid_teams import teams
|
|
||||||
from werkzeug.wrappers import Response
|
from pyfaf.storage.user import User
|
||||||
|
from webfaf.webfaf_main import db, oid, app
|
||||||
from pyfaf.storage.user import User
|
from webfaf.utils import fed_raw_name
|
||||||
from webfaf.webfaf_main import db, oid, app
|
+from onelogin.saml2.auth import OneLogin_Saml2_Auth
|
||||||
from webfaf.utils import fed_raw_name
|
|
||||||
|
-login = flask.Blueprint("login", __name__)
|
||||||
! login = flask.Blueprint("login", __name__)
|
+login = flask.Blueprint('login', __name__)
|
||||||
|
|
||||||
|
|
||||||
! @login.route("/login/", methods=["GET"])
|
-@login.route("/login/", methods=["GET"])
|
||||||
! @oid.loginhandler
|
-@oid.loginhandler
|
||||||
! def do_login() -> Response:
|
-def do_login() -> Response:
|
||||||
! if flask.g.user is not None:
|
- if flask.g.user is not None:
|
||||||
! return flask.redirect(oid.get_next_url())
|
- return flask.redirect(oid.get_next_url())
|
||||||
!
|
+def init_saml_auth(req):
|
||||||
! teams_req = teams.TeamsRequest(app.config["OPENID_PRIVILEGED_TEAMS"])
|
+ saml_config_dir = app.config['SAML_CONFIG_DIR']
|
||||||
! return oid.try_login("https://id.fedoraproject.org/",
|
+ return OneLogin_Saml2_Auth(req, custom_base_path=saml_config_dir)
|
||||||
! ask_for=["email"], extensions=[teams_req])
|
|
||||||
!
|
- teams_req = teams.TeamsRequest(app.config["OPENID_PRIVILEGED_TEAMS"])
|
||||||
!
|
- return oid.try_login("https://id.fedoraproject.org/",
|
||||||
! @oid.after_login
|
- ask_for=["email"], extensions=[teams_req])
|
||||||
! def create_or_login(resp) -> Response:
|
|
||||||
! flask.session["openid"] = resp.identity_url
|
+def prepare_flask_request(req):
|
||||||
! username = fed_raw_name(resp.identity_url)
|
+ parsed_url = urlparse(req.url)
|
||||||
|
+ return {
|
||||||
privileged = False
|
+ 'https': 'on' if req.scheme == 'https' else 'off',
|
||||||
! # "lp" is the namespace for openid-teams
|
+ 'http_host': req.host,
|
||||||
! if "lp" in resp.extensions and any(group in app.config["OPENID_PRIVILEGED_TEAMS"]
|
+ 'server_port': parsed_url.port,
|
||||||
! for group in resp.extensions["lp"].teams):
|
+ 'script_name': req.script_root + req.path,
|
||||||
privileged = True
|
+ 'get_data': req.args.copy(),
|
||||||
|
+ 'post_data': req.form.copy(),
|
||||||
user = db.session.query(User).filter(User.username == username).first()
|
+ 'query_string': req.query_string
|
||||||
if not user: # create
|
+ }
|
||||||
! user = User(username=username, mail=resp.email, privileged=privileged)
|
|
||||||
else:
|
-@oid.after_login
|
||||||
! user.mail = resp.email
|
-def create_or_login(resp) -> Response:
|
||||||
user.privileged = privileged
|
- flask.session["openid"] = resp.identity_url
|
||||||
|
- username = fed_raw_name(resp.identity_url)
|
||||||
db.session.add(user)
|
|
||||||
db.session.commit()
|
+@login.route('/login/', methods=('GET',))
|
||||||
flask.flash(u"Welcome, {0}".format(user.username))
|
+def do_login():
|
||||||
flask.g.user = user
|
+ """SSO authentication entry-point."""
|
||||||
|
+ req = prepare_flask_request(flask.request)
|
||||||
! if flask.request.url_root == oid.get_next_url():
|
+ comeback_url = urljoin(flask.request.host_url, '/faf/summary')
|
||||||
! return flask.redirect(flask.url_for("summary.index"))
|
+ return_to = flask.request.args.get('return_to')
|
||||||
|
+ if return_to:
|
||||||
! return flask.redirect(oid.get_next_url())
|
+ comeback_url += '?return_to={0}'.format(return_to)
|
||||||
|
+ auth = init_saml_auth(req)
|
||||||
|
+ return flask.redirect(auth.login(comeback_url))
|
||||||
@login.route("/logout/")
|
+
|
||||||
def do_logout() -> Response:
|
+
|
||||||
! flask.session.pop("openid", None)
|
+@login.route('/acs/', methods=('POST',))
|
||||||
flask.flash(u"You were signed out")
|
+def acs():
|
||||||
! return flask.redirect(oid.get_next_url())
|
+ req = prepare_flask_request(flask.request)
|
||||||
--- 1,113 ----
|
+ auth = init_saml_auth(req)
|
||||||
import flask
|
+ auth.process_response()
|
||||||
from openid_teams import teams
|
+ errors = auth.get_errors()
|
||||||
from werkzeug.wrappers import Response
|
+ if errors:
|
||||||
+ from urllib.parse import urlparse, urljoin
|
+ return flask.helpers.make_response('Error: {0}'.format(', '.join(errors)), 500)
|
||||||
|
+ elif not auth.is_authenticated():
|
||||||
from pyfaf.storage.user import User
|
+ return flask.helpers.make_response('Error: authentication failed', 401)
|
||||||
from webfaf.webfaf_main import db, oid, app
|
+ user_attrs = auth.get_attributes()
|
||||||
from webfaf.utils import fed_raw_name
|
+
|
||||||
+ from onelogin.saml2.auth import OneLogin_Saml2_Auth
|
privileged = False
|
||||||
|
- # "lp" is the namespace for openid-teams
|
||||||
! login = flask.Blueprint('login', __name__)
|
- if "lp" in resp.extensions and any(group in app.config["OPENID_PRIVILEGED_TEAMS"]
|
||||||
|
- for group in resp.extensions["lp"].teams):
|
||||||
|
+ is_admin = False
|
||||||
! def init_saml_auth(req):
|
+ if any(group in user_attrs['groups'] for group in ('alma_retrace_admin', 'admins')):
|
||||||
! saml_config_dir = app.config['SAML_CONFIG_DIR']
|
privileged = True
|
||||||
! return OneLogin_Saml2_Auth(req, custom_base_path=saml_config_dir)
|
+ is_admin = True
|
||||||
!
|
|
||||||
!
|
+ email = user_attrs['email'][0]
|
||||||
! def prepare_flask_request(req):
|
+ username = email.split('@')[0]
|
||||||
! parsed_url = urlparse(req.url)
|
user = db.session.query(User).filter(User.username == username).first()
|
||||||
! return {
|
if not user: # create
|
||||||
! 'https': 'on' if req.scheme == 'https' else 'off',
|
- user = User(username=username, mail=resp.email, privileged=privileged)
|
||||||
! 'http_host': req.host,
|
+ user = User(username=username, mail=email, privileged=privileged, admin=is_admin)
|
||||||
! 'server_port': parsed_url.port,
|
else:
|
||||||
! 'script_name': req.script_root + req.path,
|
- user.mail = resp.email
|
||||||
! 'get_data': req.args.copy(),
|
+ user.mail = email
|
||||||
! 'post_data': req.form.copy(),
|
user.privileged = privileged
|
||||||
! 'query_string': req.query_string
|
+ user.admin = is_admin
|
||||||
! }
|
|
||||||
!
|
db.session.add(user)
|
||||||
!
|
db.session.commit()
|
||||||
! @login.route('/login/', methods=('GET',))
|
flask.flash(u"Welcome, {0}".format(user.username))
|
||||||
! def do_login():
|
- # This is okay: https://flask.palletsprojects.com/en/2.0.x/api/#flask.g
|
||||||
! """SSO authentication entry-point."""
|
- # pylint: disable=assigning-non-slot
|
||||||
! req = prepare_flask_request(flask.request)
|
flask.g.user = user
|
||||||
! comeback_url = urljoin(flask.request.host_url, '/faf/summary')
|
+ flask.session['username'] = username
|
||||||
! return_to = flask.request.args.get('return_to')
|
|
||||||
! if return_to:
|
- if flask.request.url_root == oid.get_next_url():
|
||||||
! comeback_url += '?return_to={0}'.format(return_to)
|
- return flask.redirect(flask.url_for("summary.index"))
|
||||||
! auth = init_saml_auth(req)
|
+ return flask.redirect(flask.request.form['RelayState'])
|
||||||
! return flask.redirect(auth.login(comeback_url))
|
|
||||||
!
|
- return flask.redirect(oid.get_next_url())
|
||||||
!
|
|
||||||
! @login.route('/acs/', methods=('POST',))
|
+@login.route('/metadata/', methods=('GET',))
|
||||||
! def acs():
|
+def metadata():
|
||||||
! req = prepare_flask_request(flask.request)
|
+ """
|
||||||
! auth = init_saml_auth(req)
|
+ Returns the Build System IDP provider metadata.
|
||||||
! auth.process_response()
|
|
||||||
! errors = auth.get_errors()
|
+ Returns
|
||||||
! if errors:
|
+ -------
|
||||||
! return flask.helpers.make_response('Error: {0}'.format(', '.join(errors)), 500)
|
+ flask.wrappers.Response
|
||||||
! elif not auth.is_authenticated():
|
+ IDP provider metadata response.
|
||||||
! return flask.helpers.make_response('Error: authentication failed', 401)
|
+
|
||||||
! user_attrs = auth.get_attributes()
|
+ See Also
|
||||||
|
+ --------
|
||||||
privileged = False
|
+ https://en.wikipedia.org/wiki/SAML_Metadata#Identity_Provider_Metadata
|
||||||
! is_admin = False
|
+ """
|
||||||
! if any(group in user_attrs['groups'] for group in ('alma_retrace_admin', 'admins')):
|
+ req = prepare_flask_request(flask.request)
|
||||||
privileged = True
|
+ auth = init_saml_auth(req)
|
||||||
+ is_admin = True
|
+ settings = auth.get_settings()
|
||||||
|
+ metadata = settings.get_sp_metadata()
|
||||||
+ email = user_attrs['email'][0]
|
+ errors = settings.validate_metadata(metadata)
|
||||||
+ username = email.split('@')[0]
|
+ if errors:
|
||||||
user = db.session.query(User).filter(User.username == username).first()
|
+ rsp = flask.make_response(', '.join(errors), 500)
|
||||||
if not user: # create
|
+ else:
|
||||||
! user = User(username=username, mail=email, privileged=privileged, admin=is_admin)
|
+ rsp = flask.make_response(metadata, 200)
|
||||||
else:
|
+ rsp.headers['Content-Type'] = 'text/xml'
|
||||||
! user.mail = email
|
+ return rsp
|
||||||
user.privileged = privileged
|
+
|
||||||
+ user.admin = is_admin
|
+
|
||||||
|
@login.route("/logout/")
|
||||||
db.session.add(user)
|
def do_logout() -> Response:
|
||||||
db.session.commit()
|
- flask.session.pop("openid", None)
|
||||||
flask.flash(u"Welcome, {0}".format(user.username))
|
+ flask.session.pop("username", None)
|
||||||
flask.g.user = user
|
flask.flash(u"You were signed out")
|
||||||
+ flask.session['username'] = username
|
- return flask.redirect(oid.get_next_url())
|
||||||
|
+ return flask.redirect(flask.url_for("summary.index"))
|
||||||
! return flask.redirect(flask.request.form['RelayState'])
|
diff -aruN faf-2.6.1/src/webfaf/webfaf_main.py faf-2.6.1.alma/src/webfaf/webfaf_main.py
|
||||||
|
--- faf-2.6.1/src/webfaf/webfaf_main.py 2023-01-11 17:35:16
|
||||||
!
|
+++ faf-2.6.1.alma/src/webfaf/webfaf_main.py 2023-05-23 09:53:06
|
||||||
! @login.route('/metadata/', methods=('GET',))
|
@@ -170,8 +170,8 @@
|
||||||
! def metadata():
|
@app.before_request
|
||||||
! """
|
def before_request() -> None:
|
||||||
! Returns the Build System IDP provider metadata.
|
flask.g.user = None
|
||||||
!
|
- if "openid" in flask.session:
|
||||||
! Returns
|
- username = fed_raw_name(flask.session["openid"])
|
||||||
! -------
|
+ if "username" in flask.session:
|
||||||
! flask.wrappers.Response
|
+ username = flask.session["username"]
|
||||||
! IDP provider metadata response.
|
flask.g.user = (db.session.query(User)
|
||||||
!
|
.filter(User.username == username)
|
||||||
! See Also
|
.first())
|
||||||
! --------
|
diff -aruN faf-2.6.1/tests/test_webfaf/test_user.py faf-2.6.1.alma/tests/test_webfaf/test_user.py
|
||||||
! https://en.wikipedia.org/wiki/SAML_Metadata#Identity_Provider_Metadata
|
--- faf-2.6.1/tests/test_webfaf/test_user.py 2023-01-11 17:35:16
|
||||||
! """
|
+++ faf-2.6.1.alma/tests/test_webfaf/test_user.py 2023-05-23 09:53:28
|
||||||
! req = prepare_flask_request(flask.request)
|
@@ -24,7 +24,7 @@
|
||||||
! auth = init_saml_auth(req)
|
self.db.session.commit()
|
||||||
! settings = auth.get_settings()
|
|
||||||
! metadata = settings.get_sp_metadata()
|
with self.app.session_transaction() as session:
|
||||||
! errors = settings.validate_metadata(metadata)
|
- session['openid'] = 'faker1'
|
||||||
! if errors:
|
+ session['username'] = 'faker1'
|
||||||
! rsp = flask.make_response(', '.join(errors), 500)
|
|
||||||
! else:
|
def test_delete_user_data(self):
|
||||||
! rsp = flask.make_response(metadata, 200)
|
"""
|
||||||
! rsp.headers['Content-Type'] = 'text/xml'
|
|
||||||
! return rsp
|
|
||||||
|
|
||||||
|
|
||||||
@login.route("/logout/")
|
|
||||||
def do_logout() -> Response:
|
|
||||||
! flask.session.pop("username", None)
|
|
||||||
flask.flash(u"You were signed out")
|
|
||||||
! return flask.redirect(flask.url_for("summary.index"))
|
|
||||||
!
|
|
||||||
diff -crB src.orig/webfaf/templates/base.html src/webfaf/templates/base.html
|
|
||||||
*** src.orig/webfaf/templates/base.html 2021-02-11 11:31:12.000000000 +0200
|
|
||||||
--- src/webfaf/templates/base.html 2021-02-11 13:09:20.000000000 +0200
|
|
||||||
***************
|
|
||||||
*** 71,77 ****
|
|
||||||
</ul>
|
|
||||||
{% if config['OPENID_ENABLED'] %}
|
|
||||||
<ul class="nav navbar-nav navbar-utility">
|
|
||||||
- <li><a href="https://apps.fedoraproject.org/notifications" class="fa fa-bell notifications" title="Notifications preferences"></a></li>
|
|
||||||
{% if g.user %}
|
|
||||||
<li class="dropdown">
|
|
||||||
<a id="user-dropdown" role="button" data-toggle="dropdown">
|
|
||||||
--- 71,76 ----
|
|
||||||
diff -crB src.orig/webfaf/webfaf_main.py src/webfaf/webfaf_main.py
|
|
||||||
*** src.orig/webfaf/webfaf_main.py 2021-02-11 11:31:15.000000000 +0200
|
|
||||||
--- src/webfaf/webfaf_main.py 2021-02-10 19:55:36.000000000 +0200
|
|
||||||
***************
|
|
||||||
*** 14,20 ****
|
|
||||||
import munch
|
|
||||||
from ratelimitingfilter import RateLimitingFilter
|
|
||||||
from werkzeug.local import LocalProxy
|
|
||||||
! from werkzeug.middleware.proxy_fix import ProxyFix
|
|
||||||
|
|
||||||
from pyfaf.storage.user import User
|
|
||||||
from pyfaf.storage import OpSysComponent, Report
|
|
||||||
--- 14,23 ----
|
|
||||||
import munch
|
|
||||||
from ratelimitingfilter import RateLimitingFilter
|
|
||||||
from werkzeug.local import LocalProxy
|
|
||||||
! try:
|
|
||||||
! from werkzeug.middleware.proxy_fix import ProxyFix
|
|
||||||
! except ModuleNotFoundError:
|
|
||||||
! from werkzeug.contrib.fixers import ProxyFix
|
|
||||||
|
|
||||||
from pyfaf.storage.user import User
|
|
||||||
from pyfaf.storage import OpSysComponent, Report
|
|
||||||
***************
|
|
||||||
*** 167,174 ****
|
|
||||||
@app.before_request
|
|
||||||
def before_request() -> None:
|
|
||||||
flask.g.user = None
|
|
||||||
! if "openid" in flask.session:
|
|
||||||
! username = fed_raw_name(flask.session["openid"])
|
|
||||||
flask.g.user = (db.session.query(User)
|
|
||||||
.filter(User.username == username)
|
|
||||||
.first())
|
|
||||||
--- 170,177 ----
|
|
||||||
@app.before_request
|
|
||||||
def before_request() -> None:
|
|
||||||
flask.g.user = None
|
|
||||||
! if "username" in flask.session:
|
|
||||||
! username = flask.session["username"]
|
|
||||||
flask.g.user = (db.session.query(User)
|
|
||||||
.filter(User.username == username)
|
|
||||||
.first())
|
|
||||||
diff -crB tests.orig/test_webfaf/test_user.py tests/test_webfaf/test_user.py
|
|
||||||
*** tests.orig/test_webfaf/test_user.py 2021-02-11 11:31:18.000000000 +0200
|
|
||||||
--- tests/test_webfaf/test_user.py 2021-02-11 11:55:50.000000000 +0200
|
|
||||||
***************
|
|
||||||
*** 24,30 ****
|
|
||||||
self.db.session.commit()
|
|
||||||
|
|
||||||
with self.app.session_transaction() as session:
|
|
||||||
! session['openid'] = 'faker1'
|
|
||||||
|
|
||||||
def test_delete_user_data(self):
|
|
||||||
"""
|
|
||||||
--- 24,30 ----
|
|
||||||
self.db.session.commit()
|
|
||||||
|
|
||||||
with self.app.session_transaction() as session:
|
|
||||||
! session['username'] = 'faker1'
|
|
||||||
|
|
||||||
def test_delete_user_data(self):
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
|
@ -571,7 +571,7 @@ systemd services for the Celery task queue.
|
||||||
%setup -q
|
%setup -q
|
||||||
# AlmaLinux support patches
|
# AlmaLinux support patches
|
||||||
%patch0 -p1
|
%patch0 -p1
|
||||||
%patch1 -p0
|
%patch1 -p1
|
||||||
|
|
||||||
NOCONFIGURE=1 ./autogen.sh
|
NOCONFIGURE=1 ./autogen.sh
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue