*: 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/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) | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										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" | ||||
| 	"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, | ||||
|   | ||||
							
								
								
									
										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 ( | ||||
| 	"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, | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user