Skip to content

Commit

Permalink
PoC: ImageSignature endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
mfojtik committed Jan 16, 2017
1 parent 283a990 commit ad85566
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 1 deletion.
29 changes: 28 additions & 1 deletion pkg/cmd/dockerregistry/dockerregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"net/http"
"os"
"strings"
"time"

log "github.com/Sirupsen/logrus"
Expand Down Expand Up @@ -75,7 +76,6 @@ func Execute(configFile io.Reader) {

// TODO add https scheme
adminRouter := app.NewRoute().PathPrefix("/admin/").Subrouter()

pruneAccessRecords := func(*http.Request) []auth.Access {
return []auth.Access{
{
Expand All @@ -98,6 +98,33 @@ func Execute(configFile io.Reader) {
pruneAccessRecords,
)

signatureRouter := app.NewRoute().PathPrefix("/signature/").Subrouter()
// FIXME: We need more fine-grained role (image-admin).
signatureAccessRecords := func(*http.Request) []auth.Access {
return []auth.Access{
{
Resource: auth.Resource{
Type: "signature",
},
Action: "get",
},
}
}

// Advertise features supported by OpenShift
if app.Config.HTTP.Headers == nil {
app.Config.HTTP.Headers = http.Header{}
}
app.Config.HTTP.Headers.Set("X-Registry-Supports-Signatures", "1")

app.RegisterRoute(
// GET /admin/signatures/<reference>
signatureRouter.Path("/{reference:"+strings.TrimPrefix(reference.ReferenceRegexp.String(), "^")+"}").Methods("GET"),
server.SignatureDispatcher,
handlers.NameNotRequired,
signatureAccessRecords,
)

app.RegisterHealthChecks()
handler := alive("/", app)
// TODO: temporarily keep for backwards compatibility; remove in the future
Expand Down
8 changes: 8 additions & 0 deletions pkg/dockerregistry/server/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,14 @@ func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...reg
}
}

case "signature":
switch access.Action {
case "get":
// For /signature/<reference> we pass the request to OpenShift API using the user
// token so the authorization happen on the OpenShift API side.
continue
}

case "admin":
switch access.Action {
case "prune":
Expand Down
83 changes: 83 additions & 0 deletions pkg/dockerregistry/server/signature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package server

import (
"encoding/json"
"net/http"

ctxu "github.com/docker/distribution/context"

"github.com/docker/distribution/context"
"github.com/docker/distribution/registry/handlers"

imageapi "github.com/openshift/origin/pkg/image/api"
imageapiv1 "github.com/openshift/origin/pkg/image/api/v1"

gorillahandlers "github.com/gorilla/handlers"
)

func SignatureDispatcher(ctx *handlers.Context, r *http.Request) http.Handler {
reference := ctxu.GetStringValue(ctx, "vars.reference")

signatureHandler := &signatureHandler{
Context: ctx,
Reference: reference,
}

return gorillahandlers.MethodHandler{
"GET": http.HandlerFunc(signatureHandler.Get),
}
}

type signatureHandler struct {
Context *handlers.Context
Reference string
}

func (s *signatureHandler) Get(w http.ResponseWriter, req *http.Request) {
context.GetLogger(s.Context).Debugf("(*signatureHandler).Get")
client, ok := UserClientFrom(s.Context)
if !ok {
context.GetLogger(s.Context).Debugf("(*signatureHandler).Get: unable to get openshift client")
return
}

ref, err := imageapi.ParseDockerImageReference(s.Reference)
if err != nil {
context.GetLogger(s.Context).Debugf("(*signatureHandler).Get: %v", err)
return
}

image, err := client.ImageStreamImages(ref.Namespace).Get(ref.Name, ref.ID)
if err != nil {
w.WriteHeader(http.StatusNotFound)
context.GetLogger(s.Context).Debugf("(*signatureHandler).Get: %v", err)
return
}

type imageSignatureList struct {
Signatures []imageapiv1.ImageSignature `json:"signatures"`
}

// FIXME: Instead of importing the Kubernetes schema to make JSON serialization nice,
// do this cheap copy. We can also pick only interesting fields.
v1Signatures := imageSignatureList{
Signatures: []imageapiv1.ImageSignature{},
}
for _, s := range image.Image.Signatures {
newSig := imageapiv1.ImageSignature{}
newSig.Name = s.Name
newSig.CreationTimestamp = s.CreationTimestamp
newSig.Type = s.Type
newSig.Content = s.Content
v1Signatures.Signatures = append(v1Signatures.Signatures, newSig)
}

data, err := json.Marshal(v1Signatures)
if err != nil {
context.GetLogger(s.Context).Debugf("(*signatureHandler).Get: %v", err)
return
}

w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Write(data)
}

0 comments on commit ad85566

Please sign in to comment.