import flask import urllib.parse from flask import request # Application Config OIDC_ISSUER = "https://id.crute.me/" OIDC_AUTH_ENDPOINT = "{}login".format(OIDC_ISSUER) OIDC_JWKS_ENDPOINT = "{}jwks".format(OIDC_ISSUER) DOMAIN_WHITELIST = ["crute.me", "crute.us"] # Generic Constants JRD_MIMETYPE = "application/jrd+json" OIDC_ISSUER_QUERY = "http://openid.net/specs/connect/1.0/issuer" JRD_404 = flask.Response("Not found", status=404, mimetype=JRD_MIMETYPE) app = flask.Flask(__name__) def parse_email_addr(addr): try: user, domain = addr.split("@") return user, domain except ValueError: return None @app.route("/.well-known/webfinger", methods=["GET"]) def webfinger(): resource = request.args.get("resource") rel = request.args.get("rel") # Only support OIDC queries if not rel or not resource or not rel == OIDC_ISSUER_QUERY: return JRD_404 # Only support email address queries acct = urllib.parse.urlparse(resource) if acct.scheme != "acct": return JRD_404 # Ensure that the query is in a whitelisted domain _, domain = parse_email_addr(acct.path) if domain not in DOMAIN_WHITELIST: return JRD_404 # We don't validate that the user exists to prevent leaking information # about what users exist; plus, it doesn't really matter since the querier # only cares about the OIDC issuer endpoint which is user independent res = flask.jsonify({ "subject": resource, "links": [{ "rel": OIDC_ISSUER_QUERY, "href": OIDC_ISSUER, }] }) res.mimetype = JRD_MIMETYPE return res @app.route("/.well-known/openid-configuration", methods=["GET"]) def openid_configuration(): return flask.jsonify({ "issuer": OIDC_ISSUER, "authorization_endpoint": OIDC_AUTH_ENDPOINT, "jwks_uri": OIDC_JWKS_ENDPOINT, "scopes_supported": ["openid"], "response_types_supported": ["id_token"], "response_modes_supported": ["query"], "grant_types_supported": ["implicit"], "subject_types_supported": ["public"], "id_token_signing_alg_values_supported": ["RS256"], "acr_values_supported": ["want_mfa", "need_mfa"], }) @app.route("/login", methods=["GET", "POST"]) def login(): pass @app.route("/jwks", methods=["GET"]) def keys(): pass