265 lines
8.9 KiB
Diff
265 lines
8.9 KiB
Diff
|
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):
|
||
|
"""
|
||
|
|