github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/mw_basic_auth_test.go (about) 1 package gateway 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "net/http" 7 "strings" 8 "testing" 9 10 "github.com/TykTechnologies/tyk/storage" 11 12 "github.com/TykTechnologies/tyk/config" 13 "github.com/TykTechnologies/tyk/test" 14 "github.com/TykTechnologies/tyk/user" 15 ) 16 17 func genAuthHeader(username, password string) string { 18 toEncode := strings.Join([]string{username, password}, ":") 19 encodedPass := base64.StdEncoding.EncodeToString([]byte(toEncode)) 20 return fmt.Sprintf("Basic %s", encodedPass) 21 } 22 23 func testPrepareBasicAuth(cacheDisabled bool) *user.SessionState { 24 session := CreateStandardSession() 25 session.BasicAuthData.Password = "password" 26 session.AccessRights = map[string]user.AccessDefinition{"test": {APIID: "test", Versions: []string{"v1"}}} 27 session.OrgID = "default" 28 29 BuildAndLoadAPI(func(spec *APISpec) { 30 spec.UseBasicAuth = true 31 spec.BasicAuth.DisableCaching = cacheDisabled 32 spec.UseKeylessAccess = false 33 spec.Proxy.ListenPath = "/" 34 spec.OrgID = "default" 35 }) 36 37 return session 38 } 39 40 func TestBasicAuth(t *testing.T) { 41 ts := StartTest() 42 defer ts.Close() 43 44 session := testPrepareBasicAuth(false) 45 46 validPassword := map[string]string{"Authorization": genAuthHeader("user", "password")} 47 wrongPassword := map[string]string{"Authorization": genAuthHeader("user", "wrong")} 48 wrongFormat := map[string]string{"Authorization": genAuthHeader("user", "password:more")} 49 malformed := map[string]string{"Authorization": "not base64"} 50 51 ts.Run(t, []test.TestCase{ 52 // Create base auth based key 53 {Method: "POST", Path: "/tyk/keys/defaultuser", Data: session, AdminAuth: true, Code: 200}, 54 {Method: "GET", Path: "/", Code: 401, BodyMatch: `Authorization field missing`}, 55 {Method: "GET", Path: "/", Headers: validPassword, Code: 200}, 56 {Method: "GET", Path: "/", Headers: wrongPassword, Code: 401}, 57 {Method: "GET", Path: "/", Headers: wrongFormat, Code: 400, BodyMatch: `Attempted access with malformed header, values not in basic auth format`}, 58 {Method: "GET", Path: "/", Headers: malformed, Code: 400, BodyMatch: `Attempted access with malformed header, auth data not encoded correctly`}, 59 }...) 60 } 61 62 func TestBasicAuthFromBody(t *testing.T) { 63 ts := StartTest() 64 defer ts.Close() 65 66 session := CreateStandardSession() 67 session.BasicAuthData.Password = "password" 68 session.AccessRights = map[string]user.AccessDefinition{"test": {APIID: "test", Versions: []string{"v1"}}} 69 session.OrgID = "default" 70 71 BuildAndLoadAPI(func(spec *APISpec) { 72 spec.UseBasicAuth = true 73 spec.BasicAuth.ExtractFromBody = true 74 spec.BasicAuth.BodyUserRegexp = `<User>(.*)</User>` 75 spec.BasicAuth.BodyPasswordRegexp = `<Password>(.*)</Password>` 76 spec.UseKeylessAccess = false 77 spec.Proxy.ListenPath = "/" 78 spec.OrgID = "default" 79 }) 80 81 validPassword := `<User>user</User><Password>password</Password>` 82 wrongPassword := `<User>user</User><Password>wrong</Password>` 83 withoutPassword := `<User>user</User>` 84 malformed := `<User>User>` 85 emptyAuthHeader := map[string]string{"Www-Authenticate": ""} 86 87 ts.Run(t, []test.TestCase{ 88 // Create base auth based key 89 {Method: "POST", Path: "/tyk/keys/defaultuser", Data: session, AdminAuth: true, Code: 200}, 90 {Method: "POST", Path: "/", Code: 400, BodyMatch: `Body do not contain username`}, 91 {Method: "POST", Path: "/", Data: validPassword, Code: 200, HeadersMatch: emptyAuthHeader}, 92 {Method: "POST", Path: "/", Data: wrongPassword, Code: 401}, 93 {Method: "POST", Path: "/", Data: withoutPassword, Code: 400, BodyMatch: `Body do not contain password`}, 94 {Method: "GET", Path: "/", Data: malformed, Code: 400, BodyMatch: `Body do not contain username`}, 95 }...) 96 } 97 98 func TestBasicAuthLegacyWithHashFunc(t *testing.T) { 99 globalConf := config.Global() 100 101 globalConf.HashKeys = true 102 globalConf.EnableHashedKeysListing = true 103 // settings to create BA session with legacy key format 104 globalConf.HashKeyFunction = "" 105 config.SetGlobal(globalConf) 106 defer ResetTestConfig() 107 108 ts := StartTest() 109 defer ts.Close() 110 111 // create session with legacy key format 112 session := testPrepareBasicAuth(false) 113 114 validPassword := map[string]string{"Authorization": genAuthHeader("user", "password")} 115 116 ts.Run(t, []test.TestCase{ 117 // Create base auth based key 118 {Method: "POST", Path: "/tyk/keys/defaultuser", Data: session, AdminAuth: true, Code: 200}, 119 {Method: "GET", Path: "/", Headers: validPassword, Code: 200}, 120 }...) 121 122 // set custom hashing function and check if we still do BA session auth with legacy key format 123 globalConf.HashKeyFunction = storage.HashMurmur64 124 config.SetGlobal(globalConf) 125 126 ts.Run(t, []test.TestCase{ 127 // Create base auth based key 128 {Method: "GET", Path: "/", Headers: validPassword, Code: 200}, 129 }...) 130 } 131 132 func TestBasicAuthCachedUserCollision(t *testing.T) { 133 globalConf := config.Global() 134 globalConf.HashKeys = true 135 globalConf.HashKeyFunction = "murmur64" 136 config.SetGlobal(globalConf) 137 defer ResetTestConfig() 138 139 ts := StartTest() 140 defer ts.Close() 141 142 session := testPrepareBasicAuth(false) 143 144 correct := map[string]string{"Authorization": genAuthHeader("bellbell1", "password")} 145 remove1 := map[string]string{"Authorization": genAuthHeader("bellbell", "password")} 146 remove2 := map[string]string{"Authorization": genAuthHeader("bellbel", "password")} 147 remove3 := map[string]string{"Authorization": genAuthHeader("bellbe", "password")} 148 remove4 := map[string]string{"Authorization": genAuthHeader("bellb", "password")} 149 remove5 := map[string]string{"Authorization": genAuthHeader("bell", "password")} 150 add1 := map[string]string{"Authorization": genAuthHeader("bellbell11", "password")} 151 add2 := map[string]string{"Authorization": genAuthHeader("bellbell12", "password")} 152 add3 := map[string]string{"Authorization": genAuthHeader("bellbell13", "password")} 153 154 ts.Run(t, []test.TestCase{ 155 // Create base auth based key 156 {Method: "POST", Path: "/tyk/keys/bellbell1", Data: session, AdminAuth: true, Code: http.StatusOK}, 157 {Method: "GET", Path: "/", Headers: correct, Code: http.StatusOK}, 158 {Method: "GET", Path: "/", Headers: remove1, Code: http.StatusUnauthorized}, 159 {Method: "GET", Path: "/", Headers: remove2, Code: http.StatusUnauthorized}, 160 {Method: "GET", Path: "/", Headers: remove3, Code: http.StatusUnauthorized}, 161 {Method: "GET", Path: "/", Headers: remove4, Code: http.StatusUnauthorized}, 162 {Method: "GET", Path: "/", Headers: remove5, Code: http.StatusUnauthorized}, 163 {Method: "GET", Path: "/", Headers: add1, Code: http.StatusUnauthorized}, 164 {Method: "GET", Path: "/", Headers: add2, Code: http.StatusUnauthorized}, 165 {Method: "GET", Path: "/", Headers: add3, Code: http.StatusUnauthorized}, 166 {Method: "GET", Path: "/", Headers: correct, Code: http.StatusOK}, 167 }...) 168 } 169 170 func TestBasicAuthCachedPasswordCollision(t *testing.T) { 171 ts := StartTest() 172 defer ts.Close() 173 174 for _, useCache := range []bool{true, false} { 175 correct := map[string]string{"Authorization": genAuthHeader("bellbell1", "password")} 176 remove1 := map[string]string{"Authorization": genAuthHeader("bellbell1", "passwor")} 177 remove2 := map[string]string{"Authorization": genAuthHeader("bellbell1", "passwo")} 178 remove3 := map[string]string{"Authorization": genAuthHeader("bellbell1", "passw")} 179 remove4 := map[string]string{"Authorization": genAuthHeader("bellbell1", "pass")} 180 remove5 := map[string]string{"Authorization": genAuthHeader("bellbell1", "pas")} 181 add1 := map[string]string{"Authorization": genAuthHeader("bellbell1", "password1")} 182 add2 := map[string]string{"Authorization": genAuthHeader("bellbell1", "password22")} 183 add3 := map[string]string{"Authorization": genAuthHeader("bellbell1", "password333")} 184 185 t.Run(fmt.Sprintf("Cache disabled:%v", useCache), func(t *testing.T) { 186 session := testPrepareBasicAuth(useCache) 187 188 ts.Run(t, []test.TestCase{ 189 // Create base auth based key 190 {Method: "POST", Path: "/tyk/keys/bellbell1", Data: session, AdminAuth: true, Code: http.StatusOK}, 191 {Method: "GET", Path: "/", Headers: correct, Code: http.StatusOK}, 192 {Method: "GET", Path: "/", Headers: remove1, Code: http.StatusUnauthorized}, 193 {Method: "GET", Path: "/", Headers: remove2, Code: http.StatusUnauthorized}, 194 {Method: "GET", Path: "/", Headers: remove3, Code: http.StatusUnauthorized}, 195 {Method: "GET", Path: "/", Headers: remove4, Code: http.StatusUnauthorized}, 196 {Method: "GET", Path: "/", Headers: remove5, Code: http.StatusUnauthorized}, 197 {Method: "GET", Path: "/", Headers: add1, Code: http.StatusUnauthorized}, 198 {Method: "GET", Path: "/", Headers: add2, Code: http.StatusUnauthorized}, 199 {Method: "GET", Path: "/", Headers: add3, Code: http.StatusUnauthorized}, 200 {Method: "GET", Path: "/", Headers: correct, Code: http.StatusOK}, 201 }...) 202 }) 203 } 204 } 205 206 func BenchmarkBasicAuth(b *testing.B) { 207 b.ReportAllocs() 208 209 ts := StartTest() 210 defer ts.Close() 211 212 session := testPrepareBasicAuth(false) 213 214 validPassword := map[string]string{"Authorization": genAuthHeader("user", "password")} 215 wrongPassword := map[string]string{"Authorization": genAuthHeader("user", "wrong")} 216 wrongFormat := map[string]string{"Authorization": genAuthHeader("user", "password:more")} 217 malformed := map[string]string{"Authorization": "not base64"} 218 219 // Create base auth based key 220 ts.Run(b, test.TestCase{ 221 Method: "POST", 222 Path: "/tyk/keys/defaultuser", 223 Data: session, 224 AdminAuth: true, 225 Code: 200, 226 }) 227 228 for i := 0; i < b.N; i++ { 229 ts.Run(b, []test.TestCase{ 230 {Method: "GET", Path: "/", Code: 401, BodyMatch: `Authorization field missing`}, 231 {Method: "GET", Path: "/", Headers: validPassword, Code: 200}, 232 {Method: "GET", Path: "/", Headers: wrongPassword, Code: 401}, 233 {Method: "GET", Path: "/", Headers: wrongFormat, Code: 400, BodyMatch: `Attempted access with malformed header, values not in basic auth format`}, 234 {Method: "GET", Path: "/", Headers: malformed, Code: 400, BodyMatch: `Attempted access with malformed header, auth data not encoded correctly`}, 235 }...) 236 } 237 } 238 239 func BenchmarkBasicAuth_CacheEnabled(b *testing.B) { 240 b.ReportAllocs() 241 242 ts := StartTest() 243 defer ts.Close() 244 245 session := testPrepareBasicAuth(false) 246 247 validPassword := map[string]string{"Authorization": genAuthHeader("user", "password")} 248 249 // Create base auth based key 250 ts.Run(b, test.TestCase{ 251 Method: "POST", 252 Path: "/tyk/keys/defaultuser", 253 Data: session, 254 AdminAuth: true, 255 Code: 200, 256 }) 257 258 for i := 0; i < b.N; i++ { 259 ts.Run(b, []test.TestCase{ 260 {Method: "GET", Path: "/", Headers: validPassword, Code: 200}, 261 }...) 262 } 263 } 264 265 func BenchmarkBasicAuth_CacheDisabled(b *testing.B) { 266 b.ReportAllocs() 267 268 ts := StartTest() 269 defer ts.Close() 270 271 session := testPrepareBasicAuth(true) 272 273 validPassword := map[string]string{"Authorization": genAuthHeader("user", "password")} 274 275 // Create base auth based key 276 ts.Run(b, test.TestCase{ 277 Method: "POST", 278 Path: "/tyk/keys/defaultuser", 279 Data: session, 280 AdminAuth: true, 281 Code: 200, 282 }) 283 284 for i := 0; i < b.N; i++ { 285 ts.Run(b, []test.TestCase{ 286 {Method: "GET", Path: "/", Headers: validPassword, Code: 200}, 287 }...) 288 } 289 }