github.com/mattermost/mattermost-server/v5@v5.39.3/store/storetest/oauth_store.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package storetest
     5  
     6  import (
     7  	"context"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/mattermost/mattermost-server/v5/model"
    14  	"github.com/mattermost/mattermost-server/v5/store"
    15  )
    16  
    17  func TestOAuthStore(t *testing.T, ss store.Store) {
    18  	t.Run("SaveApp", func(t *testing.T) { testOAuthStoreSaveApp(t, ss) })
    19  	t.Run("GetApp", func(t *testing.T) { testOAuthStoreGetApp(t, ss) })
    20  	t.Run("UpdateApp", func(t *testing.T) { testOAuthStoreUpdateApp(t, ss) })
    21  	t.Run("SaveAccessData", func(t *testing.T) { testOAuthStoreSaveAccessData(t, ss) })
    22  	t.Run("OAuthUpdateAccessData", func(t *testing.T) { testOAuthUpdateAccessData(t, ss) })
    23  	t.Run("GetAccessData", func(t *testing.T) { testOAuthStoreGetAccessData(t, ss) })
    24  	t.Run("RemoveAccessData", func(t *testing.T) { testOAuthStoreRemoveAccessData(t, ss) })
    25  	t.Run("RemoveAllAccessData", func(t *testing.T) { testOAuthStoreRemoveAllAccessData(t, ss) })
    26  	t.Run("SaveAuthData", func(t *testing.T) { testOAuthStoreSaveAuthData(t, ss) })
    27  	t.Run("GetAuthData", func(t *testing.T) { testOAuthStoreGetAuthData(t, ss) })
    28  	t.Run("RemoveAuthData", func(t *testing.T) { testOAuthStoreRemoveAuthData(t, ss) })
    29  	t.Run("RemoveAuthDataByUser", func(t *testing.T) { testOAuthStoreRemoveAuthDataByUser(t, ss) })
    30  	t.Run("OAuthGetAuthorizedApps", func(t *testing.T) { testOAuthGetAuthorizedApps(t, ss) })
    31  	t.Run("OAuthGetAccessDataByUserForApp", func(t *testing.T) { testOAuthGetAccessDataByUserForApp(t, ss) })
    32  	t.Run("DeleteApp", func(t *testing.T) { testOAuthStoreDeleteApp(t, ss) })
    33  }
    34  
    35  func testOAuthStoreSaveApp(t *testing.T, ss store.Store) {
    36  	a1 := model.OAuthApp{}
    37  	a1.CreatorId = model.NewId()
    38  	a1.CallbackUrls = []string{"https://nowhere.com"}
    39  	a1.Homepage = "https://nowhere.com"
    40  
    41  	// Try to save an app that already has an Id
    42  	a1.Id = model.NewId()
    43  	_, err := ss.OAuth().SaveApp(&a1)
    44  	require.Error(t, err, "Should have failed, cannot add an OAuth app cannot be save with an Id, it has to be updated")
    45  
    46  	// Try to save an Invalid App
    47  	a1.Id = ""
    48  	_, err = ss.OAuth().SaveApp(&a1)
    49  	require.Error(t, err, "Should have failed, app should be invalid cause it doesn' have a name set")
    50  
    51  	// Save the app
    52  	a1.Id = ""
    53  	a1.Name = "TestApp" + model.NewId()
    54  	_, err = ss.OAuth().SaveApp(&a1)
    55  	require.NoError(t, err)
    56  }
    57  
    58  func testOAuthStoreGetApp(t *testing.T, ss store.Store) {
    59  	a1 := model.OAuthApp{}
    60  	a1.CreatorId = model.NewId()
    61  	a1.Name = "TestApp" + model.NewId()
    62  	a1.CallbackUrls = []string{"https://nowhere.com"}
    63  	a1.Homepage = "https://nowhere.com"
    64  	_, err := ss.OAuth().SaveApp(&a1)
    65  	require.NoError(t, err)
    66  
    67  	// Lets try to get and app that does not exists
    68  	_, err = ss.OAuth().GetApp("fake0123456789abcderfgret1")
    69  	require.Error(t, err, "Should have failed. App does not exists")
    70  
    71  	_, err = ss.OAuth().GetApp(a1.Id)
    72  	require.NoError(t, err)
    73  
    74  	// Lets try and get the app from a user that hasn't created any apps
    75  	apps, err := ss.OAuth().GetAppByUser("fake0123456789abcderfgret1", 0, 1000)
    76  	require.NoError(t, err)
    77  	assert.Empty(t, apps, "Should have failed. Fake user hasn't created any apps")
    78  
    79  	_, err = ss.OAuth().GetAppByUser(a1.CreatorId, 0, 1000)
    80  	require.NoError(t, err)
    81  
    82  	_, err = ss.OAuth().GetApps(0, 1000)
    83  	require.NoError(t, err)
    84  }
    85  
    86  func testOAuthStoreUpdateApp(t *testing.T, ss store.Store) {
    87  	a1 := model.OAuthApp{}
    88  	a1.CreatorId = model.NewId()
    89  	a1.Name = "TestApp" + model.NewId()
    90  	a1.CallbackUrls = []string{"https://nowhere.com"}
    91  	a1.Homepage = "https://nowhere.com"
    92  	_, err := ss.OAuth().SaveApp(&a1)
    93  	require.NoError(t, err)
    94  
    95  	// temporarily save the created app id
    96  	id := a1.Id
    97  
    98  	a1.CreateAt = 1
    99  	a1.ClientSecret = "pwd"
   100  	a1.CreatorId = "12345678901234567890123456"
   101  
   102  	// Lets update the app by removing the name
   103  	a1.Name = ""
   104  	_, err = ss.OAuth().UpdateApp(&a1)
   105  	require.Error(t, err, "Should have failed. App name is not set")
   106  
   107  	// Lets not find the app that we are trying to update
   108  	a1.Id = "fake0123456789abcderfgret1"
   109  	a1.Name = "NewName"
   110  	_, err = ss.OAuth().UpdateApp(&a1)
   111  	require.Error(t, err, "Should have failed. Not able to find the app")
   112  
   113  	a1.Id = id
   114  	ua, err := ss.OAuth().UpdateApp(&a1)
   115  	require.NoError(t, err)
   116  	require.Equal(t, ua.Name, "NewName", "name did not update")
   117  	require.NotEqual(t, ua.CreateAt, 1, "create at should not have updated")
   118  	require.NotEqual(t, ua.CreatorId, "12345678901234567890123456", "creator id should not have updated")
   119  }
   120  
   121  func testOAuthStoreSaveAccessData(t *testing.T, ss store.Store) {
   122  	a1 := model.AccessData{}
   123  	a1.ClientId = model.NewId()
   124  	a1.UserId = model.NewId()
   125  
   126  	// Lets try and save an incomplete access data
   127  	_, err := ss.OAuth().SaveAccessData(&a1)
   128  	require.Error(t, err, "Should have failed. Access data needs the token")
   129  
   130  	a1.Token = model.NewId()
   131  	a1.RefreshToken = model.NewId()
   132  	a1.RedirectUri = "http://example.com"
   133  
   134  	_, err = ss.OAuth().SaveAccessData(&a1)
   135  	require.NoError(t, err)
   136  }
   137  
   138  func testOAuthUpdateAccessData(t *testing.T, ss store.Store) {
   139  	a1 := model.AccessData{}
   140  	a1.ClientId = model.NewId()
   141  	a1.UserId = model.NewId()
   142  	a1.Token = model.NewId()
   143  	a1.RefreshToken = model.NewId()
   144  	a1.ExpiresAt = model.GetMillis()
   145  	a1.RedirectUri = "http://example.com"
   146  	_, err := ss.OAuth().SaveAccessData(&a1)
   147  	require.NoError(t, err)
   148  
   149  	//Try to update to invalid Refresh Token
   150  	refreshToken := a1.RefreshToken
   151  	a1.RefreshToken = model.NewId() + "123"
   152  	_, err = ss.OAuth().UpdateAccessData(&a1)
   153  	require.Error(t, err, "Should have failed with invalid token")
   154  
   155  	//Try to update to invalid RedirectUri
   156  	a1.RefreshToken = model.NewId()
   157  	a1.RedirectUri = ""
   158  	_, err = ss.OAuth().UpdateAccessData(&a1)
   159  	require.Error(t, err, "Should have failed with invalid Redirect URI")
   160  
   161  	// Should update fine
   162  	a1.RedirectUri = "http://example.com"
   163  	ra1, err := ss.OAuth().UpdateAccessData(&a1)
   164  	require.NoError(t, err)
   165  	require.NotEqual(t, ra1.RefreshToken, refreshToken, "refresh tokens didn't match")
   166  }
   167  
   168  func testOAuthStoreGetAccessData(t *testing.T, ss store.Store) {
   169  	a1 := model.AccessData{}
   170  	a1.ClientId = model.NewId()
   171  	a1.UserId = model.NewId()
   172  	a1.Token = model.NewId()
   173  	a1.RefreshToken = model.NewId()
   174  	a1.ExpiresAt = model.GetMillis()
   175  	a1.RedirectUri = "http://example.com"
   176  	_, err := ss.OAuth().SaveAccessData(&a1)
   177  	require.NoError(t, err)
   178  
   179  	_, err = ss.OAuth().GetAccessData("invalidToken")
   180  	require.Error(t, err, "Should have failed. There is no data with an invalid token")
   181  
   182  	ra1, err := ss.OAuth().GetAccessData(a1.Token)
   183  	require.NoError(t, err)
   184  	assert.Equal(t, a1.Token, ra1.Token, "tokens didn't match")
   185  
   186  	_, err = ss.OAuth().GetPreviousAccessData(a1.UserId, a1.ClientId)
   187  	require.NoError(t, err)
   188  
   189  	_, err = ss.OAuth().GetPreviousAccessData("user", "junk")
   190  	require.NoError(t, err)
   191  
   192  	// Try to get the Access data using an invalid refresh token
   193  	_, err = ss.OAuth().GetAccessDataByRefreshToken(a1.Token)
   194  	require.Error(t, err, "Should have failed. There is no data with an invalid token")
   195  
   196  	// Get the Access Data using the refresh token
   197  	ra1, err = ss.OAuth().GetAccessDataByRefreshToken(a1.RefreshToken)
   198  	require.NoError(t, err)
   199  	assert.Equal(t, a1.RefreshToken, ra1.RefreshToken, "tokens didn't match")
   200  }
   201  
   202  func testOAuthStoreRemoveAccessData(t *testing.T, ss store.Store) {
   203  	a1 := model.AccessData{}
   204  	a1.ClientId = model.NewId()
   205  	a1.UserId = model.NewId()
   206  	a1.Token = model.NewId()
   207  	a1.RefreshToken = model.NewId()
   208  	a1.RedirectUri = "http://example.com"
   209  	_, err := ss.OAuth().SaveAccessData(&a1)
   210  	require.NoError(t, err)
   211  
   212  	err = ss.OAuth().RemoveAccessData(a1.Token)
   213  	require.NoError(t, err)
   214  
   215  	result, _ := ss.OAuth().GetPreviousAccessData(a1.UserId, a1.ClientId)
   216  	require.Nil(t, result, "did not delete access token")
   217  }
   218  
   219  func testOAuthStoreRemoveAllAccessData(t *testing.T, ss store.Store) {
   220  	a1 := model.AccessData{}
   221  	a1.ClientId = model.NewId()
   222  	a1.UserId = model.NewId()
   223  	a1.Token = model.NewId()
   224  	a1.RefreshToken = model.NewId()
   225  	a1.RedirectUri = "http://example.com"
   226  	_, err := ss.OAuth().SaveAccessData(&a1)
   227  	require.NoError(t, err)
   228  
   229  	err = ss.OAuth().RemoveAllAccessData()
   230  	require.NoError(t, err)
   231  
   232  	result, _ := ss.OAuth().GetPreviousAccessData(a1.UserId, a1.ClientId)
   233  	require.Nil(t, result, "did not delete access token")
   234  }
   235  
   236  func testOAuthStoreSaveAuthData(t *testing.T, ss store.Store) {
   237  	a1 := model.AuthData{}
   238  	a1.ClientId = model.NewId()
   239  	a1.UserId = model.NewId()
   240  	a1.Code = model.NewId()
   241  	a1.RedirectUri = "http://example.com"
   242  	_, err := ss.OAuth().SaveAuthData(&a1)
   243  	require.NoError(t, err)
   244  }
   245  
   246  func testOAuthStoreGetAuthData(t *testing.T, ss store.Store) {
   247  	a1 := model.AuthData{}
   248  	a1.ClientId = model.NewId()
   249  	a1.UserId = model.NewId()
   250  	a1.Code = model.NewId()
   251  	a1.RedirectUri = "http://example.com"
   252  	_, err := ss.OAuth().SaveAuthData(&a1)
   253  	require.NoError(t, err)
   254  
   255  	_, err = ss.OAuth().GetAuthData(a1.Code)
   256  	require.NoError(t, err)
   257  }
   258  
   259  func testOAuthStoreRemoveAuthData(t *testing.T, ss store.Store) {
   260  	a1 := model.AuthData{}
   261  	a1.ClientId = model.NewId()
   262  	a1.UserId = model.NewId()
   263  	a1.Code = model.NewId()
   264  	a1.RedirectUri = "http://example.com"
   265  	_, err := ss.OAuth().SaveAuthData(&a1)
   266  	require.NoError(t, err)
   267  
   268  	err = ss.OAuth().RemoveAuthData(a1.Code)
   269  	require.NoError(t, err)
   270  
   271  	_, err = ss.OAuth().GetAuthData(a1.Code)
   272  	require.Error(t, err, "should have errored - auth code removed")
   273  }
   274  
   275  func testOAuthStoreRemoveAuthDataByUser(t *testing.T, ss store.Store) {
   276  	a1 := model.AuthData{}
   277  	a1.ClientId = model.NewId()
   278  	a1.UserId = model.NewId()
   279  	a1.Code = model.NewId()
   280  	a1.RedirectUri = "http://example.com"
   281  	_, err := ss.OAuth().SaveAuthData(&a1)
   282  	require.NoError(t, err)
   283  
   284  	err = ss.OAuth().PermanentDeleteAuthDataByUser(a1.UserId)
   285  	require.NoError(t, err)
   286  }
   287  
   288  func testOAuthGetAuthorizedApps(t *testing.T, ss store.Store) {
   289  	a1 := model.OAuthApp{}
   290  	a1.CreatorId = model.NewId()
   291  	a1.Name = "TestApp" + model.NewId()
   292  	a1.CallbackUrls = []string{"https://nowhere.com"}
   293  	a1.Homepage = "https://nowhere.com"
   294  	_, err := ss.OAuth().SaveApp(&a1)
   295  	require.NoError(t, err)
   296  
   297  	// Lets try and get an Authorized app for a user who hasn't authorized it
   298  	apps, err := ss.OAuth().GetAuthorizedApps("fake0123456789abcderfgret1", 0, 1000)
   299  	require.NoError(t, err)
   300  	assert.Empty(t, apps, "Should have failed. Fake user hasn't authorized the app")
   301  
   302  	// allow the app
   303  	p := model.Preference{}
   304  	p.UserId = a1.CreatorId
   305  	p.Category = model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP
   306  	p.Name = a1.Id
   307  	p.Value = "true"
   308  	nErr := ss.Preference().Save(&model.Preferences{p})
   309  	require.NoError(t, nErr)
   310  
   311  	apps, err = ss.OAuth().GetAuthorizedApps(a1.CreatorId, 0, 1000)
   312  	require.NoError(t, err)
   313  	assert.NotEqual(t, len(apps), 0, "It should have return apps")
   314  }
   315  
   316  func testOAuthGetAccessDataByUserForApp(t *testing.T, ss store.Store) {
   317  	a1 := model.OAuthApp{}
   318  	a1.CreatorId = model.NewId()
   319  	a1.Name = "TestApp" + model.NewId()
   320  	a1.CallbackUrls = []string{"https://nowhere.com"}
   321  	a1.Homepage = "https://nowhere.com"
   322  	_, err := ss.OAuth().SaveApp(&a1)
   323  	require.NoError(t, err)
   324  
   325  	// allow the app
   326  	p := model.Preference{}
   327  	p.UserId = a1.CreatorId
   328  	p.Category = model.PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP
   329  	p.Name = a1.Id
   330  	p.Value = "true"
   331  	nErr := ss.Preference().Save(&model.Preferences{p})
   332  	require.NoError(t, nErr)
   333  
   334  	apps, err := ss.OAuth().GetAuthorizedApps(a1.CreatorId, 0, 1000)
   335  	require.NoError(t, err)
   336  	assert.NotEqual(t, len(apps), 0, "It should have return apps")
   337  
   338  	// save the token
   339  	ad1 := model.AccessData{}
   340  	ad1.ClientId = a1.Id
   341  	ad1.UserId = a1.CreatorId
   342  	ad1.Token = model.NewId()
   343  	ad1.RefreshToken = model.NewId()
   344  	ad1.RedirectUri = "http://example.com"
   345  
   346  	_, err = ss.OAuth().SaveAccessData(&ad1)
   347  	require.NoError(t, err)
   348  
   349  	accessData, err := ss.OAuth().GetAccessDataByUserForApp(a1.CreatorId, a1.Id)
   350  	require.NoError(t, err)
   351  	assert.NotEqual(t, len(accessData), 0, "It should have return access data")
   352  }
   353  
   354  func testOAuthStoreDeleteApp(t *testing.T, ss store.Store) {
   355  	a1 := model.OAuthApp{}
   356  	a1.CreatorId = model.NewId()
   357  	a1.Name = "TestApp" + model.NewId()
   358  	a1.CallbackUrls = []string{"https://nowhere.com"}
   359  	a1.Homepage = "https://nowhere.com"
   360  	_, err := ss.OAuth().SaveApp(&a1)
   361  	require.NoError(t, err)
   362  
   363  	// delete a non-existent app
   364  	err = ss.OAuth().DeleteApp("fakeclientId")
   365  	require.NoError(t, err)
   366  
   367  	s1 := &model.Session{}
   368  	s1.UserId = model.NewId()
   369  	s1.Token = model.NewId()
   370  	s1.IsOAuth = true
   371  
   372  	s1, nErr := ss.Session().Save(s1)
   373  	require.NoError(t, nErr)
   374  
   375  	ad1 := model.AccessData{}
   376  	ad1.ClientId = a1.Id
   377  	ad1.UserId = a1.CreatorId
   378  	ad1.Token = s1.Token
   379  	ad1.RefreshToken = model.NewId()
   380  	ad1.RedirectUri = "http://example.com"
   381  
   382  	_, err = ss.OAuth().SaveAccessData(&ad1)
   383  	require.NoError(t, err)
   384  
   385  	err = ss.OAuth().DeleteApp(a1.Id)
   386  	require.NoError(t, err)
   387  
   388  	_, nErr = ss.Session().Get(context.Background(), s1.Token)
   389  	require.Error(t, nErr, "should error - session should be deleted")
   390  
   391  	_, err = ss.OAuth().GetAccessData(s1.Token)
   392  	require.Error(t, err, "should error - access data should be deleted")
   393  }