aboutsummaryrefslogtreecommitdiffstats
path: root/python/fatcat_web/auth.py
blob: 0bdb564f17f65f48fffb616fe3910ee07b982d2e (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
88
89
90

from flask import Flask, render_template, send_from_directory, request, \
    url_for, abort, g, redirect, jsonify, session, flash
from fatcat_web import login_manager, api, priv_api, Config
from flask_login import logout_user, login_user, UserMixin
import pymacaroons
import fatcat_client

def handle_logout():
    logout_user()
    for k in ('editor', 'token'):
        if k in session:
            session.pop(k)

def handle_token_login(token):
    try:
        m = pymacaroons.Macaroon.deserialize(token)
    except pymacaroons.exceptions.MacaroonDeserializationException:
        # TODO: what kind of Exceptions?
        return abort(400)
    # extract editor_id
    editor_id = None
    for caveat in m.first_party_caveats():
        caveat = caveat.caveat_id
        if caveat.startswith(b"editor_id = "):
            editor_id = caveat[12:].decode('utf-8')
    if not editor_id:
        abort(400)
    # fetch editor info
    editor = api.get_editor(editor_id)
    session['api_token'] = token
    session['editor'] = editor.to_dict()
    login_user(load_user(editor.editor_id))
    return redirect("/auth/account")

# This will need to login/signup via fatcatd API, then set token in session
def handle_oauth(remote, token, user_info):
    if user_info:
        # fetch api login/signup using user_info
        # ISS is basically the API url (though more formal in OIDC)
        # SUB is the stable internal identifier for the user (not usually the username itself)
        # TODO: should have the real sub here
        # TODO: would be nicer to pass preferred_username for account creation
        iss = remote.OAUTH_CONFIG['api_base_url']

        # we reuse 'preferred_username' for account name auto-creation (but
        # don't store it otherwise in the backend, at least currently). But i'm
        # not sure all loginpass backends will set it
        if user_info.get('preferred_username'):
            preferred_username = user_info['preferred_username']
        else:
            preferred_username = user_info['sub']

        params = fatcat_client.AuthOidc(remote.name, user_info['sub'], iss, user_info['preferred_username'])
        # this call requires admin privs
        (resp, http_status, http_headers) = priv_api.auth_oidc_with_http_info(params)
        editor = resp.editor
        api_token = resp.token

        if http_status == 201:
            flash("Welcome to Fatcat! An account has been created for you with a temporary username; you may wish to change it under account settings")
            flash("You must use the same mechanism ({}) to login in the future".format(remote.name))
        else:
            flash("Welcome back!")

        # write token and username to session
        session['api_token'] = api_token
        session['editor'] = editor.to_dict()

        # call login_user(load_user(editor_id))
        login_user(load_user(editor.editor_id))
        return redirect("/auth/account")

    raise some_error


@login_manager.user_loader
def load_user(editor_id):
    # looks for extra info in session, and updates the user object with that.
    # If session isn't loaded/valid, should return None
    if not 'editor' in session or not 'api_token' in session:
        return None
    editor = session['editor']
    token = session['api_token']
    user = UserMixin()
    user.id = editor_id
    user.editor_id = editor_id
    user.username = editor['username']
    user.token = token
    return user