*: load static clients from config file
This commit is contained in:
		| @@ -9,6 +9,7 @@ import ( | |||||||
| 	"github.com/coreos/poke/connector/mock" | 	"github.com/coreos/poke/connector/mock" | ||||||
| 	"github.com/coreos/poke/storage" | 	"github.com/coreos/poke/storage" | ||||||
| 	"github.com/coreos/poke/storage/kubernetes" | 	"github.com/coreos/poke/storage/kubernetes" | ||||||
|  | 	"github.com/coreos/poke/storage/memory" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Config is the config format for the main application. | // Config is the config format for the main application. | ||||||
| @@ -17,6 +18,8 @@ type Config struct { | |||||||
| 	Storage    Storage     `yaml:"storage"` | 	Storage    Storage     `yaml:"storage"` | ||||||
| 	Connectors []Connector `yaml:"connectors"` | 	Connectors []Connector `yaml:"connectors"` | ||||||
| 	Web        Web         `yaml:"web"` | 	Web        Web         `yaml:"web"` | ||||||
|  |  | ||||||
|  | 	StaticClients []storage.Client `yaml:"staticClients"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Web is the config format for the HTTP server. | // 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 { | 	var c struct { | ||||||
| 		Config StorageConfig `yaml:"config"` | 		Config StorageConfig `yaml:"config"` | ||||||
| 	} | 	} | ||||||
|  | 	// TODO(ericchiang): replace this with a registration process. | ||||||
| 	switch storageMeta.Type { | 	switch storageMeta.Type { | ||||||
| 	case "kubernetes": | 	case "kubernetes": | ||||||
| 		c.Config = &kubernetes.Config{} | 		c.Config = &kubernetes.Config{} | ||||||
|  | 	case "memory": | ||||||
|  | 		c.Config = &memory.Config{} | ||||||
| 	default: | 	default: | ||||||
| 		return fmt.Errorf("unknown storage type %q", storageMeta.Type) | 		return fmt.Errorf("unknown storage type %q", storageMeta.Type) | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										39
									
								
								cmd/poke/config_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								cmd/poke/config_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -7,10 +7,11 @@ import ( | |||||||
| 	"log" | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
|  | 	"github.com/spf13/cobra" | ||||||
| 	yaml "gopkg.in/yaml.v2" | 	yaml "gopkg.in/yaml.v2" | ||||||
|  |  | ||||||
| 	"github.com/coreos/poke/server" | 	"github.com/coreos/poke/server" | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/coreos/poke/storage" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func commandServe() *cobra.Command { | func commandServe() *cobra.Command { | ||||||
| @@ -83,6 +84,9 @@ func serve(cmd *cobra.Command, args []string) error { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("initializing storage: %v", err) | 		return fmt.Errorf("initializing storage: %v", err) | ||||||
| 	} | 	} | ||||||
|  | 	if len(c.StaticClients) > 0 { | ||||||
|  | 		s = storage.WithStaticClients(s, c.StaticClients) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	serverConfig := server.Config{ | 	serverConfig := server.Config{ | ||||||
| 		Issuer:     c.Issuer, | 		Issuer:     c.Issuer, | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								example/config-dev.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								example/config-dev.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
| @@ -2,6 +2,7 @@ package server | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log" | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| @@ -125,7 +126,7 @@ func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) { | |||||||
| 	for id := range s.connectors { | 	for id := range s.connectors { | ||||||
| 		connectorInfos[i] = connectorInfo{ | 		connectorInfos[i] = connectorInfo{ | ||||||
| 			DisplayName: id, | 			DisplayName: id, | ||||||
| 			URL:         s.absPath("/auth", id) + "?state=" + state, | 			URL:         s.absPath("/auth", id), | ||||||
| 		} | 		} | ||||||
| 		i++ | 		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) { | 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{ | 	claims := storage.Claims{ | ||||||
| 		UserID:        identity.UserID, | 		UserID:        identity.UserID, | ||||||
| 		Username:      identity.Username, | 		Username:      identity.Username, | ||||||
|   | |||||||
| @@ -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 { | type memStorage struct { | ||||||
| 	mu sync.Mutex | 	mu sync.Mutex | ||||||
|  |  | ||||||
|   | |||||||
| @@ -81,19 +81,19 @@ type Storage interface { | |||||||
| //   * Trusted peers: https://developers.google.com/identity/protocols/CrossClientAuth | //   * Trusted peers: https://developers.google.com/identity/protocols/CrossClientAuth | ||||||
| //   * Public clients: https://developers.google.com/api-client-library/python/auth/installed-app | //   * Public clients: https://developers.google.com/api-client-library/python/auth/installed-app | ||||||
| type Client struct { | type Client struct { | ||||||
| 	ID           string | 	ID           string   `json:"id" yaml:"id"` | ||||||
| 	Secret       string | 	Secret       string   `json:"secret" yaml:"secret"` | ||||||
| 	RedirectURIs []string | 	RedirectURIs []string `json:"redirectURIs" yaml:"redirectURIs"` | ||||||
|  |  | ||||||
| 	// TrustedPeers are a list of peers which can issue tokens on this client's behalf. | 	// TrustedPeers are a list of peers which can issue tokens on this client's behalf. | ||||||
| 	// Clients inherently trust themselves. | 	// 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 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 | 	Name    string `json:"name" yaml:"name"` | ||||||
| 	LogoURL string | 	LogoURL string `json:"logoURL" yaml:"logoURL"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Claims represents the ID Token claims supported by the server. | // Claims represents the ID Token claims supported by the server. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user