class OIDCAuthService(AuthService): def __init__(self, datasource=None, backend=None, app=None): super().__init__(datasource=datasource, backend=backend) self.oidc = OpenIDConnect(app) def authenticate(self, credentials): auth_header = request.headers.get("Authorization", "").split(" ", 1) if auth_header[0] != "Bearer" and len(auth_header) != 2: raise CredentialsAuthError(credentials) token = auth_header[1] is_valid = self.oidc.validate_token(token, ["openid", "email", "profile"]) if not is_valid: raise CredentialsAuthError(credentials) users_service = get_resource_service("users") username = g.oidc_token_info["username"] user = users_service.find_one(req=None, username=username) or {} sync_data = { "username": username, "email": g.oidc_token_info.get("email", user.get("email")), "display_name": g.oidc_token_info.get("name"), } # first name and last name is optional in Keycloak if "given_name" in g.oidc_token_info: sync_data["first_name"] = g.oidc_token_info.get("given_name") if "family_name" in g.oidc_token_info: sync_data["last_name"] = g.oidc_token_info.get("family_name") if not user: # email is optional in Keycloak if not sync_data["email"]: raise CredentialsAuthError( sync_data, message=_("Please update your account email address")) user_role = None client_id = g.oidc_token_info.get("client_id", "") keycloak_roles = g.oidc_token_info.get("resource_access", {}).get( client_id, {}).get("roles", []) for role_name in keycloak_roles: role = get_resource_service("roles").find_one( req=None, name=ignorecase_query(role_name)) if role: user_role = role.get("_id") break sync_data.update({ "password": "", "user_type": "user", "role": user_role, "needs_activation": False, }) users_service.post([sync_data]) else: users_service.patch(user[config.ID_FIELD], sync_data) user.update(sync_data) return user
def create_app(config, oidc_overrides=None): global oidc app = Flask(__name__) app.config.update(config) if oidc_overrides is None: oidc_overrides = {} oidc = OpenIDConnect(app, **oidc_overrides) app.route('/')(oidc.check(index)) app.route('/at')(oidc.check(get_at)) app.route('/rt')(oidc.check(get_rt)) # Check standalone usage rendered = oidc.accept_token(True, ['openid'])(api) app.route('/api', methods=['GET', 'POST'])(rendered) # Check combination with an external API renderer like Flask-RESTful unrendered = oidc.accept_token(True, ['openid'], render_errors=False)(raw_api) def externally_rendered_api(*args, **kwds): inner_response = unrendered(*args, **kwds) if isinstance(inner_response, tuple): raw_response, response_code, headers = inner_response rendered_response = json.dumps( raw_response), response_code, headers else: rendered_response = json.dumps(inner_response) return rendered_response app.route('/external_api', methods=['GET', 'POST'])(externally_rendered_api) return app
import json from flask_oidc_ex import OpenIDConnect from flask import Flask, g, jsonify, request, session import logging logging.basicConfig(level=logging.DEBUG) app = Flask(__name__) app.config.from_json("config/config.json") oidc = OpenIDConnect(app) @app.route("/flask-oidc/") def home(): if oidc.user_loggedin: email = oidc.user_getfield("email") return f""" <div> <div>Hello, {email}</dic> <ul> <li><a href="/flask-oidc/profile/">Profile</a></li> <li><a href="/flask-oidc/token/">complete_token</a></li> <li><a href="/flask-oidc/token_info/">token_info</a></li> <li><a href="/flask-oidc/role_protected/token_info/">role_token_info</a></li> <li><a href="/flask-oidc/logout/">Log out</a></li> </ul> </div> """ else: return 'Welcome anonymous, <a href="/flask-oidc/login/">Log in</a>'
def __init__(self, datasource=None, backend=None, app=None): super().__init__(datasource=datasource, backend=backend) self.oidc = OpenIDConnect(app)