| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package coordinator | 5 package coordinator |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 | 9 |
| 10 "github.com/luci/gae/service/info" | 10 "github.com/luci/gae/service/info" |
| 11 luciConfig "github.com/luci/luci-go/common/config" | 11 luciConfig "github.com/luci/luci-go/common/config" |
| 12 log "github.com/luci/luci-go/common/logging" | 12 log "github.com/luci/luci-go/common/logging" |
| 13 "golang.org/x/net/context" | 13 "golang.org/x/net/context" |
| 14 ) | 14 ) |
| 15 | 15 |
| 16 // NamespaceAccessType specifies the type of namespace access that is being |
| 17 // requested for WithProjectNamespace. |
| 18 type NamespaceAccessType int |
| 19 |
| 20 const ( |
| 21 // NamespaceAccessNoAuth grants unconditional access to a project's name
space. |
| 22 // |
| 23 // This must only be used by endpoints that enforce admin- or service-on
ly |
| 24 // access. |
| 25 NamespaceAccessNoAuth NamespaceAccessType = iota |
| 26 |
| 27 // NamespaceAccessREAD enforces READ permission access to a project's |
| 28 // namespace. |
| 29 NamespaceAccessREAD |
| 30 |
| 31 // NamespaceAccessWRITE enforces WRITE permission access to a project's |
| 32 // namespace. |
| 33 NamespaceAccessWRITE |
| 34 ) |
| 35 |
| 16 type servicesKeyType int | 36 type servicesKeyType int |
| 17 | 37 |
| 18 // WithServices installs the supplied Services instance into a Context. | 38 // WithServices installs the supplied Services instance into a Context. |
| 19 func WithServices(c context.Context, s Services) context.Context { | 39 func WithServices(c context.Context, s Services) context.Context { |
| 20 return context.WithValue(c, servicesKeyType(0), s) | 40 return context.WithValue(c, servicesKeyType(0), s) |
| 21 } | 41 } |
| 22 | 42 |
| 23 // GetServices gets the Services instance installed in the supplied Context. | 43 // GetServices gets the Services instance installed in the supplied Context. |
| 24 // | 44 // |
| 25 // If no Services has been installed, it will panic. | 45 // If no Services has been installed, it will panic. |
| 26 func GetServices(c context.Context) Services { | 46 func GetServices(c context.Context) Services { |
| 27 s, ok := c.Value(servicesKeyType(0)).(Services) | 47 s, ok := c.Value(servicesKeyType(0)).(Services) |
| 28 if !ok { | 48 if !ok { |
| 29 panic("no Services instance is installed") | 49 panic("no Services instance is installed") |
| 30 } | 50 } |
| 31 return s | 51 return s |
| 32 } | 52 } |
| 33 | 53 |
| 34 // WithProjectNamespace sets the current namespace to the project name. | 54 // WithProjectNamespace sets the current namespace to the project name. |
| 35 // | 55 // |
| 36 // It will return an error if the project name or the project's namespace is | 56 // It will return an error if the project name or the project's namespace is |
| 37 // invalid | 57 // invalid |
| 38 // | 58 // |
| 39 // If the current user does not have READ permission for the project, a | 59 // If the current user does not have READ permission for the project, a |
| 40 // MembershipError will be returned. | 60 // MembershipError will be returned. |
| 41 func WithProjectNamespace(c *context.Context, project luciConfig.ProjectName) er
ror { | 61 func WithProjectNamespace(c *context.Context, project luciConfig.ProjectName, at
NamespaceAccessType) error { |
| 42 » return withProjectNamespaceImpl(c, project, true) | |
| 43 } | |
| 44 | |
| 45 // WithProjectNamespaceNoAuth sets the current namespace to the project name. It | |
| 46 // does NOT assert that the current user has project access. This should only be | |
| 47 // used for service functions that are not acting on behalf of a user. | |
| 48 // | |
| 49 // It will fail if the project name is invalid. | |
| 50 func WithProjectNamespaceNoAuth(c *context.Context, project luciConfig.ProjectNa
me) error { | |
| 51 » return withProjectNamespaceImpl(c, project, false) | |
| 52 } | |
| 53 | |
| 54 func withProjectNamespaceImpl(c *context.Context, project luciConfig.ProjectName
, auth bool) error { | |
| 55 // TODO(dnj): REQUIRE this to be non-empty once namespacing is mandatory
. | 62 // TODO(dnj): REQUIRE this to be non-empty once namespacing is mandatory
. |
| 56 if project == "" { | 63 if project == "" { |
| 57 return nil | 64 return nil |
| 58 } | 65 } |
| 59 | 66 |
| 60 if err := project.Validate(); err != nil { | 67 if err := project.Validate(); err != nil { |
| 61 log.WithError(err).Errorf(*c, "Project name is invalid.") | 68 log.WithError(err).Errorf(*c, "Project name is invalid.") |
| 62 return err | 69 return err |
| 63 } | 70 } |
| 64 | 71 |
| 65 » // Validate the user's READ access to the named project, if authenticati
ng. | 72 » // Validate the current user has the requested access. |
| 66 » if auth { | 73 » switch at { |
| 74 » case NamespaceAccessNoAuth: |
| 75 » » break |
| 76 |
| 77 » case NamespaceAccessREAD: |
| 67 if err := IsProjectReader(*c, project); err != nil { | 78 if err := IsProjectReader(*c, project); err != nil { |
| 68 » » » log.WithError(err).Errorf(*c, "User cannot access reques
ted project.") | 79 » » » log.WithError(err).Errorf(*c, "User denied READ access t
o requested project.") |
| 69 return err | 80 return err |
| 70 } | 81 } |
| 82 |
| 83 case NamespaceAccessWRITE: |
| 84 if err := IsProjectWriter(*c, project); err != nil { |
| 85 log.WithError(err).Errorf(*c, "User denied WRITE access
to requested project.") |
| 86 return err |
| 87 } |
| 88 |
| 89 default: |
| 90 return fmt.Errorf("unknown access type: %v", at) |
| 71 } | 91 } |
| 72 | 92 |
| 73 pns := ProjectNamespace(project) | 93 pns := ProjectNamespace(project) |
| 74 nc, err := info.Get(*c).Namespace(pns) | 94 nc, err := info.Get(*c).Namespace(pns) |
| 75 if err != nil { | 95 if err != nil { |
| 76 log.Fields{ | 96 log.Fields{ |
| 77 log.ErrorKey: err, | 97 log.ErrorKey: err, |
| 78 "project": project, | 98 "project": project, |
| 79 "namespace": pns, | 99 "namespace": pns, |
| 80 }.Errorf(*c, "Failed to set namespace.") | 100 }.Errorf(*c, "Failed to set namespace.") |
| (...skipping 18 matching lines...) Expand all Loading... |
| 99 if ns == "" { | 119 if ns == "" { |
| 100 return "" | 120 return "" |
| 101 } | 121 } |
| 102 | 122 |
| 103 project := ProjectFromNamespace(ns) | 123 project := ProjectFromNamespace(ns) |
| 104 if project != "" { | 124 if project != "" { |
| 105 return project | 125 return project |
| 106 } | 126 } |
| 107 panic(fmt.Errorf("current namespace %q does not begin with project names
pace prefix (%q)", ns, projectNamespacePrefix)) | 127 panic(fmt.Errorf("current namespace %q does not begin with project names
pace prefix (%q)", ns, projectNamespacePrefix)) |
| 108 } | 128 } |
| OLD | NEW |