github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+incompatible/api/oauth_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package api 5 6 import ( 7 "encoding/base64" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "net/url" 12 "strings" 13 "testing" 14 15 "github.com/mattermost/mattermost-server/einterfaces" 16 "github.com/mattermost/mattermost-server/model" 17 "github.com/mattermost/mattermost-server/utils" 18 ) 19 20 func TestOAuthRegisterApp(t *testing.T) { 21 th := Setup().InitBasic().InitSystemAdmin() 22 defer th.TearDown() 23 24 Client := th.BasicClient 25 26 oauthApp := &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}, IsTrusted: true} 27 28 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 29 if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider { 30 if _, err := Client.RegisterApp(oauthApp); err == nil { 31 t.Fatal("should have failed - oauth providing turned off") 32 } 33 } 34 35 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 36 37 // calling the endpoint without an app 38 if _, err := Client.DoApiPost("/oauth/register", ""); err == nil { 39 t.Fatal("should have failed") 40 } 41 42 Client.Logout() 43 44 if _, err := Client.RegisterApp(oauthApp); err == nil { 45 t.Fatal("not logged in - should have failed") 46 } 47 48 th.LoginSystemAdmin() 49 Client = th.SystemAdminClient 50 51 if result, err := Client.RegisterApp(oauthApp); err != nil { 52 t.Fatal(err) 53 } else { 54 rapp := result.Data.(*model.OAuthApp) 55 if len(rapp.Id) != 26 { 56 t.Fatal("clientid didn't return properly") 57 } 58 if len(rapp.ClientSecret) != 26 { 59 t.Fatal("client secret didn't return properly") 60 } 61 } 62 63 oauthApp = &model.OAuthApp{Name: "", Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 64 if _, err := Client.RegisterApp(oauthApp); err == nil { 65 t.Fatal("missing name - should have failed") 66 } 67 68 oauthApp = &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 69 if _, err := Client.RegisterApp(oauthApp); err == nil { 70 t.Fatal("missing homepage - should have failed") 71 } 72 73 oauthApp = &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{}} 74 if _, err := Client.RegisterApp(oauthApp); err == nil { 75 t.Fatal("missing callback url - should have failed") 76 } 77 78 user := &model.User{Email: strings.ToLower("test+"+model.NewId()) + "@simulator.amazonses.com", Password: "hello1", Username: "n" + model.NewId(), EmailVerified: true} 79 80 ruser := Client.Must(Client.CreateUser(user, "")).Data.(*model.User) 81 th.App.UpdateUserRoles(ruser.Id, "", false) 82 83 Client.Logout() 84 Client.Login(user.Email, user.Password) 85 86 oauthApp = &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}, IsTrusted: true} 87 if _, err := Client.RegisterApp(oauthApp); err == nil { 88 t.Fatal("should have failed. not enough permissions") 89 } 90 91 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 92 93 th.LoginBasic() 94 95 if result, err := th.BasicClient.RegisterApp(oauthApp); err != nil { 96 t.Fatal(err) 97 } else { 98 rapp := result.Data.(*model.OAuthApp) 99 if rapp.IsTrusted { 100 t.Fatal("trusted should be false - created by non admin") 101 } 102 } 103 } 104 105 func TestOAuthAllow(t *testing.T) { 106 th := Setup().InitBasic().InitSystemAdmin() 107 defer th.TearDown() 108 109 Client := th.BasicClient 110 AdminClient := th.SystemAdminClient 111 112 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 113 oauthApp := &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 114 oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 115 116 state := "123" 117 118 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 119 if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", state); err == nil { 120 t.Fatal("should have failed - oauth providing turned off") 121 } 122 123 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 124 125 if result, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", state); err != nil { 126 t.Fatal(err) 127 } else { 128 redirect := result.Data.(map[string]string)["redirect"] 129 if len(redirect) == 0 { 130 t.Fatal("redirect url should be set") 131 } 132 133 ru, _ := url.Parse(redirect) 134 if ru == nil { 135 t.Fatal("redirect url unparseable") 136 } else { 137 if len(ru.Query().Get("code")) == 0 { 138 t.Fatal("authorization code not returned") 139 } 140 if ru.Query().Get("state") != state { 141 t.Fatal("returned state doesn't match") 142 } 143 } 144 } 145 146 if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "", "all", state); err == nil { 147 t.Fatal("should have failed - no redirect_url given") 148 } 149 150 if _, err := Client.AllowOAuth("", oauthApp.Id, "", "", state); err == nil { 151 t.Fatal("should have failed - no response type given") 152 } 153 154 if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "", "", state); err == nil { 155 t.Fatal("should have failed - no redirect_url given") 156 } 157 158 if result, err := Client.AllowOAuth("junk", oauthApp.Id, oauthApp.CallbackUrls[0], "all", state); err != nil { 159 t.Fatal(err) 160 } else { 161 redirect := result.Data.(map[string]string)["redirect"] 162 if len(redirect) == 0 { 163 t.Fatal("redirect url should be set") 164 } 165 166 ru, _ := url.Parse(redirect) 167 if ru == nil { 168 t.Fatal("redirect url unparseable") 169 } else { 170 if ru.Query().Get("error") != "unsupported_response_type" { 171 t.Fatal("wrong error returned") 172 } 173 if ru.Query().Get("state") != state { 174 t.Fatal("returned state doesn't match") 175 } 176 } 177 } 178 179 if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, "", oauthApp.CallbackUrls[0], "all", state); err == nil { 180 t.Fatal("should have failed - empty client id") 181 } 182 183 if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, "junk", oauthApp.CallbackUrls[0], "all", state); err == nil { 184 t.Fatal("should have failed - bad client id") 185 } 186 187 if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "https://somewhereelse.com", "", state); err == nil { 188 t.Fatal("should have failed - redirect uri host does not match app host") 189 } 190 } 191 192 func TestOAuthGetAppsByUser(t *testing.T) { 193 th := Setup().InitBasic().InitSystemAdmin() 194 defer th.TearDown() 195 196 Client := th.BasicClient 197 AdminClient := th.SystemAdminClient 198 199 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 200 if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider { 201 if _, err := Client.GetOAuthAppsByUser(); err == nil { 202 t.Fatal("should have failed - oauth providing turned off") 203 } 204 205 } 206 207 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 208 209 if _, err := Client.GetOAuthAppsByUser(); err == nil { 210 t.Fatal("Should have failed.") 211 } 212 213 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 214 215 if result, err := Client.GetOAuthAppsByUser(); err != nil { 216 t.Fatal(err) 217 } else { 218 apps := result.Data.([]*model.OAuthApp) 219 220 if len(apps) != 0 { 221 t.Fatal("incorrect number of apps should have been 0") 222 } 223 } 224 225 oauthApp := &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 226 oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 227 228 if result, err := Client.GetOAuthAppsByUser(); err != nil { 229 t.Fatal(err) 230 } else { 231 apps := result.Data.([]*model.OAuthApp) 232 233 if len(apps) != 1 { 234 t.Fatal("incorrect number of apps should have been 1") 235 } 236 } 237 238 oauthApp = &model.OAuthApp{Name: "TestApp4" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 239 oauthApp = AdminClient.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 240 241 if result, err := AdminClient.GetOAuthAppsByUser(); err != nil { 242 t.Fatal(err) 243 } else { 244 apps := result.Data.([]*model.OAuthApp) 245 246 if len(apps) < 4 { 247 t.Fatal("incorrect number of apps should have been 4 or more") 248 } 249 } 250 251 user := &model.User{Email: strings.ToLower("test+"+model.NewId()) + "@simulator.amazonses.com", Password: "hello1", Username: "n" + model.NewId(), EmailVerified: true} 252 ruser := Client.Must(AdminClient.CreateUser(user, "")).Data.(*model.User) 253 th.App.UpdateUserRoles(ruser.Id, "", false) 254 255 Client.Logout() 256 Client.Login(user.Email, user.Password) 257 258 if _, err := Client.GetOAuthAppsByUser(); err == nil { 259 t.Fatal("should have failed. not enough permissions") 260 } 261 } 262 263 func TestOAuthGetAppInfo(t *testing.T) { 264 th := Setup().InitBasic().InitSystemAdmin() 265 defer th.TearDown() 266 267 Client := th.BasicClient 268 AdminClient := th.SystemAdminClient 269 270 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 271 if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider { 272 if _, err := Client.GetOAuthAppInfo("fakeId"); err == nil { 273 t.Fatal("should have failed - oauth providing turned off") 274 } 275 276 } 277 278 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 279 280 oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 281 282 oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 283 284 if _, err := Client.GetOAuthAppInfo(model.NewId()); err == nil { 285 t.Fatal("Should have failed") 286 } 287 288 if _, err := Client.GetOAuthAppInfo(oauthApp.Id); err != nil { 289 t.Fatal(err) 290 } 291 } 292 293 func TestOAuthGetAuthorizedApps(t *testing.T) { 294 th := Setup().InitBasic().InitSystemAdmin() 295 defer th.TearDown() 296 297 Client := th.BasicClient 298 AdminClient := th.SystemAdminClient 299 300 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 301 if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider { 302 if _, err := Client.GetOAuthAuthorizedApps(); err == nil { 303 t.Fatal("should have failed - oauth providing turned off") 304 } 305 306 } 307 308 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 309 310 oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 311 oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 312 313 if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "https://nowhere.com", "user", ""); err != nil { 314 t.Fatal(err) 315 } 316 317 if result, err := Client.GetOAuthAuthorizedApps(); err != nil { 318 t.Fatal(err) 319 } else { 320 apps := result.Data.([]*model.OAuthApp) 321 322 if len(apps) != 1 { 323 t.Fatal("incorrect number of apps should have been 1") 324 } 325 } 326 } 327 328 func TestOAuthDeauthorizeApp(t *testing.T) { 329 th := Setup().InitBasic().InitSystemAdmin() 330 defer th.TearDown() 331 332 Client := th.BasicClient 333 AdminClient := th.SystemAdminClient 334 335 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 336 if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider { 337 if err := Client.OAuthDeauthorizeApp(model.NewId()); err == nil { 338 t.Fatal("should have failed - oauth providing turned off") 339 } 340 341 } 342 343 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 344 345 oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 346 347 oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 348 349 if _, err := Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, "https://nowhere.com", "user", ""); err != nil { 350 t.Fatal(err) 351 } 352 353 if err := Client.OAuthDeauthorizeApp(""); err == nil { 354 t.Fatal("Should have failed - no id provided") 355 } 356 357 a1 := model.AccessData{} 358 a1.ClientId = oauthApp.Id 359 a1.UserId = th.BasicUser.Id 360 a1.Token = model.NewId() 361 a1.RefreshToken = model.NewId() 362 a1.ExpiresAt = model.GetMillis() 363 a1.RedirectUri = "http://example.com" 364 <-th.App.Srv.Store.OAuth().SaveAccessData(&a1) 365 366 if err := Client.OAuthDeauthorizeApp(oauthApp.Id); err != nil { 367 t.Fatal(err) 368 } 369 370 if result, err := Client.GetOAuthAuthorizedApps(); err != nil { 371 t.Fatal(err) 372 } else { 373 apps := result.Data.([]*model.OAuthApp) 374 375 if len(apps) != 0 { 376 t.Fatal("incorrect number of apps should have been 0") 377 } 378 } 379 } 380 381 func TestOAuthRegenerateAppSecret(t *testing.T) { 382 th := Setup().InitBasic().InitSystemAdmin() 383 defer th.TearDown() 384 385 Client := th.BasicClient 386 AdminClient := th.SystemAdminClient 387 388 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 389 if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider { 390 if _, err := AdminClient.RegenerateOAuthAppSecret(model.NewId()); err == nil { 391 t.Fatal("should have failed - oauth providing turned off") 392 } 393 394 } 395 396 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 397 398 oauthApp := &model.OAuthApp{Name: "TestApp6" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 399 400 oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 401 402 if _, err := AdminClient.RegenerateOAuthAppSecret(model.NewId()); err == nil { 403 t.Fatal("Should have failed - invalid app id") 404 } 405 406 if _, err := Client.RegenerateOAuthAppSecret(oauthApp.Id); err == nil { 407 t.Fatal("Should have failed - only admin or the user who registered the app are allowed to perform this action") 408 } 409 410 if regenApp, err := AdminClient.RegenerateOAuthAppSecret(oauthApp.Id); err != nil { 411 t.Fatal(err) 412 } else { 413 app2 := regenApp.Data.(*model.OAuthApp) 414 if app2.Id != oauthApp.Id { 415 t.Fatal("Should have been the same app Id") 416 } 417 418 if app2.ClientSecret == oauthApp.ClientSecret { 419 t.Fatal("Should have been diferent client Secrets") 420 } 421 } 422 } 423 424 func TestOAuthDeleteApp(t *testing.T) { 425 th := Setup().InitBasic().InitSystemAdmin() 426 defer th.TearDown() 427 428 Client := th.BasicClient 429 AdminClient := th.SystemAdminClient 430 431 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 432 if !th.App.Config().ServiceSettings.EnableOAuthServiceProvider { 433 if _, err := Client.DeleteOAuthApp("fakeId"); err == nil { 434 t.Fatal("should have failed - oauth providing turned off") 435 } 436 437 } 438 439 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 440 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 441 442 oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 443 444 oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 445 446 if _, err := Client.DeleteOAuthApp(oauthApp.Id); err != nil { 447 t.Fatal(err) 448 } 449 450 oauthApp = &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 451 452 oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 453 454 if _, err := AdminClient.DeleteOAuthApp(""); err == nil { 455 t.Fatal("Should have failed - id not provided") 456 } 457 458 if _, err := AdminClient.DeleteOAuthApp(model.NewId()); err == nil { 459 t.Fatal("Should have failed - invalid id") 460 } 461 462 if _, err := AdminClient.DeleteOAuthApp(oauthApp.Id); err != nil { 463 t.Fatal(err) 464 } 465 466 oauthApp = &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 467 oauthApp = AdminClient.Must(AdminClient.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 468 469 if _, err := Client.DeleteOAuthApp(oauthApp.Id); err == nil { 470 t.Fatal("Should have failed - only admin or the user who registered the app are allowed to perform this action") 471 } 472 473 user := &model.User{Email: strings.ToLower("test+"+model.NewId()) + "@simulator.amazonses.com", Password: "hello1", Username: "n" + model.NewId(), EmailVerified: true} 474 ruser := Client.Must(AdminClient.CreateUser(user, "")).Data.(*model.User) 475 th.App.UpdateUserRoles(ruser.Id, "", false) 476 477 Client.Logout() 478 Client.Login(user.Email, user.Password) 479 if _, err := Client.DeleteOAuthApp(oauthApp.Id); err == nil { 480 t.Fatal("Should have failed - not enough permissions") 481 } 482 } 483 484 func TestOAuthAccessToken(t *testing.T) { 485 if testing.Short() { 486 t.SkipNow() 487 } 488 489 th := Setup().InitBasic() 490 defer th.TearDown() 491 492 Client := th.BasicClient 493 494 enableOAuth := th.App.Config().ServiceSettings.EnableOAuthServiceProvider 495 adminOnly := *th.App.Config().ServiceSettings.EnableOnlyAdminIntegrations 496 defer func() { 497 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = enableOAuth }) 498 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = adminOnly }) 499 }() 500 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 501 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 502 503 oauthApp := &model.OAuthApp{Name: "TestApp5" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}} 504 oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 505 506 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = false }) 507 data := url.Values{"grant_type": []string{"junk"}, "client_id": []string{"12345678901234567890123456"}, "client_secret": []string{"12345678901234567890123456"}, "code": []string{"junk"}, "redirect_uri": []string{oauthApp.CallbackUrls[0]}} 508 509 if _, err := Client.GetAccessToken(data); err == nil { 510 t.Fatal("should have failed - oauth providing turned off") 511 } 512 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 513 514 redirect := Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"] 515 rurl, _ := url.Parse(redirect) 516 517 Client.Logout() 518 519 data = url.Values{"grant_type": []string{"junk"}, "client_id": []string{oauthApp.Id}, "client_secret": []string{oauthApp.ClientSecret}, "code": []string{rurl.Query().Get("code")}, "redirect_uri": []string{oauthApp.CallbackUrls[0]}} 520 521 if _, err := Client.GetAccessToken(data); err == nil { 522 t.Fatal("should have failed - bad grant type") 523 } 524 525 data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE) 526 data.Set("client_id", "") 527 if _, err := Client.GetAccessToken(data); err == nil { 528 t.Fatal("should have failed - missing client id") 529 } 530 data.Set("client_id", "junk") 531 if _, err := Client.GetAccessToken(data); err == nil { 532 t.Fatal("should have failed - bad client id") 533 } 534 535 data.Set("client_id", oauthApp.Id) 536 data.Set("client_secret", "") 537 if _, err := Client.GetAccessToken(data); err == nil { 538 t.Fatal("should have failed - missing client secret") 539 } 540 541 data.Set("client_secret", "junk") 542 if _, err := Client.GetAccessToken(data); err == nil { 543 t.Fatal("should have failed - bad client secret") 544 } 545 546 data.Set("client_secret", oauthApp.ClientSecret) 547 data.Set("code", "") 548 if _, err := Client.GetAccessToken(data); err == nil { 549 t.Fatal("should have failed - missing code") 550 } 551 552 data.Set("code", "junk") 553 if _, err := Client.GetAccessToken(data); err == nil { 554 t.Fatal("should have failed - bad code") 555 } 556 557 data.Set("code", rurl.Query().Get("code")) 558 data.Set("redirect_uri", "junk") 559 if _, err := Client.GetAccessToken(data); err == nil { 560 t.Fatal("should have failed - non-matching redirect uri") 561 } 562 563 // reset data for successful request 564 data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE) 565 data.Set("client_id", oauthApp.Id) 566 data.Set("client_secret", oauthApp.ClientSecret) 567 data.Set("code", rurl.Query().Get("code")) 568 data.Set("redirect_uri", oauthApp.CallbackUrls[0]) 569 570 token := "" 571 refreshToken := "" 572 if result, err := Client.GetAccessToken(data); err != nil { 573 t.Fatal(err) 574 } else { 575 rsp := result.Data.(*model.AccessResponse) 576 if len(rsp.AccessToken) == 0 { 577 t.Fatal("access token not returned") 578 } else if len(rsp.RefreshToken) == 0 { 579 t.Fatal("refresh token not returned") 580 } else { 581 token = rsp.AccessToken 582 refreshToken = rsp.RefreshToken 583 } 584 if rsp.TokenType != model.ACCESS_TOKEN_TYPE { 585 t.Fatal("access token type incorrect") 586 } 587 } 588 589 if result, err := Client.DoApiGet("/teams/"+th.BasicTeam.Id+"/users/0/100?access_token="+token, "", ""); err != nil { 590 t.Fatal(err) 591 } else { 592 userMap := model.UserMapFromJson(result.Body) 593 if len(userMap) == 0 { 594 t.Fatal("user map empty - did not get results correctly") 595 } 596 } 597 598 if _, err := Client.DoApiGet("/teams/"+th.BasicTeam.Id+"/users/0/100", "", ""); err == nil { 599 t.Fatal("should have failed - no access token provided") 600 } 601 602 if _, err := Client.DoApiGet("/teams/"+th.BasicTeam.Id+"/users/0/100?access_token=junk", "", ""); err == nil { 603 t.Fatal("should have failed - bad access token provided") 604 } 605 606 Client.SetOAuthToken(token) 607 if result, err := Client.DoApiGet("/teams/"+th.BasicTeam.Id+"/users/0/100", "", ""); err != nil { 608 t.Fatal(err) 609 } else { 610 userMap := model.UserMapFromJson(result.Body) 611 if len(userMap) == 0 { 612 t.Fatal("user map empty - did not get results correctly") 613 } 614 } 615 616 if _, err := Client.GetAccessToken(data); err == nil { 617 t.Fatal("should have failed - tried to reuse auth code") 618 } 619 620 data.Set("grant_type", model.REFRESH_TOKEN_GRANT_TYPE) 621 data.Set("client_id", oauthApp.Id) 622 data.Set("client_secret", oauthApp.ClientSecret) 623 data.Set("refresh_token", "") 624 data.Set("redirect_uri", oauthApp.CallbackUrls[0]) 625 data.Del("code") 626 if _, err := Client.GetAccessToken(data); err == nil { 627 t.Fatal("Should have failed - refresh token empty") 628 } 629 630 data.Set("refresh_token", refreshToken) 631 if result, err := Client.GetAccessToken(data); err != nil { 632 t.Fatal(err) 633 } else { 634 rsp := result.Data.(*model.AccessResponse) 635 if len(rsp.AccessToken) == 0 { 636 t.Fatal("access token not returned") 637 } else if len(rsp.RefreshToken) == 0 { 638 t.Fatal("refresh token not returned") 639 } else if rsp.RefreshToken == refreshToken { 640 t.Fatal("refresh token did not update") 641 } 642 643 if rsp.TokenType != model.ACCESS_TOKEN_TYPE { 644 t.Fatal("access token type incorrect") 645 } 646 Client.SetOAuthToken(rsp.AccessToken) 647 _, err = Client.GetMe("") 648 if err != nil { 649 t.Fatal(err) 650 } 651 652 data.Set("refresh_token", rsp.RefreshToken) 653 } 654 655 if result, err := Client.GetAccessToken(data); err != nil { 656 t.Fatal(err) 657 } else { 658 rsp := result.Data.(*model.AccessResponse) 659 if len(rsp.AccessToken) == 0 { 660 t.Fatal("access token not returned") 661 } else if len(rsp.RefreshToken) == 0 { 662 t.Fatal("refresh token not returned") 663 } else if rsp.RefreshToken == refreshToken { 664 t.Fatal("refresh token did not update") 665 } 666 667 if rsp.TokenType != model.ACCESS_TOKEN_TYPE { 668 t.Fatal("access token type incorrect") 669 } 670 Client.SetOAuthToken(rsp.AccessToken) 671 _, err = Client.GetMe("") 672 if err != nil { 673 t.Fatal(err) 674 } 675 } 676 677 authData := &model.AuthData{ClientId: oauthApp.Id, RedirectUri: oauthApp.CallbackUrls[0], UserId: th.BasicUser.Id, Code: model.NewId(), ExpiresIn: -1} 678 <-th.App.Srv.Store.OAuth().SaveAuthData(authData) 679 680 data.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE) 681 data.Set("client_id", oauthApp.Id) 682 data.Set("client_secret", oauthApp.ClientSecret) 683 data.Set("redirect_uri", oauthApp.CallbackUrls[0]) 684 data.Set("code", authData.Code) 685 data.Del("refresh_token") 686 if _, err := Client.GetAccessToken(data); err == nil { 687 t.Fatal("Should have failed - code is expired") 688 } 689 690 Client.ClearOAuthToken() 691 } 692 693 func TestOAuthComplete(t *testing.T) { 694 if testing.Short() { 695 t.SkipNow() 696 } 697 698 th := Setup().InitBasic() 699 defer th.TearDown() 700 701 Client := th.BasicClient 702 703 if r, err := HttpGet(Client.Url+"/login/gitlab/complete", Client.HttpClient, "", true); err == nil { 704 t.Fatal("should have failed - no code provided") 705 closeBody(r) 706 } 707 708 if r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123", Client.HttpClient, "", true); err == nil { 709 t.Fatal("should have failed - gitlab disabled") 710 closeBody(r) 711 } 712 713 th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Enable = true }) 714 if r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123&state=!#$#F@#Yˆ&~ñ", Client.HttpClient, "", true); err == nil { 715 t.Fatal("should have failed - gitlab disabled") 716 closeBody(r) 717 } 718 719 th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.AuthEndpoint = Client.Url + "/oauth/authorize" }) 720 th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Id = model.NewId() }) 721 722 stateProps := map[string]string{} 723 stateProps["action"] = model.OAUTH_ACTION_LOGIN 724 stateProps["team_id"] = th.BasicTeam.Id 725 stateProps["redirect_to"] = th.App.Config().GitLabSettings.AuthEndpoint 726 727 state := base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps))) 728 if r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123&state="+url.QueryEscape(state), Client.HttpClient, "", true); err == nil { 729 t.Fatal("should have failed - bad state") 730 closeBody(r) 731 } 732 733 stateProps["hash"] = utils.HashSha256(th.App.Config().GitLabSettings.Id) 734 state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps))) 735 if r, err := HttpGet(Client.Url+"/login/gitlab/complete?code=123&state="+url.QueryEscape(state), Client.HttpClient, "", true); err == nil { 736 t.Fatal("should have failed - no connection") 737 closeBody(r) 738 } 739 740 // We are going to use mattermost as the provider emulating gitlab 741 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOAuthServiceProvider = true }) 742 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableOnlyAdminIntegrations = false }) 743 744 oauthApp := &model.OAuthApp{ 745 Name: "TestApp5" + model.NewId(), 746 Homepage: "https://nowhere.com", 747 Description: "test", 748 CallbackUrls: []string{ 749 Client.Url + "/signup/" + model.SERVICE_GITLAB + "/complete", 750 Client.Url + "/login/" + model.SERVICE_GITLAB + "/complete", 751 }, 752 IsTrusted: true, 753 } 754 oauthApp = Client.Must(Client.RegisterApp(oauthApp)).Data.(*model.OAuthApp) 755 756 th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Id = oauthApp.Id }) 757 th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.Secret = oauthApp.ClientSecret }) 758 th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.AuthEndpoint = Client.Url + "/oauth/authorize" }) 759 th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.TokenEndpoint = Client.Url + "/oauth/access_token" }) 760 th.App.UpdateConfig(func(cfg *model.Config) { cfg.GitLabSettings.UserApiEndpoint = Client.ApiUrl + "/users/me" }) 761 762 provider := &MattermostTestProvider{} 763 764 redirect := Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"] 765 rurl, _ := url.Parse(redirect) 766 code := rurl.Query().Get("code") 767 stateProps["action"] = model.OAUTH_ACTION_EMAIL_TO_SSO 768 delete(stateProps, "team_id") 769 stateProps["redirect_to"] = th.App.Config().GitLabSettings.AuthEndpoint 770 stateProps["hash"] = utils.HashSha256(th.App.Config().GitLabSettings.Id) 771 stateProps["redirect_to"] = "/oauth/authorize" 772 state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps))) 773 if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil { 774 closeBody(r) 775 } 776 777 einterfaces.RegisterOauthProvider(model.SERVICE_GITLAB, provider) 778 redirect = Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"] 779 rurl, _ = url.Parse(redirect) 780 code = rurl.Query().Get("code") 781 if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil { 782 closeBody(r) 783 } 784 785 if result := <-th.App.Srv.Store.User().UpdateAuthData( 786 th.BasicUser.Id, model.SERVICE_GITLAB, &th.BasicUser.Email, th.BasicUser.Email, true); result.Err != nil { 787 t.Fatal(result.Err) 788 } 789 790 redirect = Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"] 791 rurl, _ = url.Parse(redirect) 792 code = rurl.Query().Get("code") 793 stateProps["action"] = model.OAUTH_ACTION_LOGIN 794 state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps))) 795 if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil { 796 closeBody(r) 797 } 798 799 redirect = Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"] 800 rurl, _ = url.Parse(redirect) 801 code = rurl.Query().Get("code") 802 delete(stateProps, "action") 803 state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps))) 804 if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil { 805 closeBody(r) 806 } 807 808 redirect = Client.Must(Client.AllowOAuth(model.AUTHCODE_RESPONSE_TYPE, oauthApp.Id, oauthApp.CallbackUrls[0], "all", "123")).Data.(map[string]string)["redirect"] 809 rurl, _ = url.Parse(redirect) 810 code = rurl.Query().Get("code") 811 stateProps["action"] = model.OAUTH_ACTION_SIGNUP 812 state = base64.StdEncoding.EncodeToString([]byte(model.MapToJson(stateProps))) 813 if r, err := HttpGet(Client.Url+"/login/"+model.SERVICE_GITLAB+"/complete?code="+url.QueryEscape(code)+"&state="+url.QueryEscape(state), Client.HttpClient, "", false); err == nil { 814 closeBody(r) 815 } 816 } 817 818 func HttpGet(url string, httpClient *http.Client, authToken string, followRedirect bool) (*http.Response, *model.AppError) { 819 rq, _ := http.NewRequest("GET", url, nil) 820 rq.Close = true 821 822 if len(authToken) > 0 { 823 rq.Header.Set(model.HEADER_AUTH, authToken) 824 } 825 826 if !followRedirect { 827 httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { 828 return http.ErrUseLastResponse 829 } 830 } 831 832 if rp, err := httpClient.Do(rq); err != nil { 833 return nil, model.NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0) 834 } else if rp.StatusCode == 304 { 835 return rp, nil 836 } else if rp.StatusCode == 307 { 837 return rp, nil 838 } else if rp.StatusCode >= 300 { 839 defer closeBody(rp) 840 return rp, model.AppErrorFromJson(rp.Body) 841 } else { 842 return rp, nil 843 } 844 } 845 846 func closeBody(r *http.Response) { 847 if r.Body != nil { 848 ioutil.ReadAll(r.Body) 849 r.Body.Close() 850 } 851 } 852 853 type MattermostTestProvider struct { 854 } 855 856 func (m *MattermostTestProvider) GetIdentifier() string { 857 return model.SERVICE_GITLAB 858 } 859 860 func (m *MattermostTestProvider) GetUserFromJson(data io.Reader) *model.User { 861 return model.UserFromJson(data) 862 } 863 864 func (m *MattermostTestProvider) GetAuthDataFromJson(data io.Reader) string { 865 authData := model.UserFromJson(data) 866 return authData.Email 867 }