*: 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:
Eric Chiang 2016-11-03 14:32:23 -07:00
parent 74eaec60cb
commit aa7f304bc1
13 changed files with 185 additions and 238 deletions

View File

@ -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

View File

@ -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 {
return err
}
c.Type = connectorMetadata.Type
c.Name = connectorMetadata.Name
c.ID = connectorMetadata.ID
var err error // UnmarshalJSON allows Connector to implement the unmarshaler interface to
switch c.Type { // dynamically determine the type of the connector config.
case "mockCallback": func (c *Connector) UnmarshalJSON(b []byte) error {
var config struct { var conn struct {
Config mock.CallbackConfig `yaml:"config"` Type string `json:"type"`
Name string `json:"name"`
ID string `json:"id"`
Config json.RawMessage `json:"config"`
} }
err = unmarshal(&config) if err := json.Unmarshal(b, &conn); err != nil {
c.Config = &config.Config return fmt.Errorf("parse connector: %v", err)
case "mockPassword":
var config struct {
Config mock.PasswordConfig `yaml:"config"`
} }
err = unmarshal(&config) f, ok := connectors[conn.Type]
c.Config = &config.Config if !ok {
case "ldap": return fmt.Errorf("unknown connector type %q", conn.Type)
var config struct {
Config ldap.Config `yaml:"config"`
} }
err = unmarshal(&config)
c.Config = &config.Config connConfig := f()
case "github": if len(conn.Config) != 0 {
var config struct { if err := json.Unmarshal([]byte(conn.Config), connConfig); err != nil {
Config github.Config `yaml:"config"` return fmt.Errorf("parse connector config: %v", err)
} }
err = unmarshal(&config)
c.Config = &config.Config
case "oidc":
var config struct {
Config oidc.Config `yaml:"config"`
} }
err = unmarshal(&config) *c = Connector{
c.Config = &config.Config Type: conn.Type,
default: Name: conn.Type,
return fmt.Errorf("unknown connector type %q", c.Type) ID: conn.ID,
Config: connConfig,
} }
return err return nil
} }

View File

@ -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{

View File

@ -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.

View File

@ -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) {

View File

@ -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.

View File

@ -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
View File

@ -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

View File

@ -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"

View File

@ -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"`
} }

View File

@ -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.

View File

@ -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

View File

@ -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