Files
mostlymatter/server/public/model/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 669da23e8ee47525ccaa6f59cbbd20bf8a121191.

* Revert "updated i18n file"

This reverts commit d0882c0dd7587533f0d0f7a7b7b190684186158a.

* Revert "fixed i18n"

This reverts commit 3108866bc19139182dfd094921c56cdefc4695ea.

* 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

386 строки
10 KiB
Go

package model
import (
"testing"
"github.com/stretchr/testify/require"
)
var (
emptyString = ""
someString = "userorpass"
)
func newValidOutgoingOAuthConnection() *OutgoingOAuthConnection {
return &OutgoingOAuthConnection{
Id: NewId(),
CreatorId: NewId(),
Name: "Test Connection",
ClientId: NewId(),
ClientSecret: NewId(),
CredentialsUsername: NewString(NewId()),
CredentialsPassword: NewString(NewId()),
OAuthTokenURL: "https://nowhere.com/oauth/token",
GrantType: OutgoingOAuthConnectionGrantTypeClientCredentials,
CreateAt: GetMillis(),
UpdateAt: GetMillis(),
Audiences: []string{"https://nowhere.com"},
}
}
func TestOutgoingOAuthConnectionIsValid(t *testing.T) {
var cases = []struct {
name string
item func() *OutgoingOAuthConnection
assert func(t *testing.T, oa *OutgoingOAuthConnection)
}{
{
name: "valid",
item: func() *OutgoingOAuthConnection {
return newValidOutgoingOAuthConnection()
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Nil(t, oa.IsValid())
},
},
{
name: "invalid id",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.Id = ""
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "empty name",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.Name = ""
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid create_at",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.CreateAt = 0
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid update_at",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.UpdateAt = 0
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid creator_id",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.CreatorId = ""
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid name",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.Name = ""
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid client_id",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.ClientId = ""
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "long client_id",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.ClientId = string(make([]byte, 257))
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid client_secret",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.ClientSecret = ""
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "long client_secret",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.ClientSecret = string(make([]byte, 257))
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "empty oauth_token_url",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.OAuthTokenURL = ""
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "long oauth_token_url",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.OAuthTokenURL = string(make([]byte, 257))
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid oauth_token_url",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.OAuthTokenURL = "invalid"
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid grant_type",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.GrantType = ""
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "nil password credentials",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.GrantType = OutgoingOAuthConnectionGrantTypePassword
oa.CredentialsUsername = nil
oa.CredentialsPassword = nil
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid password credentials username",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.GrantType = OutgoingOAuthConnectionGrantTypePassword
oa.CredentialsUsername = &emptyString
oa.CredentialsPassword = &someString
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid password credentials password",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.GrantType = OutgoingOAuthConnectionGrantTypePassword
oa.CredentialsUsername = &someString
oa.CredentialsPassword = &emptyString
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "empty password credentials",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.GrantType = OutgoingOAuthConnectionGrantTypePassword
oa.CredentialsUsername = &emptyString
oa.CredentialsPassword = &emptyString
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "correct password credentials",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.GrantType = OutgoingOAuthConnectionGrantTypePassword
oa.CredentialsUsername = &someString
oa.CredentialsPassword = &someString
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Nil(t, oa.IsValid())
},
},
{
name: "empty audience",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.Audiences = []string{}
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
{
name: "invalid audience",
item: func() *OutgoingOAuthConnection {
oa := newValidOutgoingOAuthConnection()
oa.Audiences = []string{"https://nowhere.com", "invalid"}
return oa
},
assert: func(t *testing.T, oa *OutgoingOAuthConnection) {
require.Error(t, oa.IsValid())
},
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
tc.assert(t, tc.item())
})
}
}
func TestOutgoingOAuthConnectionPreSave(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.PreSave()
require.NotEmpty(t, oa.Id)
require.NotZero(t, oa.CreateAt)
require.NotZero(t, oa.UpdateAt)
}
func TestOutgoingOAuthConnectionPreUpdate(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.PreUpdate()
require.NotZero(t, oa.UpdateAt)
}
func TestOutgoingOAuthConnectionEtag(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.PreSave()
require.NotEmpty(t, oa.Etag())
}
func TestOutgoingOAuthConnectionSanitize(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Sanitize()
require.NotEmpty(t, oa.ClientId)
require.Empty(t, oa.ClientSecret)
require.NotEmpty(t, oa.CredentialsUsername)
require.Empty(t, oa.CredentialsPassword)
}
func TestOutgoingOAuthConnectionPatch(t *testing.T) {
t.Run("name", func(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Patch(&OutgoingOAuthConnection{Name: "new name"})
require.Equal(t, "new name", oa.Name)
})
t.Run("client_id", func(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Patch(&OutgoingOAuthConnection{ClientId: "new client id"})
require.Equal(t, "new client id", oa.ClientId)
})
t.Run("client_secret", func(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Patch(&OutgoingOAuthConnection{ClientSecret: "new client secret"})
require.Equal(t, "new client secret", oa.ClientSecret)
})
t.Run("oauth_token_url", func(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Patch(&OutgoingOAuthConnection{OAuthTokenURL: "new oauth token url"})
require.Equal(t, "new oauth token url", oa.OAuthTokenURL)
})
t.Run("grant_type", func(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Patch(&OutgoingOAuthConnection{GrantType: OutgoingOAuthConnectionGrantTypePassword})
require.Equal(t, OutgoingOAuthConnectionGrantTypePassword, oa.GrantType)
})
t.Run("audiences", func(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Patch(&OutgoingOAuthConnection{Audiences: StringArray{"new audience"}})
require.Equal(t, StringArray{"new audience"}, oa.Audiences)
})
t.Run("credentials_username", func(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Patch(&OutgoingOAuthConnection{CredentialsUsername: &someString})
require.Equal(t, &someString, oa.CredentialsUsername)
})
t.Run("credentials_password", func(t *testing.T) {
oa := newValidOutgoingOAuthConnection()
oa.Patch(&OutgoingOAuthConnection{CredentialsPassword: &someString})
require.Equal(t, &someString, oa.CredentialsPassword)
})
}