summaryrefslogtreecommitdiff
path: root/server.py
blob: 0bebe2ab7e87a48a2ef19cddecc2235aebed84ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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