def login() -> Union[str, Response]: """User login page.""" if current_user.get_id(): next_url = request.args.get("next", default="/") if is_safe_url(next_url, app.config["ALLOWED_HOSTS"]) is False: return abort(400) return redirect(next_url) # if demo, login as first user if app.config.get("DEMO"): session.pop("_flashes", None) user = User.query.first() if user: login_user(user, remember=True) else: flash("Something broke!") next_url = request.args.get("next", default="/") if is_safe_url(next_url, app.config["ALLOWED_HOSTS"]) is False: return abort(400) return redirect(next_url) if request.method == "POST" and app.config["AUTH_METHOD"] in ["LDAP", "DEV"]: user = request.form.get("user", "") password = request.form.get("password", "") if app.config["AUTH_METHOD"] == "LDAP": # pragma: no cover ldap = LDAP(app) # type: ignore[no-untyped-call] ldap_details = ldap.bind_user(user, password) # type: ignore[no-untyped-call] if ldap_details is None or password == "": # noqa: S105 executor.submit(log_login, request.form["user"], 3) flash("Invalid login, please try again!") return render_template("pages/login.html.j2", title="Login") # require specific user group # fmt: off if "REQUIRED_GROUPS" in app.config and not set( app.config["REQUIRED_GROUPS"] ).issubset( set(ldap.get_user_groups(user=user.lower())) # type: ignore[no-untyped-call] ): executor.submit(log_login, request.form["user"], 3) flash( "You must be part of the %s group(s) to use this site." % app.config["REQUIRED_GROUPS"] ) return render_template("pages/login.html.j2", title="Login") # fmt: on executor.submit(log_login, request.form["user"], 1) user = User.query.filter( (User.account_name == user.lower()) | (User.email == user.lower()) ).first() # if user isn't existing, create if not user: user = User() # type: ignore[call-arg] # update user attributes user.account_name = ( ldap_details.get(app.config["LDAP_ATTR_MAP"]["account_name"])[0] .decode("utf-8") .lower() ) user.email = ( ldap_details.get(app.config["LDAP_ATTR_MAP"]["email"])[0] .decode("utf-8") .lower() ) user.full_name = ldap_details.get(app.config["LDAP_ATTR_MAP"]["full_name"])[ 0 ].decode("utf-8") user.first_name = ldap_details.get( app.config["LDAP_ATTR_MAP"]["first_name"] )[0].decode("utf-8") db.session.add(user) db.session.commit() login_user(user, remember=True) next_url = request.args.get("next", default="/") if is_safe_url(next_url, app.config["ALLOWED_HOSTS"]) is False: return abort(400) return redirect(next_url) if app.config["AUTH_METHOD"] == "DEV": # pragma: no cover user = User.query.filter( (User.account_name == user.lower()) | (User.email == user.lower()) ).first() if user: login_user(user, remember=True) else: flash("Invalid login, please try again!") next_url = request.args.get("next", default="/") if is_safe_url(next_url, app.config["ALLOWED_HOSTS"]) is False: return abort(400) return redirect(next_url) # if login methods fail, add flash message flash("Invalid login, please try again!") # saml does not have a login page but redirects to idp if app.config["AUTH_METHOD"] == "SAML": # pragma: no cover saml = SAML(app) saml_client = saml.saml_client_for() # pylint: disable=W0612 reqid, info = saml_client.prepare_for_authenticate() redirect_url = "" # Select the IdP URL to send the AuthN request to for key, value in info["headers"]: if key == "Location": redirect_url = value # add next url to request to be appropriatly redirected # after a successful login next_url = request.args.get("next", "/") if is_safe_url(next_url, app.config["ALLOWED_HOSTS"]): redirect_url += "&RelayState=" + next_url return redirect(redirect_url) return render_template("pages/login.html.j2", title="Login")
def idp_initiated() -> Response: """Get response from IDP.""" try: saml = SAML(app) saml_client = saml.saml_client_for() authn_response = saml_client.parse_authn_request_response( request.form["SAMLResponse"], entity.BINDING_HTTP_POST) identity = authn_response.get_identity() if "REQUIRED_GROUPS" in app.config and not set( app.config["REQUIRED_GROUPS"]).issubset( set(identity.get(app.config["SAML_ATTR_MAP"]["groups"]))): session.pop("_flashes", None) # user is not authorized. flash("You must be part of the %s group(s) to use this site." % app.config["REQUIRED_GROUPS"]) return redirect(app.config["NOT_AUTHORIZED_URL"]) logging.warning(identity) if identity: account_name = identity.get( app.config["SAML_ATTR_MAP"]["account_name"])[0].lower() email = identity.get( app.config["SAML_ATTR_MAP"]["email"])[0].lower() user = User.query.filter((User.account_name == account_name) | (User.email == email)).first() # if user isn't existing, create if not user: user = User() # update user attributes user.account_name = account_name user.email = email user.full_name = "%s %s" % ( identity.get(app.config["SAML_ATTR_MAP"]["first_name"])[0], identity.get(app.config["SAML_ATTR_MAP"]["last_name"])[0], ) user.first_name = identity.get( app.config["SAML_ATTR_MAP"]["first_name"])[0] db.session.add(user) db.session.commit() login_user(user, remember=True) next_url = (request.args.get("next") or request.args.get("RelayState") or request.form.get("RelayState") or app.config["LOGIN_REDIRECT_URL"]) if not is_safe_url(next_url, app.config["ALLOWED_HOSTS"]): return abort(400) session.pop("_flashes", None) return redirect(next_url) return redirect(app.congif["LOGIN_VIEW"]) except SignatureError as e: flash(str(e)) return redirect(app.congif["SAML_ATTR_MAP"])