91 lines
1.8 KiB
Go
91 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
type contextKey string
|
|
|
|
const userContextKey contextKey = "auth_user"
|
|
|
|
type User struct {
|
|
Sub string
|
|
Email string
|
|
Name string
|
|
}
|
|
|
|
type Auth struct {
|
|
devMode bool
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewAuth(cfg Config) (*Auth, error) {
|
|
return &Auth{devMode: cfg.DevMode}, nil
|
|
}
|
|
|
|
func (a *Auth) WithDB(db *sql.DB) {
|
|
a.db = db
|
|
}
|
|
|
|
func (a *Auth) RequireAuth(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
user, ok := a.userFromRequest(r)
|
|
if !ok {
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
if a.db != nil {
|
|
_, _ = a.db.ExecContext(r.Context(), `
|
|
INSERT INTO users (sub, email, name)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (sub) DO UPDATE
|
|
SET email = EXCLUDED.email, name = EXCLUDED.name
|
|
`, user.Sub, user.Email, user.Name)
|
|
}
|
|
|
|
ctx := context.WithValue(r.Context(), userContextKey, user)
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
|
|
func (a *Auth) userFromRequest(r *http.Request) (User, bool) {
|
|
if a.devMode {
|
|
return User{Sub: "demo-user-001", Email: "demo@example.com", Name: "Demo User"}, true
|
|
}
|
|
|
|
sub := strings.TrimSpace(r.Header.Get("X-Authentik-Uid"))
|
|
if sub == "" {
|
|
sub = strings.TrimSpace(r.Header.Get("X-Forwarded-User"))
|
|
}
|
|
email := strings.TrimSpace(r.Header.Get("X-Authentik-Email"))
|
|
name := strings.TrimSpace(r.Header.Get("X-Authentik-Name"))
|
|
if name == "" {
|
|
name = strings.TrimSpace(r.Header.Get("X-Forwarded-Preferred-Username"))
|
|
}
|
|
|
|
if sub == "" {
|
|
return User{}, false
|
|
}
|
|
if email == "" {
|
|
email = sub
|
|
}
|
|
if name == "" {
|
|
name = email
|
|
}
|
|
return User{Sub: sub, Email: email, Name: name}, true
|
|
}
|
|
|
|
func MustUserFromContext(ctx context.Context) User {
|
|
v := ctx.Value(userContextKey)
|
|
if v == nil {
|
|
return User{}
|
|
}
|
|
if u, ok := v.(User); ok {
|
|
return u
|
|
}
|
|
return User{}
|
|
}
|