mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-07-10 14:09:20 +02:00
chore: add tests for admin auth
subcommands (#8433)
This PR is adds almost all tests in `cmd/admin_auth_oauth_test.go` with a bit of refactoring beforehand to make the tests easier to write. These should be legitimate refactors where the implementation changes but the public API/behavior does not change. All of the changes in this PR are done to align with how tests are written in `cmd/admin_auth_ldap_test.go`. Since `cmd/admin_auth_ldap.go` is a sibling file to `cmd/admin_auth_oauth.go`, it seems like their test files should also be aligned. There are some tests added that show the current behavior as not ideal. E.g. not being able to update certain fields, or being able to set fields that are ultimately ignored. These are added so that the behavior is at least shown a bit more visibly. There should likely be a follow-up to fix some of these issues. But that will almost certainly be a breaking change that I'd rather avoid in this PR. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8433 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Co-authored-by: joneshf <jones3.hardy@gmail.com> Co-committed-by: joneshf <jones3.hardy@gmail.com>
This commit is contained in:
parent
32e8610b20
commit
48035bbd4e
4 changed files with 732 additions and 28 deletions
|
@ -17,6 +17,15 @@ import (
|
|||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type (
|
||||
authService struct {
|
||||
initDB func(ctx context.Context) error
|
||||
createAuthSource func(context.Context, *auth_model.Source) error
|
||||
updateAuthSource func(context.Context, *auth_model.Source) error
|
||||
getAuthSourceByID func(ctx context.Context, id int64) (*auth_model.Source, error)
|
||||
}
|
||||
)
|
||||
|
||||
func microcmdAuthDelete() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "delete",
|
||||
|
@ -60,6 +69,16 @@ func microcmdAuthList() *cli.Command {
|
|||
}
|
||||
}
|
||||
|
||||
// newAuthService creates a service with default functions.
|
||||
func newAuthService() *authService {
|
||||
return &authService{
|
||||
initDB: initDB,
|
||||
createAuthSource: auth_model.CreateSource,
|
||||
updateAuthSource: auth_model.UpdateSource,
|
||||
getAuthSourceByID: auth_model.GetSourceByID,
|
||||
}
|
||||
}
|
||||
|
||||
func runListAuth(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
|
|
@ -14,15 +14,6 @@ import (
|
|||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
type (
|
||||
authService struct {
|
||||
initDB func(ctx context.Context) error
|
||||
createAuthSource func(context.Context, *auth.Source) error
|
||||
updateAuthSource func(context.Context, *auth.Source) error
|
||||
getAuthSourceByID func(ctx context.Context, id int64) (*auth.Source, error)
|
||||
}
|
||||
)
|
||||
|
||||
func commonLdapCLIFlags() []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
|
@ -184,16 +175,6 @@ func microcmdAuthUpdateLdapSimpleAuth() *cli.Command {
|
|||
}
|
||||
}
|
||||
|
||||
// newAuthService creates a service with default functions.
|
||||
func newAuthService() *authService {
|
||||
return &authService{
|
||||
initDB: initDB,
|
||||
createAuthSource: auth.CreateSource,
|
||||
updateAuthSource: auth.UpdateSource,
|
||||
getAuthSourceByID: auth.GetSourceByID,
|
||||
}
|
||||
}
|
||||
|
||||
// parseAuthSource assigns values on authSource according to command line flags.
|
||||
func parseAuthSource(c *cli.Command, authSource *auth.Source) {
|
||||
if c.IsSet("name") {
|
||||
|
|
|
@ -132,7 +132,7 @@ func microcmdAuthAddOauth() *cli.Command {
|
|||
return &cli.Command{
|
||||
Name: "add-oauth",
|
||||
Usage: "Add new Oauth authentication source",
|
||||
Action: runAddOauth,
|
||||
Action: newAuthService().addOauth,
|
||||
Flags: oauthCLIFlags(),
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ func microcmdAuthUpdateOauth() *cli.Command {
|
|||
return &cli.Command{
|
||||
Name: "update-oauth",
|
||||
Usage: "Update existing Oauth authentication source",
|
||||
Action: runUpdateOauth,
|
||||
Action: newAuthService().updateOauth,
|
||||
Flags: append(oauthCLIFlags()[:1], append([]cli.Flag{idFlag()}, oauthCLIFlags()[1:]...)...),
|
||||
}
|
||||
}
|
||||
|
@ -179,11 +179,11 @@ func parseOAuth2Config(_ context.Context, c *cli.Command) *oauth2.Source {
|
|||
}
|
||||
}
|
||||
|
||||
func runAddOauth(ctx context.Context, c *cli.Command) error {
|
||||
func (a *authService) addOauth(ctx context.Context, c *cli.Command) error {
|
||||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
if err := a.initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ func runAddOauth(ctx context.Context, c *cli.Command) error {
|
|||
}
|
||||
}
|
||||
|
||||
return auth_model.CreateSource(ctx, &auth_model.Source{
|
||||
return a.createAuthSource(ctx, &auth_model.Source{
|
||||
Type: auth_model.OAuth2,
|
||||
Name: c.String("name"),
|
||||
IsActive: true,
|
||||
|
@ -203,7 +203,7 @@ func runAddOauth(ctx context.Context, c *cli.Command) error {
|
|||
})
|
||||
}
|
||||
|
||||
func runUpdateOauth(ctx context.Context, c *cli.Command) error {
|
||||
func (a *authService) updateOauth(ctx context.Context, c *cli.Command) error {
|
||||
if !c.IsSet("id") {
|
||||
return errors.New("--id flag is missing")
|
||||
}
|
||||
|
@ -211,11 +211,11 @@ func runUpdateOauth(ctx context.Context, c *cli.Command) error {
|
|||
ctx, cancel := installSignals(ctx)
|
||||
defer cancel()
|
||||
|
||||
if err := initDB(ctx); err != nil {
|
||||
if err := a.initDB(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := auth_model.GetSourceByID(ctx, c.Int64("id"))
|
||||
source, err := a.getAuthSourceByID(ctx, c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -310,5 +310,5 @@ func runUpdateOauth(ctx context.Context, c *cli.Command) error {
|
|||
oAuth2Config.CustomURLMapping = customURLMapping
|
||||
source.Cfg = oAuth2Config
|
||||
|
||||
return auth_model.UpdateSource(ctx, source)
|
||||
return a.updateAuthSource(ctx, source)
|
||||
}
|
||||
|
|
704
cmd/admin_auth_oauth_test.go
Normal file
704
cmd/admin_auth_oauth_test.go
Normal file
|
@ -0,0 +1,704 @@
|
|||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"forgejo.org/models/auth"
|
||||
"forgejo.org/modules/test"
|
||||
"forgejo.org/services/auth/source/oauth2"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/cli/v3"
|
||||
)
|
||||
|
||||
func TestAddOauth(t *testing.T) {
|
||||
// Mock cli functions to do not exit on error
|
||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||
|
||||
// Test cases
|
||||
cases := []struct {
|
||||
args []string
|
||||
source *auth.Source
|
||||
errMsg string
|
||||
}{
|
||||
// case 0
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--name", "oauth2 (via openidConnect) source full",
|
||||
"--provider", "openidConnect",
|
||||
"--key", "client id",
|
||||
"--secret", "client secret",
|
||||
"--auto-discover-url", "https://example.com/.well-known/openid-configuration",
|
||||
"--use-custom-urls", "",
|
||||
"--custom-tenant-id", "tenant id",
|
||||
"--custom-auth-url", "https://example.com/auth",
|
||||
"--custom-token-url", "https://example.com/token",
|
||||
"--custom-profile-url", "https://example.com/profile",
|
||||
"--custom-email-url", "https://example.com/email",
|
||||
"--icon-url", "https://example.com/icon.svg",
|
||||
"--skip-local-2fa",
|
||||
"--scopes", "address",
|
||||
"--scopes", "email",
|
||||
"--scopes", "phone",
|
||||
"--scopes", "profile",
|
||||
"--attribute-ssh-public-key", "ssh_public_key",
|
||||
"--required-claim-name", "can_access",
|
||||
"--required-claim-value", "yes",
|
||||
"--group-claim-name", "groups",
|
||||
"--admin-group", "admin",
|
||||
"--restricted-group", "restricted",
|
||||
"--group-team-map", `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`,
|
||||
"--group-team-map-removal",
|
||||
},
|
||||
source: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source full",
|
||||
IsActive: true,
|
||||
Cfg: &oauth2.Source{
|
||||
Provider: "openidConnect",
|
||||
ClientID: "client id",
|
||||
ClientSecret: "client secret",
|
||||
OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration",
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{
|
||||
AuthURL: "https://example.com/auth",
|
||||
TokenURL: "https://example.com/token",
|
||||
ProfileURL: "https://example.com/profile",
|
||||
EmailURL: "https://example.com/email",
|
||||
Tenant: "tenant id",
|
||||
},
|
||||
IconURL: "https://example.com/icon.svg",
|
||||
Scopes: []string{"address", "email", "phone", "profile"},
|
||||
AttributeSSHPublicKey: "ssh_public_key",
|
||||
RequiredClaimName: "can_access",
|
||||
RequiredClaimValue: "yes",
|
||||
GroupClaimName: "groups",
|
||||
AdminGroup: "admin",
|
||||
GroupTeamMap: `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`,
|
||||
GroupTeamMapRemoval: true,
|
||||
RestrictedGroup: "restricted",
|
||||
SkipLocalTwoFA: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 1
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--name", "oauth2 (via openidConnect) source min",
|
||||
"--provider", "openidConnect",
|
||||
"--auto-discover-url", "https://example.com/.well-known/openid-configuration",
|
||||
},
|
||||
source: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source min",
|
||||
IsActive: true,
|
||||
Cfg: &oauth2.Source{
|
||||
Provider: "openidConnect",
|
||||
OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration",
|
||||
Scopes: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 2
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--name", "oauth2 (via openidConnect) source `--use-custom-urls` required for `--custom-*` flags",
|
||||
"--custom-tenant-id", "tenant id",
|
||||
"--custom-auth-url", "https://example.com/auth",
|
||||
"--custom-token-url", "https://example.com/token",
|
||||
"--custom-profile-url", "https://example.com/profile",
|
||||
"--custom-email-url", "https://example.com/email",
|
||||
},
|
||||
source: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source `--use-custom-urls` required for `--custom-*` flags",
|
||||
IsActive: true,
|
||||
Cfg: &oauth2.Source{
|
||||
Scopes: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 3
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--name", "oauth2 (via openidConnect) source `--scopes` aggregates multiple uses",
|
||||
"--provider", "openidConnect",
|
||||
"--auto-discover-url", "https://example.com/.well-known/openid-configuration",
|
||||
"--scopes", "address",
|
||||
"--scopes", "email",
|
||||
"--scopes", "phone",
|
||||
"--scopes", "profile",
|
||||
},
|
||||
source: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source `--scopes` aggregates multiple uses",
|
||||
IsActive: true,
|
||||
Cfg: &oauth2.Source{
|
||||
Provider: "openidConnect",
|
||||
OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration",
|
||||
Scopes: []string{"address", "email", "phone", "profile"},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 4
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--name", "oauth2 (via openidConnect) source `--scopes` supports commas as separators",
|
||||
"--provider", "openidConnect",
|
||||
"--auto-discover-url", "https://example.com/.well-known/openid-configuration",
|
||||
"--scopes", "address,email,phone,profile",
|
||||
},
|
||||
source: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source `--scopes` supports commas as separators",
|
||||
IsActive: true,
|
||||
Cfg: &oauth2.Source{
|
||||
Provider: "openidConnect",
|
||||
OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration",
|
||||
Scopes: []string{"address", "email", "phone", "profile"},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 5
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--name", "oauth2 (via openidConnect) source",
|
||||
"--provider", "openidConnect",
|
||||
},
|
||||
errMsg: "invalid Auto Discovery URL: (this must be a valid URL starting with http:// or https://)",
|
||||
},
|
||||
// case 6
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--name", "oauth2 (via openidConnect) source",
|
||||
"--provider", "openidConnect",
|
||||
"--auto-discover-url", "example.com",
|
||||
},
|
||||
errMsg: "invalid Auto Discovery URL: example.com (this must be a valid URL starting with http:// or https://)",
|
||||
},
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
// Mock functions.
|
||||
var createdAuthSource *auth.Source
|
||||
service := &authService{
|
||||
initDB: func(context.Context) error {
|
||||
return nil
|
||||
},
|
||||
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||
createdAuthSource = authSource
|
||||
return nil
|
||||
},
|
||||
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||
assert.FailNow(t, "should not call updateAuthSource", "case: %d", n)
|
||||
return nil
|
||||
},
|
||||
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
|
||||
assert.FailNow(t, "should not call getAuthSourceByID", "case: %d", n)
|
||||
return nil, nil
|
||||
},
|
||||
}
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.Command{}
|
||||
app.Flags = microcmdAuthAddOauth().Flags
|
||||
app.Action = service.addOauth
|
||||
|
||||
// Run it
|
||||
err := app.Run(t.Context(), c.args)
|
||||
if c.errMsg != "" {
|
||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||
} else {
|
||||
require.NoError(t, err, "case %d: should have no errors", n)
|
||||
assert.Equal(t, c.source, createdAuthSource, "case %d: wrong authSource", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateOauth(t *testing.T) {
|
||||
// Mock cli functions to do not exit on error
|
||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||
|
||||
// Test cases
|
||||
cases := []struct {
|
||||
args []string
|
||||
id int64
|
||||
existingAuthSource *auth.Source
|
||||
authSource *auth.Source
|
||||
errMsg string
|
||||
}{
|
||||
// case 0
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "23",
|
||||
"--name", "oauth2 (via openidConnect) source full",
|
||||
"--provider", "openidConnect",
|
||||
"--key", "client id",
|
||||
"--secret", "client secret",
|
||||
"--auto-discover-url", "https://example.com/.well-known/openid-configuration",
|
||||
"--use-custom-urls", "",
|
||||
"--custom-tenant-id", "tenant id",
|
||||
"--custom-auth-url", "https://example.com/auth",
|
||||
"--custom-token-url", "https://example.com/token",
|
||||
"--custom-profile-url", "https://example.com/profile",
|
||||
"--custom-email-url", "https://example.com/email",
|
||||
"--icon-url", "https://example.com/icon.svg",
|
||||
"--skip-local-2fa",
|
||||
"--scopes", "address",
|
||||
"--scopes", "email",
|
||||
"--scopes", "phone",
|
||||
"--scopes", "profile",
|
||||
"--attribute-ssh-public-key", "ssh_public_key",
|
||||
"--required-claim-name", "can_access",
|
||||
"--required-claim-value", "yes",
|
||||
"--group-claim-name", "groups",
|
||||
"--admin-group", "admin",
|
||||
"--restricted-group", "restricted",
|
||||
"--group-team-map", `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`,
|
||||
"--group-team-map-removal",
|
||||
},
|
||||
id: 23,
|
||||
existingAuthSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{},
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source full",
|
||||
Cfg: &oauth2.Source{
|
||||
Provider: "openidConnect",
|
||||
ClientID: "client id",
|
||||
ClientSecret: "client secret",
|
||||
OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration",
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{
|
||||
AuthURL: "https://example.com/auth",
|
||||
TokenURL: "https://example.com/token",
|
||||
ProfileURL: "https://example.com/profile",
|
||||
EmailURL: "https://example.com/email",
|
||||
Tenant: "tenant id",
|
||||
},
|
||||
IconURL: "https://example.com/icon.svg",
|
||||
Scopes: []string{"address", "email", "phone", "profile"},
|
||||
AttributeSSHPublicKey: "ssh_public_key",
|
||||
RequiredClaimName: "can_access",
|
||||
RequiredClaimValue: "yes",
|
||||
GroupClaimName: "groups",
|
||||
AdminGroup: "admin",
|
||||
GroupTeamMap: `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`,
|
||||
GroupTeamMapRemoval: true,
|
||||
RestrictedGroup: "restricted",
|
||||
// `--skip-local-2fa` is currently ignored.
|
||||
// SkipLocalTwoFA: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 1
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 2
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--name", "oauth2 (via openidConnect) source full",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source full",
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 3
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--provider", "openidConnect",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
Provider: "openidConnect",
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 4
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--key", "client id",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
ClientID: "client id",
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 5
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--secret", "client secret",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
ClientSecret: "client secret",
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 6
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--auto-discover-url", "https://example.com/.well-known/openid-configuration",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
OpenIDConnectAutoDiscoveryURL: "https://example.com/.well-known/openid-configuration",
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 7
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--use-custom-urls", "",
|
||||
"--custom-tenant-id", "tenant id",
|
||||
"--custom-auth-url", "https://example.com/auth",
|
||||
"--custom-token-url", "https://example.com/token",
|
||||
"--custom-profile-url", "https://example.com/profile",
|
||||
"--custom-email-url", "https://example.com/email",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{
|
||||
AuthURL: "https://example.com/auth",
|
||||
TokenURL: "https://example.com/token",
|
||||
ProfileURL: "https://example.com/profile",
|
||||
EmailURL: "https://example.com/email",
|
||||
Tenant: "tenant id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 8
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--name", "oauth2 (via openidConnect) source `--use-custom-urls` required for `--custom-*` flags",
|
||||
"--custom-tenant-id", "tenant id",
|
||||
"--custom-auth-url", "https://example.com/auth",
|
||||
"--custom-token-url", "https://example.com/token",
|
||||
"--custom-profile-url", "https://example.com/profile",
|
||||
"--custom-email-url", "https://example.com/email",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source `--use-custom-urls` required for `--custom-*` flags",
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 9
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--icon-url", "https://example.com/icon.svg",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
IconURL: "https://example.com/icon.svg",
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 10
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--name", "oauth2 (via openidConnect) source `--skip-local-2fa` is currently ignored",
|
||||
"--skip-local-2fa",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source `--skip-local-2fa` is currently ignored",
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
// `--skip-local-2fa` is currently ignored.
|
||||
// SkipLocalTwoFA: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 11
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--name", "oauth2 (via openidConnect) source `--scopes` aggregates multiple uses",
|
||||
"--scopes", "address",
|
||||
"--scopes", "email",
|
||||
"--scopes", "phone",
|
||||
"--scopes", "profile",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source `--scopes` aggregates multiple uses",
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
Scopes: []string{"address", "email", "phone", "profile"},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 12
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--name", "oauth2 (via openidConnect) source `--scopes` supports commas as separators",
|
||||
"--scopes", "address,email,phone,profile",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Name: "oauth2 (via openidConnect) source `--scopes` supports commas as separators",
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
Scopes: []string{"address", "email", "phone", "profile"},
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 13
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--attribute-ssh-public-key", "ssh_public_key",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
AttributeSSHPublicKey: "ssh_public_key",
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 14
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--required-claim-name", "can_access",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
RequiredClaimName: "can_access",
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 15
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--required-claim-value", "yes",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
RequiredClaimValue: "yes",
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 16
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--group-claim-name", "groups",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
GroupClaimName: "groups",
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 17
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--admin-group", "admin",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
AdminGroup: "admin",
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 18
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--restricted-group", "restricted",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
RestrictedGroup: "restricted",
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 19
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--group-team-map", `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`,
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
GroupTeamMap: `{"org_a_team_1": {"organization-a": ["Team 1"]}, "org_a_all_teams": {"organization-a": ["Team 1", "Team 2", "Team 3"]}}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 20
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "1",
|
||||
"--group-team-map-removal",
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
GroupTeamMapRemoval: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 21
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
"--id", "23",
|
||||
"--group-team-map-removal=false",
|
||||
},
|
||||
id: 23,
|
||||
existingAuthSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
GroupTeamMapRemoval: true,
|
||||
},
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{
|
||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
||||
GroupTeamMapRemoval: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
// case 22
|
||||
{
|
||||
args: []string{
|
||||
"oauth-test",
|
||||
},
|
||||
errMsg: "--id flag is missing",
|
||||
},
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
// Mock functions.
|
||||
var updatedAuthSource *auth.Source
|
||||
service := &authService{
|
||||
initDB: func(context.Context) error {
|
||||
return nil
|
||||
},
|
||||
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||
assert.FailNow(t, "should not call createAuthSource", "case: %d", n)
|
||||
return nil
|
||||
},
|
||||
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||
updatedAuthSource = authSource
|
||||
return nil
|
||||
},
|
||||
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
|
||||
if c.id != 0 {
|
||||
assert.Equal(t, c.id, id, "case %d: wrong id", n)
|
||||
}
|
||||
if c.existingAuthSource != nil {
|
||||
return c.existingAuthSource, nil
|
||||
}
|
||||
return &auth.Source{
|
||||
Type: auth.OAuth2,
|
||||
Cfg: &oauth2.Source{},
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
|
||||
// Create a copy of command to test
|
||||
app := cli.Command{}
|
||||
app.Flags = microcmdAuthUpdateOauth().Flags
|
||||
app.Action = service.updateOauth
|
||||
|
||||
// Run it
|
||||
err := app.Run(t.Context(), c.args)
|
||||
if c.errMsg != "" {
|
||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||
} else {
|
||||
require.NoError(t, err, "case %d: should have no errors", n)
|
||||
assert.Equal(t, c.authSource, updatedAuthSource, "case %d: wrong authSource", n)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue