Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | |
| 3 // that can be found in the LICENSE file. | |
| 4 | |
| 5 // Package access implements a software config.Authority access check against a | |
|
iannucci
2017/01/07 20:29:23
not sure `software` is the right adjective. maybe
dnj
2017/01/10 03:27:13
Done.
| |
| 6 // project config. | |
| 7 // | |
| 8 // Note that this is a soft check, as the true access authority is the config | |
| 9 // service, and this check is not hitting that service. | |
| 10 // | |
| 11 // If access is granted, this function will return nil. If access is explicitly | |
| 12 // denied, this will return ErrNoAccess. | |
| 13 // | |
| 14 // This is a port of the ACL implementation from the config service: | |
| 15 // https://chromium.googlesource.com/external/github.com/luci/luci-py/+/e3fbb1f5 dafa59a2c57cf3a9fe3708f4309ab653/appengine/components/components/config/api.py | |
| 16 package access | |
| 17 | |
| 18 import ( | |
| 19 "strings" | |
| 20 | |
| 21 "github.com/luci/luci-go/common/errors" | |
| 22 configPB "github.com/luci/luci-go/common/proto/config" | |
| 23 "github.com/luci/luci-go/server/auth" | |
| 24 "github.com/luci/luci-go/server/auth/identity" | |
| 25 "github.com/luci/luci-go/server/config" | |
| 26 "github.com/luci/luci-go/server/config/textproto" | |
| 27 | |
| 28 "golang.org/x/net/context" | |
| 29 ) | |
| 30 | |
| 31 // ErrNoAccess is an error returned by CheckAccess if the supplied Authority | |
| 32 // does not have access to the supplied config set. | |
| 33 var ErrNoAccess = errors.New("no access") | |
| 34 | |
| 35 // Check tests if a given Authority can access the named config set. | |
| 36 func Check(c context.Context, a config.Authority, configSet string) error { | |
| 37 if a == config.AsService { | |
| 38 return nil | |
| 39 } | |
| 40 | |
| 41 _, projectConfigSet, _ := config.ParseProjectConfigSet(configSet) | |
| 42 if projectConfigSet == "" { | |
| 43 // Not a project config set, so neither remaining Authority can access. | |
| 44 return ErrNoAccess | |
| 45 } | |
| 46 | |
| 47 // Load the project config. We execute this RPC as the service, not the user, | |
| 48 // so while this will recurse (and hopefully take advantage of the cache ), it | |
| 49 // will not trigger an infinite access check loop. | |
| 50 var pcfg configPB.ProjectCfg | |
| 51 if err := config.Get(c, config.AsService, projectConfigSet, config.Proje ctConfigPath, | |
| 52 textproto.Message(&pcfg), nil); err != nil { | |
| 53 return errors.Annotate(err).Reason("failed to load %(path)q in % (configSet)q"). | |
| 54 D("path", config.ProjectConfigPath).D("configSet", proje ctConfigSet).Err() | |
| 55 } | |
| 56 | |
| 57 id := identity.AnonymousIdentity | |
| 58 if a == config.AsUser { | |
| 59 id = auth.CurrentIdentity(c) | |
| 60 } | |
| 61 checkGroups := make([]string, 0, len(pcfg.Access)) | |
| 62 for _, access := range pcfg.Access { | |
| 63 if group, ok := trimPrefix(access, "group:"); ok { | |
| 64 // If "group" is "all", then short-circuit to permitted. | |
|
iannucci
2017/01/07 20:29:23
!!! but `all` is a valid group name!
can't we mak
Vadim Sh.
2017/01/07 21:04:23
We should just remove this short-circuit (if luci-
dnj
2017/01/10 03:27:13
Done.
| |
| 65 if group == "all" { | |
| 66 return nil | |
| 67 } | |
| 68 | |
| 69 // Check group membership. | |
| 70 checkGroups = append(checkGroups, group) | |
| 71 } else { | |
| 72 // If there is no ":" in the access string, this is a us er ACL. | |
|
iannucci
2017/01/07 20:29:23
bummer that we couldn't have made the access strin
Vadim Sh.
2017/01/07 21:04:23
It is the same. "user:" is just default prefix.
S
| |
| 73 if strings.IndexRune(access, ':') < 0 { | |
| 74 access = "user:" + access | |
| 75 } | |
| 76 if identity.Identity(access) == id { | |
| 77 return nil | |
| 78 } | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 // No individual accesses, check groups if we're not anonymous. | |
| 83 if a != config.AsAnonymous && len(checkGroups) > 0 { | |
| 84 switch canAccess, err := auth.IsMember(c, checkGroups...); { | |
| 85 case err != nil: | |
| 86 return errors.Annotate(err).Reason("failed to check grou p membership").Err() | |
| 87 case canAccess: | |
| 88 return nil | |
| 89 } | |
| 90 } | |
| 91 return ErrNoAccess | |
| 92 } | |
| 93 | |
| 94 func trimPrefix(v, pfx string) (string, bool) { | |
| 95 if strings.HasPrefix(v, pfx) { | |
| 96 return v[len(pfx):], true | |
| 97 } | |
| 98 return v, false | |
| 99 } | |
| OLD | NEW |