package middleware import ( "net/http" "time" "forge.cadoles.com/arcad/edge/pkg/jwtutil" "forge.cadoles.com/arcad/edge/pkg/module/auth" "github.com/lestrrat-go/jwx/v2/jwa" "github.com/lestrrat-go/jwx/v2/jwk" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) func DefaultUser(key jwk.Key, signingAlgorithm jwa.SignatureAlgorithm, funcs ...DefaultUserOptionFunc) func(next http.Handler) http.Handler { opts := defaultUserOptions() for _, fn := range funcs { fn(opts) } return func(next http.Handler) http.Handler { handler := func(w http.ResponseWriter, r *http.Request) { rawToken, err := jwtutil.FindRawToken(r, jwtutil.WithFinders( jwtutil.FindTokenFromAuthorizationHeader, jwtutil.FindTokenFromQueryString(auth.CookieName), jwtutil.FindTokenFromCookie(auth.CookieName), )) // If request already has a raw token, we do nothing if rawToken != "" && err == nil { next.ServeHTTP(w, r) return } ctx := r.Context() subject, err := opts.GetSubject(r) if err != nil { logger.Error(ctx, "could not retrieve user subject", logger.CapturedE(errors.WithStack(err))) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } preferredUsername, err := opts.GetPreferredUsername(r) if err != nil { logger.Error(ctx, "could not retrieve user preferred username", logger.CapturedE(errors.WithStack(err))) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } claims := map[string]any{ auth.ClaimSubject: subject, auth.ClaimIssuer: opts.Issuer, auth.ClaimPreferredUsername: preferredUsername, auth.ClaimEdgeRole: opts.Role, auth.ClaimEdgeEntrypoint: opts.Entrypoint, auth.ClaimEdgeTenant: opts.Tenant, } token, err := jwtutil.SignedToken(key, signingAlgorithm, claims) if err != nil { logger.Error(ctx, "could not generate signed token", logger.CapturedE(errors.WithStack(err))) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } cookieDomain, err := opts.GetCookieDomain(r) if err != nil { logger.Error(ctx, "could not retrieve cookie domain", logger.CapturedE(errors.WithStack(err))) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } cookie := http.Cookie{ Name: auth.CookieName, Value: string(token), Domain: cookieDomain, HttpOnly: false, Expires: time.Now().Add(opts.CookieDuration), Path: "/", } http.SetCookie(w, &cookie) next.ServeHTTP(w, r) } return http.HandlerFunc(handler) } }