Chromium Code Reviews| 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. | |
|
nodir
2016/05/19 16:43:17
please clarify that this simply skips the check
dnj (Google)
2016/05/19 22:52:04
Done.
| |
| 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. |
|
nodir
2016/05/19 16:43:17
this comment needs an update
dnj (Google)
2016/05/19 22:52:04
Done.
| |
| 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) |
|
nodir
2016/05/19 16:43:17
please add a check that namespace is not set alrea
dnj (Google)
2016/05/19 22:52:04
That's allowed. This function only enters namespac
nodir
2016/05/25 17:34:05
Acknowledged.
| |
| 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.") |
| 81 return err | 101 return err |
| 82 } | 102 } |
| 83 | 103 |
| 84 *c = nc | 104 *c = nc |
| (...skipping 14 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 |