mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-05-17 09:40:14 +00:00
* feat: add support for oauth whitelist file (#817) * Merge branch 'main' into feat/oauth-whitelist-file * fix: fix conflicts * tests: use testify for testing --------- Co-authored-by: Stavros <steveiliop56@gmail.com>
This commit is contained in:
@@ -91,6 +91,8 @@ TINYAUTH_APPS_name_LDAP_GROUPS=
|
|||||||
|
|
||||||
# Comma-separated list of allowed OAuth domains.
|
# Comma-separated list of allowed OAuth domains.
|
||||||
TINYAUTH_OAUTH_WHITELIST=
|
TINYAUTH_OAUTH_WHITELIST=
|
||||||
|
# Path to the OAuth whitelist file.
|
||||||
|
TINYAUTH_OAUTH_WHITELISTFILE=
|
||||||
# The OAuth provider to use for automatic redirection.
|
# The OAuth provider to use for automatic redirection.
|
||||||
TINYAUTH_OAUTH_AUTOREDIRECT=
|
TINYAUTH_OAUTH_AUTOREDIRECT=
|
||||||
# OAuth client ID.
|
# OAuth client ID.
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type BootstrapApp struct {
|
|||||||
oauthSessionCookieName string
|
oauthSessionCookieName string
|
||||||
localUsers *[]model.LocalUser
|
localUsers *[]model.LocalUser
|
||||||
oauthProviders map[string]model.OAuthServiceConfig
|
oauthProviders map[string]model.OAuthServiceConfig
|
||||||
|
oauthWhitelist []string
|
||||||
configuredProviders []controller.Provider
|
configuredProviders []controller.Provider
|
||||||
oidcClients []model.OIDCClientConfig
|
oidcClients []model.OIDCClientConfig
|
||||||
}
|
}
|
||||||
@@ -71,6 +72,13 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
|
|
||||||
app.context.localUsers = users
|
app.context.localUsers = users
|
||||||
|
|
||||||
|
oauthWhitelist, err := utils.GetStringList(app.config.OAuth.Whitelist, app.config.OAuth.WhitelistFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
app.context.oauthWhitelist = oauthWhitelist
|
||||||
|
|
||||||
// Setup OAuth providers
|
// Setup OAuth providers
|
||||||
app.context.oauthProviders = app.config.OAuth.Providers
|
app.context.oauthProviders = app.config.OAuth.Providers
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ func (app *BootstrapApp) initServices(queries *repository.Queries) (Services, er
|
|||||||
|
|
||||||
authService := service.NewAuthService(service.AuthServiceConfig{
|
authService := service.NewAuthService(service.AuthServiceConfig{
|
||||||
LocalUsers: app.context.localUsers,
|
LocalUsers: app.context.localUsers,
|
||||||
OauthWhitelist: app.config.OAuth.Whitelist,
|
OauthWhitelist: app.context.oauthWhitelist,
|
||||||
SessionExpiry: app.config.Auth.SessionExpiry,
|
SessionExpiry: app.config.Auth.SessionExpiry,
|
||||||
SessionMaxLifetime: app.config.Auth.SessionMaxLifetime,
|
SessionMaxLifetime: app.config.Auth.SessionMaxLifetime,
|
||||||
SecureCookie: app.config.Auth.SecureCookie,
|
SecureCookie: app.config.Auth.SecureCookie,
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ type IPConfig struct {
|
|||||||
|
|
||||||
type OAuthConfig struct {
|
type OAuthConfig struct {
|
||||||
Whitelist []string `description:"Comma-separated list of allowed OAuth domains." yaml:"whitelist"`
|
Whitelist []string `description:"Comma-separated list of allowed OAuth domains." yaml:"whitelist"`
|
||||||
|
WhitelistFile string `description:"Path to the OAuth whitelist file." yaml:"whitelistFile"`
|
||||||
AutoRedirect string `description:"The OAuth provider to use for automatic redirection." yaml:"autoRedirect"`
|
AutoRedirect string `description:"The OAuth provider to use for automatic redirection." yaml:"autoRedirect"`
|
||||||
Providers map[string]OAuthServiceConfig `description:"OAuth providers configuration." yaml:"providers"`
|
Providers map[string]OAuthServiceConfig `description:"OAuth providers configuration." yaml:"providers"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,3 +28,41 @@ func CoalesceToString(value any) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ParseNonEmptyLines(contents string) []string {
|
||||||
|
lines := make([]string, 0)
|
||||||
|
|
||||||
|
for line := range strings.SplitSeq(contents, "\n") {
|
||||||
|
lineTrimmed := strings.TrimSpace(line)
|
||||||
|
if lineTrimmed == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lines = append(lines, lineTrimmed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStringList(valuesCfg []string, valuesPath string) ([]string, error) {
|
||||||
|
values := make([]string, 0, len(valuesCfg))
|
||||||
|
|
||||||
|
for _, value := range valuesCfg {
|
||||||
|
valueTrimmed := strings.TrimSpace(value)
|
||||||
|
if valueTrimmed == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
values = append(values, valueTrimmed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if valuesPath == "" {
|
||||||
|
return values, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
contents, err := ReadFile(valuesPath)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
values = append(values, ParseNonEmptyLines(contents)...)
|
||||||
|
return values, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package utils_test
|
package utils_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -56,3 +57,33 @@ func TestCompileUserEmail(t *testing.T) {
|
|||||||
// Test with invalid email
|
// Test with invalid email
|
||||||
assert.Equal(t, "user@example.com", utils.CompileUserEmail("user", "example.com"))
|
assert.Equal(t, "user@example.com", utils.CompileUserEmail("user", "example.com"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseNonEmptyLines(t *testing.T) {
|
||||||
|
lines := utils.ParseNonEmptyLines(" first@example.com \n\n second@example.com \n \n")
|
||||||
|
|
||||||
|
assert.Equal(t, []string{"first@example.com", "second@example.com"}, lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetStringList(t *testing.T) {
|
||||||
|
file, err := os.Create("/tmp/tinyauth_list_test_file")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = file.WriteString(" third@example.com \n\n fourth@example.com \n")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = file.Close()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer os.Remove("/tmp/tinyauth_list_test_file")
|
||||||
|
|
||||||
|
values, err := utils.GetStringList([]string{" first@example.com ", "", "second@example.com"}, "/tmp/tinyauth_list_test_file")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []string{"first@example.com", "second@example.com", "third@example.com", "fourth@example.com"}, values)
|
||||||
|
|
||||||
|
values, err = utils.GetStringList(nil, "")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, []string{}, values)
|
||||||
|
|
||||||
|
values, err = utils.GetStringList(nil, "/tmp/non_existing_list_file")
|
||||||
|
assert.ErrorContains(t, err, "no such file or directory")
|
||||||
|
assert.Equal(t, []string{}, values)
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ func ParseUsers(usersStr []string, userAttributes map[string]model.UserAttribute
|
|||||||
var users []model.LocalUser
|
var users []model.LocalUser
|
||||||
|
|
||||||
if len(usersStr) == 0 {
|
if len(usersStr) == 0 {
|
||||||
return &users, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, user := range usersStr {
|
for _, user := range usersStr {
|
||||||
@@ -34,32 +34,9 @@ func ParseUsers(usersStr []string, userAttributes map[string]model.UserAttribute
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetUsers(usersCfg []string, usersPath string, userAttributes map[string]model.UserAttributes) (*[]model.LocalUser, error) {
|
func GetUsers(usersCfg []string, usersPath string, userAttributes map[string]model.UserAttributes) (*[]model.LocalUser, error) {
|
||||||
var usersStr []string
|
usersStr, err := GetStringList(usersCfg, usersPath)
|
||||||
|
if err != nil {
|
||||||
if len(usersCfg) == 0 && usersPath == "" {
|
return nil, err
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(usersCfg) > 0 {
|
|
||||||
usersStr = append(usersStr, usersCfg...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if usersPath != "" {
|
|
||||||
contents, err := ReadFile(usersPath)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
lines := strings.SplitSeq(contents, "\n")
|
|
||||||
|
|
||||||
for line := range lines {
|
|
||||||
lineTrimmed := strings.TrimSpace(line)
|
|
||||||
if lineTrimmed == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
usersStr = append(usersStr, lineTrimmed)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseUsers(usersStr, userAttributes)
|
return ParseUsers(usersStr, userAttributes)
|
||||||
|
|||||||
Reference in New Issue
Block a user