From 53d1be4a87e8ef4913325ef53204e6d3de6dd9db Mon Sep 17 00:00:00 2001 From: Eric Chiang Date: Fri, 5 Aug 2016 09:50:22 -0700 Subject: [PATCH] *: load static clients from config file --- cmd/poke/config.go | 6 ++++++ cmd/poke/config_test.go | 39 +++++++++++++++++++++++++++++++++++++++ cmd/poke/serve.go | 6 +++++- example/config-dev.yaml | 27 +++++++++++++++++++++++++++ server/handlers.go | 6 +++++- storage/memory/memory.go | 12 ++++++++++++ storage/storage.go | 14 +++++++------- 7 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 cmd/poke/config_test.go create mode 100644 example/config-dev.yaml diff --git a/cmd/poke/config.go b/cmd/poke/config.go index 3d840a40..fc06b208 100644 --- a/cmd/poke/config.go +++ b/cmd/poke/config.go @@ -9,6 +9,7 @@ import ( "github.com/coreos/poke/connector/mock" "github.com/coreos/poke/storage" "github.com/coreos/poke/storage/kubernetes" + "github.com/coreos/poke/storage/memory" ) // Config is the config format for the main application. @@ -17,6 +18,8 @@ type Config struct { Storage Storage `yaml:"storage"` Connectors []Connector `yaml:"connectors"` Web Web `yaml:"web"` + + StaticClients []storage.Client `yaml:"staticClients"` } // Web is the config format for the HTTP server. @@ -46,9 +49,12 @@ func (s *Storage) UnmarshalYAML(unmarshal func(interface{}) error) error { var c struct { Config StorageConfig `yaml:"config"` } + // TODO(ericchiang): replace this with a registration process. switch storageMeta.Type { case "kubernetes": c.Config = &kubernetes.Config{} + case "memory": + c.Config = &memory.Config{} default: return fmt.Errorf("unknown storage type %q", storageMeta.Type) } diff --git a/cmd/poke/config_test.go b/cmd/poke/config_test.go new file mode 100644 index 00000000..f4158bc3 --- /dev/null +++ b/cmd/poke/config_test.go @@ -0,0 +1,39 @@ +package main + +import ( + "testing" + + "github.com/coreos/poke/storage" + "github.com/kylelemons/godebug/pretty" + + yaml "gopkg.in/yaml.v2" +) + +func TestUnmarshalClients(t *testing.T) { + data := `staticClients: +- id: example-app + redirectURIs: + - 'http://127.0.0.1:5555/callback' + name: 'Example App' + secret: ZXhhbXBsZS1hcHAtc2VjcmV0 +` + var c Config + if err := yaml.Unmarshal([]byte(data), &c); err != nil { + t.Fatal(err) + } + + wantClients := []storage.Client{ + { + ID: "example-app", + Name: "Example App", + Secret: "ZXhhbXBsZS1hcHAtc2VjcmV0", + RedirectURIs: []string{ + "http://127.0.0.1:5555/callback", + }, + }, + } + + if diff := pretty.Compare(wantClients, c.StaticClients); diff != "" { + t.Errorf("did not get expected clients: %s", diff) + } +} diff --git a/cmd/poke/serve.go b/cmd/poke/serve.go index 28611f50..24bb4917 100644 --- a/cmd/poke/serve.go +++ b/cmd/poke/serve.go @@ -7,10 +7,11 @@ import ( "log" "net/http" + "github.com/spf13/cobra" yaml "gopkg.in/yaml.v2" "github.com/coreos/poke/server" - "github.com/spf13/cobra" + "github.com/coreos/poke/storage" ) func commandServe() *cobra.Command { @@ -83,6 +84,9 @@ func serve(cmd *cobra.Command, args []string) error { if err != nil { return fmt.Errorf("initializing storage: %v", err) } + if len(c.StaticClients) > 0 { + s = storage.WithStaticClients(s, c.StaticClients) + } serverConfig := server.Config{ Issuer: c.Issuer, diff --git a/example/config-dev.yaml b/example/config-dev.yaml new file mode 100644 index 00000000..d3d01afb --- /dev/null +++ b/example/config-dev.yaml @@ -0,0 +1,27 @@ +issuer: http://127.0.0.1:5556 +storage: + # NOTE(ericchiang): This will be replaced by sqlite3 in the future. + type: memory + +web: + http: 127.0.0.1:5556 + +connectors: +- type: mock + id: mock + name: Mock +- type: github + id: github + name: GitHub + config: + clientID: "$GITHUB_CLIENT_ID" + clientSecret: "$GITHUB_CLIENT_SECRET" + redirectURI: http://127.0.0.1:5556/callback/github + org: kubernetes + +staticClients: +- id: example-app + redirectURIs: + - 'http://127.0.0.1:5555/callback' + name: 'Example App' + secret: ZXhhbXBsZS1hcHAtc2VjcmV0 diff --git a/server/handlers.go b/server/handlers.go index 85214a41..76bdbc5f 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -2,6 +2,7 @@ package server import ( "encoding/json" + "errors" "fmt" "log" "net/http" @@ -125,7 +126,7 @@ func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) { for id := range s.connectors { connectorInfos[i] = connectorInfo{ DisplayName: id, - URL: s.absPath("/auth", id) + "?state=" + state, + URL: s.absPath("/auth", id), } i++ } @@ -224,6 +225,9 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request) } func (s *Server) finalizeLogin(identity connector.Identity, authReqID, connectorID string, conn connector.Connector) (string, error) { + if authReqID == "" { + return "", errors.New("no auth request ID passed") + } claims := storage.Claims{ UserID: identity.UserID, Username: identity.Username, diff --git a/storage/memory/memory.go b/storage/memory/memory.go index 748e9528..d4bb1bcd 100644 --- a/storage/memory/memory.go +++ b/storage/memory/memory.go @@ -18,6 +18,18 @@ func New() storage.Storage { } } +// Config is an implementation of a storage configuration. +// +// TODO(ericchiang): Actually define a storage config interface and have registration. +type Config struct { + // The in memory implementation has no config. +} + +// Open always returns a new in memory storage. +func (c *Config) Open() (storage.Storage, error) { + return New(), nil +} + type memStorage struct { mu sync.Mutex diff --git a/storage/storage.go b/storage/storage.go index 88b11542..399b35cd 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -81,19 +81,19 @@ type Storage interface { // * Trusted peers: https://developers.google.com/identity/protocols/CrossClientAuth // * Public clients: https://developers.google.com/api-client-library/python/auth/installed-app type Client struct { - ID string - Secret string - RedirectURIs []string + ID string `json:"id" yaml:"id"` + Secret string `json:"secret" yaml:"secret"` + RedirectURIs []string `json:"redirectURIs" yaml:"redirectURIs"` // TrustedPeers are a list of peers which can issue tokens on this client's behalf. // Clients inherently trust themselves. - TrustedPeers []string + TrustedPeers []string `json:"trustedPeers" yaml:"trustedPeers"` // Public clients must use either use a redirectURL 127.0.0.1:X or "urn:ietf:wg:oauth:2.0:oob" - Public bool + Public bool `json:"public" yaml:"public"` - Name string - LogoURL string + Name string `json:"name" yaml:"name"` + LogoURL string `json:"logoURL" yaml:"logoURL"` } // Claims represents the ID Token claims supported by the server.