Files
podman/pkg/api/handlers/libpod/manifests.go
Valentin Rothberg dc80267b59 compat handlers: add X-Registry-Auth header support
* Support the `X-Registry-Auth` http-request header.

 * The content of the header is a base64 encoded JSON payload which can
   either be a single auth config or a map of auth configs (user+pw or
   token) with the corresponding registries being the keys.  Vanilla
   Docker, projectatomic Docker and the bindings are transparantly
   supported.

 * Add a hidden `--registries-conf` flag.  Buildah exposes the same
   flag, mostly for testing purposes.

 * Do all credential parsing in the client (i.e., `cmd/podman`) pass
   the username and password in the backend instead of unparsed
   credentials.

 * Add a `pkg/auth` which handles most of the heavy lifting.

 * Go through the authentication-handling code of most commands, bindings
   and endpoints.  Migrate them to the new code and fix issues as seen.
   A final evaluation and more tests is still required *after* this
   change.

 * The manifest-push endpoint is missing certain parameters and should
   use the ABI function instead.  Adding auth-support isn't really
   possible without these parts working.

 * The container commands and endpoints (i.e., create and run) have not
   been changed yet.  The APIs don't yet account for the authfile.

 * Add authentication tests to `pkg/bindings`.

Fixes: #6384
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
2020-05-29 15:39:37 +02:00

172 lines
5.3 KiB
Go

package libpod
import (
"encoding/json"
"net/http"
"github.com/containers/buildah/manifests"
copy2 "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/gorilla/schema"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
)
func ManifestCreate(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Name []string `schema:"name"`
Image []string `schema:"image"`
All bool `schema:"all"`
}{
// Add defaults here once needed.
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
rtc, err := runtime.GetConfig()
if err != nil {
utils.InternalServerError(w, err)
return
}
sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
manID, err := image.CreateManifestList(runtime.ImageRuntime(), *sc, query.Name, query.Image, query.All)
if err != nil {
utils.InternalServerError(w, err)
return
}
utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: manID})
}
func ManifestInspect(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
newImage, err := runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
utils.ImageNotFound(w, name, err)
return
}
data, err := newImage.InspectManifest()
if err != nil {
utils.InternalServerError(w, err)
return
}
utils.WriteResponse(w, http.StatusOK, data)
}
func ManifestAdd(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
var manifestInput image.ManifestAddOpts
if err := json.NewDecoder(r.Body).Decode(&manifestInput); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
name := utils.GetName(r)
newImage, err := runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
utils.ImageNotFound(w, name, err)
return
}
rtc, err := runtime.GetConfig()
if err != nil {
utils.InternalServerError(w, err)
return
}
sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
newID, err := newImage.AddManifest(*sc, manifestInput)
if err != nil {
utils.InternalServerError(w, err)
return
}
utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: newID})
}
func ManifestRemove(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
Digest string `schema:"digest"`
}{
// Add defaults here once needed.
}
name := utils.GetName(r)
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
newImage, err := runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
utils.ImageNotFound(w, name, err)
return
}
d, err := digest.Parse(query.Digest)
if err != nil {
utils.Error(w, "invalid digest", http.StatusBadRequest, err)
return
}
newID, err := newImage.RemoveManifest(d)
if err != nil {
utils.InternalServerError(w, err)
return
}
utils.WriteResponse(w, http.StatusOK, handlers.IDResponse{ID: newID})
}
func ManifestPush(w http.ResponseWriter, r *http.Request) {
// FIXME: parameters are missing (tlsVerify, format).
// Also, we should use the ABI function to avoid duplicate code.
// Also, support for XRegistryAuth headers are missing.
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
All bool `schema:"all"`
Destination string `schema:"destination"`
}{
// Add defaults here once needed.
}
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
name := utils.GetName(r)
newImage, err := runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
utils.ImageNotFound(w, name, err)
return
}
dest, err := alltransports.ParseImageName(query.Destination)
if err != nil {
utils.Error(w, "invalid destination parameter", http.StatusBadRequest, errors.Errorf("invalid destination parameter %q", query.Destination))
return
}
rtc, err := runtime.GetConfig()
if err != nil {
utils.InternalServerError(w, err)
return
}
sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
opts := manifests.PushOptions{
Store: runtime.GetStore(),
ImageListSelection: copy2.CopySpecificImages,
SystemContext: sc,
}
if query.All {
opts.ImageListSelection = copy2.CopyAllImages
}
newD, err := newImage.PushManifest(dest, opts)
if err != nil {
utils.InternalServerError(w, err)
return
}
utils.WriteResponse(w, http.StatusOK, newD.String())
}