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