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 "errors" | |
9 "fmt" | 8 "fmt" |
9 "strings" | |
10 | 10 |
11 "github.com/luci/gae/service/info" | 11 "github.com/luci/gae/service/info" |
12 "github.com/luci/luci-go/appengine/logdog/coordinator/config" | |
13 log "github.com/luci/luci-go/common/logging" | 12 log "github.com/luci/luci-go/common/logging" |
14 "github.com/luci/luci-go/common/proto/logdog/svcconfig" | 13 "github.com/luci/luci-go/common/proto/logdog/svcconfig" |
15 "github.com/luci/luci-go/server/auth" | 14 "github.com/luci/luci-go/server/auth" |
16 "github.com/luci/luci-go/server/auth/identity" | 15 "github.com/luci/luci-go/server/auth/identity" |
17 "golang.org/x/net/context" | 16 "golang.org/x/net/context" |
18 ) | 17 ) |
19 | 18 |
20 // ErrNoAccess is returned if the user has no access to the requested project. | |
21 var ErrNoAccess = config.ErrNoAccess | |
22 | |
23 // IsAdminUser tests whether the current user belongs to the administrative | 19 // IsAdminUser tests whether the current user belongs to the administrative |
24 // users group. It will return an error if the user does not. | 20 // users group. |
21 // | |
nodir
2016/05/19 17:17:20
I think separating these two paragraphs is unneces
dnj (Google)
2016/05/19 20:10:46
I'm okay with it. I like to separate the purpose o
| |
22 // If the user is not, a MembershipError will be returned. | |
25 func IsAdminUser(c context.Context) error { | 23 func IsAdminUser(c context.Context) error { |
26 » return isMember(c, func(cfg *svcconfig.Coordinator) string { | 24 » cfg, err := GetServices(c).Config(c) |
27 » » return cfg.AdminAuthGroup | 25 » if err != nil { |
28 » }) | 26 » » return err |
27 » } | |
28 » return checkMember(c, cfg.Coordinator.AdminAuthGroup) | |
29 } | 29 } |
30 | 30 |
31 // IsServiceUser tests whether the current user belongs to the backend services | 31 // IsServiceUser tests whether the current user belongs to the backend services |
32 // users group. It will return an error if the user does not. | 32 // users group. |
33 // | |
34 // If the user is not, a MembershipError will be returned. | |
33 func IsServiceUser(c context.Context) error { | 35 func IsServiceUser(c context.Context) error { |
34 » return isMember(c, func(cfg *svcconfig.Coordinator) string { | 36 » cfg, err := GetServices(c).Config(c) |
35 » » return cfg.ServiceAuthGroup | 37 » if err != nil { |
36 » }) | 38 » » return err |
39 » } | |
40 » return checkMember(c, cfg.Coordinator.ServiceAuthGroup) | |
37 } | 41 } |
38 | 42 |
39 func isMember(c context.Context, groupNameFunc func(*svcconfig.Coordinator) stri ng) error { | 43 // IsProjectReader tests whether the current user belongs to one of the |
44 // project's declared reader groups. | |
45 // | |
46 // If the user is not, a MembershipError will be returned. | |
47 func IsProjectReader(c context.Context, pcfg *svcconfig.ProjectConfig) error { | |
48 » return checkMember(c, pcfg.ReaderAuthGroups...) | |
49 } | |
50 | |
51 func checkMember(c context.Context, groups ...string) error { | |
40 // On dev-appserver, the superuser has implicit group membership to | 52 // On dev-appserver, the superuser has implicit group membership to |
41 // everything. | 53 // everything. |
42 if info.Get(c).IsDevAppServer() { | 54 if info.Get(c).IsDevAppServer() { |
43 if u := auth.CurrentUser(c); u.Superuser { | 55 if u := auth.CurrentUser(c); u.Superuser { |
44 log.Fields{ | 56 log.Fields{ |
45 "identity": u.Identity, | 57 "identity": u.Identity, |
58 "groups": groups, | |
46 }.Infof(c, "Granting superuser implicit group membership on development server.") | 59 }.Infof(c, "Granting superuser implicit group membership on development server.") |
47 return nil | 60 return nil |
48 } | 61 } |
49 } | 62 } |
50 | 63 |
51 » cfg, err := GetServices(c).Config(c) | 64 » id := auth.CurrentIdentity(c) |
52 » if err != nil { | 65 » for _, group := range groups { |
53 » » return err | 66 » » is, err := auth.IsMember(c, group) |
67 » » if err != nil { | |
68 » » » return err | |
69 » » } | |
70 » » if is { | |
71 » » » log.Fields{ | |
72 » » » » "identity": id, | |
73 » » » » "group": group, | |
74 » » » }.Debugf(c, "User access granted.") | |
75 » » » return nil | |
76 » » } | |
54 } | 77 } |
55 | 78 |
56 » if cfg.Coordinator == nil { | 79 » return &MembershipError{ |
57 » » return errors.New("no coordinator configuration") | 80 » » Identity: id, |
81 » » Groups: groups, | |
58 } | 82 } |
59 | |
60 groupName := groupNameFunc(cfg.Coordinator) | |
61 if groupName == "" { | |
62 return errors.New("no auth group is configured") | |
63 } | |
64 | |
65 is, err := auth.IsMember(c, groupName) | |
66 if err != nil { | |
67 return err | |
68 } | |
69 if !is { | |
70 return &MembershipError{ | |
71 Identity: auth.CurrentIdentity(c), | |
72 Group: groupName, | |
73 } | |
74 } | |
75 return nil | |
76 } | 83 } |
77 | 84 |
78 // MembershipError is an error returned by group membership checking functions | 85 // MembershipError is an error returned by group membership checking functions |
79 // if the current identity is not a member of the requested group. | 86 // if the current identity is not a member of the requested group. |
80 type MembershipError struct { | 87 type MembershipError struct { |
81 Identity identity.Identity | 88 Identity identity.Identity |
82 » Group string | 89 » Groups []string |
83 } | 90 } |
84 | 91 |
85 func (e *MembershipError) Error() string { | 92 func (e *MembershipError) Error() string { |
86 » return fmt.Sprintf("user %q is not a member of group %q", e.Identity, e. Group) | 93 » return fmt.Sprintf("user %q is not a member of [%s]", e.Identity, string s.Join(e.Groups, ", ")) |
87 } | 94 } |
88 | 95 |
89 // IsMembershipError returns whether a given error is a membership error. | 96 // IsMembershipError returns whether a given error is a membership error. |
90 func IsMembershipError(e error) bool { | 97 func IsMembershipError(e error) bool { |
91 _, ok := e.(*MembershipError) | 98 _, ok := e.(*MembershipError) |
92 return ok | 99 return ok |
93 } | 100 } |
OLD | NEW |