add a simple auth function
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
parent
e1aff8d16b
commit
87fe581353
10 changed files with 206 additions and 8 deletions
91
internal/api/auth.go
Normal file
91
internal/api/auth.go
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
// Action identifies the operation being performed.
|
||||
// Format: "resource:verb"
|
||||
type Action string
|
||||
|
||||
const (
|
||||
ActionRepoList Action = "repos:list"
|
||||
ActionRepoCreate Action = "repos:create"
|
||||
ActionRepoRead Action = "repos:read"
|
||||
ActionRepoUpdate Action = "repos:update"
|
||||
ActionRepoDelete Action = "repos:delete"
|
||||
|
||||
ActionCloneStart Action = "clone:start"
|
||||
ActionCloneRead Action = "clone:read"
|
||||
|
||||
ActionSyncTrigger Action = "sync:trigger"
|
||||
ActionSyncRead Action = "sync:read"
|
||||
ActionSyncApprove Action = "sync:approve"
|
||||
ActionSyncReject Action = "sync:reject"
|
||||
ActionSyncBlock Action = "sync:block"
|
||||
|
||||
ActionSnapshotCreate Action = "snapshots:create"
|
||||
ActionSnapshotRead Action = "snapshots:read"
|
||||
ActionSnapshotDelete Action = "snapshots:delete"
|
||||
ActionSnapshotRollback Action = "snapshots:rollback"
|
||||
)
|
||||
|
||||
var ErrForbidden = errors.New("forbidden")
|
||||
|
||||
// Caller holds the identity injected into the request context by LocalhostAuth.
|
||||
type Caller struct {
|
||||
IP string
|
||||
RequestID string
|
||||
LocalhostPrivileged bool
|
||||
}
|
||||
|
||||
type contextKey string
|
||||
|
||||
const callerKey contextKey = "caller"
|
||||
|
||||
// CallerFromContext returns the Caller injected by LocalhostAuth, or nil.
|
||||
func CallerFromContext(ctx context.Context) *Caller {
|
||||
c, _ := ctx.Value(callerKey).(*Caller)
|
||||
return c
|
||||
}
|
||||
|
||||
// Authorize checks whether the caller in ctx is allowed to perform action on repoID.
|
||||
// repoID == 0 means the action is not scoped to a specific repo (e.g. list, create).
|
||||
//
|
||||
// If localhost_privileged is enabled, 127.0.0.1/::1 are always allowed without a token.
|
||||
// Other callers are currently allowed too; token enforcement will be added with the web UI.
|
||||
func Authorize(ctx context.Context, action Action, repoID int64) error {
|
||||
caller := CallerFromContext(ctx)
|
||||
if caller == nil {
|
||||
return ErrForbidden
|
||||
}
|
||||
if caller.LocalhostPrivileged && (caller.IP == "127.0.0.1" || caller.IP == "::1") {
|
||||
return nil
|
||||
}
|
||||
// Future: look up token permissions for non-localhost callers.
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalhostAuth injects a Caller into the context for downstream Authorize calls.
|
||||
// localhostPrivileged controls whether 127.0.0.1/::1 bypass future token enforcement.
|
||||
func LocalhostAuth(localhostPrivileged bool) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
ip = r.RemoteAddr
|
||||
}
|
||||
caller := &Caller{
|
||||
IP: ip,
|
||||
RequestID: middleware.GetReqID(r.Context()),
|
||||
LocalhostPrivileged: localhostPrivileged,
|
||||
}
|
||||
next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), callerKey, caller)))
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue