func (root *rootHandler) doAuth(ctx context.Context, imageName string, w http.ResponseWriter) (context.Context, error) { var access []auth.Access if imageName == "" { access = buildCatalogRecord(root.actions...) } else { access = buildAccessRecords(imageName, root.actions...) } log := ctxu.GetRequestLogger(ctx) var authCtx context.Context var err error if authCtx, err = root.auth.Authorized(ctx, access...); err != nil { if challenge, ok := err.(auth.Challenge); ok { // Let the challenge write the response. challenge.SetHeaders(w) if err := errcode.ServeJSON(w, errcode.ErrorCodeUnauthorized.WithDetail(access)); err != nil { log.Errorf("failed to serve challenge response: %s", err.Error()) return nil, err } return nil, err } errcode.ServeJSON(w, errcode.ErrorCodeUnauthorized) return nil, err } return authCtx, nil }
// ServeHTTP serves an HTTP request and implements the http.Handler interface. func (root *rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) ctx := ctxu.WithRequest(root.context, r) ctx, w = ctxu.WithResponseWriter(ctx, w) ctx = ctxu.WithLogger(ctx, ctxu.GetRequestLogger(ctx)) ctx = context.WithValue(ctx, "repo", vars["imageName"]) ctx = context.WithValue(ctx, "cryptoService", root.trust) defer func() { ctxu.GetResponseLogger(ctx).Info("response completed") }() if root.auth != nil { access := buildAccessRecords(vars["imageName"], root.actions...) var authCtx context.Context var err error if authCtx, err = root.auth.Authorized(ctx, access...); err != nil { if err, ok := err.(auth.Challenge); ok { err.ServeHTTP(w, r) w.WriteHeader(http.StatusUnauthorized) return } errcode.ServeJSON(w, v2.ErrorCodeUnauthorized) return } ctx = authCtx } if err := root.handler(ctx, w, r); err != nil { e := errcode.ServeJSON(w, err) if e != nil { logrus.Error(e) } return } }
// ServeHTTP serves an HTTP request and implements the http.Handler interface. func (root *rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var ( err error ctx = ctxu.WithRequest(root.context, r) log = ctxu.GetRequestLogger(ctx) vars = mux.Vars(r) ) ctx, w = ctxu.WithResponseWriter(ctx, w) ctx = ctxu.WithLogger(ctx, log) ctx = context.WithValue(ctx, notary.CtxKeyCryptoSvc, root.trust) defer func() { ctxu.GetResponseLogger(ctx).Info("response completed") }() if root.auth != nil { ctx = context.WithValue(ctx, notary.CtxKeyRepo, vars["imageName"]) if ctx, err = root.doAuth(ctx, vars["imageName"], w); err != nil { // errors have already been logged/output to w inside doAuth // just return return } } if err := root.handler(ctx, w, r); err != nil { serveError(log, w, err) } }
// handlerWithContext wraps the given context-aware handler by setting up the // request context from a base context. func handlerWithContext(ctx context.Context, handler func(context.Context, http.ResponseWriter, *http.Request)) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := context.WithRequest(ctx, r) logger := context.GetRequestLogger(ctx) ctx = context.WithLogger(ctx, logger) handler(ctx, w, r) }) }
// ServeHTTP serves an HTTP request and implements the http.Handler interface. func (root *rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) ctx := ctxu.WithRequest(root.context, r) log := ctxu.GetRequestLogger(ctx) ctx, w = ctxu.WithResponseWriter(ctx, w) ctx = ctxu.WithLogger(ctx, log) ctx = context.WithValue(ctx, "repo", vars["imageName"]) ctx = context.WithValue(ctx, "cryptoService", root.trust) defer func() { ctxu.GetResponseLogger(ctx).Info("response completed") }() if root.auth != nil { access := buildAccessRecords(vars["imageName"], root.actions...) var authCtx context.Context var err error if authCtx, err = root.auth.Authorized(ctx, access...); err != nil { if challenge, ok := err.(auth.Challenge); ok { // Let the challenge write the response. challenge.SetHeaders(w) if err := errcode.ServeJSON(w, errcode.ErrorCodeUnauthorized.WithDetail(access)); err != nil { log.Errorf("failed to serve challenge response: %s", err.Error()) } return } errcode.ServeJSON(w, errcode.ErrorCodeUnauthorized) return } ctx = authCtx } if err := root.handler(ctx, w, r); err != nil { if httpErr, ok := err.(errcode.ErrorCoder); ok { // info level logging for non-5XX http errors httpErrCode := httpErr.ErrorCode().Descriptor().HTTPStatusCode if httpErrCode >= http.StatusInternalServerError { // error level logging for 5XX http errors log.Error(httpErr) } else { log.Info(httpErr) } } e := errcode.ServeJSON(w, err) if e != nil { log.Error(e) } return } }
func (t *tokenHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { ctx := context.WithRequest(t.ctx, req) // If no authorization is provided, return a token the auth provider will treat as an anonymous user if len(req.Header.Get("Authorization")) == 0 { context.GetRequestLogger(ctx).Debugf("anonymous token request") t.writeToken(anonymousToken, w, req) return } // use the password as the token _, token, ok := req.BasicAuth() if !ok { context.GetRequestLogger(ctx).Debugf("no basic auth credentials provided") t.writeUnauthorized(w, req) return } // TODO: if this doesn't validate as an API token, attempt to obtain an API token using the given username/password copied := t.anonymousConfig copied.BearerToken = token osClient, err := client.New(&copied) if err != nil { context.GetRequestLogger(ctx).Errorf("error building client: %v", err) t.writeError(w, req) return } if _, err := osClient.Users().Get("~"); err != nil { context.GetRequestLogger(ctx).Debugf("invalid token: %v", err) t.writeUnauthorized(w, req) return } t.writeToken(token, w, req) }
// context either returns a new context or looks it up in the manager. func (cm *contextManager) context(parent context.Context, w http.ResponseWriter, r *http.Request) context.Context { cm.mu.Lock() defer cm.mu.Unlock() ctx, ok := cm.contexts[r] if ok { return ctx } if parent == nil { parent = ctxu.Background() } ctx = ctxu.WithRequest(parent, r) ctx, w = ctxu.WithResponseWriter(ctx, w) ctx = ctxu.WithLogger(ctx, ctxu.GetRequestLogger(ctx)) cm.contexts[r] = ctx return ctx }