mattermost/server/channels/api4/outgoing_oauth_connection_test.go
Michael Kochell 4e071e861c
Webapp - Outgoing OAuth Connections (#25507)
* added store

* make generated

* add missing license headers

* fix receiver name

* i18n

* i18n sorting

* update migrations from master

* make migrations-extract

* update retrylayer tests

* replaced sql query with id pagination

* fixed flaky tests

* missing columns

* missing columns on save/update

* typo

* improved tests

* remove enum from mysql colum

* add password credentials to store

* license changes

* OAuthOutgoingConnectionInterface

* Oauth -> OAuth

* make generated

* copied over installed_oauth_apps component and renamed things to installed_outgoing_oauth_connections

* merge migrations

* renamed migrations

* model change suggestions

* refactor test functionsn

* migration typo

* refactor store table names

* updated sanitize test

* cleanup merge

* refactor symbol

* "installed outgoing oauth connections" page works

* move things into a nested folder

* add and edit page stubs work

* list endpoint

* oauthoutgoingconnection -> outgoingoauthconnection

* signature change

* i18n update

* granttype typo

* naming

* api list

* uppercase typo

* i18n

* missing license header

* fixed path in comments

* updated openapi definitions

* changes to support selecting command request url

* sanitize connections

* make generated

* test license and no feature flag

* removed t.fatal

* updated testhelper calls

* yaml schema fixes

* switched interface name

* suggested translation

* missing i18n translation

* management permission

* moved permission initalization to proper place

* endpoints

* put tests

* error check typo

* fixed specific enttity urls

* tests

* read permission check

* updated openapi definitions

* i18n

* GetConnectionByAudience method

* notes

* replaced GetConnectionsByAudience with a filter

* added custom oauth token object

* updated interface and usage

* properly set enterprise interface

* move retrieval logic to impl

* webhook tests

* translations

* i18n: updates

* address comments

* endpoint and tests

* i18n

* api docs

* fixed endpoint path

* sq.like

* use filter object instead of parameters

* set url values if not empty

* typos

* converted some components to function components, and move around files

* correctly check token url

* restore flag to previous value

* added command oauth handler

* update enterprise imports

* migrate last component to function component

* Added enterprise import

* refactor permissions and add necessary webapp code

* Check correct flag in permission tree

* allow partial updates

* sort i18n webapp

* missing test modification

* fixed webapp i18n sorting

* allow validating stored connections

* added missing translation

* fix finished adding connection link and text on result page

* added missing permission to smoke tests

* missing role in smoke test

* updated translations

* updated translations

* support editing client secret on existing connection

* fix some i18n strings

* updated translations

* better error messages

* progress on using react select for command request url while maintaining typed in value

* remove writeheader, test

* HasValidGrantType

* end early to avoid nil pointer errors

* move slash command request url input box into its own component

* wrap components related to oauth connections in config check

* fix tests

* i18n-extract

* change some i18n strings to say "Outgoing OAuth 2.0 Connections"

* remove debug code

* fixed i18n

* updated i18n file

* feature configuration backend

* typo

* add system console setting

* Revert "typo"

This reverts commit 669da23e8e.

* Revert "updated i18n file"

This reverts commit d0882c0dd7.

* Revert "fixed i18n"

This reverts commit 3108866bc1.

* fixed i18n

* updated i18n file

* typo

* updated i18n

* updated i18n

* updated i18n

* updated version to 9.6

* replace feature flag with system console configuration

* i18n

* updated tests

* pr feedback

* fix styling of disabled text box

* fix styling of action links in integration console

* server changes for validation feature

* webapp changes for validation feature

* pencil icon styling

* styling fixes for oauth audience correct configuration message

* fix sanitize test

* remove max lengths from outgoing oauth connection form

* use config var in webapp instead of feature flag

* change asterisks to bullets

* update api docs for validate endpoint

* feedback from ux review

* fix lint, types, tests

* fix stylelint

* implement validation button under the token url input

* support wildcard for matching audience urls

* updates for styling

* update snapshots

* add doc links for the outgoing oauth connections feature

* change doc links to use permalink

* add docs link to system console

* fix: use limitedreader in json decoding

* fix: form error in validation

* management permission can read now

* updated api documentation

* doc typo

* require one permission to read only

* fix api connection list audience filter

* fix audience matching and add loading indicator

* fix team permissions on outgoing oauth connection api calls

* fix api doc and test, for adding team id to query params

* handle read permissions by adding a team in the payload

* missing teamid query parameter in test

* change validate button logic to not require audience urls to be filled out

* fix redux type

---------

Co-authored-by: Felipe Martin <me@fmartingr.com>
2024-02-09 14:49:49 -05:00

1653 lines
58 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package api4
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/plugin/plugintest/mock"
"github.com/mattermost/mattermost/server/v8/channels/web"
"github.com/mattermost/mattermost/server/v8/einterfaces/mocks"
"github.com/stretchr/testify/require"
)
func newOutgoingOAuthConnection() *model.OutgoingOAuthConnection {
return &model.OutgoingOAuthConnection{
Name: "test",
ClientId: "test",
ClientSecret: "test",
OAuthTokenURL: "http://localhost:9999/oauth/token",
GrantType: model.OutgoingOAuthConnectionGrantTypeClientCredentials,
Audiences: []string{"http://example.com"},
}
}
func outgoingOauthConnectionsCleanup(t *testing.T, th *TestHelper) {
t.Helper()
// Remove all connections
conns, errCleanup := th.App.Srv().Store().OutgoingOAuthConnection().GetConnections(th.Context, model.OutgoingOAuthConnectionGetConnectionsFilter{})
require.NoError(t, errCleanup)
for _, c := range conns {
require.NoError(t, th.App.Srv().Store().OutgoingOAuthConnection().DeleteConnection(th.Context, c.Id))
}
}
// Helper tests
func TestCheckOutgoingOAuthConnectionReadPermissions(t *testing.T) {
t.Run("no permissions", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c := &Context{}
c.AppContext = th.Context.WithSession(&session)
c.App = th.App
c.Logger = th.App.Srv().Log()
canRead := checkOutgoingOAuthConnectionReadPermissions(c, th.BasicTeam.Id)
require.False(t, canRead)
})
t.Run("with management permissions", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c := &Context{}
c.AppContext = th.Context.WithSession(&session)
c.App = th.App
c.Logger = th.App.Srv().Log()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
canReadWithTeam := checkOutgoingOAuthConnectionReadPermissions(c, th.BasicTeam.Id)
require.True(t, canReadWithTeam)
canReadWithoutTeam := checkOutgoingOAuthConnectionReadPermissions(c, "")
require.True(t, canReadWithoutTeam)
})
t.Run("with slash command management permissions", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.TeamAdminRoleId,
}
c := &Context{}
c.AppContext = th.Context.WithSession(&session)
c.App = th.App
c.Logger = th.App.Srv().Log()
th.AddPermissionToRole(model.PermissionManageSlashCommands.Id, model.TeamAdminRoleId)
canRead := checkOutgoingOAuthConnectionReadPermissions(c, th.BasicTeam.Id)
require.True(t, canRead)
})
t.Run("with outgoing webhooks management permissions", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.TeamAdminRoleId,
}
c := &Context{}
c.AppContext = th.Context.WithSession(&session)
c.App = th.App
c.Logger = th.App.Srv().Log()
th.AddPermissionToRole(model.PermissionManageOutgoingWebhooks.Id, model.TeamAdminRoleId)
canRead := checkOutgoingOAuthConnectionReadPermissions(c, th.BasicTeam.Id)
require.True(t, canRead)
})
}
func TestCheckOutgoingOAuthConnectionWritePermissions(t *testing.T) {
t.Run("no permissions", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c := &Context{}
c.AppContext = th.Context.WithSession(&session)
c.App = th.App
c.Logger = th.App.Srv().Log()
canWrite := checkOutgoingOAuthConnectionWritePermissions(c)
require.False(t, canWrite)
})
t.Run("with permissions", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c := &Context{}
c.AppContext = th.Context.WithSession(&session)
c.App = th.App
c.Logger = th.App.Srv().Log()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
canWrite := checkOutgoingOAuthConnectionWritePermissions(c)
require.True(t, canWrite)
})
}
// Client tests
func TestClientOutgoingOAuthConnectionGet(t *testing.T) {
t.Run("No license returns 501", func(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTION", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTION")
th := Setup(t).InitBasic()
defer th.TearDown()
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingWebhooks.Id, model.TeamAdminRoleId)
th.AddPermissionToRole(model.PermissionManageSlashCommands.Id, model.TeamAdminRoleId)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
defer func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
}()
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
// th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
th.LoginTeamAdmin()
filters := model.OutgoingOAuthConnectionGetConnectionsFilter{
Limit: 10,
TeamId: th.BasicTeam.Id,
}
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), filters)
require.Error(t, err)
require.Nil(t, connections)
require.Equal(t, 501, response.StatusCode)
})
t.Run("license but no config enabled returns 501", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingWebhooks.Id, model.TeamAdminRoleId)
th.AddPermissionToRole(model.PermissionManageSlashCommands.Id, model.TeamAdminRoleId)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(false)
defer func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
}()
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
th.App.Srv().RemoveLicense()
th.LoginTeamAdmin()
filters := model.OutgoingOAuthConnectionGetConnectionsFilter{
Limit: 10,
TeamId: th.BasicTeam.Id,
}
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), filters)
require.Error(t, err)
require.Nil(t, connections)
require.Equal(t, 501, response.StatusCode)
})
}
func TestClientListOutgoingOAuthConnection(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
t.Run("no permissions", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
filters := model.OutgoingOAuthConnectionGetConnectionsFilter{
Limit: 10,
TeamId: th.BasicTeam.Id,
}
connection, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), filters)
require.Error(t, err)
require.Nil(t, connection)
require.Equal(t, http.StatusForbidden, response.StatusCode)
})
t.Run("manager do not require team id", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", mock.Anything, mock.Anything).Return([]*model.OutgoingOAuthConnection{}, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
filters := model.OutgoingOAuthConnectionGetConnectionsFilter{
Limit: 10,
}
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), filters)
require.NoError(t, err)
require.Equal(t, 200, response.StatusCode)
require.Equal(t, 0, len(connections))
})
t.Run("empty", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingWebhooks.Id, model.SystemUserRoleId)
th.AddPermissionToRole(model.PermissionManageSlashCommands.Id, model.SystemUserRoleId)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", mock.Anything, mock.Anything).Return([]*model.OutgoingOAuthConnection{}, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
filters := model.OutgoingOAuthConnectionGetConnectionsFilter{
Limit: 10,
TeamId: th.BasicTeam.Id,
}
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), filters)
require.NoError(t, err)
require.Equal(t, 200, response.StatusCode)
require.Equal(t, 0, len(connections))
})
t.Run("filter by audience", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingWebhooks.Id, model.SystemUserRoleId)
th.AddPermissionToRole(model.PermissionManageSlashCommands.Id, model.SystemUserRoleId)
conn := newOutgoingOAuthConnection()
conn.Audiences = []string{"http://knowhere.com"}
conn.CreatorId = model.NewId()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnectionForAudience", mock.Anything, "knowhere.com").Return(conn, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
filters := model.OutgoingOAuthConnectionGetConnectionsFilter{
Limit: 1,
Audience: "knowhere.com",
TeamId: th.BasicTeam.Id,
}
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), filters)
require.NoError(t, err)
require.Equal(t, 200, response.StatusCode)
require.Equal(t, 1, len(connections))
require.Equal(t, conn, connections[0])
})
t.Run("return result", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingWebhooks.Id, model.SystemUserRoleId)
th.AddPermissionToRole(model.PermissionManageSlashCommands.Id, model.SystemUserRoleId)
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", mock.Anything, mock.Anything).Return([]*model.OutgoingOAuthConnection{conn}, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
filters := model.OutgoingOAuthConnectionGetConnectionsFilter{
Limit: 10,
TeamId: th.BasicTeam.Id,
}
connections, response, err := th.Client.GetOutgoingOAuthConnections(context.Background(), filters)
require.NoError(t, err)
require.Equal(t, 200, response.StatusCode)
require.Equal(t, 1, len(connections))
require.Equal(t, conn, connections[0])
})
}
func TestClientGetOutgoingOAuthConnection(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
defer th.App.Srv().RemoveLicense()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
t.Run("no permissions", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
connection, response, err := th.Client.GetOutgoingOAuthConnection(context.Background(), "test")
require.Error(t, err)
require.Nil(t, connection)
require.Equal(t, http.StatusForbidden, response.StatusCode)
})
t.Run("return result (management permissions)", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthIface.Mock.On("GetConnection", mock.Anything, mock.Anything).Return(conn, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.LoginSystemAdmin()
connection, response, err := th.Client.GetOutgoingOAuthConnection(context.Background(), conn.Id)
require.NoError(t, err)
require.Equal(t, 200, response.StatusCode)
require.NotNil(t, connection)
require.Equal(t, conn.Id, connection.Id)
require.Equal(t, conn, connection)
})
}
func TestClientCreateOutgoingOAuthConnection(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
defer th.App.Srv().RemoveLicense()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
t.Run("no permissions", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthIface.Mock.On("SaveConnection", mock.Anything, mock.Anything).Return(conn, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.LoginSystemAdmin()
connection, response, err := th.Client.CreateOutgoingOAuthConnection(context.Background(), conn)
require.Error(t, err)
require.Nil(t, connection)
require.Equal(t, http.StatusForbidden, response.StatusCode)
})
t.Run("ok", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthIface.Mock.On("SaveConnection", mock.Anything, mock.Anything).Return(conn, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.LoginSystemAdmin()
connection, response, err := th.Client.CreateOutgoingOAuthConnection(context.Background(), conn)
require.NoError(t, err)
require.NotNil(t, connection)
require.Equal(t, http.StatusCreated, response.StatusCode)
require.Equal(t, conn, connection)
})
}
func TestClientUpdateOutgoingOAuthConnection(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
defer th.App.Srv().RemoveLicense()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
t.Run("no permissions", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.LoginSystemAdmin()
connection, response, err := th.Client.UpdateOutgoingOAuthConnection(context.Background(), conn)
require.Error(t, err)
require.Nil(t, connection)
require.Equal(t, http.StatusForbidden, response.StatusCode)
})
t.Run("ok", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthIface.Mock.On("GetConnection", mock.Anything, conn.Id).Return(conn, nil)
outgoingOauthIface.Mock.On("UpdateConnection", mock.Anything, conn).Return(conn, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.LoginSystemAdmin()
updatedConn := conn
updatedConn.Name = "updated name"
connection, response, err := th.Client.UpdateOutgoingOAuthConnection(context.Background(), conn)
require.NoError(t, err)
require.NotNil(t, connection)
require.Equal(t, http.StatusOK, response.StatusCode)
require.Equal(t, updatedConn, connection)
})
}
func TestClientDeleteOutgoingOAuthConnection(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
defer th.App.Srv().RemoveLicense()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
t.Run("no permissions", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.LoginSystemAdmin()
response, err := th.Client.DeleteOutgoingOAuthConnection(context.Background(), conn.Id)
require.Error(t, err)
require.Equal(t, http.StatusForbidden, response.StatusCode)
})
t.Run("ok", func(t *testing.T) {
defer outgoingOauthConnectionsCleanup(t, th)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn, err := th.App.Srv().Store().OutgoingOAuthConnection().SaveConnection(th.Context, conn)
require.NoError(t, err)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthIface.Mock.On("GetConnection", mock.Anything, conn.Id).Return(conn, nil)
outgoingOauthIface.Mock.On("DeleteConnection", mock.Anything, conn.Id).Return(nil)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
th.LoginSystemAdmin()
response, err := th.Client.DeleteOutgoingOAuthConnection(context.Background(), conn.Id)
require.NoError(t, err)
require.Equal(t, http.StatusOK, response.StatusCode)
})
}
// Handler tests
func TestEnsureOutgoingOAuthConnectionInterface(t *testing.T) {
t.Run("no feature flag, no interface, no license", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
th.App.Srv().OutgoingOAuthConnection = nil
_, valid := ensureOutgoingOAuthConnectionInterface(c, "api")
require.False(t, valid)
})
t.Run("config, no interface, no license", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
th.App.Srv().OutgoingOAuthConnection = nil
_, valid := ensureOutgoingOAuthConnectionInterface(c, "api")
require.False(t, valid)
})
t.Run("feature flag, interface defined, no license", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
_, valid := ensureOutgoingOAuthConnectionInterface(c, "api")
require.False(t, valid)
})
t.Run("feature flag, interface defined, valid license", func(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
defer th.App.Srv().RemoveLicense()
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
svc, valid := ensureOutgoingOAuthConnectionInterface(c, "api")
require.True(t, valid)
require.NotNil(t, svc)
})
}
func TestHandlerOutgoingOAuthConnectionListGet(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
defer th.App.Srv().RemoveLicense()
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
conn := newOutgoingOAuthConnection()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
t.Run("getOutgoingOAuthConnection", func(t *testing.T) {
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Error(err)
}
c.Params = &web.Params{
OutgoingOAuthConnectionID: conn.Id,
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnection", c.AppContext, c.Params.OutgoingOAuthConnectionID).Return(conn, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
var buf bytes.Buffer
require.NoError(t, json.NewEncoder(&buf).Encode(conn))
})
t.Run("listOutgoingOAuthConnections", func(t *testing.T) {
req, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Error(err)
}
conns := []*model.OutgoingOAuthConnection{conn}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", c.AppContext, mock.Anything).Return(conns, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
listOutgoingOAuthConnections(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
var buf bytes.Buffer
require.NoError(t, json.NewEncoder(&buf).Encode(conn))
})
t.Run("listOutgoingOAuthConnections with limit", func(t *testing.T) {
req, err := http.NewRequest("GET", "/?limit=2", nil)
if err != nil {
t.Error(err)
}
conns := []*model.OutgoingOAuthConnection{conn}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", c.AppContext, model.OutgoingOAuthConnectionGetConnectionsFilter{Limit: 2}).Return(conns, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
listOutgoingOAuthConnections(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
var buf bytes.Buffer
require.NoError(t, json.NewEncoder(&buf).Encode(conn))
})
}
func TestHandlerOutgoingOAuthConnectionListReadOnly(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
defer th.App.Srv().RemoveLicense()
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
conn := newOutgoingOAuthConnection()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.TeamAdminRoleId,
}
c.AppContext = th.Context.WithSession(&session)
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOthersOutgoingWebhooks.Id, model.TeamAdminRoleId)
t.Run("listOutgoingOAuthConnections", func(t *testing.T) {
req, err := http.NewRequest("GET", "/?team_id="+th.BasicTeam.Id, nil)
if err != nil {
t.Error(err)
}
conns := []*model.OutgoingOAuthConnection{conn}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", c.AppContext, mock.Anything).Return(conns, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
listOutgoingOAuthConnections(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
var buf bytes.Buffer
require.NoError(t, json.NewEncoder(&buf).Encode(conn))
})
t.Run("listOutgoingOAuthConnections with limit", func(t *testing.T) {
req, err := http.NewRequest("GET", "/?limit=2&team_id="+th.BasicTeam.Id, nil)
if err != nil {
t.Error(err)
}
conns := []*model.OutgoingOAuthConnection{conn}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnections", c.AppContext, model.OutgoingOAuthConnectionGetConnectionsFilter{Limit: 2}).Return(conns, nil)
outgoingOauthIface.Mock.On("SanitizeConnections", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
listOutgoingOAuthConnections(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
var buf bytes.Buffer
require.NoError(t, json.NewEncoder(&buf).Encode(conn))
})
}
func TestHandlerOutgoingOAuthConnectionUpdate(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
defer th.App.Srv().RemoveLicense()
t.Run("no permissions", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
req, err := http.NewRequest("PUT", "/", nil)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
c.Params = &web.Params{
OutgoingOAuthConnectionID: model.NewId(),
}
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
updateOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusForbidden, c.Err.StatusCode)
})
t.Run("bad json", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
body := &bytes.Buffer{}
body.Write([]byte(`{/}`))
req, err := http.NewRequest("PUT", "/", body)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
c.Params = &web.Params{
OutgoingOAuthConnectionID: model.NewId(),
}
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
updateOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusBadRequest, c.Err.StatusCode)
})
t.Run("wrong id", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
body := &bytes.Buffer{}
body.Write([]byte(`{"Id": "` + model.NewId() + `", "name": "changed name"}`))
req, err := http.NewRequest("PUT", "/", body)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
c.Params = &web.Params{
OutgoingOAuthConnectionID: model.NewId(),
}
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
updateOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusBadRequest, c.Err.StatusCode)
})
t.Run("ok", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
conn := newOutgoingOAuthConnection()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
conn.Id = model.NewId() // Faking an ID for the connection
t.Cleanup(func() {
conn.Id = ""
})
body := &bytes.Buffer{}
inputConnection := conn
inputConnection.Name = "changed name"
require.NoError(t, json.NewEncoder(body).Encode(inputConnection))
req, err := http.NewRequest("PUT", "/"+conn.Id, body)
if err != nil {
t.Error(err)
}
c.Params = &web.Params{
OutgoingOAuthConnectionID: conn.Id,
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnection", c.AppContext, c.Params.OutgoingOAuthConnectionID).Return(conn, nil)
outgoingOauthIface.Mock.On("UpdateConnection", c.AppContext, inputConnection).Return(inputConnection, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
updateOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
})
}
func TestHandlerOutgoingOAuthConnectionHandlerCreate(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
defer th.App.Srv().RemoveLicense()
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
t.Run("no permissions", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
req, err := http.NewRequest("POST", "/", nil)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
createOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusForbidden, c.Err.StatusCode)
})
t.Run("bad json", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
body := &bytes.Buffer{}
body.Write([]byte(`{/}`))
req, err := http.NewRequest("POST", "/", body)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
createOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusBadRequest, c.Err.StatusCode)
})
t.Run("ok", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
conn := newOutgoingOAuthConnection()
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
body := &bytes.Buffer{}
require.NoError(t, json.NewEncoder(body).Encode(conn))
req, err := http.NewRequest("POST", "/", body)
if err != nil {
t.Error(err)
}
// Handler sets the connection creator ID to the session user ID
handlerConn := conn
handlerConn.CreatorId = session.UserId
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("SaveConnection", c.AppContext, handlerConn).Return(handlerConn, nil)
outgoingOauthIface.Mock.On("SanitizeConnection", mock.Anything)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
createOutgoingOAuthConnection(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusCreated, httpRecorder.Code)
require.NotEmpty(t, httpRecorder.Body.String())
})
}
func TestHandlerOutgoingOAuthConnectionHandlerValidate(t *testing.T) {
os.Setenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS", "true")
defer os.Unsetenv("MM_FEATUREFLAGS_OUTGOINGOAUTHCONNECTIONS")
th := Setup(t).InitBasic()
defer th.TearDown()
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise, "outgoing_oauth_connections")
license.Id = "test-license-id"
th.App.Srv().SetLicense(license)
defer th.App.Srv().RemoveLicense()
// Run a server to fake the valid and invalid requests made to the oauth server
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch strings.TrimSpace(r.URL.Path) {
case "/valid":
w.WriteHeader(http.StatusOK)
case "/invalid":
w.WriteHeader(http.StatusBadRequest)
default:
http.NotFoundHandler().ServeHTTP(w, r)
}
}))
t.Cleanup(func() {
server.Close()
})
t.Run("no permissions", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
req, err := http.NewRequest("POST", "/", nil)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
validateOutgoingOAuthConnectionCredentials(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusForbidden, c.Err.StatusCode)
})
t.Run("no interface", func(t *testing.T) {
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
req, err := http.NewRequest("POST", "/", nil)
if err != nil {
t.Error(err)
}
session := model.Session{
Id: model.NewId(),
UserId: model.NewId(),
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
defer func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
}()
th.App.Srv().OutgoingOAuthConnection = nil
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
validateOutgoingOAuthConnectionCredentials(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusNotImplemented, c.Err.StatusCode)
})
t.Run("invalid", func(t *testing.T) {
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn.OAuthTokenURL = server.URL + "/invalid"
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
session := model.Session{
Id: model.NewId(),
UserId: conn.CreatorId,
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
body := &bytes.Buffer{}
require.NoError(t, json.NewEncoder(body).Encode(conn))
req, err := http.NewRequest("POST", "/", body)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("RetrieveTokenForConnection", c.AppContext, conn).Return(&model.OutgoingOAuthConnectionToken{}, model.NewAppError(whereOutgoingOAuthConnection, "api.context.outgoing_oauth_connection.validate_connection_credentials.input_error", nil, "error", http.StatusBadRequest))
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
validateOutgoingOAuthConnectionCredentials(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusBadRequest, httpRecorder.Code)
})
t.Run("success", func(t *testing.T) {
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn.OAuthTokenURL = server.URL + "/valid"
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
session := model.Session{
Id: model.NewId(),
UserId: conn.CreatorId,
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
body := &bytes.Buffer{}
require.NoError(t, json.NewEncoder(body).Encode(conn))
req, err := http.NewRequest("POST", "/", body)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("RetrieveTokenForConnection", c.AppContext, conn).Return(&model.OutgoingOAuthConnectionToken{}, nil)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
validateOutgoingOAuthConnectionCredentials(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
})
t.Run("success (stored connection)", func(t *testing.T) {
conn := newOutgoingOAuthConnection()
conn.CreatorId = model.NewId()
conn.OAuthTokenURL = server.URL + "/valid"
c := &Context{}
c.AppContext = th.Context
c.App = th.App
c.Logger = th.App.Srv().Log()
session := model.Session{
Id: model.NewId(),
UserId: conn.CreatorId,
Roles: model.SystemUserRoleId,
}
c.AppContext = th.Context.WithSession(&session)
c.Params = &web.Params{
OutgoingOAuthConnectionID: conn.Id,
}
defaultRolePermissions := th.SaveDefaultRolePermissions()
defer func() {
th.RestoreDefaultRolePermissions(defaultRolePermissions)
}()
th.AddPermissionToRole(model.PermissionManageOutgoingOAuthConnections.Id, model.SystemUserRoleId)
body := &bytes.Buffer{}
require.NoError(t, json.NewEncoder(body).Encode(conn))
req, err := http.NewRequest("POST", "/", body)
if err != nil {
t.Error(err)
}
outgoingOauthIface := &mocks.OutgoingOAuthConnectionInterface{}
outgoingOauthImpl := th.App.Srv().OutgoingOAuthConnection
outgoingOAuthConnectionConfig := th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = model.NewBool(true)
t.Cleanup(func() {
th.App.Srv().OutgoingOAuthConnection = outgoingOauthImpl
th.App.Config().ServiceSettings.EnableOutgoingOAuthConnections = outgoingOAuthConnectionConfig
})
th.App.Srv().OutgoingOAuthConnection = outgoingOauthIface
outgoingOauthIface.Mock.On("GetConnection", c.AppContext, conn.Id).Return(conn, nil)
outgoingOauthIface.Mock.On("RetrieveTokenForConnection", c.AppContext, conn).Return(&model.OutgoingOAuthConnectionToken{}, nil)
httpRecorder := httptest.NewRecorder()
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
validateOutgoingOAuthConnectionCredentials(c, w, r)
})
handler.ServeHTTP(httpRecorder, req)
require.Equal(t, http.StatusOK, httpRecorder.Code)
})
}