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  }