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  }