67 lines
2.1 KiB
Go
67 lines
2.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
)
|
|
|
|
// Middleware resolves the current user for each request, from a session
|
|
// cookie first and falling back to trusted external auth, then makes it
|
|
// available via UserFromContext.
|
|
type Middleware struct {
|
|
Sessions *Sessions
|
|
ExtAuth *ExtAuth
|
|
}
|
|
|
|
// Authenticate resolves the current user (session cookie, then trusted
|
|
// external auth) and stores it in the request context, without requiring
|
|
// one to be present. Handlers that need to know whether someone is
|
|
// signed in (e.g. the login page, the home page) should use this.
|
|
func (m *Middleware) Authenticate(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
user := m.Sessions.CurrentUser(r)
|
|
if user == nil && m.ExtAuth != nil {
|
|
if username := m.ExtAuth.IdentityFromRequest(r); username != "" {
|
|
if u, err := m.ExtAuth.ResolveUser(username); err == nil && !u.Disabled {
|
|
user = u
|
|
_ = m.Sessions.Issue(w, r, u.ID)
|
|
}
|
|
}
|
|
}
|
|
if user != nil {
|
|
r = r.WithContext(WithUser(r.Context(), user))
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// RequireUser redirects unauthenticated requests to /login, preserving
|
|
// the original destination.
|
|
func (m *Middleware) RequireUser(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if UserFromContext(r.Context()) == nil {
|
|
http.Redirect(w, r, "/login?next="+url.QueryEscape(r.URL.RequestURI()), http.StatusFound)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// RequireAdmin is like RequireUser but also rejects non-admin users with
|
|
// 403. Authorization is enforced here, on the server, not merely by
|
|
// hiding admin links in the UI.
|
|
func (m *Middleware) RequireAdmin(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
user := UserFromContext(r.Context())
|
|
if user == nil {
|
|
http.Redirect(w, r, "/login?next="+url.QueryEscape(r.URL.RequestURI()), http.StatusFound)
|
|
return
|
|
}
|
|
if !user.IsAdmin {
|
|
http.Error(w, "403 Forbidden: administrator access required", http.StatusForbidden)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|