github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/api/auth_test.go (about) 1 package api_test 2 3 import ( 4 "net/http" 5 "net/http/httptest" 6 7 "github.com/golang/mock/gomock" 8 . "github.com/onsi/ginkgo/v2" 9 "github.com/sirupsen/logrus" 10 11 "github.com/pyroscope-io/pyroscope/pkg/api" 12 "github.com/pyroscope-io/pyroscope/pkg/api/mocks" 13 "github.com/pyroscope-io/pyroscope/pkg/api/router" 14 "github.com/pyroscope-io/pyroscope/pkg/model" 15 ) 16 17 var _ = Describe("AuthMiddleware", func() { 18 defer GinkgoRecover() 19 20 var ( 21 // Mocks setup. 22 ctrl *gomock.Controller 23 server *httptest.Server 24 authServiceMock *mocks.MockAuthService 25 26 // The service is a sample target. 27 apiKeyServiceMock *mocks.MockAPIKeyService 28 ) 29 30 BeforeEach(func() { 31 ctrl = gomock.NewController(GinkgoT()) 32 authServiceMock = mocks.NewMockAuthService(ctrl) 33 apiKeyServiceMock = mocks.NewMockAPIKeyService(ctrl) 34 server = httptest.NewServer(newTestRouter(defaultReqCtx, router.Services{ 35 Logger: logrus.StandardLogger(), 36 AuthService: authServiceMock, 37 APIKeyService: apiKeyServiceMock, 38 })) 39 }) 40 41 AfterEach(func() { 42 ctrl.Finish() 43 server.Close() 44 }) 45 46 Describe("request authentication", func() { 47 var ( 48 // API key and the token string returned by mocked service. 49 expectedAPIKey model.APIKey 50 expectedUser model.User 51 expectedToken string 52 ) 53 54 BeforeEach(func() { 55 expectedToken = "some-token" 56 expectedAPIKey = model.APIKey{ 57 Name: "test-api-key", 58 Role: model.AdminRole, 59 } 60 expectedUser = model.User{ 61 Name: "test-user", 62 Role: model.AdminRole, 63 } 64 }) 65 66 Context("when request has a valid API key in the header", func() { 67 It("authenticates request", func() { 68 authServiceMock.EXPECT(). 69 APIKeyFromToken(gomock.Any(), expectedToken). 70 Return(expectedAPIKey, nil). 71 Times(1) 72 73 apiKeyServiceMock.EXPECT(). 74 GetAllAPIKeys(gomock.Any()). 75 Times(1) 76 77 req := newRequest(http.MethodGet, server.URL+"/keys", "") 78 req.Header.Set("Authorization", "Bearer "+expectedToken) 79 expectResponse(req, 80 "response_empty_array.json", 81 http.StatusOK) 82 }) 83 }) 84 85 Context("when request has an invalid API key in the header", func() { 86 It("returns status code Unauthorized", func() { 87 authServiceMock.EXPECT(). 88 APIKeyFromToken(gomock.Any(), expectedToken). 89 Return(expectedAPIKey, model.ErrAPIKeyNotFound). 90 Times(1) 91 92 authServiceMock.EXPECT(). 93 UserFromJWTToken(gomock.Any(), expectedToken). 94 Times(0) 95 96 apiKeyServiceMock.EXPECT(). 97 GetAllAPIKeys(gomock.Any()). 98 Times(0) 99 100 req := newRequest(http.MethodGet, server.URL+"/keys", "") 101 req.Header.Set("Authorization", "Bearer "+expectedToken) 102 expectResponse(req, 103 "response_invalid_credentials.json", 104 http.StatusUnauthorized) 105 }) 106 }) 107 108 Context("when request has a valid user token in the cookies", func() { 109 It("authenticates request", func() { 110 authServiceMock.EXPECT(). 111 UserFromJWTToken(gomock.Any(), expectedToken). 112 Return(expectedUser, nil). 113 Times(1) 114 115 authServiceMock.EXPECT(). 116 APIKeyFromToken(gomock.Any(), expectedToken). 117 Times(0) 118 119 apiKeyServiceMock.EXPECT(). 120 GetAllAPIKeys(gomock.Any()). 121 Times(1) 122 123 req := newRequest(http.MethodGet, server.URL+"/keys", "") 124 req.AddCookie(&http.Cookie{Name: api.JWTCookieName, Value: expectedToken}) 125 expectResponse(req, 126 "response_empty_array.json", 127 http.StatusOK) 128 }) 129 }) 130 131 Context("when user token is invalid or can not be found", func() { 132 It("redirects request", func() { 133 authServiceMock.EXPECT(). 134 UserFromJWTToken(gomock.Any(), expectedToken). 135 Return(expectedUser, model.ErrUserNotFound). 136 Times(1) 137 138 authServiceMock.EXPECT(). 139 APIKeyFromToken(gomock.Any(), expectedToken). 140 Times(0) 141 142 apiKeyServiceMock.EXPECT(). 143 GetAllAPIKeys(gomock.Any()). 144 Times(0) 145 146 req := newRequest(http.MethodGet, server.URL+"/keys", "") 147 req.AddCookie(&http.Cookie{Name: api.JWTCookieName, Value: expectedToken}) 148 expectResponse(req, 149 "", // Empty response body. 150 http.StatusTemporaryRedirect) 151 }) 152 }) 153 154 Context("when credentials are not provided", func() { 155 It("redirects request", func() { 156 authServiceMock.EXPECT(). 157 APIKeyFromToken(gomock.Any(), expectedToken). 158 Return(expectedAPIKey, nil). 159 Times(0) 160 161 authServiceMock.EXPECT(). 162 UserFromJWTToken(gomock.Any(), expectedToken). 163 Return(expectedUser, model.ErrUserNotFound). 164 Times(0) 165 166 apiKeyServiceMock.EXPECT(). 167 GetAllAPIKeys(gomock.Any()). 168 Times(0) 169 170 expectResponse(newRequest(http.MethodGet, server.URL+"/keys", 171 ""), // Empty request body. 172 "", // Empty response. 173 http.StatusTemporaryRedirect) 174 }) 175 }) 176 }) 177 })