Newer
Older
"github.com/zachmann/mytoken/internal/utils/issuerUtils"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/zachmann/mytoken/internal/model"
"github.com/zachmann/mytoken/internal/utils/fileutil"
// Config holds the server configuration
type Config struct {
DB dbConf `yaml:"database"`
Server serverConf `yaml:"server"`
Providers []*ProviderConf `yaml:"providers"`
ProviderByIssuer map[string]*ProviderConf `yaml:"-"`
IssuerURL string `yaml:"issuer"`
EnabledOIDCFlows []model.OIDCFlow `yaml:"enabled_oidc_flows"`
EnabledSuperTokenEndpointGrantTypes []model.GrantType `yaml:"enabled_super_token_endpoint_grant_types"`
ServiceDocumentation string `yaml:"service_documentation"`
Polling pollingConf `yaml:"polling_codes"`
}
type pollingConf struct {
PollingCodeExpiresAfter int64 `yaml:"expires_after"`
PollingInterval int64 `yaml:"polling_interval"`
}
type dbConf struct {
Host string `yaml:"host"`
User string `yaml:"user"`
Password string `yaml:"password"`
DB string `yaml:"db"`
}
type serverConf struct {
Hostname string `yaml:"hostname"`
}
Alg string `yaml:"alg"`
KeyFile string `yaml:"key_file"`
RSAKeyLen int `yaml:"rsa_key_len"`
// ProviderConf holds information about a provider
type ProviderConf struct {
Issuer string `yaml:"issuer"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
Scopes []string `yaml:"scopes"`
Provider *oidc.Provider `yaml:"-"`
}
var conf *Config
// Get returns the config
func Get() *Config {
return conf
}
return fmt.Errorf("config not set")
}
if conf.Server.Hostname == "" {
return fmt.Errorf("invalid config: server.hostname not set")
}
return fmt.Errorf("invalid config: providers must have at least one entry")
}
for i, p := range conf.Providers {
if p.Issuer == "" {
return fmt.Errorf("invalid config: provider.issuer not set (Index %d)", i)
}
ctx := context.Background()
var err error
p.Provider, err = oidc.NewProvider(ctx, p.Issuer)
if err != nil {
return fmt.Errorf("Error '%s' for provider.issuer '%s' (Index %d)", err, p.Issuer, i)
}
if p.ClientID == "" {
return fmt.Errorf("invalid config: provider.clientid not set (Index %d)", i)
}
if p.ClientSecret == "" {
return fmt.Errorf("invalid config: provider.clientsecret not set (Index %d)", i)
}
return fmt.Errorf("invalid config: provider.scopes not set (Index %d)", i)
}
iss0, iss1 := issuerUtils.GetIssuerWithAndWithoutSlash(p.Issuer)
conf.ProviderByIssuer[iss0] = p
conf.ProviderByIssuer[iss1] = p
if conf.IssuerURL == "" {
return fmt.Errorf("invalid config: issuerurl not set")
}
return fmt.Errorf("invalid config: signingkeyfile not set")
}
return fmt.Errorf("invalid config: tokensigningalg not set")
}
if conf.Polling.PollingInterval == 0 {
conf.Polling.PollingInterval = 5
}
if conf.Polling.PollingCodeExpiresAfter == 0 {
conf.Polling.PollingCodeExpiresAfter = 300
}
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
model.OIDCFlowAuthorizationCode.AddToSliceIfNotFound(conf.EnabledOIDCFlows)
model.GrantTypeOIDCFlow.AddToSliceIfNotFound(conf.EnabledSuperTokenEndpointGrantTypes)
model.GrantTypeSuperToken.AddToSliceIfNotFound(conf.EnabledSuperTokenEndpointGrantTypes)
return nil
}
var possibleConfigLocations = []string{
"config",
"/etc/mytoken",
}
// readConfigFile checks if a file exists in one of the configuration
// directories and returns the content. If no file is found, mytoken exists.
func readConfigFile(filename string) []byte {
for _, dir := range possibleConfigLocations {
filep := filepath.Join(dir, filename)
if strings.HasPrefix(filep, "~") {
homeDir := os.Getenv("HOME")
filep = filepath.Join(homeDir, filep[1:])
}
log.Printf("Looking for config file at: %s\n", filep)
if fileutil.FileExists(filep) {
return fileutil.MustReadFile(filep)
}
}
fmt.Printf("Could not find config file %s in any of the possible directories\n", filename)
os.Exit(1)
return nil
}
// Load reads the config file and populates the config struct; then validates the config
func Load() {
load()
if err := validate(); err != nil {
log.Fatal(err)
}
}
func load() {
err := yaml.Unmarshal(data, conf)
if err != nil {
log.Fatal(err)
return
}
}
// LoadForSetup reads the config file and populates the config struct; it does not validate the config, since this is not required for setup
func LoadForSetup() {
load()
func newConfig() *Config {
return &Config{
ProviderByIssuer: make(map[string]*ProviderConf),
}
}