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