github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/api/auth/check_build_read_access_handler_test.go (about) 1 package auth_test 2 3 import ( 4 "errors" 5 "fmt" 6 "net/http" 7 "net/http/httptest" 8 9 "github.com/pf-qiu/concourse/v6/atc/api/accessor" 10 "github.com/pf-qiu/concourse/v6/atc/api/accessor/accessorfakes" 11 "github.com/pf-qiu/concourse/v6/atc/api/auth" 12 "github.com/pf-qiu/concourse/v6/atc/auditor/auditorfakes" 13 "github.com/pf-qiu/concourse/v6/atc/db" 14 "github.com/pf-qiu/concourse/v6/atc/db/dbfakes" 15 . "github.com/onsi/ginkgo" 16 . "github.com/onsi/gomega" 17 ) 18 19 var _ = Describe("CheckBuildReadAccessHandler", func() { 20 var ( 21 response *http.Response 22 server *httptest.Server 23 delegate *buildDelegateHandler 24 buildFactory *dbfakes.FakeBuildFactory 25 handlerFactory auth.CheckBuildReadAccessHandlerFactory 26 handler http.Handler 27 fakeAccessor *accessorfakes.FakeAccessFactory 28 fakeaccess *accessorfakes.FakeAccess 29 build *dbfakes.FakeBuild 30 pipeline *dbfakes.FakePipeline 31 ) 32 33 BeforeEach(func() { 34 buildFactory = new(dbfakes.FakeBuildFactory) 35 handlerFactory = auth.NewCheckBuildReadAccessHandlerFactory(buildFactory) 36 fakeAccessor = new(accessorfakes.FakeAccessFactory) 37 fakeaccess = new(accessorfakes.FakeAccess) 38 39 delegate = &buildDelegateHandler{} 40 41 build = new(dbfakes.FakeBuild) 42 pipeline = new(dbfakes.FakePipeline) 43 build.PipelineIDReturns(41) 44 build.PipelineReturns(pipeline, true, nil) 45 build.TeamIDReturns(42) 46 build.TeamNameReturns("some-team") 47 build.JobIDReturns(43) 48 build.JobNameReturns("some-job") 49 }) 50 51 JustBeforeEach(func() { 52 fakeAccessor.CreateReturns(fakeaccess, nil) 53 server = httptest.NewServer(handler) 54 55 request, err := http.NewRequest("POST", server.URL+"?:build_id=55", nil) 56 Expect(err).NotTo(HaveOccurred()) 57 58 response, err = new(http.Client).Do(request) 59 Expect(err).NotTo(HaveOccurred()) 60 }) 61 62 var _ = AfterEach(func() { 63 server.Close() 64 }) 65 66 ItReturnsTheBuild := func() { 67 It("returns 200 ok", func() { 68 Expect(response.StatusCode).To(Equal(http.StatusOK)) 69 }) 70 71 It("calls delegate with the build context", func() { 72 Expect(delegate.IsCalled).To(BeTrue()) 73 Expect(delegate.ContextBuild).To(BeIdenticalTo(build)) 74 }) 75 } 76 77 WithExistingBuild := func(buildExistsFunc func()) { 78 Context("when build exists", func() { 79 BeforeEach(func() { 80 buildFactory.BuildReturns(build, true, nil) 81 }) 82 83 buildExistsFunc() 84 }) 85 86 Context("when build is not found", func() { 87 BeforeEach(func() { 88 buildFactory.BuildReturns(nil, false, nil) 89 }) 90 91 It("returns 404", func() { 92 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 93 }) 94 }) 95 96 Context("when getting build fails", func() { 97 BeforeEach(func() { 98 buildFactory.BuildReturns(nil, false, errors.New("disaster")) 99 }) 100 101 It("returns 404", func() { 102 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 103 }) 104 }) 105 } 106 107 Context("AnyJobHandler", func() { 108 BeforeEach(func() { 109 innerHandler := handlerFactory.AnyJobHandler(delegate, auth.UnauthorizedRejector{}) 110 111 handler = accessor.NewHandler( 112 logger, 113 "some-action", 114 innerHandler, 115 fakeAccessor, 116 new(auditorfakes.FakeAuditor), 117 map[string]string{}, 118 ) 119 }) 120 121 Context("when authenticated and accessing same team's build", func() { 122 BeforeEach(func() { 123 fakeaccess.IsAuthenticatedReturns(true) 124 fakeaccess.IsAuthorizedReturns(true) 125 }) 126 127 WithExistingBuild(ItReturnsTheBuild) 128 }) 129 130 Context("when authenticated but accessing different team's build", func() { 131 BeforeEach(func() { 132 fakeaccess.IsAuthenticatedReturns(true) 133 fakeaccess.IsAuthorizedReturns(false) 134 }) 135 136 WithExistingBuild(func() { 137 Context("when pipeline is public", func() { 138 BeforeEach(func() { 139 pipeline.PublicReturns(true) 140 build.PipelineReturns(pipeline, true, nil) 141 }) 142 143 ItReturnsTheBuild() 144 }) 145 146 Context("when pipeline is private", func() { 147 BeforeEach(func() { 148 pipeline.PublicReturns(false) 149 build.PipelineReturns(pipeline, true, nil) 150 }) 151 152 It("returns 403", func() { 153 Expect(response.StatusCode).To(Equal(http.StatusForbidden)) 154 }) 155 }) 156 Context("when fetching pipeline throws error", func() { 157 BeforeEach(func() { 158 build.PipelineReturns(pipeline, true, errors.New("some-error")) 159 }) 160 It("return 500", func() { 161 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 162 }) 163 }) 164 Context("when the build is not for a pipeline", func() { 165 BeforeEach(func() { 166 build.PipelineIDReturns(0) 167 }) 168 It("return 403", func() { 169 Expect(response.StatusCode).To(Equal(http.StatusForbidden)) 170 }) 171 }) 172 Context("when pipeline is not found", func() { 173 BeforeEach(func() { 174 build.PipelineReturns(nil, false, nil) 175 }) 176 It("return 404", func() { 177 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 178 }) 179 }) 180 }) 181 }) 182 183 Context("when not authenticated", func() { 184 BeforeEach(func() { 185 fakeaccess.IsAuthenticatedReturns(false) 186 }) 187 188 WithExistingBuild(func() { 189 Context("when pipeline is public", func() { 190 BeforeEach(func() { 191 pipeline.PublicReturns(true) 192 build.PipelineReturns(pipeline, true, nil) 193 }) 194 195 ItReturnsTheBuild() 196 }) 197 198 Context("when pipeline is private", func() { 199 BeforeEach(func() { 200 pipeline.PublicReturns(false) 201 build.PipelineReturns(pipeline, true, nil) 202 }) 203 204 It("returns 401", func() { 205 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 206 }) 207 }) 208 Context("when fetching pipeline throws error", func() { 209 BeforeEach(func() { 210 build.PipelineReturns(pipeline, true, errors.New("some-error")) 211 }) 212 It("return 500", func() { 213 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 214 }) 215 }) 216 Context("when the build is not for a pipeline", func() { 217 BeforeEach(func() { 218 build.PipelineIDReturns(0) 219 }) 220 It("return 401", func() { 221 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 222 }) 223 }) 224 Context("when pipeline is not found", func() { 225 BeforeEach(func() { 226 build.PipelineReturns(nil, false, nil) 227 }) 228 It("return 404", func() { 229 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 230 }) 231 }) 232 }) 233 }) 234 }) 235 236 Context("CheckIfPrivateJobHandler", func() { 237 var fakeJob *dbfakes.FakeJob 238 239 BeforeEach(func() { 240 fakeJob = new(dbfakes.FakeJob) 241 innerHandler := handlerFactory.CheckIfPrivateJobHandler(delegate, auth.UnauthorizedRejector{}) 242 243 handler = accessor.NewHandler( 244 logger, 245 "some-action", 246 innerHandler, 247 fakeAccessor, 248 new(auditorfakes.FakeAuditor), 249 map[string]string{}, 250 ) 251 }) 252 253 ItChecksIfJobIsPrivate := func(status int) { 254 Context("when pipeline is public", func() { 255 BeforeEach(func() { 256 pipeline.PublicReturns(true) 257 build.PipelineReturns(pipeline, true, nil) 258 }) 259 260 Context("when the build is not for a job", func() { 261 BeforeEach(func() { 262 build.JobIDReturns(0) 263 build.JobNameReturns("") 264 }) 265 266 It("returns "+fmt.Sprint(status), func() { 267 Expect(response.StatusCode).To(Equal(status)) 268 }) 269 }) 270 271 Context("and job is public", func() { 272 BeforeEach(func() { 273 fakeJob.NameReturns("some-job") 274 fakeJob.PublicReturns(true) 275 276 pipeline.JobReturns(fakeJob, true, nil) 277 }) 278 279 ItReturnsTheBuild() 280 }) 281 282 Context("and job is private", func() { 283 BeforeEach(func() { 284 fakeJob.NameReturns("some-job") 285 fakeJob.PublicReturns(false) 286 287 pipeline.JobReturns(fakeJob, true, nil) 288 }) 289 290 It("returns "+fmt.Sprint(status), func() { 291 Expect(response.StatusCode).To(Equal(status)) 292 }) 293 }) 294 295 Context("getting the job fails", func() { 296 BeforeEach(func() { 297 pipeline.JobReturns(nil, false, errors.New("error")) 298 }) 299 300 It("returns 500", func() { 301 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 302 }) 303 }) 304 305 Context("when the job is not found", func() { 306 BeforeEach(func() { 307 pipeline.JobReturns(nil, false, nil) 308 }) 309 310 It("return 404", func() { 311 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 312 }) 313 }) 314 }) 315 316 Context("when pipeline is private", func() { 317 BeforeEach(func() { 318 pipeline.PublicReturns(false) 319 build.PipelineReturns(pipeline, true, nil) 320 }) 321 322 It("returns "+fmt.Sprint(status), func() { 323 Expect(response.StatusCode).To(Equal(status)) 324 }) 325 }) 326 } 327 328 Context("when authenticated and accessing same team's build", func() { 329 BeforeEach(func() { 330 fakeaccess.IsAuthenticatedReturns(true) 331 fakeaccess.IsAuthorizedReturns(true) 332 }) 333 334 WithExistingBuild(ItReturnsTheBuild) 335 }) 336 337 Context("when authenticated but accessing different team's build", func() { 338 BeforeEach(func() { 339 fakeaccess.IsAuthenticatedReturns(true) 340 fakeaccess.IsAuthorizedReturns(false) 341 }) 342 343 WithExistingBuild(func() { 344 ItChecksIfJobIsPrivate(http.StatusForbidden) 345 }) 346 }) 347 348 Context("when not authenticated", func() { 349 BeforeEach(func() { 350 fakeaccess.IsAuthenticatedReturns(false) 351 }) 352 353 WithExistingBuild(func() { 354 ItChecksIfJobIsPrivate(http.StatusUnauthorized) 355 }) 356 }) 357 }) 358 }) 359 360 type buildDelegateHandler struct { 361 IsCalled bool 362 ContextBuild db.Build 363 } 364 365 func (handler *buildDelegateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 366 handler.IsCalled = true 367 handler.ContextBuild = r.Context().Value(auth.BuildContextKey).(db.Build) 368 }