Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Side by Side Diff: milo/appengine/swarming/build.go

Issue 2818563002: Milo: ACLs for internal swarm jobs (Closed)
Patch Set: Review Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « milo/appengine/frontend/main_test.go ('k') | milo/appengine/swarming/build_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package swarming 5 package swarming
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "fmt" 9 "fmt"
10 "net/http" 10 "net/http"
11 "net/url" 11 "net/url"
12 "strings" 12 "strings"
13 "time" 13 "time"
14 14
15 "golang.org/x/net/context" 15 "golang.org/x/net/context"
16 16
17 swarming "github.com/luci/luci-go/common/api/swarming/swarming/v1" 17 swarming "github.com/luci/luci-go/common/api/swarming/swarming/v1"
18 "github.com/luci/luci-go/common/errors" 18 "github.com/luci/luci-go/common/errors"
19 "github.com/luci/luci-go/common/logging" 19 "github.com/luci/luci-go/common/logging"
20 "github.com/luci/luci-go/common/proto/google" 20 "github.com/luci/luci-go/common/proto/google"
21 miloProto "github.com/luci/luci-go/common/proto/milo" 21 miloProto "github.com/luci/luci-go/common/proto/milo"
22 "github.com/luci/luci-go/common/sync/parallel" 22 "github.com/luci/luci-go/common/sync/parallel"
23 "github.com/luci/luci-go/logdog/client/annotee" 23 "github.com/luci/luci-go/logdog/client/annotee"
24 "github.com/luci/luci-go/logdog/client/coordinator" 24 "github.com/luci/luci-go/logdog/client/coordinator"
25 "github.com/luci/luci-go/logdog/common/types" 25 "github.com/luci/luci-go/logdog/common/types"
26 "github.com/luci/luci-go/milo/api/resp" 26 "github.com/luci/luci-go/milo/api/resp"
27 "github.com/luci/luci-go/milo/appengine/common"
27 "github.com/luci/luci-go/milo/appengine/logdog" 28 "github.com/luci/luci-go/milo/appengine/logdog"
28 "github.com/luci/luci-go/server/auth" 29 "github.com/luci/luci-go/server/auth"
29 ) 30 )
30 31
31 // errNotMiloJob is returned if a Swarming task is fetched that does not self- 32 // errNotMiloJob is returned if a Swarming task is fetched that does not self-
32 // identify as a Milo job. 33 // identify as a Milo job.
33 var errNotMiloJob = errors.New("Not a Milo Job") 34 var errNotMiloJob = errors.New("Not a Milo Job or access denied")
34 35
35 // SwarmingTimeLayout is time layout used by swarming. 36 // SwarmingTimeLayout is time layout used by swarming.
36 const SwarmingTimeLayout = "2006-01-02T15:04:05.999999999" 37 const SwarmingTimeLayout = "2006-01-02T15:04:05.999999999"
37 38
38 // logDogFetchTimeout is the amount of time to wait while fetching a LogDog 39 // logDogFetchTimeout is the amount of time to wait while fetching a LogDog
39 // stream before we time out the fetch. 40 // stream before we time out the fetch.
40 const logDogFetchTimeout = 30 * time.Second 41 const logDogFetchTimeout = 30 * time.Second
41 42
42 // Swarming task states.. 43 // Swarming task states..
43 const ( 44 const (
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 // If the log fetch was cancelled, this is undefined. 139 // If the log fetch was cancelled, this is undefined.
139 log string 140 log string
140 } 141 }
141 142
142 // swarmingFetch fetches (in parallel) the components that it is configured to 143 // swarmingFetch fetches (in parallel) the components that it is configured to
143 // fetch. 144 // fetch.
144 // 145 //
145 // After fetching, an ACL check is performed to confirm that the user is 146 // After fetching, an ACL check is performed to confirm that the user is
146 // permitted to view the resulting data. If this check fails, get returns 147 // permitted to view the resulting data. If this check fails, get returns
147 // errNotMiloJob. 148 // errNotMiloJob.
148 //
149 // TODO(hinoka): Make this ACL check something more specific than the
150 // resence of the "allow_milo" dimension.
151 func swarmingFetch(c context.Context, svc swarmingService, taskID string, req sw armingFetchParams) ( 149 func swarmingFetch(c context.Context, svc swarmingService, taskID string, req sw armingFetchParams) (
152 *swarmingFetchResult, error) { 150 *swarmingFetchResult, error) {
153 151
154 // logErr is managed separately from other fetch errors, since in some 152 // logErr is managed separately from other fetch errors, since in some
155 // situations it's acceptable to not have a log stream. 153 // situations it's acceptable to not have a log stream.
156 var logErr error 154 var logErr error
157 var fr swarmingFetchResult 155 var fr swarmingFetchResult
158 156
159 // Special Context to enable the cancellation of log fetching. 157 // Special Context to enable the cancellation of log fetching.
160 logsCancelled := false 158 logsCancelled := false
(...skipping 26 matching lines...) Expand all
187 // explicitly. 185 // explicitly.
188 fr.log, logErr = svc.getTaskOutput(logCtx, taskI D) 186 fr.log, logErr = svc.getTaskOutput(logCtx, taskI D)
189 return nil 187 return nil
190 } 188 }
191 } 189 }
192 }) 190 })
193 if err != nil { 191 if err != nil {
194 return nil, err 192 return nil, err
195 } 193 }
196 194
197 » // Current ACL implementation: error if this is not a Milo job. 195 » // Current ACL implementation:
196 » // If allow_milo:1 is present, it is a public job. Don't bother with AC L check.
197 » // If it is not present, check the luci_project tag, and see if user is allowed
198 » // to access said project.
198 switch { 199 switch {
199 case req.fetchReq: 200 case req.fetchReq:
200 » » if !isMiloJob(fr.req.Tags) { 201 » » if !isAllowed(c, fr.req.Tags) {
201 return nil, errNotMiloJob 202 return nil, errNotMiloJob
202 } 203 }
203 204
204 case req.fetchRes: 205 case req.fetchRes:
205 » » if !isMiloJob(fr.res.Tags) { 206 » » if !isAllowed(c, fr.res.Tags) {
206 return nil, errNotMiloJob 207 return nil, errNotMiloJob
207 } 208 }
208 209
209 default: 210 default:
210 // No metadata to decide if this is a Milo job, so assume that i t is not. 211 // No metadata to decide if this is a Milo job, so assume that i t is not.
211 return nil, errNotMiloJob 212 return nil, errNotMiloJob
212 } 213 }
213 214
214 if req.fetchRes && logErr != nil { 215 if req.fetchRes && logErr != nil {
215 switch fr.res.State { 216 switch fr.res.State {
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 659
659 func infoComponent(st resp.Status, label, text string) *resp.BuildComponent { 660 func infoComponent(st resp.Status, label, text string) *resp.BuildComponent {
660 return &resp.BuildComponent{ 661 return &resp.BuildComponent{
661 Type: resp.Summary, 662 Type: resp.Summary,
662 Label: label, 663 Label: label,
663 Text: []string{text}, 664 Text: []string{text},
664 Status: st, 665 Status: st,
665 } 666 }
666 } 667 }
667 668
668 func isMiloJob(tags []string) bool { 669 // isAllowed checks if:
670 // 1. allow_milo:1 is present. If so, it's a public job.
671 // 2. luci_project is present, and if the logged in user has access to that proj ect.
672 func isAllowed(c context.Context, tags []string) bool {
669 for _, t := range tags { 673 for _, t := range tags {
670 if t == "allow_milo:1" { 674 if t == "allow_milo:1" {
671 return true 675 return true
672 } 676 }
673 } 677 }
678 for _, t := range tags {
679 if strings.HasPrefix(t, "luci_project:") {
680 sp := strings.SplitN(t, ":", 2)
681 if len(sp) != 2 {
682 return false
683 }
684 logging.Debugf(c, "Checking if user has access to %s", s p[1])
685 // sp[1] is the project ID.
686 allowed, err := common.IsAllowed(c, sp[1])
687 if err != nil {
688 logging.WithError(err).Errorf(c, "could not perf orm acl check")
689 return false
690 }
691 return allowed
692 }
693 }
674 return false 694 return false
675 } 695 }
676 696
677 // taskPageURL returns a URL to a human-consumable page of a swarming task. 697 // taskPageURL returns a URL to a human-consumable page of a swarming task.
678 // Supports server aliases. 698 // Supports server aliases.
679 func taskPageURL(swarmingHostname, taskID string) string { 699 func taskPageURL(swarmingHostname, taskID string) string {
680 return fmt.Sprintf("https://%s/user/task/%s", swarmingHostname, taskID) 700 return fmt.Sprintf("https://%s/user/task/%s", swarmingHostname, taskID)
681 } 701 }
682 702
683 // botPageURL returns a URL to a human-consumable page of a swarming bot. 703 // botPageURL returns a URL to a human-consumable page of a swarming bot.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
733 for _, tag := range v { 753 for _, tag := range v {
734 var value string 754 var value string
735 parts := strings.SplitN(tag, ":", 2) 755 parts := strings.SplitN(tag, ":", 2)
736 if len(parts) == 2 { 756 if len(parts) == 2 {
737 value = parts[1] 757 value = parts[1]
738 } 758 }
739 res[parts[0]] = value 759 res[parts[0]] = value
740 } 760 }
741 return res 761 return res
742 } 762 }
OLDNEW
« no previous file with comments | « milo/appengine/frontend/main_test.go ('k') | milo/appengine/swarming/build_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698