refactor(configuration): remove ptr for duoapi and notifier (#3200)
This adds to the ongoing effort to remove all pointers to structs in the configuration without breaking backwards compatibility.pull/3202/head^2
parent
c9568caf4d
commit
4710de33a4
|
@ -158,6 +158,7 @@ webauthn:
|
|||
## Parameters used to contact the Duo API. Those are generated when you protect an application of type
|
||||
## "Partner Auth API" in the management panel.
|
||||
duo_api:
|
||||
disable: false
|
||||
hostname: api-123456789.example.com
|
||||
integration_key: ABCDEF
|
||||
## Secret can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html
|
||||
|
|
|
@ -21,6 +21,7 @@ section of the configuration.
|
|||
The configuration is as follows:
|
||||
```yaml
|
||||
duo_api:
|
||||
disable: false
|
||||
hostname: api-123456789.example.com
|
||||
integration_key: ABCDEF
|
||||
secret_key: 1234567890abcdefghifjkl
|
||||
|
@ -32,6 +33,19 @@ variable as described [here](./secrets.md).
|
|||
|
||||
## Options
|
||||
|
||||
### disable:
|
||||
<div markdown="1">
|
||||
type: boolean
|
||||
{: .label .label-config .label-purple }
|
||||
default: false
|
||||
{: .label .label-config .label-blue }
|
||||
required: no
|
||||
{: .label .label-config .label-green }
|
||||
</div>
|
||||
|
||||
Disables Duo. If the hostname, integration_key, and secret_key are all empty strings or undefined this is automatically
|
||||
true.
|
||||
|
||||
### hostname
|
||||
<div markdown="1">
|
||||
type: string
|
||||
|
|
|
@ -158,6 +158,7 @@ webauthn:
|
|||
## Parameters used to contact the Duo API. Those are generated when you protect an application of type
|
||||
## "Partner Auth API" in the management panel.
|
||||
duo_api:
|
||||
disable: false
|
||||
hostname: api-123456789.example.com
|
||||
integration_key: ABCDEF
|
||||
## Secret can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html
|
||||
|
|
|
@ -273,7 +273,7 @@ func TestShouldHandleErrInvalidatorWhenSMTPSenderBlank(t *testing.T) {
|
|||
assert.Equal(t, "", config.Notifier.SMTP.Sender.Name)
|
||||
assert.Equal(t, "", config.Notifier.SMTP.Sender.Address)
|
||||
|
||||
validator.ValidateNotifier(config.Notifier, val)
|
||||
validator.ValidateNotifier(&config.Notifier, val)
|
||||
|
||||
require.Len(t, val.Errors(), 1)
|
||||
assert.Len(t, val.Warnings(), 0)
|
||||
|
|
|
@ -12,12 +12,12 @@ type Configuration struct {
|
|||
AuthenticationBackend AuthenticationBackendConfiguration `koanf:"authentication_backend"`
|
||||
Session SessionConfiguration `koanf:"session"`
|
||||
TOTP TOTPConfiguration `koanf:"totp"`
|
||||
DuoAPI *DuoAPIConfiguration `koanf:"duo_api"`
|
||||
DuoAPI DuoAPIConfiguration `koanf:"duo_api"`
|
||||
AccessControl AccessControlConfiguration `koanf:"access_control"`
|
||||
NTP NTPConfiguration `koanf:"ntp"`
|
||||
Regulation RegulationConfiguration `koanf:"regulation"`
|
||||
Storage StorageConfiguration `koanf:"storage"`
|
||||
Notifier *NotifierConfiguration `koanf:"notifier"`
|
||||
Notifier NotifierConfiguration `koanf:"notifier"`
|
||||
Server ServerConfiguration `koanf:"server"`
|
||||
Webauthn WebauthnConfiguration `koanf:"webauthn"`
|
||||
PasswordPolicy PasswordPolicyConfiguration `koanf:"password_policy"`
|
||||
|
|
|
@ -2,8 +2,9 @@ package schema
|
|||
|
||||
// DuoAPIConfiguration represents the configuration related to Duo API.
|
||||
type DuoAPIConfiguration struct {
|
||||
Disable bool `koanf:"disable"`
|
||||
Hostname string `koanf:"hostname"`
|
||||
EnableSelfEnrollment bool `koanf:"enable_self_enrollment"`
|
||||
IntegrationKey string `koanf:"integration_key"`
|
||||
SecretKey string `koanf:"secret_key"`
|
||||
EnableSelfEnrollment bool `koanf:"enable_self_enrollment"`
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ func ValidateConfiguration(config *schema.Configuration, validator *schema.Struc
|
|||
|
||||
ValidateLog(config, validator)
|
||||
|
||||
ValidateDuo(config, validator)
|
||||
|
||||
ValidateTOTP(config, validator)
|
||||
|
||||
ValidateWebauthn(config, validator)
|
||||
|
@ -55,7 +57,7 @@ func ValidateConfiguration(config *schema.Configuration, validator *schema.Struc
|
|||
|
||||
ValidateStorage(config.Storage, validator)
|
||||
|
||||
ValidateNotifier(config.Notifier, validator)
|
||||
ValidateNotifier(&config.Notifier, validator)
|
||||
|
||||
ValidateIdentityProviders(&config.IdentityProviders, validator)
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ func newDefaultConfig() schema.Configuration {
|
|||
config.Storage.Local = &schema.LocalStorageConfiguration{
|
||||
Path: "abc",
|
||||
}
|
||||
config.Notifier = &schema.NotifierConfiguration{
|
||||
config.Notifier = schema.NotifierConfiguration{
|
||||
FileSystem: &schema.FileSystemNotifierConfiguration{
|
||||
Filename: "/tmp/file",
|
||||
},
|
||||
|
@ -48,7 +48,8 @@ func TestShouldEnsureNotifierConfigIsProvided(t *testing.T) {
|
|||
ValidateConfiguration(&config, validator)
|
||||
require.Len(t, validator.Errors(), 0)
|
||||
|
||||
config.Notifier = nil
|
||||
config.Notifier.SMTP = nil
|
||||
config.Notifier.FileSystem = nil
|
||||
|
||||
ValidateConfiguration(&config, validator)
|
||||
require.Len(t, validator.Errors(), 1)
|
||||
|
|
|
@ -249,6 +249,10 @@ const (
|
|||
errFmtPasswordPolicyZXCVBNMinScoreInvalid = "password_policy: zxcvbn: option 'min_score' is invalid: must be between 1 and 4 but it's configured as %d"
|
||||
)
|
||||
|
||||
const (
|
||||
errFmtDuoMissingOption = "duo_api: option '%s' is required when duo is enabled but it is missing"
|
||||
)
|
||||
|
||||
// Error constants.
|
||||
const (
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
)
|
||||
|
||||
// ValidateDuo validates and updates the Duo configuration.
|
||||
func ValidateDuo(config *schema.Configuration, validator *schema.StructValidator) {
|
||||
if config.DuoAPI.Disable {
|
||||
return
|
||||
}
|
||||
|
||||
if config.DuoAPI.Hostname == "" && config.DuoAPI.IntegrationKey == "" && config.DuoAPI.SecretKey == "" {
|
||||
config.DuoAPI.Disable = true
|
||||
}
|
||||
|
||||
if config.DuoAPI.Disable {
|
||||
return
|
||||
}
|
||||
|
||||
if config.DuoAPI.Hostname == "" {
|
||||
validator.Push(fmt.Errorf(errFmtDuoMissingOption, "hostname"))
|
||||
}
|
||||
|
||||
if config.DuoAPI.IntegrationKey == "" {
|
||||
validator.Push(fmt.Errorf(errFmtDuoMissingOption, "integration_key"))
|
||||
}
|
||||
|
||||
if config.DuoAPI.SecretKey == "" {
|
||||
validator.Push(fmt.Errorf(errFmtDuoMissingOption, "secret_key"))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
)
|
||||
|
||||
func TestValidateDuo(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
have *schema.Configuration
|
||||
expected schema.DuoAPIConfiguration
|
||||
errs []string
|
||||
}{
|
||||
{
|
||||
desc: "ShouldDisableDuo",
|
||||
have: &schema.Configuration{},
|
||||
expected: schema.DuoAPIConfiguration{Disable: true},
|
||||
},
|
||||
{
|
||||
desc: "ShouldNotDisableDuo",
|
||||
have: &schema.Configuration{DuoAPI: schema.DuoAPIConfiguration{
|
||||
Hostname: "test",
|
||||
IntegrationKey: "test",
|
||||
SecretKey: "test",
|
||||
}},
|
||||
expected: schema.DuoAPIConfiguration{
|
||||
Hostname: "test",
|
||||
IntegrationKey: "test",
|
||||
SecretKey: "test",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "ShouldDetectMissingSecretKey",
|
||||
have: &schema.Configuration{DuoAPI: schema.DuoAPIConfiguration{
|
||||
Hostname: "test",
|
||||
IntegrationKey: "test",
|
||||
}},
|
||||
expected: schema.DuoAPIConfiguration{
|
||||
Hostname: "test",
|
||||
IntegrationKey: "test",
|
||||
},
|
||||
errs: []string{
|
||||
"duo_api: option 'secret_key' is required when duo is enabled but it is missing",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "ShouldDetectMissingIntegrationKey",
|
||||
have: &schema.Configuration{DuoAPI: schema.DuoAPIConfiguration{
|
||||
Hostname: "test",
|
||||
SecretKey: "test",
|
||||
}},
|
||||
expected: schema.DuoAPIConfiguration{
|
||||
Hostname: "test",
|
||||
SecretKey: "test",
|
||||
},
|
||||
errs: []string{
|
||||
"duo_api: option 'integration_key' is required when duo is enabled but it is missing",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "ShouldDetectMissingHostname",
|
||||
have: &schema.Configuration{DuoAPI: schema.DuoAPIConfiguration{
|
||||
IntegrationKey: "test",
|
||||
SecretKey: "test",
|
||||
}},
|
||||
expected: schema.DuoAPIConfiguration{
|
||||
IntegrationKey: "test",
|
||||
SecretKey: "test",
|
||||
},
|
||||
errs: []string{
|
||||
"duo_api: option 'hostname' is required when duo is enabled but it is missing",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
val := schema.NewStructValidator()
|
||||
|
||||
ValidateDuo(tc.have, val)
|
||||
|
||||
assert.Equal(t, tc.expected.Disable, tc.have.DuoAPI.Disable)
|
||||
assert.Equal(t, tc.expected.Hostname, tc.have.DuoAPI.Hostname)
|
||||
assert.Equal(t, tc.expected.IntegrationKey, tc.have.DuoAPI.IntegrationKey)
|
||||
assert.Equal(t, tc.expected.SecretKey, tc.have.DuoAPI.SecretKey)
|
||||
assert.Equal(t, tc.expected.EnableSelfEnrollment, tc.have.DuoAPI.EnableSelfEnrollment)
|
||||
|
||||
require.Len(t, val.Errors(), len(tc.errs))
|
||||
|
||||
if len(tc.errs) != 0 {
|
||||
for i, err := range tc.errs {
|
||||
t.Run(fmt.Sprintf("Err%d", i+1), func(t *testing.T) {
|
||||
assert.EqualError(t, val.Errors()[i], err)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ import (
|
|||
|
||||
// ValidateNotifier validates and update notifier configuration.
|
||||
func ValidateNotifier(config *schema.NotifierConfiguration, validator *schema.StructValidator) {
|
||||
if config == nil || (config.SMTP == nil && config.FileSystem == nil) {
|
||||
if config.SMTP == nil && config.FileSystem == nil {
|
||||
validator.Push(fmt.Errorf(errFmtNotifierNotConfigured))
|
||||
|
||||
return
|
||||
|
|
|
@ -30,7 +30,9 @@ func (s *SecondFactorAvailableMethodsFixture) TearDownTest() {
|
|||
|
||||
func (s *SecondFactorAvailableMethodsFixture) TestShouldHaveAllConfiguredMethods() {
|
||||
s.mock.Ctx.Configuration = schema.Configuration{
|
||||
DuoAPI: &schema.DuoAPIConfiguration{},
|
||||
DuoAPI: schema.DuoAPIConfiguration{
|
||||
Disable: false,
|
||||
},
|
||||
TOTP: schema.TOTPConfiguration{
|
||||
Disable: false,
|
||||
},
|
||||
|
@ -58,7 +60,9 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldHaveAllConfiguredMethods
|
|||
|
||||
func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveTOTPFromAvailableMethodsWhenDisabled() {
|
||||
s.mock.Ctx.Configuration = schema.Configuration{
|
||||
DuoAPI: &schema.DuoAPIConfiguration{},
|
||||
DuoAPI: schema.DuoAPIConfiguration{
|
||||
Disable: false,
|
||||
},
|
||||
TOTP: schema.TOTPConfiguration{
|
||||
Disable: true,
|
||||
},
|
||||
|
@ -86,7 +90,9 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveTOTPFromAvailableM
|
|||
|
||||
func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveWebauthnFromAvailableMethodsWhenDisabled() {
|
||||
s.mock.Ctx.Configuration = schema.Configuration{
|
||||
DuoAPI: &schema.DuoAPIConfiguration{},
|
||||
DuoAPI: schema.DuoAPIConfiguration{
|
||||
Disable: false,
|
||||
},
|
||||
TOTP: schema.TOTPConfiguration{
|
||||
Disable: false,
|
||||
},
|
||||
|
@ -114,7 +120,9 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveWebauthnFromAvaila
|
|||
|
||||
func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveDuoFromAvailableMethodsWhenNotConfigured() {
|
||||
s.mock.Ctx.Configuration = schema.Configuration{
|
||||
DuoAPI: nil,
|
||||
DuoAPI: schema.DuoAPIConfiguration{
|
||||
Disable: true,
|
||||
},
|
||||
TOTP: schema.TOTPConfiguration{
|
||||
Disable: false,
|
||||
},
|
||||
|
@ -142,7 +150,9 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveDuoFromAvailableMe
|
|||
|
||||
func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveAllMethodsWhenNoTwoFactorACLRulesConfigured() {
|
||||
s.mock.Ctx.Configuration = schema.Configuration{
|
||||
DuoAPI: &schema.DuoAPIConfiguration{},
|
||||
DuoAPI: schema.DuoAPIConfiguration{
|
||||
Disable: false,
|
||||
},
|
||||
TOTP: schema.TOTPConfiguration{
|
||||
Disable: false,
|
||||
},
|
||||
|
@ -170,7 +180,9 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveAllMethodsWhenNoTw
|
|||
|
||||
func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveAllMethodsWhenAllDisabledOrNotConfigured() {
|
||||
s.mock.Ctx.Configuration = schema.Configuration{
|
||||
DuoAPI: nil,
|
||||
DuoAPI: schema.DuoAPIConfiguration{
|
||||
Disable: true,
|
||||
},
|
||||
TOTP: schema.TOTPConfiguration{
|
||||
Disable: true,
|
||||
},
|
||||
|
|
|
@ -80,7 +80,7 @@ func ResetPasswordPOST(ctx *middlewares.AutheliaCtx) {
|
|||
bufHTML := new(bytes.Buffer)
|
||||
|
||||
disableHTML := false
|
||||
if ctx.Configuration.Notifier != nil && ctx.Configuration.Notifier.SMTP != nil {
|
||||
if ctx.Configuration.Notifier.SMTP != nil {
|
||||
disableHTML = ctx.Configuration.Notifier.SMTP.DisableHTMLEmails
|
||||
}
|
||||
|
||||
|
|
|
@ -101,8 +101,6 @@ func TestUserInfoEndpoint_SetCorrectMethod(t *testing.T) {
|
|||
|
||||
mock := mocks.NewMockAutheliaCtx(t)
|
||||
|
||||
mock.Ctx.Configuration.DuoAPI = &schema.DuoAPIConfiguration{}
|
||||
|
||||
// Set the initial user session.
|
||||
userSession := mock.Ctx.GetSession()
|
||||
userSession.Username = testUsername
|
||||
|
@ -172,9 +170,7 @@ func TestUserInfoEndpoint_SetDefaultMethod(t *testing.T) {
|
|||
HasWebauthn: false,
|
||||
HasDuo: false,
|
||||
},
|
||||
config: &schema.Configuration{
|
||||
DuoAPI: &schema.DuoAPIConfiguration{},
|
||||
},
|
||||
config: &schema.Configuration{},
|
||||
loadErr: nil,
|
||||
saveErr: nil,
|
||||
},
|
||||
|
@ -192,9 +188,7 @@ func TestUserInfoEndpoint_SetDefaultMethod(t *testing.T) {
|
|||
HasWebauthn: false,
|
||||
HasDuo: true,
|
||||
},
|
||||
config: &schema.Configuration{
|
||||
DuoAPI: &schema.DuoAPIConfiguration{},
|
||||
},
|
||||
config: &schema.Configuration{},
|
||||
loadErr: nil,
|
||||
saveErr: nil,
|
||||
},
|
||||
|
@ -212,6 +206,7 @@ func TestUserInfoEndpoint_SetDefaultMethod(t *testing.T) {
|
|||
HasWebauthn: false,
|
||||
HasDuo: true,
|
||||
},
|
||||
config: &schema.Configuration{DuoAPI: schema.DuoAPIConfiguration{Disable: true}},
|
||||
loadErr: nil,
|
||||
saveErr: nil,
|
||||
},
|
||||
|
@ -233,7 +228,6 @@ func TestUserInfoEndpoint_SetDefaultMethod(t *testing.T) {
|
|||
TOTP: schema.TOTPConfiguration{
|
||||
Disable: true,
|
||||
},
|
||||
DuoAPI: &schema.DuoAPIConfiguration{},
|
||||
},
|
||||
loadErr: nil,
|
||||
saveErr: nil,
|
||||
|
@ -252,104 +246,104 @@ func TestUserInfoEndpoint_SetDefaultMethod(t *testing.T) {
|
|||
HasWebauthn: true,
|
||||
HasDuo: true,
|
||||
},
|
||||
config: &schema.Configuration{
|
||||
DuoAPI: &schema.DuoAPIConfiguration{},
|
||||
},
|
||||
config: &schema.Configuration{},
|
||||
loadErr: nil,
|
||||
saveErr: errors.New("could not save"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, resp := range expectedResponses {
|
||||
if resp.api == nil {
|
||||
resp.api = &resp.db
|
||||
}
|
||||
t.Run(resp.description, func(t *testing.T) {
|
||||
if resp.api == nil {
|
||||
resp.api = &resp.db
|
||||
}
|
||||
|
||||
mock := mocks.NewMockAutheliaCtx(t)
|
||||
mock := mocks.NewMockAutheliaCtx(t)
|
||||
|
||||
if resp.config != nil {
|
||||
mock.Ctx.Configuration = *resp.config
|
||||
}
|
||||
if resp.config != nil {
|
||||
mock.Ctx.Configuration = *resp.config
|
||||
}
|
||||
|
||||
// Set the initial user session.
|
||||
userSession := mock.Ctx.GetSession()
|
||||
userSession.Username = testUsername
|
||||
userSession.AuthenticationLevel = 1
|
||||
err := mock.Ctx.SaveSession(userSession)
|
||||
require.NoError(t, err)
|
||||
// Set the initial user session.
|
||||
userSession := mock.Ctx.GetSession()
|
||||
userSession.Username = testUsername
|
||||
userSession.AuthenticationLevel = 1
|
||||
err := mock.Ctx.SaveSession(userSession)
|
||||
require.NoError(t, err)
|
||||
|
||||
if resp.db.Method == "" {
|
||||
gomock.InOrder(
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
LoadPreferred2FAMethod(mock.Ctx, gomock.Eq("john")).
|
||||
Return("", sql.ErrNoRows),
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
SavePreferred2FAMethod(mock.Ctx, gomock.Eq("john"), gomock.Eq("")).
|
||||
Return(resp.saveErr),
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
LoadUserInfo(mock.Ctx, gomock.Eq("john")).
|
||||
Return(resp.db, nil),
|
||||
mock.StorageMock.EXPECT().
|
||||
SavePreferred2FAMethod(mock.Ctx, gomock.Eq("john"), gomock.Eq(resp.api.Method)).
|
||||
Return(resp.saveErr),
|
||||
)
|
||||
} else {
|
||||
gomock.InOrder(
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
LoadPreferred2FAMethod(mock.Ctx, gomock.Eq("john")).
|
||||
Return(resp.db.Method, nil),
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
LoadUserInfo(mock.Ctx, gomock.Eq("john")).
|
||||
Return(resp.db, nil),
|
||||
mock.StorageMock.EXPECT().
|
||||
SavePreferred2FAMethod(mock.Ctx, gomock.Eq("john"), gomock.Eq(resp.api.Method)).
|
||||
Return(resp.saveErr),
|
||||
)
|
||||
}
|
||||
if resp.db.Method == "" {
|
||||
gomock.InOrder(
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
LoadPreferred2FAMethod(mock.Ctx, gomock.Eq("john")).
|
||||
Return("", sql.ErrNoRows),
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
SavePreferred2FAMethod(mock.Ctx, gomock.Eq("john"), gomock.Eq("")).
|
||||
Return(resp.saveErr),
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
LoadUserInfo(mock.Ctx, gomock.Eq("john")).
|
||||
Return(resp.db, nil),
|
||||
mock.StorageMock.EXPECT().
|
||||
SavePreferred2FAMethod(mock.Ctx, gomock.Eq("john"), gomock.Eq(resp.api.Method)).
|
||||
Return(resp.saveErr),
|
||||
)
|
||||
} else {
|
||||
gomock.InOrder(
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
LoadPreferred2FAMethod(mock.Ctx, gomock.Eq("john")).
|
||||
Return(resp.db.Method, nil),
|
||||
mock.StorageMock.
|
||||
EXPECT().
|
||||
LoadUserInfo(mock.Ctx, gomock.Eq("john")).
|
||||
Return(resp.db, nil),
|
||||
mock.StorageMock.EXPECT().
|
||||
SavePreferred2FAMethod(mock.Ctx, gomock.Eq("john"), gomock.Eq(resp.api.Method)).
|
||||
Return(resp.saveErr),
|
||||
)
|
||||
}
|
||||
|
||||
UserInfoPOST(mock.Ctx)
|
||||
UserInfoPOST(mock.Ctx)
|
||||
|
||||
if resp.loadErr == nil && resp.saveErr == nil {
|
||||
t.Run(fmt.Sprintf("%s/%s", resp.description, "expected status code"), func(t *testing.T) {
|
||||
assert.Equal(t, 200, mock.Ctx.Response.StatusCode())
|
||||
})
|
||||
if resp.loadErr == nil && resp.saveErr == nil {
|
||||
t.Run(fmt.Sprintf("%s/%s", resp.description, "expected status code"), func(t *testing.T) {
|
||||
assert.Equal(t, 200, mock.Ctx.Response.StatusCode())
|
||||
})
|
||||
|
||||
actualPreferences := model.UserInfo{}
|
||||
actualPreferences := model.UserInfo{}
|
||||
|
||||
mock.GetResponseData(t, &actualPreferences)
|
||||
mock.GetResponseData(t, &actualPreferences)
|
||||
|
||||
t.Run(fmt.Sprintf("%s/%s", resp.description, "expected method"), func(t *testing.T) {
|
||||
assert.Equal(t, resp.api.Method, actualPreferences.Method)
|
||||
})
|
||||
t.Run("expected method", func(t *testing.T) {
|
||||
assert.Equal(t, resp.api.Method, actualPreferences.Method)
|
||||
})
|
||||
|
||||
t.Run(fmt.Sprintf("%s/%s", resp.description, "registered webauthn"), func(t *testing.T) {
|
||||
assert.Equal(t, resp.api.HasWebauthn, actualPreferences.HasWebauthn)
|
||||
})
|
||||
t.Run("registered webauthn", func(t *testing.T) {
|
||||
assert.Equal(t, resp.api.HasWebauthn, actualPreferences.HasWebauthn)
|
||||
})
|
||||
|
||||
t.Run(fmt.Sprintf("%s/%s", resp.description, "registered totp"), func(t *testing.T) {
|
||||
assert.Equal(t, resp.api.HasTOTP, actualPreferences.HasTOTP)
|
||||
})
|
||||
t.Run("registered totp", func(t *testing.T) {
|
||||
assert.Equal(t, resp.api.HasTOTP, actualPreferences.HasTOTP)
|
||||
})
|
||||
|
||||
t.Run(fmt.Sprintf("%s/%s", resp.description, "registered duo"), func(t *testing.T) {
|
||||
assert.Equal(t, resp.api.HasDuo, actualPreferences.HasDuo)
|
||||
})
|
||||
} else {
|
||||
t.Run("expected status code", func(t *testing.T) {
|
||||
assert.Equal(t, 200, mock.Ctx.Response.StatusCode())
|
||||
})
|
||||
t.Run("registered duo", func(t *testing.T) {
|
||||
assert.Equal(t, resp.api.HasDuo, actualPreferences.HasDuo)
|
||||
})
|
||||
} else {
|
||||
t.Run("expected status code", func(t *testing.T) {
|
||||
assert.Equal(t, 200, mock.Ctx.Response.StatusCode())
|
||||
})
|
||||
|
||||
errResponse := mock.GetResponseError(t)
|
||||
errResponse := mock.GetResponseError(t)
|
||||
|
||||
assert.Equal(t, "KO", errResponse.Status)
|
||||
assert.Equal(t, "Operation failed.", errResponse.Message)
|
||||
}
|
||||
assert.Equal(t, "KO", errResponse.Status)
|
||||
assert.Equal(t, "Operation failed.", errResponse.Message)
|
||||
}
|
||||
|
||||
mock.Close()
|
||||
mock.Close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,7 +414,7 @@ func (s *SaveSuite) TestShouldReturnError500WhenBadMethodProvided() {
|
|||
MethodPreferencePOST(s.mock.Ctx)
|
||||
|
||||
s.mock.Assert200KO(s.T(), "Operation failed.")
|
||||
assert.Equal(s.T(), "unknown or unavailable method 'abc', it should be one of totp, webauthn", s.mock.Hook.LastEntry().Message)
|
||||
assert.Equal(s.T(), "unknown or unavailable method 'abc', it should be one of totp, webauthn, mobile_push", s.mock.Hook.LastEntry().Message)
|
||||
assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level)
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ func (ctx *AutheliaCtx) AvailableSecondFactorMethods() (methods []string) {
|
|||
methods = append(methods, model.SecondFactorMethodWebauthn)
|
||||
}
|
||||
|
||||
if ctx.Configuration.DuoAPI != nil {
|
||||
if !ctx.Configuration.DuoAPI.Disable {
|
||||
methods = append(methods, model.SecondFactorMethodDuo)
|
||||
}
|
||||
|
||||
|
|
|
@ -121,9 +121,11 @@ func TestShouldReturnCorrectSecondFactorMethods(t *testing.T) {
|
|||
mock := mocks.NewMockAutheliaCtx(t)
|
||||
defer mock.Close()
|
||||
|
||||
mock.Ctx.Configuration.DuoAPI.Disable = true
|
||||
|
||||
assert.Equal(t, []string{model.SecondFactorMethodTOTP, model.SecondFactorMethodWebauthn}, mock.Ctx.AvailableSecondFactorMethods())
|
||||
|
||||
mock.Ctx.Configuration.DuoAPI = &schema.DuoAPIConfiguration{}
|
||||
mock.Ctx.Configuration.DuoAPI.Disable = false
|
||||
|
||||
assert.Equal(t, []string{model.SecondFactorMethodTOTP, model.SecondFactorMethodWebauthn, model.SecondFactorMethodDuo}, mock.Ctx.AvailableSecondFactorMethods())
|
||||
|
||||
|
@ -135,7 +137,7 @@ func TestShouldReturnCorrectSecondFactorMethods(t *testing.T) {
|
|||
|
||||
assert.Equal(t, []string{model.SecondFactorMethodDuo}, mock.Ctx.AvailableSecondFactorMethods())
|
||||
|
||||
mock.Ctx.Configuration.DuoAPI = nil
|
||||
mock.Ctx.Configuration.DuoAPI.Disable = true
|
||||
|
||||
assert.Equal(t, []string{}, mock.Ctx.AvailableSecondFactorMethods())
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ func IdentityVerificationStart(args IdentityVerificationStartArgs, delayFunc Tim
|
|||
bufHTML := new(bytes.Buffer)
|
||||
|
||||
disableHTML := false
|
||||
if ctx.Configuration.Notifier != nil && ctx.Configuration.Notifier.SMTP != nil {
|
||||
if ctx.Configuration.Notifier.SMTP != nil {
|
||||
disableHTML = ctx.Configuration.Notifier.SMTP.DisableHTMLEmails
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
|
|||
resetPasswordCustomURL := config.AuthenticationBackend.PasswordReset.CustomURL.String()
|
||||
|
||||
duoSelfEnrollment := f
|
||||
if config.DuoAPI != nil {
|
||||
if !config.DuoAPI.Disable {
|
||||
duoSelfEnrollment = strconv.FormatBool(config.DuoAPI.EnableSelfEnrollment)
|
||||
}
|
||||
|
||||
|
@ -184,7 +184,7 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
|
|||
}
|
||||
|
||||
// Configure DUO api endpoint only if configuration exists.
|
||||
if config.DuoAPI != nil {
|
||||
if !config.DuoAPI.Disable {
|
||||
var duoAPI duo.API
|
||||
if os.Getenv("ENVIRONMENT") == dev {
|
||||
duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi(
|
||||
|
|
Loading…
Reference in New Issue