[MM-37984] Allow Desktop App to authenticate via external providers outside of the app on supported servers (#24140)
* [MM-37984] Allow Desktop App to authenticate via external providers outside of the app on supported servers * PR feedback * Add support for mattermost-dev protocol for development use * Update server/channels/db/migrations/postgres/000110_create_desktop_tokens.up.sql * Fix silly typo * Update server/channels/db/migrations/postgres/000110_create_desktop_tokens.up.sql * Remove storage of client token, only validate it on the client * Update migrations * Add concurrently create index * Remove CONCURRENTLY for now * Fix issue with changing history * Remove old migration * Use idempotent statement to drop old index * Remove reference to old table
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
105fa4a195
Коммит
a3b194581f
110
server/channels/store/storetest/desktop_tokens_store.go
Обычный файл
110
server/channels/store/storetest/desktop_tokens_store.go
Обычный файл
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package storetest
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost/server/v8/channels/store"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDesktopTokensStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("GetUserId", func(t *testing.T) { testGetUserId(t, ss) })
|
||||
t.Run("Insert", func(t *testing.T) { testInsert(t, ss) })
|
||||
t.Run("Delete", func(t *testing.T) { testDeleteToken(t, ss) })
|
||||
t.Run("DeleteByUserId", func(t *testing.T) { testDeleteByUserId(t, ss) })
|
||||
t.Run("DeleteOlderThan", func(t *testing.T) { testDeleteOlderThan(t, ss) })
|
||||
}
|
||||
|
||||
func testGetUserId(t *testing.T, ss store.Store) {
|
||||
err := ss.DesktopTokens().Insert("token_with_id", 1000, "user_id")
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("get user id", func(t *testing.T) {
|
||||
userId, err := ss.DesktopTokens().GetUserId("token_with_id", 1000)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "user_id", *userId)
|
||||
})
|
||||
|
||||
t.Run("get user id - expired", func(t *testing.T) {
|
||||
userId, err := ss.DesktopTokens().GetUserId("token_with_id", 10000)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, &store.ErrNotFound{}, err)
|
||||
assert.Nil(t, userId)
|
||||
})
|
||||
}
|
||||
|
||||
func testInsert(t *testing.T, ss store.Store) {
|
||||
t.Run("insert", func(t *testing.T) {
|
||||
err := ss.DesktopTokens().Insert("token", 1000, "user_id")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("insert - token too long", func(t *testing.T) {
|
||||
err := ss.DesktopTokens().Insert(
|
||||
"this token is way way way WAAAAAAAAAAAAAY WAAAAAAAAAAAAAY WAAAAAAAAAAAAAY TOO LONG",
|
||||
1000,
|
||||
"user_id",
|
||||
)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func testDeleteToken(t *testing.T, ss store.Store) {
|
||||
err := ss.DesktopTokens().Insert("deleteable_token", 3000, "user_id")
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("delete", func(t *testing.T) {
|
||||
userId, err := ss.DesktopTokens().GetUserId("deleteable_token", 3000)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "user_id", *userId)
|
||||
|
||||
err = ss.DesktopTokens().Delete("deleteable_token")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = ss.DesktopTokens().GetUserId("deleteable_token", 3000)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func testDeleteByUserId(t *testing.T, ss store.Store) {
|
||||
err := ss.DesktopTokens().Insert("deleteable_token_2", 4000, "deleteable_user_id")
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("delete by user id", func(t *testing.T) {
|
||||
userId, err := ss.DesktopTokens().GetUserId("deleteable_token_2", 3000)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "deleteable_user_id", *userId)
|
||||
|
||||
err = ss.DesktopTokens().DeleteByUserId("deleteable_user_id")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = ss.DesktopTokens().GetUserId("deleteable_token_2", 3000)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func testDeleteOlderThan(t *testing.T, ss store.Store) {
|
||||
err := ss.DesktopTokens().Insert("deleteable_token_old", 1000, "deleteable_user_id")
|
||||
require.NoError(t, err)
|
||||
err = ss.DesktopTokens().Insert("deleteable_token_new", 5000, "deleteable_user_id")
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("delete older than", func(t *testing.T) {
|
||||
_, err := ss.DesktopTokens().GetUserId("deleteable_token_old", 1000)
|
||||
assert.NoError(t, err)
|
||||
_, err = ss.DesktopTokens().GetUserId("deleteable_token_new", 5000)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = ss.DesktopTokens().DeleteOlderThan(2000)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = ss.DesktopTokens().GetUserId("deleteable_token_old", 1000)
|
||||
assert.Error(t, err)
|
||||
_, err = ss.DesktopTokens().GetUserId("deleteable_token_new", 5000)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
109
server/channels/store/storetest/mocks/DesktopTokensStore.go
Обычный файл
109
server/channels/store/storetest/mocks/DesktopTokensStore.go
Обычный файл
@@ -0,0 +1,109 @@
|
||||
// Code generated by mockery v2.23.2. DO NOT EDIT.
|
||||
|
||||
// Regenerate this file using `make store-mocks`.
|
||||
|
||||
package mocks
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
|
||||
// DesktopTokensStore is an autogenerated mock type for the DesktopTokensStore type
|
||||
type DesktopTokensStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: token
|
||||
func (_m *DesktopTokensStore) Delete(token string) error {
|
||||
ret := _m.Called(token)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string) error); ok {
|
||||
r0 = rf(token)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteByUserId provides a mock function with given fields: userId
|
||||
func (_m *DesktopTokensStore) DeleteByUserId(userId string) error {
|
||||
ret := _m.Called(userId)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string) error); ok {
|
||||
r0 = rf(userId)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteOlderThan provides a mock function with given fields: minCreatedAt
|
||||
func (_m *DesktopTokensStore) DeleteOlderThan(minCreatedAt int64) error {
|
||||
ret := _m.Called(minCreatedAt)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(int64) error); ok {
|
||||
r0 = rf(minCreatedAt)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetUserId provides a mock function with given fields: token, minCreatedAt
|
||||
func (_m *DesktopTokensStore) GetUserId(token string, minCreatedAt int64) (*string, error) {
|
||||
ret := _m.Called(token, minCreatedAt)
|
||||
|
||||
var r0 *string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64) (*string, error)); ok {
|
||||
return rf(token, minCreatedAt)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string, int64) *string); ok {
|
||||
r0 = rf(token, minCreatedAt)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string, int64) error); ok {
|
||||
r1 = rf(token, minCreatedAt)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Insert provides a mock function with given fields: token, createdAt, userId
|
||||
func (_m *DesktopTokensStore) Insert(token string, createdAt int64, userId string) error {
|
||||
ret := _m.Called(token, createdAt, userId)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64, string) error); ok {
|
||||
r0 = rf(token, createdAt, userId)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewDesktopTokensStore interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewDesktopTokensStore creates a new instance of DesktopTokensStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewDesktopTokensStore(t mockConstructorTestingTNewDesktopTokensStore) *DesktopTokensStore {
|
||||
mock := &DesktopTokensStore{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -187,6 +187,22 @@ func (_m *Store) Context() context.Context {
|
||||
return r0
|
||||
}
|
||||
|
||||
// DesktopTokens provides a mock function with given fields:
|
||||
func (_m *Store) DesktopTokens() store.DesktopTokensStore {
|
||||
ret := _m.Called()
|
||||
|
||||
var r0 store.DesktopTokensStore
|
||||
if rf, ok := ret.Get(0).(func() store.DesktopTokensStore); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(store.DesktopTokensStore)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Draft provides a mock function with given fields:
|
||||
func (_m *Store) Draft() store.DraftStore {
|
||||
ret := _m.Called()
|
||||
|
||||
@@ -61,6 +61,7 @@ type Store struct {
|
||||
PostAcknowledgementStore mocks.PostAcknowledgementStore
|
||||
PostPersistentNotificationStore mocks.PostPersistentNotificationStore
|
||||
TrueUpReviewStore mocks.TrueUpReviewStore
|
||||
DesktopTokensStore mocks.DesktopTokensStore
|
||||
}
|
||||
|
||||
func (s *Store) SetContext(context context.Context) { s.context = context }
|
||||
@@ -103,6 +104,7 @@ func (s *Store) ChannelMemberHistory() store.ChannelMemberHistoryStore {
|
||||
return &s.ChannelMemberHistoryStore
|
||||
}
|
||||
func (s *Store) TrueUpReview() store.TrueUpReviewStore { return &s.TrueUpReviewStore }
|
||||
func (s *Store) DesktopTokens() store.DesktopTokensStore { return &s.DesktopTokensStore }
|
||||
func (s *Store) NotifyAdmin() store.NotifyAdminStore { return &s.NotifyAdminStore }
|
||||
func (s *Store) Group() store.GroupStore { return &s.GroupStore }
|
||||
func (s *Store) LinkMetadata() store.LinkMetadataStore { return &s.LinkMetadataStore }
|
||||
@@ -177,5 +179,6 @@ func (s *Store) AssertExpectations(t mock.TestingT) bool {
|
||||
&s.PostPriorityStore,
|
||||
&s.PostAcknowledgementStore,
|
||||
&s.PostPersistentNotificationStore,
|
||||
&s.DesktopTokensStore,
|
||||
)
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user