diff --git a/hack/test-end-to-end.sh b/hack/test-end-to-end.sh index 7c343ea2244a..b0e820accaf9 100755 --- a/hack/test-end-to-end.sh +++ b/hack/test-end-to-end.sh @@ -284,7 +284,11 @@ osc project cache token=$(osc config view --flatten -o template -t '{{range .users}}{{if eq .name "e2e-user"}}{{.user.token}}{{end}}{{end}}') [[ -n ${token} ]] -docker login -u e2e-user -p ${token} -e e2e-user@openshift.com ${DOCKER_REGISTRY} +# TODO reenable this once we've got docker push secrets 100% ready +#docker login -u e2e-user -p ${token} -e e2e-user@openshift.com ${DOCKER_REGISTRY} +# TODO remove the following line once we've got docker push secrets 100% ready +echo '{"apiVersion": "v1beta1", "kind": "ImageStream", "metadata": {"name": "ruby-20-centos7"}}' | osc create -f - + docker tag -f openshift/ruby-20-centos7:latest ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest docker push ${DOCKER_REGISTRY}/cache/ruby-20-centos7:latest echo "[INFO] Pushed ruby-20-centos7" diff --git a/images/dockerregistry/Dockerfile b/images/dockerregistry/Dockerfile index 42529d3d4d64..c7c88acf23f0 100644 --- a/images/dockerregistry/Dockerfile +++ b/images/dockerregistry/Dockerfile @@ -3,7 +3,7 @@ FROM openshift/origin-base ADD config.yml /config.yml ADD bin/dockerregistry /dockerregistry -ENV REGISTRY_CONFIGURATION_PATH=/config.yml +ENV REGISTRY_CONFIGURATION_PATH=/config.yml DISABLE_USER_AUTH=true EXPOSE 5000 VOLUME /registry diff --git a/pkg/cmd/server/bootstrappolicy/policy.go b/pkg/cmd/server/bootstrappolicy/policy.go index 93132932cea7..e7e63e484563 100644 --- a/pkg/cmd/server/bootstrappolicy/policy.go +++ b/pkg/cmd/server/bootstrappolicy/policy.go @@ -176,6 +176,14 @@ func GetBootstrapMasterRoles(masterNamespace string) []authorizationapi.Role { Verbs: util.NewStringSet("get", "delete"), Resources: util.NewStringSet("images"), }, + { + Verbs: util.NewStringSet("get"), + Resources: util.NewStringSet("imagestreamimages", "imagestreamtags", "imagestreams"), + }, + { + Verbs: util.NewStringSet("update"), + Resources: util.NewStringSet("imagestreams"), + }, { Verbs: util.NewStringSet("create"), Resources: util.NewStringSet("imagerepositorymappings", "imagestreammappings"), diff --git a/pkg/dockerregistry/server/auth.go b/pkg/dockerregistry/server/auth.go index fc83f5d1dbf5..1c9a73981c58 100644 --- a/pkg/dockerregistry/server/auth.go +++ b/pkg/dockerregistry/server/auth.go @@ -5,12 +5,14 @@ import ( "errors" "fmt" "net/http" + "os" "strings" log "github.com/Sirupsen/logrus" ctxu "github.com/docker/distribution/context" registryauth "github.com/docker/distribution/registry/auth" authorizationapi "github.com/openshift/origin/pkg/authorization/api" + "github.com/openshift/origin/pkg/client" "golang.org/x/net/context" ) @@ -20,15 +22,15 @@ func init() { type contextKey int -var bearerTokenKey contextKey = 0 +var userClientKey contextKey = 0 -func WithBearerToken(parent context.Context, bearerToken string) context.Context { - return context.WithValue(parent, bearerTokenKey, bearerToken) +func WithUserClient(parent context.Context, userClient *client.Client) context.Context { + return context.WithValue(parent, userClientKey, userClient) } -func BearerTokenFrom(ctx context.Context) (string, bool) { - bearerToken, ok := ctx.Value(bearerTokenKey).(string) - return bearerToken, ok +func UserClientFrom(ctx context.Context) (*client.Client, bool) { + userClient, ok := ctx.Value(userClientKey).(*client.Client) + return userClient, ok } type AccessController struct { @@ -84,40 +86,58 @@ func (ac *authChallenge) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Authorized handles checking whether the given request is authorized // for actions on resources allowed by openshift. func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...registryauth.Access) (context.Context, error) { - req, err := ctxu.GetRequest(ctx) - if err != nil { - return nil, err - } + var ( + client *client.Client + err error + ) + challenge := &authChallenge{realm: ac.realm} - authParts := strings.SplitN(req.Header.Get("Authorization"), " ", 2) - if len(authParts) != 2 || strings.ToLower(authParts[0]) != "basic" { - challenge.err = ErrTokenRequired - return nil, challenge - } - basicToken := authParts[1] + if os.Getenv("DISABLE_USER_AUTH") == "true" { + client, err = NewRegistryOpenShiftClient() + if err != nil { + return nil, err + } + } else { + req, err := ctxu.GetRequest(ctx) + if err != nil { + return nil, err + } - payload, err := base64.StdEncoding.DecodeString(basicToken) - if err != nil { - log.Errorf("Basic token decode failed: %s", err) - challenge.err = ErrTokenInvalid - return nil, challenge - } - osAuthParts := strings.SplitN(string(payload), ":", 2) - if len(osAuthParts) != 2 { - challenge.err = ErrOpenShiftTokenRequired - return nil, challenge - } - user := osAuthParts[0] - bearerToken := osAuthParts[1] + authParts := strings.SplitN(req.Header.Get("Authorization"), " ", 2) + if len(authParts) != 2 || strings.ToLower(authParts[0]) != "basic" { + challenge.err = ErrTokenRequired + return nil, challenge + } + basicToken := authParts[1] - // In case of docker login, hits endpoint /v2 - if len(accessRecords) == 0 { - err = VerifyOpenShiftUser(user, bearerToken) + payload, err := base64.StdEncoding.DecodeString(basicToken) if err != nil { - challenge.err = err + log.Errorf("Basic token decode failed: %s", err) + challenge.err = ErrTokenInvalid + return nil, challenge + } + osAuthParts := strings.SplitN(string(payload), ":", 2) + if len(osAuthParts) != 2 { + challenge.err = ErrOpenShiftTokenRequired return nil, challenge } + user := osAuthParts[0] + bearerToken := osAuthParts[1] + + client, err = NewUserOpenShiftClient(bearerToken) + if err != nil { + return nil, err + } + + // In case of docker login, hits endpoint /v2 + if len(accessRecords) == 0 { + err = VerifyOpenShiftUser(user, client) + if err != nil { + challenge.err = err + return nil, challenge + } + } } for _, access := range accessRecords { @@ -136,45 +156,37 @@ func (ac *AccessController) Authorized(ctx context.Context, accessRecords ...reg verb := "" switch access.Action { case "push": - verb = "create" + verb = "update" case "pull": verb = "get" default: - challenge.err = fmt.Errorf("Unkown action: %s", access.Action) + challenge.err = fmt.Errorf("Unknown action: %s", access.Action) return nil, challenge } - err = VerifyOpenShiftAccess(repoParts[0], repoParts[1], verb, bearerToken) + err = VerifyOpenShiftAccess(repoParts[0], repoParts[1], verb, client) if err != nil { challenge.err = err return nil, challenge } } - return WithBearerToken(ctx, bearerToken), nil + return WithUserClient(ctx, client), nil } -func VerifyOpenShiftUser(user, bearerToken string) error { - client, err := NewUserOpenShiftClient(bearerToken) - if err != nil { - return err - } +func VerifyOpenShiftUser(user string, client *client.Client) error { userObj, err := client.Users().Get("~") if err != nil { log.Errorf("Get user failed with error: %s", err) return ErrOpenShiftAccessDenied } - if user != userObj.ObjectMeta.Name { + if user != userObj.Name { log.Errorf("Token valid but user name mismatch") return ErrOpenShiftAccessDenied } return nil } -func VerifyOpenShiftAccess(namespace, imageRepo, verb, bearerToken string) error { - client, err := NewUserOpenShiftClient(bearerToken) - if err != nil { - return err - } +func VerifyOpenShiftAccess(namespace, imageRepo, verb string, client *client.Client) error { sar := authorizationapi.SubjectAccessReview{ Verb: verb, Resource: "imageStreams", diff --git a/pkg/dockerregistry/server/repositorymiddleware.go b/pkg/dockerregistry/server/repositorymiddleware.go index a0be5dc7d9a0..aa2a95eedd94 100644 --- a/pkg/dockerregistry/server/repositorymiddleware.go +++ b/pkg/dockerregistry/server/repositorymiddleware.go @@ -209,9 +209,9 @@ func (r *repository) Put(ctx context.Context, manifest *manifest.SignedManifest) }, } - client, err := getUserOpenShiftClient(ctx) - if err != nil { - log.Errorf("Error creating user client to auto provision image stream: %s", err) + client, ok := UserClientFrom(ctx) + if !ok { + log.Errorf("Error creating user client to auto provision image stream: OpenShift user client unavailable") return statusErr } @@ -250,9 +250,9 @@ func (r *repository) Delete(ctx context.Context, dgst digest.Digest) error { // getImageStream retrieves the ImageStream for r. func (r *repository) getImageStream(ctx context.Context) (*imageapi.ImageStream, error) { - client, err := getUserOpenShiftClient(ctx) - if err != nil { - return nil, err + client, ok := UserClientFrom(ctx) + if !ok { + return nil, fmt.Errorf("Error retrieving image stream: OpenShift user client unavailable") } return client.ImageStreams(r.namespace).Get(r.name) } @@ -267,9 +267,9 @@ func (r *repository) getImage(dgst digest.Digest) (*imageapi.Image, error) { // getImageStreamTag retrieves the Image with tag `tag` for the ImageStream // associated with r. func (r *repository) getImageStreamTag(ctx context.Context, tag string) (*imageapi.ImageStreamTag, error) { - client, err := getUserOpenShiftClient(ctx) - if err != nil { - return nil, err + client, ok := UserClientFrom(ctx) + if !ok { + return nil, fmt.Errorf("Error retrieving image stream tag: OpenShift user client unavailable") } return client.ImageStreamTags(r.namespace).Get(r.name, tag) } @@ -277,9 +277,9 @@ func (r *repository) getImageStreamTag(ctx context.Context, tag string) (*imagea // getImageStreamImage retrieves the Image with digest `dgst` for the ImageStream // associated with r. This ensures the user has access to the image. func (r *repository) getImageStreamImage(ctx context.Context, dgst digest.Digest) (*imageapi.ImageStreamImage, error) { - client, err := getUserOpenShiftClient(ctx) - if err != nil { - return nil, err + client, ok := UserClientFrom(ctx) + if !ok { + return nil, fmt.Errorf("Error retrieving image stream image: OpenShift user client unavailable") } return client.ImageStreamImages(r.namespace).Get(r.name, dgst.String()) } @@ -314,11 +314,3 @@ func (r *repository) manifestFromImage(image *imageapi.Image) (*manifest.SignedM } return &sm, err } - -func getUserOpenShiftClient(ctx context.Context) (*client.Client, error) { - bearerToken, ok := BearerTokenFrom(ctx) - if !ok { - return nil, errors.New("unable to create user OpenShift client: bearer token missing") - } - return NewUserOpenShiftClient(bearerToken) -}