github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/ctl/auth/simple_test.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package auth 22 23 import ( 24 "bytes" 25 "context" 26 "fmt" 27 "net/http" 28 "net/http/httptest" 29 "testing" 30 31 "github.com/stretchr/testify/require" 32 yaml "gopkg.in/yaml.v2" 33 ) 34 35 var ( 36 testUser = "testUser" 37 testOriginator = "testOriginator" 38 testUserIDHeader = "testUserIDHeader" 39 testOriginatorIDHeader = "testOriginatorIDHeader" 40 testConfig = SimpleAuthConfig{ 41 Authentication: authenticationConfig{ 42 UserIDHeader: "testHeader", 43 }, 44 Authorization: authorizationConfig{ 45 ReadWhitelistEnabled: true, 46 WriteWhitelistEnabled: false, 47 ReadWhitelistedUserIDs: []string{testUser}, 48 WriteWhitelistedUserIDs: []string{}, 49 }, 50 } 51 testConfigWithOriginatorID = SimpleAuthConfig{ 52 Authentication: authenticationConfig{ 53 UserIDHeader: testUserIDHeader, 54 OriginatorIDHeader: testOriginatorIDHeader, 55 }, 56 Authorization: authorizationConfig{ 57 ReadWhitelistEnabled: true, 58 WriteWhitelistEnabled: true, 59 ReadWhitelistedUserIDs: []string{}, 60 WriteWhitelistedUserIDs: []string{testUser}, 61 }, 62 } 63 ) 64 65 func TestSimpleAuthConfigUnmarshal(t *testing.T) { 66 configStr := ` 67 authentication: 68 userIDHeader: user-id 69 authorization: 70 readWhitelistEnabled: true 71 readWhitelistedUserIDs: 72 - foo 73 - bar 74 writeWhitelistEnabled: true 75 writeWhitelistedUserIDs: 76 - bar 77 - baz 78 ` 79 var cfg SimpleAuthConfig 80 require.NoError(t, yaml.Unmarshal([]byte(configStr), &cfg)) 81 require.Equal(t, "user-id", cfg.Authentication.UserIDHeader) 82 require.True(t, cfg.Authorization.ReadWhitelistEnabled) 83 require.Equal(t, []string{"foo", "bar"}, cfg.Authorization.ReadWhitelistedUserIDs) 84 require.True(t, cfg.Authorization.WriteWhitelistEnabled) 85 require.Equal(t, []string{"bar", "baz"}, cfg.Authorization.WriteWhitelistedUserIDs) 86 } 87 88 func TestNewSimpleAuth(t *testing.T) { 89 an := testConfig.NewSimpleAuth().(simpleAuth).authentication 90 az := testConfig.NewSimpleAuth().(simpleAuth).authorization 91 require.Equal(t, an.userIDHeader, "testHeader") 92 require.Equal(t, az.readWhitelistEnabled, true) 93 require.Equal(t, az.writeWhitelistEnabled, false) 94 require.Equal(t, az.readWhitelistedUserIDs, []string{"testUser"}) 95 require.Equal(t, az.writeWhitelistedUserIDs, []string{}) 96 } 97 98 func TestSetUser(t *testing.T) { 99 a := testConfig.NewSimpleAuth() 100 ctx := context.Background() 101 require.Nil(t, ctx.Value(UserIDField)) 102 ctx = a.SetUser(ctx, "foo") 103 require.Equal(t, "foo", ctx.Value(UserIDField).(string)) 104 } 105 106 func TestGetUser(t *testing.T) { 107 a := testConfig.NewSimpleAuth() 108 ctx := context.Background() 109 110 id, err := a.GetUser(ctx) 111 require.Empty(t, id) 112 require.Error(t, err) 113 114 ctx = a.SetUser(ctx, "foo") 115 id, err = a.GetUser(ctx) 116 require.Equal(t, "foo", id) 117 require.NoError(t, err) 118 } 119 120 func TestSimpleAuthenticationAuthenticate(t *testing.T) { 121 authentication := simpleAuthentication{ 122 userIDHeader: "foo", 123 } 124 125 require.Nil(t, authentication.authenticate("bar")) 126 require.EqualError(t, authentication.authenticate(""), "must provide header: [foo]") 127 } 128 129 func TestSimpleAuthorizationAuthorize(t *testing.T) { 130 authorization := simpleAuthorization{ 131 readWhitelistEnabled: true, 132 writeWhitelistEnabled: false, 133 readWhitelistedUserIDs: []string{"foo", "bar"}, 134 writeWhitelistedUserIDs: []string{"foo", "bar", "baz"}, 135 } 136 137 require.Nil(t, authorization.authorize(ReadOnlyAuthorization, "foo")) 138 require.Nil(t, authorization.authorize(WriteOnlyAuthorization, "foo")) 139 require.Nil(t, authorization.authorize(NoAuthorization, "foo")) 140 require.Nil(t, authorization.authorize(WriteOnlyAuthorization, "baz")) 141 require.EqualError(t, authorization.authorize(ReadOnlyAuthorization, "baz"), "supplied userID: [baz] is not authorized") 142 require.EqualError(t, authorization.authorize(ReadWriteAuthorization, "baz"), "supplied userID: [baz] is not authorized") 143 require.EqualError(t, authorization.authorize(AuthorizationType(100), "baz"), "unsupported authorization type 100 passed to handler") 144 } 145 146 func TestAuthorizeUserForAccess(t *testing.T) { 147 userID := "user2" 148 whitelistedUserIDs := []string{"user1", "user2", "user3"} 149 require.NoError(t, authorizeUserForAccess(userID, whitelistedUserIDs, false)) 150 require.NoError(t, authorizeUserForAccess(userID, whitelistedUserIDs, true)) 151 } 152 153 func TestAuthorizeUserForAccessUserNotWhitelisted(t *testing.T) { 154 userID := "user4" 155 whitelistedUserIDs := []string{"user1", "user2", "user3"} 156 require.NoError(t, authorizeUserForAccess(userID, whitelistedUserIDs, false)) 157 require.EqualError( 158 t, 159 authorizeUserForAccess(userID, whitelistedUserIDs, true), 160 fmt.Sprintf("supplied userID: [%s] is not authorized", userID), 161 ) 162 } 163 164 func TestHealthCheck(t *testing.T) { 165 a := testConfig.NewSimpleAuth() 166 f := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 167 v, err := a.GetUser(r.Context()) 168 require.NoError(t, err) 169 require.Equal(t, "testHeader", v) 170 }) 171 172 wrappedCall := a.NewAuthHandler(NoAuthorization, f, writeAPIResponse) 173 wrappedCall.ServeHTTP(httptest.NewRecorder(), &http.Request{}) 174 } 175 176 func TestAuthenticateFailure(t *testing.T) { 177 a := testConfig.NewSimpleAuth() 178 f := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 179 v, err := a.GetUser(r.Context()) 180 require.NoError(t, err) 181 require.Equal(t, "testHeader", v) 182 }) 183 recorder := httptest.NewRecorder() 184 185 wrappedCall := a.NewAuthHandler(NoAuthorization, f, writeAPIResponse) 186 wrappedCall.ServeHTTP(recorder, &http.Request{}) 187 require.Equal(t, http.StatusUnauthorized, recorder.Code) 188 require.Equal(t, "application/json", recorder.HeaderMap["Content-Type"][0]) 189 } 190 191 func TestAuthenticateWithOriginatorID(t *testing.T) { 192 req, err := http.NewRequest(http.MethodPost, "/update", nil) 193 require.NoError(t, err) 194 req.Header.Add(testUserIDHeader, testUser) 195 req.Header.Add(testOriginatorIDHeader, testOriginator) 196 197 a := testConfigWithOriginatorID.NewSimpleAuth() 198 f := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 199 v, err := a.GetUser(r.Context()) 200 require.NoError(t, err) 201 require.Equal(t, testOriginator, v) 202 writeAPIResponse(w, http.StatusOK, "success!") 203 }) 204 recorder := httptest.NewRecorder() 205 wrappedCall := a.NewAuthHandler(NoAuthorization, f, writeAPIResponse) 206 wrappedCall.ServeHTTP(recorder, req) 207 require.Equal(t, http.StatusOK, recorder.Code) 208 require.Equal(t, "application/json", recorder.HeaderMap["Content-Type"][0]) 209 } 210 211 func TestAuthorizeFailure(t *testing.T) { 212 a := testConfig.NewSimpleAuth() 213 f := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 214 v, err := a.GetUser(r.Context()) 215 require.NoError(t, err) 216 require.Equal(t, "testHeader", v) 217 }) 218 recorder := httptest.NewRecorder() 219 req, err := http.NewRequest("Get", "/create", bytes.NewBuffer(nil)) 220 require.NoError(t, err) 221 req.Header.Add("testHeader", "validUserID") 222 223 wrappedCall := a.NewAuthHandler(ReadOnlyAuthorization, f, writeAPIResponse) 224 wrappedCall.ServeHTTP(recorder, req) 225 require.Equal(t, http.StatusForbidden, recorder.Code) 226 require.Equal(t, "application/json", recorder.HeaderMap["Content-Type"][0]) 227 } 228 229 func writeAPIResponse(w http.ResponseWriter, code int, msg string) error { 230 w.Header().Set("Content-Type", "application/json") 231 w.WriteHeader(code) 232 _, err := w.Write([]byte(msg)) 233 234 return err 235 }