mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-19 08:44:14 +00:00
cleanup more auth
This commit is contained in:
+43
-28
@@ -7,26 +7,29 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bluesky-social/indigo/atproto/identity"
|
||||
"github.com/bluesky-social/indigo/atproto/syntax"
|
||||
|
||||
"atcr.io/pkg/appview/apikey"
|
||||
mainAtproto "atcr.io/pkg/atproto"
|
||||
"atcr.io/pkg/auth"
|
||||
"atcr.io/pkg/auth/atproto"
|
||||
"atcr.io/pkg/auth/session"
|
||||
)
|
||||
|
||||
// Handler handles /auth/token requests
|
||||
type Handler struct {
|
||||
issuer *Issuer
|
||||
validator *atproto.SessionValidator
|
||||
sessionManager *session.Manager // For validating session tokens
|
||||
apiKeyStore *apikey.Store // For validating API keys
|
||||
defaultHoldEndpoint string
|
||||
}
|
||||
|
||||
// NewHandler creates a new token handler
|
||||
func NewHandler(issuer *Issuer, sessionManager *session.Manager, defaultHoldEndpoint string) *Handler {
|
||||
func NewHandler(issuer *Issuer, apiKeyStore *apikey.Store, defaultHoldEndpoint string) *Handler {
|
||||
return &Handler{
|
||||
issuer: issuer,
|
||||
validator: atproto.NewSessionValidator(),
|
||||
sessionManager: sessionManager,
|
||||
apiKeyStore: apiKeyStore,
|
||||
defaultHoldEndpoint: defaultHoldEndpoint,
|
||||
}
|
||||
}
|
||||
@@ -80,19 +83,25 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var handle string
|
||||
var accessToken string
|
||||
|
||||
// Try to validate as session token first (our OAuth flow)
|
||||
// Session tokens have format: <base64_claims>.<base64_signature>
|
||||
sessionClaims, sessionErr := h.sessionManager.Validate(password)
|
||||
if sessionErr == nil {
|
||||
// Successfully validated as session token
|
||||
did = sessionClaims.DID
|
||||
handle = sessionClaims.Handle
|
||||
fmt.Printf("DEBUG [token/handler]: Session token validated for DID=%s, handle=%s\n", did, handle)
|
||||
// For session tokens, we don't have a PDS access token here
|
||||
// The registry will use OAuth refresh tokens to get one when needed
|
||||
// 1. Check if it's an API key (starts with "atcr_")
|
||||
if strings.HasPrefix(password, "atcr_") {
|
||||
apiKey, err := h.apiKeyStore.Validate(password)
|
||||
if err != nil {
|
||||
fmt.Printf("DEBUG [token/handler]: API key validation failed: %v\n", err)
|
||||
w.Header().Set("WWW-Authenticate", `Basic realm="ATCR Registry"`)
|
||||
http.Error(w, "authentication failed", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
did = apiKey.DID
|
||||
handle = apiKey.Handle
|
||||
fmt.Printf("DEBUG [token/handler]: API key validated for DID=%s, handle=%s\n", did, handle)
|
||||
|
||||
// API key is linked to OAuth session
|
||||
// OAuth refresher will provide access token when needed via middleware
|
||||
} else {
|
||||
// Not a session token, try app password (Basic Auth flow)
|
||||
fmt.Printf("DEBUG [token/handler]: Not a session token, trying app password for %s\n", username)
|
||||
// 2. Try app password (direct PDS authentication)
|
||||
fmt.Printf("DEBUG [token/handler]: Not an API key, trying app password for %s\n", username)
|
||||
did, handle, accessToken, err = h.validator.CreateSessionAndGetToken(r.Context(), username, password)
|
||||
if err != nil {
|
||||
fmt.Printf("DEBUG [token/handler]: App password validation failed: %v\n", err)
|
||||
@@ -110,19 +119,25 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Ensure user profile exists (creates with default hold if needed)
|
||||
// Resolve PDS endpoint for profile management
|
||||
resolver := mainAtproto.NewResolver()
|
||||
_, pdsEndpoint, err := resolver.ResolveIdentity(r.Context(), username)
|
||||
if err != nil {
|
||||
// Log error but don't fail auth - profile management is not critical
|
||||
fmt.Printf("WARNING: failed to resolve PDS for profile management: %v\n", err)
|
||||
} else {
|
||||
// Create ATProto client with validated token
|
||||
atprotoClient := mainAtproto.NewClient(pdsEndpoint, did, accessToken)
|
||||
|
||||
// Ensure profile exists (will create with default hold if not exists and default is configured)
|
||||
if err := mainAtproto.EnsureProfile(r.Context(), atprotoClient, h.defaultHoldEndpoint); err != nil {
|
||||
directory := identity.DefaultDirectory()
|
||||
atID, err := syntax.ParseAtIdentifier(username)
|
||||
if err == nil {
|
||||
ident, err := directory.Lookup(r.Context(), *atID)
|
||||
if err != nil {
|
||||
// Log error but don't fail auth - profile management is not critical
|
||||
fmt.Printf("WARNING: failed to ensure profile for %s: %v\n", did, err)
|
||||
fmt.Printf("WARNING: failed to resolve PDS for profile management: %v\n", err)
|
||||
} else {
|
||||
pdsEndpoint := ident.PDSEndpoint()
|
||||
if pdsEndpoint != "" {
|
||||
// Create ATProto client with validated token
|
||||
atprotoClient := mainAtproto.NewClient(pdsEndpoint, did, accessToken)
|
||||
|
||||
// Ensure profile exists (will create with default hold if not exists and default is configured)
|
||||
if err := mainAtproto.EnsureProfile(r.Context(), atprotoClient, h.defaultHoldEndpoint); err != nil {
|
||||
// Log error but don't fail auth - profile management is not critical
|
||||
fmt.Printf("WARNING: failed to ensure profile for %s: %v\n", did, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user