mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-27 11:09:04 +01:00
Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
co-authored by
Elias Schneider
parent
7c55bdf115
commit
1934efa84c
@@ -61,6 +61,8 @@ type AppConfigModel struct {
|
||||
LdapAttributeGroupName AppConfigValue `json:"ldapAttributeGroupName"`
|
||||
LdapAdminGroupName AppConfigValue `json:"ldapAdminGroupName"`
|
||||
LdapSoftDeleteUsers AppConfigValue `json:"ldapSoftDeleteUsers" type:"bool"`
|
||||
// OIDC
|
||||
CIMDURLAllowlist AppConfigValue `json:"cimdUrlAllowlist"` // JSON-encoded array of strings
|
||||
}
|
||||
|
||||
// Clone returns a deep copy of the AppConfigModel.
|
||||
@@ -145,6 +147,8 @@ func getDefaultConfig() *AppConfigModel {
|
||||
LdapAttributeGroupName: "",
|
||||
LdapAdminGroupName: "",
|
||||
LdapSoftDeleteUsers: "true",
|
||||
// OIDC
|
||||
CIMDURLAllowlist: "[]",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package appconfig
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -94,6 +95,24 @@ func (s *AppConfigService) GetConfig(parentCtx context.Context) (*AppConfigModel
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// GetCIMDURLAllowlist returns the configured CIMD metadata-document URL
|
||||
// allowlist. Returns an empty slice if unset or malformed (which denies all).
|
||||
func (s *AppConfigService) GetCIMDURLAllowlist() []string {
|
||||
cfg, err := s.GetConfig(context.Background())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
raw := string(cfg.CIMDURLAllowlist)
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
var patterns []string
|
||||
if err := json.Unmarshal([]byte(raw), &patterns); err != nil {
|
||||
return nil
|
||||
}
|
||||
return patterns
|
||||
}
|
||||
|
||||
// UpdateAppConfig replaces the entire application configuration with the values from the input DTO.
|
||||
func (s *AppConfigService) UpdateAppConfig(ctx context.Context, input dto.AppConfigUpdateDto) ([]AppConfigVariable, error) {
|
||||
// If the UI config is disabled, we cannot continue
|
||||
@@ -101,6 +120,19 @@ func (s *AppConfigService) UpdateAppConfig(ctx context.Context, input dto.AppCon
|
||||
return nil, &common.UiConfigDisabledError{}
|
||||
}
|
||||
|
||||
// Validate the CIMD URL allowlist patterns, if provided
|
||||
if input.CIMDURLAllowlist != "" {
|
||||
var patterns []string
|
||||
if err := json.Unmarshal([]byte(input.CIMDURLAllowlist), &patterns); err != nil {
|
||||
return nil, &common.InvalidCIMDURLPatternError{Pattern: input.CIMDURLAllowlist}
|
||||
}
|
||||
for _, p := range patterns {
|
||||
if err := utils.ValidateCallbackURLPattern(p); err != nil {
|
||||
return nil, &common.InvalidCIMDURLPatternError{Pattern: p}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the entire config by invoking the actor
|
||||
cfg, err := s.invokeConfigActor(ctx, "replace", input)
|
||||
if err != nil {
|
||||
|
||||
@@ -342,3 +342,53 @@ func TestService_ListAppConfig(t *testing.T) {
|
||||
assert.Equal(t, "XXXXXXXXXX", got)
|
||||
})
|
||||
}
|
||||
|
||||
func TestService_CIMDURLAllowlist(t *testing.T) {
|
||||
t.Run("defaults to empty", func(t *testing.T) {
|
||||
setUIConfigDisabled(t, false)
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
svc := newActorBackedService(t, db)
|
||||
|
||||
assert.Empty(t, svc.GetCIMDURLAllowlist())
|
||||
})
|
||||
|
||||
t.Run("round-trips a valid allowlist", func(t *testing.T) {
|
||||
setUIConfigDisabled(t, false)
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
svc := newActorBackedService(t, db)
|
||||
|
||||
_, err := svc.UpdateAppConfig(t.Context(), dto.AppConfigUpdateDto{
|
||||
AppName: "App",
|
||||
SessionDuration: "60",
|
||||
CIMDURLAllowlist: `["https://app.example.com/**","https://*.trusted.com/oauth"]`,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t,
|
||||
[]string{"https://app.example.com/**", "https://*.trusted.com/oauth"},
|
||||
svc.GetCIMDURLAllowlist(),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("rejects an invalid pattern", func(t *testing.T) {
|
||||
setUIConfigDisabled(t, false)
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
svc := newActorBackedService(t, db)
|
||||
|
||||
_, err := svc.UpdateAppConfig(t.Context(), dto.AppConfigUpdateDto{
|
||||
AppName: "App",
|
||||
SessionDuration: "60",
|
||||
CIMDURLAllowlist: `["javascript:alert(1)"]`,
|
||||
})
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("returns empty on malformed value", func(t *testing.T) {
|
||||
setUIConfigDisabled(t, false)
|
||||
db := testutils.NewDatabaseForTest(t)
|
||||
svc := newActorBackedService(t, db)
|
||||
|
||||
require.NoError(t, svc.UpdateAppConfigValues(t.Context(), "cimdUrlAllowlist", "not-json"))
|
||||
assert.Empty(t, svc.GetCIMDURLAllowlist())
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user