/letmein

SSO and auth proxy with some authorization

Primary LanguageGo

LetMeIn

A simple AuthForwarder handler for the Traefik reverse proxy. It might work for other reverse proxies as well, as it returns HTTP status codes for authorization requests.

Rationale

I wanted to avoid creating new passwords for the web services I host and run, so I figured creating kind of an SSO with authorization would be a nice exercise.

Requirements

A postgresql server with the following tables:

Users

lmi=> \d users
                                    Table "public.users"
Column  |          Type          | Collation | Nullable |              Default
----------+------------------------+-----------+----------+-----------------------------------
id       | integer                |           | not null | nextval('users_id_seq'::regclass)
username | character varying(255) |           | not null |
password | text                   |           | not null |
salt     | text                   |           | not null |
admin    | boolean                |           | not null | false
Indexes:
    "id_user" PRIMARY KEY, btree (id)
    "username_unique" UNIQUE CONSTRAINT, btree (username)
Referenced by:
    TABLE "claims" CONSTRAINT "claims_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)

Sites

lmi=> \d sites
                            Table "public.sites"
Column |  Type   | Collation | Nullable |              Default
--------+---------+-----------+----------+-----------------------------------
id     | integer |           | not null | nextval('sites_id_seq'::regclass)
url    | text    |           | not null |
Indexes:
    "id_site" PRIMARY KEY, btree (id)
    "url_unique" UNIQUE CONSTRAINT, btree (url)
Referenced by:
    TABLE "claims" CONSTRAINT "claims_site_id_fkey" FOREIGN KEY (site_id) REFERENCES sites(id)

Claims

lmi=> \d claims
            Table "public.claims"
Column  |  Type   | Collation | Nullable | Default
---------+---------+-----------+----------+---------
user_id | integer |           | not null |
site_id | integer |           | not null |
Indexes:
    "claims_unique_user_url" UNIQUE CONSTRAINT, btree (user_id, site_id)
Foreign-key constraints:
    "claims_site_id_fkey" FOREIGN KEY (site_id) REFERENCES sites(id)
    "claims_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)

And a traefik configuration similar to the following

# Routers
[http.routers]
# The app to auth proxy
[http.routers.my-router]
    rule = "Path(`/foo`)"
    middlewares = ["letmein"]
    service = "foo"

# LetMeIn, the auth proxy - login view
[http.routers.login]
    rule = "Path(`/login`)"
    service = "letmein"

# Middlewares
# Set up LetMeIn as an auth proxy
[http.middlewares]
    [http.middlewares.letmein.forwardAuth]
    address = "http://[::1]:8003/auth"
    authResponseHeaders = ["X-Auth-User"]

## Services
[http.services]
[http.services.foo.loadBalancer]

    [[http.services.foo.loadBalancer.servers]]
    url = "http://foo/"

    # LetMeIn, the auth proxy - login view
    [[http.services.letmein.loadBalancer.servers]]
    url = "http://[::1]:8003/login"

Screenshots

https://i.imgur.com/QURv4ir.png