forked from mystiq/dex
*: switch to github.com/ghodss/yaml for more consistent YAML parsing
ghodss/yaml converts from YAML to JSON before attempting to unmarshal. This allows us to: * Get the correct behavor when decoding base64'd []byte slices. * Use *json.RawMessage. * Not have to support extravagant YAML features. * Let our structs use `json:` tags
This commit is contained in:
parent
74eaec60cb
commit
aa7f304bc1
13 changed files with 185 additions and 238 deletions
1
TODO.md
1
TODO.md
|
@ -48,4 +48,3 @@ Backend
|
||||||
|
|
||||||
- [ ] Improve logging, possibly switch to logrus
|
- [ ] Improve logging, possibly switch to logrus
|
||||||
- [ ] Standardize OAuth2 error handling
|
- [ ] Standardize OAuth2 error handling
|
||||||
- [ ] Switch to github.com/ghodss/yaml for []byte to base64 string logic
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/coreos/dex/connector"
|
"github.com/coreos/dex/connector"
|
||||||
|
@ -18,129 +18,58 @@ import (
|
||||||
|
|
||||||
// Config is the config format for the main application.
|
// Config is the config format for the main application.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Issuer string `yaml:"issuer"`
|
Issuer string `json:"issuer"`
|
||||||
Storage Storage `yaml:"storage"`
|
Storage Storage `json:"storage"`
|
||||||
Connectors []Connector `yaml:"connectors"`
|
Connectors []Connector `json:"connectors"`
|
||||||
Web Web `yaml:"web"`
|
Web Web `json:"web"`
|
||||||
OAuth2 OAuth2 `yaml:"oauth2"`
|
OAuth2 OAuth2 `json:"oauth2"`
|
||||||
GRPC GRPC `yaml:"grpc"`
|
GRPC GRPC `json:"grpc"`
|
||||||
|
|
||||||
Templates server.TemplateConfig `yaml:"templates"`
|
Templates server.TemplateConfig `json:"templates"`
|
||||||
|
|
||||||
// StaticClients cause the server to use this list of clients rather than
|
// StaticClients cause the server to use this list of clients rather than
|
||||||
// querying the storage. Write operations, like creating a client, will fail.
|
// querying the storage. Write operations, like creating a client, will fail.
|
||||||
StaticClients []storage.Client `yaml:"staticClients"`
|
StaticClients []storage.Client `json:"staticClients"`
|
||||||
|
|
||||||
// If enabled, the server will maintain a list of passwords which can be used
|
// If enabled, the server will maintain a list of passwords which can be used
|
||||||
// to identify a user.
|
// to identify a user.
|
||||||
EnablePasswordDB bool `yaml:"enablePasswordDB"`
|
EnablePasswordDB bool `json:"enablePasswordDB"`
|
||||||
|
|
||||||
// StaticPasswords cause the server use this list of passwords rather than
|
// StaticPasswords cause the server use this list of passwords rather than
|
||||||
// querying the storage. Cannot be specified without enabling a passwords
|
// querying the storage. Cannot be specified without enabling a passwords
|
||||||
// database.
|
// database.
|
||||||
//
|
StaticPasswords []storage.Password `json:"staticPasswords"`
|
||||||
// The "password" type is identical to the storage.Password type, but does
|
|
||||||
// unmarshaling into []byte correctly.
|
|
||||||
StaticPasswords []password `yaml:"staticPasswords"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type password struct {
|
|
||||||
Email string `yaml:"email"`
|
|
||||||
Username string `yaml:"username"`
|
|
||||||
UserID string `yaml:"userID"`
|
|
||||||
|
|
||||||
// Because our YAML parser doesn't base64, we have to do it ourselves.
|
|
||||||
//
|
|
||||||
// TODO(ericchiang): switch to github.com/ghodss/yaml
|
|
||||||
Hash string `yaml:"hash"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode the hash appropriately and convert to the storage passwords.
|
|
||||||
func (p password) toPassword() (storage.Password, error) {
|
|
||||||
hash, err := base64.StdEncoding.DecodeString(p.Hash)
|
|
||||||
if err != nil {
|
|
||||||
return storage.Password{}, fmt.Errorf("decoding hash: %v", err)
|
|
||||||
}
|
|
||||||
return storage.Password{
|
|
||||||
Email: p.Email,
|
|
||||||
Username: p.Username,
|
|
||||||
UserID: p.UserID,
|
|
||||||
Hash: hash,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OAuth2 describes enabled OAuth2 extensions.
|
// OAuth2 describes enabled OAuth2 extensions.
|
||||||
type OAuth2 struct {
|
type OAuth2 struct {
|
||||||
ResponseTypes []string `yaml:"responseTypes"`
|
ResponseTypes []string `json:"responseTypes"`
|
||||||
// If specified, do not prompt the user to approve client authorization. The
|
// If specified, do not prompt the user to approve client authorization. The
|
||||||
// act of logging in implies authorization.
|
// act of logging in implies authorization.
|
||||||
SkipApprovalScreen bool `yaml:"skipApprovalScreen"`
|
SkipApprovalScreen bool `json:"skipApprovalScreen"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web is the config format for the HTTP server.
|
// Web is the config format for the HTTP server.
|
||||||
type Web struct {
|
type Web struct {
|
||||||
HTTP string `yaml:"http"`
|
HTTP string `json:"http"`
|
||||||
HTTPS string `yaml:"https"`
|
HTTPS string `json:"https"`
|
||||||
TLSCert string `yaml:"tlsCert"`
|
TLSCert string `json:"tlsCert"`
|
||||||
TLSKey string `yaml:"tlsKey"`
|
TLSKey string `json:"tlsKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GRPC is the config for the gRPC API.
|
// GRPC is the config for the gRPC API.
|
||||||
type GRPC struct {
|
type GRPC struct {
|
||||||
// The port to listen on.
|
// The port to listen on.
|
||||||
Addr string `yaml:"addr"`
|
Addr string `json:"addr"`
|
||||||
TLSCert string `yaml:"tlsCert"`
|
TLSCert string `json:"tlsCert"`
|
||||||
TLSKey string `yaml:"tlsKey"`
|
TLSKey string `json:"tlsKey"`
|
||||||
TLSClientCA string `yaml:"tlsClientCA"`
|
TLSClientCA string `json:"tlsClientCA"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage holds app's storage configuration.
|
// Storage holds app's storage configuration.
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
Type string `yaml:"type"`
|
Type string `json:"type"`
|
||||||
Config StorageConfig `yaml:"config"`
|
Config StorageConfig `json:"config"`
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalYAML allows Storage to unmarshal its config field dynamically
|
|
||||||
// depending on the type of storage.
|
|
||||||
func (s *Storage) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var storageMeta struct {
|
|
||||||
Type string `yaml:"type"`
|
|
||||||
}
|
|
||||||
if err := unmarshal(&storageMeta); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.Type = storageMeta.Type
|
|
||||||
// TODO(ericchiang): replace this with a registration process.
|
|
||||||
var err error
|
|
||||||
switch storageMeta.Type {
|
|
||||||
case "kubernetes":
|
|
||||||
var config struct {
|
|
||||||
Config kubernetes.Config `yaml:"config"`
|
|
||||||
}
|
|
||||||
err = unmarshal(&config)
|
|
||||||
s.Config = &config.Config
|
|
||||||
case "memory":
|
|
||||||
var config struct {
|
|
||||||
Config memory.Config `yaml:"config"`
|
|
||||||
}
|
|
||||||
err = unmarshal(&config)
|
|
||||||
s.Config = &config.Config
|
|
||||||
case "sqlite3":
|
|
||||||
var config struct {
|
|
||||||
Config sql.SQLite3 `yaml:"config"`
|
|
||||||
}
|
|
||||||
err = unmarshal(&config)
|
|
||||||
s.Config = &config.Config
|
|
||||||
case "postgres":
|
|
||||||
var config struct {
|
|
||||||
Config sql.Postgres `yaml:"config"`
|
|
||||||
}
|
|
||||||
err = unmarshal(&config)
|
|
||||||
s.Config = &config.Config
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown storage type %q", storageMeta.Type)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageConfig is a configuration that can create a storage.
|
// StorageConfig is a configuration that can create a storage.
|
||||||
|
@ -148,14 +77,49 @@ type StorageConfig interface {
|
||||||
Open() (storage.Storage, error)
|
Open() (storage.Storage, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var storages = map[string]func() StorageConfig{
|
||||||
|
"kubernetes": func() StorageConfig { return new(kubernetes.Config) },
|
||||||
|
"memory": func() StorageConfig { return new(memory.Config) },
|
||||||
|
"sqlite3": func() StorageConfig { return new(sql.SQLite3) },
|
||||||
|
"postgres": func() StorageConfig { return new(sql.Postgres) },
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON allows Storage to implement the unmarshaler interface to
|
||||||
|
// dynamically determine the type of the storage config.
|
||||||
|
func (s *Storage) 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 := storages[store.Type]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unknown storage type %q", store.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
storageConfig := f()
|
||||||
|
if len(store.Config) != 0 {
|
||||||
|
if err := json.Unmarshal([]byte(store.Config), storageConfig); err != nil {
|
||||||
|
return fmt.Errorf("parse storace config: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*s = Storage{
|
||||||
|
Type: store.Type,
|
||||||
|
Config: storageConfig,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Connector is a magical type that can unmarshal YAML dynamically. The
|
// Connector is a magical type that can unmarshal YAML dynamically. The
|
||||||
// Type field determines the connector type, which is then customized for Config.
|
// Type field determines the connector type, which is then customized for Config.
|
||||||
type Connector struct {
|
type Connector struct {
|
||||||
Type string `yaml:"type"`
|
Type string `json:"type"`
|
||||||
Name string `yaml:"name"`
|
Name string `json:"name"`
|
||||||
ID string `yaml:"id"`
|
ID string `json:"id"`
|
||||||
|
|
||||||
Config ConnectorConfig `yaml:"config"`
|
Config ConnectorConfig `json:"config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnectorConfig is a configuration that can open a connector.
|
// ConnectorConfig is a configuration that can open a connector.
|
||||||
|
@ -163,55 +127,43 @@ type ConnectorConfig interface {
|
||||||
Open() (connector.Connector, error)
|
Open() (connector.Connector, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML allows Connector to unmarshal its config field dynamically
|
var connectors = map[string]func() ConnectorConfig{
|
||||||
// depending on the type of connector.
|
"mockCallback": func() ConnectorConfig { return new(mock.CallbackConfig) },
|
||||||
func (c *Connector) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
"mockPassword": func() ConnectorConfig { return new(mock.PasswordConfig) },
|
||||||
var connectorMetadata struct {
|
"ldap": func() ConnectorConfig { return new(ldap.Config) },
|
||||||
Type string `yaml:"type"`
|
"github": func() ConnectorConfig { return new(github.Config) },
|
||||||
Name string `yaml:"name"`
|
"oidc": func() ConnectorConfig { return new(oidc.Config) },
|
||||||
ID string `yaml:"id"`
|
}
|
||||||
}
|
|
||||||
if err := unmarshal(&connectorMetadata); err != nil {
|
// UnmarshalJSON allows Connector to implement the unmarshaler interface to
|
||||||
return err
|
// dynamically determine the type of the connector config.
|
||||||
}
|
func (c *Connector) UnmarshalJSON(b []byte) error {
|
||||||
c.Type = connectorMetadata.Type
|
var conn struct {
|
||||||
c.Name = connectorMetadata.Name
|
Type string `json:"type"`
|
||||||
c.ID = connectorMetadata.ID
|
Name string `json:"name"`
|
||||||
|
ID string `json:"id"`
|
||||||
var err error
|
|
||||||
switch c.Type {
|
Config json.RawMessage `json:"config"`
|
||||||
case "mockCallback":
|
}
|
||||||
var config struct {
|
if err := json.Unmarshal(b, &conn); err != nil {
|
||||||
Config mock.CallbackConfig `yaml:"config"`
|
return fmt.Errorf("parse connector: %v", err)
|
||||||
}
|
}
|
||||||
err = unmarshal(&config)
|
f, ok := connectors[conn.Type]
|
||||||
c.Config = &config.Config
|
if !ok {
|
||||||
case "mockPassword":
|
return fmt.Errorf("unknown connector type %q", conn.Type)
|
||||||
var config struct {
|
}
|
||||||
Config mock.PasswordConfig `yaml:"config"`
|
|
||||||
}
|
connConfig := f()
|
||||||
err = unmarshal(&config)
|
if len(conn.Config) != 0 {
|
||||||
c.Config = &config.Config
|
if err := json.Unmarshal([]byte(conn.Config), connConfig); err != nil {
|
||||||
case "ldap":
|
return fmt.Errorf("parse connector config: %v", err)
|
||||||
var config struct {
|
}
|
||||||
Config ldap.Config `yaml:"config"`
|
}
|
||||||
}
|
*c = Connector{
|
||||||
err = unmarshal(&config)
|
Type: conn.Type,
|
||||||
c.Config = &config.Config
|
Name: conn.Type,
|
||||||
case "github":
|
ID: conn.ID,
|
||||||
var config struct {
|
Config: connConfig,
|
||||||
Config github.Config `yaml:"config"`
|
}
|
||||||
}
|
return nil
|
||||||
err = unmarshal(&config)
|
|
||||||
c.Config = &config.Config
|
|
||||||
case "oidc":
|
|
||||||
var config struct {
|
|
||||||
Config oidc.Config `yaml:"config"`
|
|
||||||
}
|
|
||||||
err = unmarshal(&config)
|
|
||||||
c.Config = &config.Config
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown connector type %q", c.Type)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,11 +11,11 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
yaml "gopkg.in/yaml.v2"
|
|
||||||
|
|
||||||
"github.com/coreos/dex/api"
|
"github.com/coreos/dex/api"
|
||||||
"github.com/coreos/dex/server"
|
"github.com/coreos/dex/server"
|
||||||
|
@ -136,13 +136,7 @@ func serve(cmd *cobra.Command, args []string) error {
|
||||||
s = storage.WithStaticClients(s, c.StaticClients)
|
s = storage.WithStaticClients(s, c.StaticClients)
|
||||||
}
|
}
|
||||||
if len(c.StaticPasswords) > 0 {
|
if len(c.StaticPasswords) > 0 {
|
||||||
p := make([]storage.Password, len(c.StaticPasswords))
|
s = storage.WithStaticPasswords(s, c.StaticPasswords)
|
||||||
for i, pw := range c.StaticPasswords {
|
|
||||||
if p[i], err = pw.toPassword(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = storage.WithStaticPasswords(s, p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfig := server.Config{
|
serverConfig := server.Config{
|
||||||
|
|
|
@ -19,10 +19,10 @@ const baseURL = "https://api.github.com"
|
||||||
|
|
||||||
// Config holds configuration options for github logins.
|
// Config holds configuration options for github logins.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ClientID string `yaml:"clientID"`
|
ClientID string `json:"clientID"`
|
||||||
ClientSecret string `yaml:"clientSecret"`
|
ClientSecret string `json:"clientSecret"`
|
||||||
RedirectURI string `yaml:"redirectURI"`
|
RedirectURI string `json:"redirectURI"`
|
||||||
Org string `yaml:"org"`
|
Org string `json:"org"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open returns a strategy for logging in through GitHub.
|
// Open returns a strategy for logging in through GitHub.
|
||||||
|
|
|
@ -53,52 +53,52 @@ import (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// The host and optional port of the LDAP server. If port isn't supplied, it will be
|
// The host and optional port of the LDAP server. If port isn't supplied, it will be
|
||||||
// guessed based on the TLS configuration. 389 or 636.
|
// guessed based on the TLS configuration. 389 or 636.
|
||||||
Host string `yaml:"host"`
|
Host string `json:"host"`
|
||||||
|
|
||||||
// Required if LDAP host does not use TLS.
|
// Required if LDAP host does not use TLS.
|
||||||
InsecureNoSSL bool `yaml:"insecureNoSSL"`
|
InsecureNoSSL bool `json:"insecureNoSSL"`
|
||||||
|
|
||||||
// Path to a trusted root certificate file.
|
// Path to a trusted root certificate file.
|
||||||
RootCA string `yaml:"rootCA"`
|
RootCA string `json:"rootCA"`
|
||||||
|
|
||||||
// BindDN and BindPW for an application service account. The connector uses these
|
// BindDN and BindPW for an application service account. The connector uses these
|
||||||
// credentials to search for users and groups.
|
// credentials to search for users and groups.
|
||||||
BindDN string `yaml:"bindDN"`
|
BindDN string `json:"bindDN"`
|
||||||
BindPW string `yaml:"bindPW"`
|
BindPW string `json:"bindPW"`
|
||||||
|
|
||||||
// User entry search configuration.
|
// User entry search configuration.
|
||||||
UserSearch struct {
|
UserSearch struct {
|
||||||
// BsaeDN to start the search from. For example "cn=users,dc=example,dc=com"
|
// BsaeDN to start the search from. For example "cn=users,dc=example,dc=com"
|
||||||
BaseDN string `yaml:"baseDN"`
|
BaseDN string `json:"baseDN"`
|
||||||
|
|
||||||
// Optional filter to apply when searching the directory. For example "(objectClass=person)"
|
// Optional filter to apply when searching the directory. For example "(objectClass=person)"
|
||||||
Filter string `yaml:"filter"`
|
Filter string `json:"filter"`
|
||||||
|
|
||||||
// Attribute to match against the inputted username. This will be translated and combined
|
// Attribute to match against the inputted username. This will be translated and combined
|
||||||
// with the other filter as "(<attr>=<username>)".
|
// with the other filter as "(<attr>=<username>)".
|
||||||
Username string `yaml:"username"`
|
Username string `json:"username"`
|
||||||
|
|
||||||
// Can either be:
|
// Can either be:
|
||||||
// * "sub" - search the whole sub tree
|
// * "sub" - search the whole sub tree
|
||||||
// * "one" - only search one level
|
// * "one" - only search one level
|
||||||
Scope string `yaml:"scope"`
|
Scope string `json:"scope"`
|
||||||
|
|
||||||
// A mapping of attributes on the user entry to claims.
|
// A mapping of attributes on the user entry to claims.
|
||||||
IDAttr string `yaml:"idAttr"` // Defaults to "uid"
|
IDAttr string `json:"idAttr"` // Defaults to "uid"
|
||||||
EmailAttr string `yaml:"emailAttr"` // Defaults to "mail"
|
EmailAttr string `json:"emailAttr"` // Defaults to "mail"
|
||||||
NameAttr string `yaml:"nameAttr"` // No default.
|
NameAttr string `json:"nameAttr"` // No default.
|
||||||
|
|
||||||
} `yaml:"userSearch"`
|
} `json:"userSearch"`
|
||||||
|
|
||||||
// Group search configuration.
|
// Group search configuration.
|
||||||
GroupSearch struct {
|
GroupSearch struct {
|
||||||
// BsaeDN to start the search from. For example "cn=groups,dc=example,dc=com"
|
// BsaeDN to start the search from. For example "cn=groups,dc=example,dc=com"
|
||||||
BaseDN string `yaml:"baseDN"`
|
BaseDN string `json:"baseDN"`
|
||||||
|
|
||||||
// Optional filter to apply when searching the directory. For example "(objectClass=posixGroup)"
|
// Optional filter to apply when searching the directory. For example "(objectClass=posixGroup)"
|
||||||
Filter string `yaml:"filter"`
|
Filter string `json:"filter"`
|
||||||
|
|
||||||
Scope string `yaml:"scope"` // Defaults to "sub"
|
Scope string `json:"scope"` // Defaults to "sub"
|
||||||
|
|
||||||
// These two fields are use to match a user to a group.
|
// These two fields are use to match a user to a group.
|
||||||
//
|
//
|
||||||
|
@ -108,12 +108,12 @@ type Config struct {
|
||||||
//
|
//
|
||||||
// (<groupAttr>=<userAttr value>)
|
// (<groupAttr>=<userAttr value>)
|
||||||
//
|
//
|
||||||
UserAttr string `yaml:"userAttr"`
|
UserAttr string `json:"userAttr"`
|
||||||
GroupAttr string `yaml:"groupAttr"`
|
GroupAttr string `json:"groupAttr"`
|
||||||
|
|
||||||
// The attribute of the group that represents its name.
|
// The attribute of the group that represents its name.
|
||||||
NameAttr string `yaml:"nameAttr"`
|
NameAttr string `json:"nameAttr"`
|
||||||
} `yaml:"groupSearch"`
|
} `json:"groupSearch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseScope(s string) (int, bool) {
|
func parseScope(s string) (int, bool) {
|
||||||
|
|
|
@ -69,8 +69,8 @@ func (c *CallbackConfig) Open() (connector.Connector, error) {
|
||||||
// PasswordConfig holds the configuration for a mock connector which prompts for the supplied
|
// PasswordConfig holds the configuration for a mock connector which prompts for the supplied
|
||||||
// username and password.
|
// username and password.
|
||||||
type PasswordConfig struct {
|
type PasswordConfig struct {
|
||||||
Username string `yaml:"username"`
|
Username string `json:"username"`
|
||||||
Password string `yaml:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open returns an authentication strategy which prompts for a predefined username and password.
|
// Open returns an authentication strategy which prompts for a predefined username and password.
|
||||||
|
|
|
@ -15,12 +15,12 @@ import (
|
||||||
|
|
||||||
// Config holds configuration options for OpenID Connect logins.
|
// Config holds configuration options for OpenID Connect logins.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Issuer string `yaml:"issuer"`
|
Issuer string `json:"issuer"`
|
||||||
ClientID string `yaml:"clientID"`
|
ClientID string `json:"clientID"`
|
||||||
ClientSecret string `yaml:"clientSecret"`
|
ClientSecret string `json:"clientSecret"`
|
||||||
RedirectURI string `yaml:"redirectURI"`
|
RedirectURI string `json:"redirectURI"`
|
||||||
|
|
||||||
Scopes []string `yaml:"scopes"` // defaults to "profile" and "email"
|
Scopes []string `json:"scopes"` // defaults to "profile" and "email"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open returns a connector which can be used to login users through an upstream
|
// Open returns a connector which can be used to login users through an upstream
|
||||||
|
|
6
glide.lock
generated
6
glide.lock
generated
|
@ -1,5 +1,5 @@
|
||||||
hash: a813cbca07393d7cbe35d411cdef588afac7a3bab8a287ffe7b9587516ef5898
|
hash: bc7fa6bbfddcb39710064a9d6dab090d49bd88486571cae12c68c4b70093e716
|
||||||
updated: 2016-10-23T20:51:55.313818678-07:00
|
updated: 2016-11-03T14:31:37.323302694-07:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/cockroachdb/cockroach-go
|
- name: github.com/cockroachdb/cockroach-go
|
||||||
version: 31611c0501c812f437d4861d87d117053967c955
|
version: 31611c0501c812f437d4861d87d117053967c955
|
||||||
|
@ -7,6 +7,8 @@ imports:
|
||||||
- crdb
|
- crdb
|
||||||
- name: github.com/ericchiang/oidc
|
- name: github.com/ericchiang/oidc
|
||||||
version: 1907f0e61549f9081f26bdf269f11603496c9dee
|
version: 1907f0e61549f9081f26bdf269f11603496c9dee
|
||||||
|
- name: github.com/ghodss/yaml
|
||||||
|
version: bea76d6a4713e18b7f5321a2b020738552def3ea
|
||||||
- name: github.com/go-sql-driver/mysql
|
- name: github.com/go-sql-driver/mysql
|
||||||
version: 0b58b37b664c21f3010e836f1b931e1d0b0b0685
|
version: 0b58b37b664c21f3010e836f1b931e1d0b0b0685
|
||||||
- name: github.com/golang/protobuf
|
- name: github.com/golang/protobuf
|
||||||
|
|
|
@ -21,9 +21,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
"github.com/gtank/cryptopasta"
|
"github.com/gtank/cryptopasta"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
yaml "gopkg.in/yaml.v2"
|
|
||||||
|
|
||||||
"github.com/coreos/dex/storage"
|
"github.com/coreos/dex/storage"
|
||||||
"github.com/coreos/dex/storage/kubernetes/k8sapi"
|
"github.com/coreos/dex/storage/kubernetes/k8sapi"
|
||||||
|
|
|
@ -23,124 +23,124 @@ package k8sapi
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Legacy field from pkg/api/types.go TypeMeta.
|
// Legacy field from pkg/api/types.go TypeMeta.
|
||||||
// TODO(jlowdermilk): remove this after eliminating downstream dependencies.
|
// TODO(jlowdermilk): remove this after eliminating downstream dependencies.
|
||||||
Kind string `yaml:"kind,omitempty"`
|
Kind string `json:"kind,omitempty"`
|
||||||
// DEPRECATED: APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc).
|
// DEPRECATED: APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc).
|
||||||
// Because a cluster can run multiple API groups and potentially multiple versions of each, it no longer makes sense to specify
|
// Because a cluster can run multiple API groups and potentially multiple versions of each, it no longer makes sense to specify
|
||||||
// a single value for the cluster version.
|
// a single value for the cluster version.
|
||||||
// This field isn't really needed anyway, so we are deprecating it without replacement.
|
// This field isn't really needed anyway, so we are deprecating it without replacement.
|
||||||
// It will be ignored if it is present.
|
// It will be ignored if it is present.
|
||||||
APIVersion string `yaml:"apiVersion,omitempty"`
|
APIVersion string `json:"apiVersion,omitempty"`
|
||||||
// Preferences holds general information to be use for cli interactions
|
// Preferences holds general information to be use for cli interactions
|
||||||
Preferences Preferences `yaml:"preferences"`
|
Preferences Preferences `json:"preferences"`
|
||||||
// Clusters is a map of referencable names to cluster configs
|
// Clusters is a map of referencable names to cluster configs
|
||||||
Clusters []NamedCluster `yaml:"clusters"`
|
Clusters []NamedCluster `json:"clusters"`
|
||||||
// AuthInfos is a map of referencable names to user configs
|
// AuthInfos is a map of referencable names to user configs
|
||||||
AuthInfos []NamedAuthInfo `yaml:"users"`
|
AuthInfos []NamedAuthInfo `json:"users"`
|
||||||
// Contexts is a map of referencable names to context configs
|
// Contexts is a map of referencable names to context configs
|
||||||
Contexts []NamedContext `yaml:"contexts"`
|
Contexts []NamedContext `json:"contexts"`
|
||||||
// CurrentContext is the name of the context that you would like to use by default
|
// CurrentContext is the name of the context that you would like to use by default
|
||||||
CurrentContext string `yaml:"current-context"`
|
CurrentContext string `json:"current-context"`
|
||||||
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
||||||
Extensions []NamedExtension `yaml:"extensions,omitempty"`
|
Extensions []NamedExtension `json:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preferences contains information about the users command line experience preferences.
|
// Preferences contains information about the users command line experience preferences.
|
||||||
type Preferences struct {
|
type Preferences struct {
|
||||||
Colors bool `yaml:"colors,omitempty"`
|
Colors bool `json:"colors,omitempty"`
|
||||||
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
||||||
Extensions []NamedExtension `yaml:"extensions,omitempty"`
|
Extensions []NamedExtension `json:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cluster contains information about how to communicate with a kubernetes cluster
|
// Cluster contains information about how to communicate with a kubernetes cluster
|
||||||
type Cluster struct {
|
type Cluster struct {
|
||||||
// Server is the address of the kubernetes cluster (https://hostname:port).
|
// Server is the address of the kubernetes cluster (https://hostname:port).
|
||||||
Server string `yaml:"server"`
|
Server string `json:"server"`
|
||||||
// APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc).
|
// APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc).
|
||||||
APIVersion string `yaml:"api-version,omitempty"`
|
APIVersion string `json:"api-version,omitempty"`
|
||||||
// InsecureSkipTLSVerify skips the validity check for the server's certificate. This will make your HTTPS connections insecure.
|
// InsecureSkipTLSVerify skips the validity check for the server's certificate. This will make your HTTPS connections insecure.
|
||||||
InsecureSkipTLSVerify bool `yaml:"insecure-skip-tls-verify,omitempty"`
|
InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"`
|
||||||
// CertificateAuthority is the path to a cert file for the certificate authority.
|
// CertificateAuthority is the path to a cert file for the certificate authority.
|
||||||
CertificateAuthority string `yaml:"certificate-authority,omitempty"`
|
CertificateAuthority string `json:"certificate-authority,omitempty"`
|
||||||
// CertificateAuthorityData contains PEM-encoded certificate authority certificates. Overrides CertificateAuthority
|
// CertificateAuthorityData contains PEM-encoded certificate authority certificates. Overrides CertificateAuthority
|
||||||
//
|
//
|
||||||
// NOTE(ericchiang): Our yaml parser doesn't assume []byte is a base64 encoded string.
|
// NOTE(ericchiang): Our yaml parser doesn't assume []byte is a base64 encoded string.
|
||||||
CertificateAuthorityData string `yaml:"certificate-authority-data,omitempty"`
|
CertificateAuthorityData string `json:"certificate-authority-data,omitempty"`
|
||||||
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
||||||
Extensions []NamedExtension `yaml:"extensions,omitempty"`
|
Extensions []NamedExtension `json:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthInfo contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
|
// AuthInfo contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
|
||||||
type AuthInfo struct {
|
type AuthInfo struct {
|
||||||
// ClientCertificate is the path to a client cert file for TLS.
|
// ClientCertificate is the path to a client cert file for TLS.
|
||||||
ClientCertificate string `yaml:"client-certificate,omitempty"`
|
ClientCertificate string `json:"client-certificate,omitempty"`
|
||||||
// ClientCertificateData contains PEM-encoded data from a client cert file for TLS. Overrides ClientCertificate
|
// ClientCertificateData contains PEM-encoded data from a client cert file for TLS. Overrides ClientCertificate
|
||||||
//
|
//
|
||||||
// NOTE(ericchiang): Our yaml parser doesn't assume []byte is a base64 encoded string.
|
// NOTE(ericchiang): Our yaml parser doesn't assume []byte is a base64 encoded string.
|
||||||
ClientCertificateData string `yaml:"client-certificate-data,omitempty"`
|
ClientCertificateData string `json:"client-certificate-data,omitempty"`
|
||||||
// ClientKey is the path to a client key file for TLS.
|
// ClientKey is the path to a client key file for TLS.
|
||||||
ClientKey string `yaml:"client-key,omitempty"`
|
ClientKey string `json:"client-key,omitempty"`
|
||||||
// ClientKeyData contains PEM-encoded data from a client key file for TLS. Overrides ClientKey
|
// ClientKeyData contains PEM-encoded data from a client key file for TLS. Overrides ClientKey
|
||||||
//
|
//
|
||||||
// NOTE(ericchiang): Our yaml parser doesn't assume []byte is a base64 encoded string.
|
// NOTE(ericchiang): Our yaml parser doesn't assume []byte is a base64 encoded string.
|
||||||
ClientKeyData string `yaml:"client-key-data,omitempty"`
|
ClientKeyData string `json:"client-key-data,omitempty"`
|
||||||
// Token is the bearer token for authentication to the kubernetes cluster.
|
// Token is the bearer token for authentication to the kubernetes cluster.
|
||||||
Token string `yaml:"token,omitempty"`
|
Token string `json:"token,omitempty"`
|
||||||
// Impersonate is the username to imperonate. The name matches the flag.
|
// Impersonate is the username to imperonate. The name matches the flag.
|
||||||
Impersonate string `yaml:"as,omitempty"`
|
Impersonate string `json:"as,omitempty"`
|
||||||
// Username is the username for basic authentication to the kubernetes cluster.
|
// Username is the username for basic authentication to the kubernetes cluster.
|
||||||
Username string `yaml:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
// Password is the password for basic authentication to the kubernetes cluster.
|
// Password is the password for basic authentication to the kubernetes cluster.
|
||||||
Password string `yaml:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
// AuthProvider specifies a custom authentication plugin for the kubernetes cluster.
|
// AuthProvider specifies a custom authentication plugin for the kubernetes cluster.
|
||||||
AuthProvider *AuthProviderConfig `yaml:"auth-provider,omitempty"`
|
AuthProvider *AuthProviderConfig `json:"auth-provider,omitempty"`
|
||||||
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
||||||
Extensions []NamedExtension `yaml:"extensions,omitempty"`
|
Extensions []NamedExtension `json:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context is a tuple of references to a cluster (how do I communicate with a kubernetes cluster), a user (how do I identify myself), and a namespace (what subset of resources do I want to work with)
|
// Context is a tuple of references to a cluster (how do I communicate with a kubernetes cluster), a user (how do I identify myself), and a namespace (what subset of resources do I want to work with)
|
||||||
type Context struct {
|
type Context struct {
|
||||||
// Cluster is the name of the cluster for this context
|
// Cluster is the name of the cluster for this context
|
||||||
Cluster string `yaml:"cluster"`
|
Cluster string `json:"cluster"`
|
||||||
// AuthInfo is the name of the authInfo for this context
|
// AuthInfo is the name of the authInfo for this context
|
||||||
AuthInfo string `yaml:"user"`
|
AuthInfo string `json:"user"`
|
||||||
// Namespace is the default namespace to use on unspecified requests
|
// Namespace is the default namespace to use on unspecified requests
|
||||||
Namespace string `yaml:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty"`
|
||||||
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
// Extensions holds additional information. This is useful for extenders so that reads and writes don't clobber unknown fields
|
||||||
Extensions []NamedExtension `yaml:"extensions,omitempty"`
|
Extensions []NamedExtension `json:"extensions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamedCluster relates nicknames to cluster information
|
// NamedCluster relates nicknames to cluster information
|
||||||
type NamedCluster struct {
|
type NamedCluster struct {
|
||||||
// Name is the nickname for this Cluster
|
// Name is the nickname for this Cluster
|
||||||
Name string `yaml:"name"`
|
Name string `json:"name"`
|
||||||
// Cluster holds the cluster information
|
// Cluster holds the cluster information
|
||||||
Cluster Cluster `yaml:"cluster"`
|
Cluster Cluster `json:"cluster"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamedContext relates nicknames to context information
|
// NamedContext relates nicknames to context information
|
||||||
type NamedContext struct {
|
type NamedContext struct {
|
||||||
// Name is the nickname for this Context
|
// Name is the nickname for this Context
|
||||||
Name string `yaml:"name"`
|
Name string `json:"name"`
|
||||||
// Context holds the context information
|
// Context holds the context information
|
||||||
Context Context `yaml:"context"`
|
Context Context `json:"context"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamedAuthInfo relates nicknames to auth information
|
// NamedAuthInfo relates nicknames to auth information
|
||||||
type NamedAuthInfo struct {
|
type NamedAuthInfo struct {
|
||||||
// Name is the nickname for this AuthInfo
|
// Name is the nickname for this AuthInfo
|
||||||
Name string `yaml:"name"`
|
Name string `json:"name"`
|
||||||
// AuthInfo holds the auth information
|
// AuthInfo holds the auth information
|
||||||
AuthInfo AuthInfo `yaml:"user"`
|
AuthInfo AuthInfo `json:"user"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamedExtension relates nicknames to extension information
|
// NamedExtension relates nicknames to extension information
|
||||||
type NamedExtension struct {
|
type NamedExtension struct {
|
||||||
// Name is the nickname for this Extension
|
// Name is the nickname for this Extension
|
||||||
Name string `yaml:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AuthProviderConfig holds the configuration for a specified auth provider.
|
// AuthProviderConfig holds the configuration for a specified auth provider.
|
||||||
type AuthProviderConfig struct {
|
type AuthProviderConfig struct {
|
||||||
Name string `yaml:"name"`
|
Name string `json:"name"`
|
||||||
Config map[string]string `yaml:"config"`
|
Config map[string]string `json:"config"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,8 @@ const (
|
||||||
|
|
||||||
// Config values for the Kubernetes storage type.
|
// Config values for the Kubernetes storage type.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
InCluster bool `yaml:"inCluster"`
|
InCluster bool `json:"inCluster"`
|
||||||
KubeConfigFile string `yaml:"kubeConfigFile"`
|
KubeConfigFile string `json:"kubeConfigFile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open returns a storage using Kubernetes third party resource.
|
// Open returns a storage using Kubernetes third party resource.
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
// SQLite3 options for creating an SQL db.
|
// SQLite3 options for creating an SQL db.
|
||||||
type SQLite3 struct {
|
type SQLite3 struct {
|
||||||
// File to
|
// File to
|
||||||
File string `yaml:"file"`
|
File string `json:"file"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open creates a new storage implementation backed by SQLite3
|
// Open creates a new storage implementation backed by SQLite3
|
||||||
|
|
|
@ -247,16 +247,16 @@ type Password struct {
|
||||||
//
|
//
|
||||||
// Storages that don't support an extended character set for IDs, such as '.' and '@'
|
// Storages that don't support an extended character set for IDs, such as '.' and '@'
|
||||||
// (cough cough, kubernetes), must map this value appropriately.
|
// (cough cough, kubernetes), must map this value appropriately.
|
||||||
Email string `yaml:"email"`
|
Email string `json:"email"`
|
||||||
|
|
||||||
// Bcrypt encoded hash of the password. This package enforces a min cost value of 10
|
// Bcrypt encoded hash of the password. This package enforces a min cost value of 10
|
||||||
Hash []byte `yaml:"hash"`
|
Hash []byte `json:"hash"`
|
||||||
|
|
||||||
// Optional username to display. NOT used during login.
|
// Optional username to display. NOT used during login.
|
||||||
Username string `yaml:"username"`
|
Username string `json:"username"`
|
||||||
|
|
||||||
// Randomly generated user ID. This is NOT the primary ID of the Password object.
|
// Randomly generated user ID. This is NOT the primary ID of the Password object.
|
||||||
UserID string `yaml:"userID"`
|
UserID string `json:"userID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerificationKey is a rotated signing key which can still be used to verify
|
// VerificationKey is a rotated signing key which can still be used to verify
|
||||||
|
|
Loading…
Reference in a new issue