From 73c7353be33b538847531aa7d760528d36f7c50b Mon Sep 17 00:00:00 2001 From: Paul Greenberg Date: Sat, 23 Mar 2024 03:08:23 -0400 Subject: [PATCH] feature: allow configuration of default admin, user, and guest roles --- pkg/authn/config.go | 81 ++++++++++++++++++++++++++++++++++++++++ pkg/authn/portal_test.go | 12 +++++- server_test.go | 15 +++++++- 3 files changed, 106 insertions(+), 2 deletions(-) diff --git a/pkg/authn/config.go b/pkg/authn/config.go index 3c6c0bd..959664e 100644 --- a/pkg/authn/config.go +++ b/pkg/authn/config.go @@ -15,6 +15,7 @@ package authn import ( + "regexp" "strings" "github.com/greenpau/go-authcrunch/pkg/acl" @@ -58,6 +59,23 @@ type PortalConfig struct { // TrustedLogoutRedirectURIConfigs holds the configuration of trusted logout redirect URIs. TrustedLogoutRedirectURIConfigs []*redirects.RedirectURIMatchConfig `json:"trusted_logout_redirect_uri_configs,omitempty" xml:"trusted_logout_redirect_uri_configs,omitempty" yaml:"trusted_logout_redirect_uri_configs,omitempty"` + // PortalAdminRoles holds the list of role names granted to do administrative tasks in the portal. + PortalAdminRoles map[string]interface{} `json:"portal_admin_roles,omitempty" xml:"portal_admin_roles,omitempty" yaml:"portal_admin_roles,omitempty"` + // PortalUserRoles holds the list of role names granted to do perform profile tasks in the portal. + PortalUserRoles map[string]interface{} `json:"portal_user_roles,omitempty" xml:"portal_user_roles,omitempty" yaml:"portal_user_roles,omitempty"` + // PortalGuestRoles holds the list of role names without admin or user privileges in the portal. + PortalGuestRoles map[string]interface{} `json:"portal_guest_roles,omitempty" xml:"portal_guest_roles,omitempty" yaml:"portal_guest_roles,omitempty"` + + // PortalAdminRolePatterns holds the list of regular expressions for the role names granted to do administrative tasks in the portal. + PortalAdminRolePatterns []string `json:"portal_admin_role_patterns,omitempty" xml:"portal_admin_role_patterns,omitempty" yaml:"portal_admin_role_patterns,omitempty"` + adminRolePatterns []*regexp.Regexp + // PortalUserRolePatterns holds the list of regular expressions for the role names granted to do perform profile tasks in the portal. + PortalUserRolePatterns []string `json:"portal_user_role_patterns,omitempty" xml:"portal_user_role_patterns,omitempty" yaml:"portal_user_role_patterns,omitempty"` + userRolePatterns []*regexp.Regexp + // PortalGuestRolePatterns holds the list of regular expressions for the role names without admin or user privileges in the portal. + PortalGuestRolePatterns []string `json:"portal_guest_role_patterns,omitempty" xml:"portal_guest_role_patterns,omitempty" yaml:"portal_guest_role_patterns,omitempty"` + guestRolePatterns []*regexp.Regexp + // API holds the configuration for API endpoints. API *APIConfig `json:"api,omitempty" xml:"api,omitempty" yaml:"api,omitempty"` @@ -116,6 +134,65 @@ func (cfg *PortalConfig) parseRawCryptoConfigs() error { return nil } +// parsePortalRoles validates the configuration of portal roles. +func (cfg *PortalConfig) parsePortalRoles() error { + if cfg.PortalAdminRoles == nil { + cfg.PortalAdminRoles = make(map[string]interface{}) + } + if len(cfg.PortalAdminRoles) < 1 { + cfg.PortalAdminRoles["authp/admin"] = true + } + + if cfg.PortalUserRoles == nil { + cfg.PortalUserRoles = make(map[string]interface{}) + } + if len(cfg.PortalUserRoles) < 1 { + cfg.PortalUserRoles["authp/user"] = true + } + + if cfg.PortalGuestRoles == nil { + cfg.PortalGuestRoles = make(map[string]interface{}) + } + if len(cfg.PortalGuestRoles) < 1 { + cfg.PortalGuestRoles["authp/guest"] = true + } + + for _, ptrn := range cfg.PortalAdminRolePatterns { + if ptrn == "" { + return errors.ErrInvalidConfiguration.WithArgs("portal", "admin role pattern is empty") + } + r, err := regexp.Compile(ptrn) + if err != nil { + return errors.ErrInvalidConfiguration.WithArgs("portal admin role pattern", err) + } + cfg.adminRolePatterns = append(cfg.adminRolePatterns, r) + } + + for _, ptrn := range cfg.PortalUserRolePatterns { + if ptrn == "" { + return errors.ErrInvalidConfiguration.WithArgs("portal", "user role pattern is empty") + } + r, err := regexp.Compile(ptrn) + if err != nil { + return errors.ErrInvalidConfiguration.WithArgs("portal user role pattern", err) + } + cfg.userRolePatterns = append(cfg.userRolePatterns, r) + } + + for _, ptrn := range cfg.PortalGuestRolePatterns { + if ptrn == "" { + return errors.ErrInvalidConfiguration.WithArgs("portal", "guest role pattern is empty") + } + r, err := regexp.Compile(ptrn) + if err != nil { + return errors.ErrInvalidConfiguration.WithArgs("portal guest role pattern", err) + } + cfg.guestRolePatterns = append(cfg.guestRolePatterns, r) + } + + return nil +} + // Validate validates PortalConfig. func (cfg *PortalConfig) Validate() error { if cfg.validated { @@ -129,6 +206,10 @@ func (cfg *PortalConfig) Validate() error { // return errors.ErrPortalConfigBackendsNotFound // } + if err := cfg.parsePortalRoles(); err != nil { + return err + } + if err := cfg.parseRawCryptoConfigs(); err != nil { return err } diff --git a/pkg/authn/portal_test.go b/pkg/authn/portal_test.go index 480c340..bb8965f 100644 --- a/pkg/authn/portal_test.go +++ b/pkg/authn/portal_test.go @@ -15,6 +15,8 @@ package authn import ( + "testing" + "github.com/google/go-cmp/cmp" "github.com/greenpau/go-authcrunch/internal/tests" "github.com/greenpau/go-authcrunch/internal/testutils" @@ -27,7 +29,6 @@ import ( "github.com/greenpau/go-authcrunch/pkg/ids" logutil "github.com/greenpau/go-authcrunch/pkg/util/log" "go.uber.org/zap" - "testing" ) func TestNewPortal(t *testing.T) { @@ -133,6 +134,15 @@ func TestNewPortal(t *testing.T) { "ui": { "theme": "basic" }, + "portal_admin_roles": { + "authp/admin": true + }, + "portal_user_roles": { + "authp/user": true + }, + "portal_guest_roles": { + "authp/guest": true + }, "token_validator_options": { "validate_bearer_header": true }, diff --git a/server_test.go b/server_test.go index 9a90f60..7bd9a78 100644 --- a/server_test.go +++ b/server_test.go @@ -16,21 +16,25 @@ package authcrunch import ( "fmt" + "github.com/google/go-cmp/cmp" "github.com/greenpau/go-authcrunch/internal/tests" "github.com/greenpau/go-authcrunch/internal/testutils" "github.com/greenpau/go-authcrunch/pkg/acl" "github.com/greenpau/go-authcrunch/pkg/authn" + // "github.com/greenpau/go-authcrunch/pkg/authn/registration" "github.com/greenpau/go-authcrunch/pkg/authz" "github.com/greenpau/go-authcrunch/pkg/credentials" + // "github.com/greenpau/go-authcrunch/pkg/errors" + "testing" + "github.com/greenpau/go-authcrunch/pkg/idp" "github.com/greenpau/go-authcrunch/pkg/ids" "github.com/greenpau/go-authcrunch/pkg/messaging" logutil "github.com/greenpau/go-authcrunch/pkg/util/log" "go.uber.org/zap" - "testing" ) func TestNewServer(t *testing.T) { @@ -153,6 +157,15 @@ func TestNewServer(t *testing.T) { "localdb" ], "name": "myportal", + "portal_admin_roles": { + "authp/admin": true + }, + "portal_user_roles": { + "authp/user": true + }, + "portal_guest_roles": { + "authp/guest": true + }, "token_validator_options": { "validate_bearer_header": true },