mirror of
https://github.com/MirageNetwork/MirageServer.git
synced 2025-09-26 20:41:34 +08:00
220 lines
6.3 KiB
Go
220 lines
6.3 KiB
Go
package controller
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
dexlog "github.com/dexidp/dex/pkg/log"
|
|
"github.com/dexidp/dex/server"
|
|
"github.com/dexidp/dex/storage"
|
|
"github.com/dexidp/dex/storage/ent"
|
|
"github.com/dexidp/dex/storage/etcd"
|
|
"github.com/dexidp/dex/storage/kubernetes"
|
|
"github.com/dexidp/dex/storage/memory"
|
|
"github.com/dexidp/dex/storage/sql"
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
// Storage holds app's storage configuration.
|
|
type DexStorage struct {
|
|
Type string `json:"type"`
|
|
Config DexStorageConfig `json:"config"`
|
|
}
|
|
|
|
// StorageConfig is a configuration that can create a storage.
|
|
type DexStorageConfig interface {
|
|
Open(logger dexlog.Logger) (storage.Storage, error)
|
|
}
|
|
|
|
var (
|
|
_ DexStorageConfig = (*etcd.Etcd)(nil)
|
|
_ DexStorageConfig = (*kubernetes.Config)(nil)
|
|
_ DexStorageConfig = (*memory.Config)(nil)
|
|
_ DexStorageConfig = (*sql.SQLite3)(nil)
|
|
_ DexStorageConfig = (*sql.Postgres)(nil)
|
|
_ DexStorageConfig = (*sql.MySQL)(nil)
|
|
_ DexStorageConfig = (*ent.SQLite3)(nil)
|
|
_ DexStorageConfig = (*ent.Postgres)(nil)
|
|
_ DexStorageConfig = (*ent.MySQL)(nil)
|
|
)
|
|
|
|
func getORMBasedSQLStorage(normal, entBased DexStorageConfig) func() DexStorageConfig {
|
|
return func() DexStorageConfig {
|
|
switch os.Getenv("DEX_ENT_ENABLED") {
|
|
case "true", "yes":
|
|
return entBased
|
|
default:
|
|
return normal
|
|
}
|
|
}
|
|
}
|
|
|
|
var dexstorages = map[string]func() DexStorageConfig{
|
|
"etcd": func() DexStorageConfig { return new(etcd.Etcd) },
|
|
"kubernetes": func() DexStorageConfig { return new(kubernetes.Config) },
|
|
"memory": func() DexStorageConfig { return new(memory.Config) },
|
|
"sqlite3": getORMBasedSQLStorage(&sql.SQLite3{}, &ent.SQLite3{}),
|
|
"postgres": getORMBasedSQLStorage(&sql.Postgres{}, &ent.Postgres{}),
|
|
"mysql": getORMBasedSQLStorage(&sql.MySQL{}, &ent.MySQL{}),
|
|
}
|
|
|
|
// isExpandEnvEnabled returns if os.ExpandEnv should be used for each storage and connector config.
|
|
// Disabling this feature avoids surprises e.g. if the LDAP bind password contains a dollar character.
|
|
// Returns false if the env variable "DEX_EXPAND_ENV" is a falsy string, e.g. "false".
|
|
// Returns true if the env variable is unset or a truthy string, e.g. "true", or can't be parsed as bool.
|
|
func isExpandEnvEnabled() bool {
|
|
enabled, err := strconv.ParseBool(os.Getenv("DEX_EXPAND_ENV"))
|
|
if err != nil {
|
|
// Unset, empty string or can't be parsed as bool: Default = true.
|
|
return true
|
|
}
|
|
return enabled
|
|
}
|
|
|
|
// UnmarshalJSON allows Storage to implement the unmarshaler interface to
|
|
// dynamically determine the type of the storage config.
|
|
func (s *DexStorage) UnmarshalJSON(b []byte) error {
|
|
var store struct {
|
|
Type string `json:"type"`
|
|
Config json.RawMessage `json:"config"`
|
|
}
|
|
if err := json.Unmarshal(b, &store); err != nil {
|
|
return fmt.Errorf("parse storage: %v", err)
|
|
}
|
|
f, ok := dexstorages[store.Type]
|
|
if !ok {
|
|
return fmt.Errorf("unknown storage type %q", store.Type)
|
|
}
|
|
|
|
storageConfig := f()
|
|
if len(store.Config) != 0 {
|
|
data := []byte(store.Config)
|
|
if isExpandEnvEnabled() {
|
|
// Caution, we're expanding in the raw JSON/YAML source. This may not be what the admin expects.
|
|
data = []byte(os.ExpandEnv(string(store.Config)))
|
|
}
|
|
if err := json.Unmarshal(data, storageConfig); err != nil {
|
|
return fmt.Errorf("parse storage config: %v", err)
|
|
}
|
|
}
|
|
*s = DexStorage{
|
|
Type: store.Type,
|
|
Config: storageConfig,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Connector is a magical type that can unmarshal YAML dynamically. The
|
|
// Type field determines the connector type, which is then customized for Config.
|
|
type Connector struct {
|
|
Type string `json:"type"`
|
|
Name string `json:"name"`
|
|
ID string `json:"id"`
|
|
|
|
Config server.ConnectorConfig `json:"config"`
|
|
}
|
|
|
|
// UnmarshalJSON allows Connector to implement the unmarshaler interface to
|
|
// dynamically determine the type of the connector config.
|
|
func (c *Connector) UnmarshalJSON(b []byte) error {
|
|
var conn struct {
|
|
Type string `json:"type"`
|
|
Name string `json:"name"`
|
|
ID string `json:"id"`
|
|
|
|
Config json.RawMessage `json:"config"`
|
|
}
|
|
if err := json.Unmarshal(b, &conn); err != nil {
|
|
return fmt.Errorf("parse connector: %v", err)
|
|
}
|
|
f, ok := server.ConnectorsConfig[conn.Type]
|
|
if !ok {
|
|
return fmt.Errorf("unknown connector type %q", conn.Type)
|
|
}
|
|
|
|
connConfig := f()
|
|
if len(conn.Config) != 0 {
|
|
data := []byte(conn.Config)
|
|
if isExpandEnvEnabled() {
|
|
// Caution, we're expanding in the raw JSON/YAML source. This may not be what the admin expects.
|
|
data = []byte(os.ExpandEnv(string(conn.Config)))
|
|
}
|
|
if err := json.Unmarshal(data, connConfig); err != nil {
|
|
return fmt.Errorf("parse connector config: %v", err)
|
|
}
|
|
}
|
|
*c = Connector{
|
|
Type: conn.Type,
|
|
Name: conn.Name,
|
|
ID: conn.ID,
|
|
Config: connConfig,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ToStorageConnector converts an object to storage connector type.
|
|
func ToStorageConnector(c Connector) (storage.Connector, error) {
|
|
data, err := json.Marshal(c.Config)
|
|
if err != nil {
|
|
return storage.Connector{}, fmt.Errorf("failed to marshal connector config: %v", err)
|
|
}
|
|
|
|
return storage.Connector{
|
|
ID: c.ID,
|
|
Type: c.Type,
|
|
Name: c.Name,
|
|
Config: data,
|
|
}, nil
|
|
}
|
|
|
|
func newLogger(level string) (dexlog.Logger, error) {
|
|
var logLevel zerolog.Level
|
|
switch strings.ToLower(level) {
|
|
case "debug":
|
|
logLevel = zerolog.DebugLevel
|
|
case "", "info":
|
|
logLevel = zerolog.InfoLevel
|
|
case "error":
|
|
logLevel = zerolog.ErrorLevel
|
|
default:
|
|
return nil, fmt.Errorf("log level is not one of the supported values : %s", level)
|
|
}
|
|
|
|
return &zlog{
|
|
Logger: log.Logger.Level(logLevel).With().Logger(),
|
|
}, nil
|
|
}
|
|
|
|
type zlog struct {
|
|
Logger zerolog.Logger
|
|
}
|
|
|
|
func (zl *zlog) Debug(args ...interface{}) {
|
|
zl.Logger.Debug().Msg(fmt.Sprint(args...))
|
|
}
|
|
func (zl *zlog) Info(args ...interface{}) {
|
|
zl.Logger.Info().Msg(fmt.Sprint(args...))
|
|
}
|
|
func (zl *zlog) Warn(args ...interface{}) {
|
|
zl.Logger.Warn().Msg(fmt.Sprint(args...))
|
|
}
|
|
func (zl *zlog) Error(args ...interface{}) {
|
|
zl.Logger.Error().Msg(fmt.Sprint(args...))
|
|
}
|
|
func (zl *zlog) Debugf(format string, args ...interface{}) {
|
|
zl.Logger.Debug().Msgf(format, args...)
|
|
}
|
|
func (zl *zlog) Infof(format string, args ...interface{}) {
|
|
zl.Logger.Info().Msgf(format, args...)
|
|
}
|
|
func (zl *zlog) Warnf(format string, args ...interface{}) {
|
|
zl.Logger.Warn().Msgf(format, args...)
|
|
}
|
|
func (zl *zlog) Errorf(format string, args ...interface{}) {
|
|
zl.Logger.Error().Msgf(format, args...)
|
|
}
|