Skip to content
Snippets Groups Projects
Commit a03243a8 authored by Marco Bonetti's avatar Marco Bonetti
Browse files

Add support for a users whitelist

parent c074b869
No related branches found
No related tags found
No related merge requests found
...@@ -48,7 +48,8 @@ For the server you need the following: ...@@ -48,7 +48,8 @@ For the server you need the following:
## Installation using Go tools ## Installation using Go tools
1. Use the Go tools to install cashier. The binaries `cashierd` and `cashier` will be installed in your $GOPATH. 1. Use the Go tools to install cashier. The binaries `cashierd` and `cashier` will be installed in your $GOPATH.
``` ```
go get github.com/nsheridan/cashier/cmd/... go get -u github.com/nsheridan/cashier/cmd/cashier
go get -u github.com/nsheridan/cashier/cmd/cashierd
``` ```
2. Create a signing key with `ssh-keygen` and a [cashierd.conf](example-server.conf) 2. Create a signing key with `ssh-keygen` and a [cashierd.conf](example-server.conf)
3. Run the cashier server with `cashierd` and the cli with `cashier`. 3. Run the cashier server with `cashierd` and the cli with `cashier`.
...@@ -85,6 +86,7 @@ Configuration is divided into different sections: `server`, `auth`, `ssh`, and ` ...@@ -85,6 +86,7 @@ Configuration is divided into different sections: `server`, `auth`, `ssh`, and `
- `oauth_client_secret` : string. Oauth secret. - `oauth_client_secret` : string. Oauth secret.
- `oauth_callback_url` : string. URL that the Oauth provider will redirect to after user authorisation. The path is hardcoded to `"/auth/callback"` in the source. - `oauth_callback_url` : string. URL that the Oauth provider will redirect to after user authorisation. The path is hardcoded to `"/auth/callback"` in the source.
- `provider_opts` : object. Additional options for the provider. - `provider_opts` : object. Additional options for the provider.
- `users_whitelist` : array of strings. Optional list of whitelisted usernames. If missing, all users of your current domain/organization are allowed to authenticate against cashierd.
#### Provider-specific options #### Provider-specific options
......
...@@ -16,6 +16,7 @@ auth { ...@@ -16,6 +16,7 @@ auth {
provider_opts { provider_opts {
domain = "example.com" # Oauth-provider specific options domain = "example.com" # Oauth-provider specific options
} }
users_whitelist = ["marco", "niall", "patrick"] # Optional
} }
# Configuration for the certificate signer. # Configuration for the certificate signer.
......
...@@ -22,12 +22,17 @@ const ( ...@@ -22,12 +22,17 @@ const (
type Config struct { type Config struct {
config *oauth2.Config config *oauth2.Config
organization string organization string
whitelist map[string]bool
} }
// New creates a new Github provider from a configuration. // New creates a new Github provider from a configuration.
func New(c *config.Auth) (auth.Provider, error) { func New(c *config.Auth) (auth.Provider, error) {
if c.ProviderOpts["organization"] == "" { uw := make(map[string]bool)
return nil, errors.New("github_opts organization must not be empty") for _, u := range c.UsersWhitelist {
uw[u] = true
}
if c.ProviderOpts["organization"] == "" && len(uw) == 0 {
return nil, errors.New("github_opts organization and the users whitelist must not be both empty")
} }
return &Config{ return &Config{
config: &oauth2.Config{ config: &oauth2.Config{
...@@ -41,6 +46,7 @@ func New(c *config.Auth) (auth.Provider, error) { ...@@ -41,6 +46,7 @@ func New(c *config.Auth) (auth.Provider, error) {
}, },
}, },
organization: c.ProviderOpts["organization"], organization: c.ProviderOpts["organization"],
whitelist: uw,
}, nil }, nil
} }
...@@ -56,6 +62,9 @@ func (c *Config) Name() string { ...@@ -56,6 +62,9 @@ func (c *Config) Name() string {
// Valid validates the oauth token. // Valid validates the oauth token.
func (c *Config) Valid(token *oauth2.Token) bool { func (c *Config) Valid(token *oauth2.Token) bool {
if len(c.whitelist) == 0 && !c.whitelist[c.Username(token)] {
return false
}
if !token.Valid() { if !token.Valid() {
return false return false
} }
......
...@@ -32,7 +32,7 @@ func TestNewEmptyOrganization(t *testing.T) { ...@@ -32,7 +32,7 @@ func TestNewEmptyOrganization(t *testing.T) {
a := assert.New(t) a := assert.New(t)
_, err := newGithub() _, err := newGithub()
a.EqualError(err, "github_opts organization must not be empty") a.EqualError(err, "github_opts organization and the users whitelist must not be both empty")
organization = "exampleorg" organization = "exampleorg"
} }
......
...@@ -24,12 +24,17 @@ const ( ...@@ -24,12 +24,17 @@ const (
type Config struct { type Config struct {
config *oauth2.Config config *oauth2.Config
domain string domain string
whitelist map[string]bool
} }
// New creates a new Google provider from a configuration. // New creates a new Google provider from a configuration.
func New(c *config.Auth) (auth.Provider, error) { func New(c *config.Auth) (auth.Provider, error) {
if c.ProviderOpts["domain"] == "" { uw := make(map[string]bool)
return nil, errors.New("google_opts domain must not be empty") for _, u := range c.UsersWhitelist {
uw[u] = true
}
if c.ProviderOpts["domain"] == "" && len(uw) == 0 {
return nil, errors.New("google_opts domain and the users whitelist must not be both empty")
} }
return &Config{ return &Config{
...@@ -41,6 +46,7 @@ func New(c *config.Auth) (auth.Provider, error) { ...@@ -41,6 +46,7 @@ func New(c *config.Auth) (auth.Provider, error) {
Scopes: []string{googleapi.UserinfoEmailScope, googleapi.UserinfoProfileScope}, Scopes: []string{googleapi.UserinfoEmailScope, googleapi.UserinfoProfileScope},
}, },
domain: c.ProviderOpts["domain"], domain: c.ProviderOpts["domain"],
whitelist: uw,
}, nil }, nil
} }
...@@ -56,6 +62,9 @@ func (c *Config) Name() string { ...@@ -56,6 +62,9 @@ func (c *Config) Name() string {
// Valid validates the oauth token. // Valid validates the oauth token.
func (c *Config) Valid(token *oauth2.Token) bool { func (c *Config) Valid(token *oauth2.Token) bool {
if len(c.whitelist) == 0 && !c.whitelist[c.Username(token)] {
return false
}
if !token.Valid() { if !token.Valid() {
return false return false
} }
......
...@@ -33,7 +33,7 @@ func TestNewWithoutDomain(t *testing.T) { ...@@ -33,7 +33,7 @@ func TestNewWithoutDomain(t *testing.T) {
domain = "" domain = ""
_, err := newGoogle() _, err := newGoogle()
a.EqualError(err, "google_opts domain must not be empty") a.EqualError(err, "google_opts domain and the users whitelist must not be both empty")
domain = "example.com" domain = "example.com"
} }
......
...@@ -40,6 +40,7 @@ type Auth struct { ...@@ -40,6 +40,7 @@ type Auth struct {
OauthCallbackURL string `mapstructure:"oauth_callback_url"` OauthCallbackURL string `mapstructure:"oauth_callback_url"`
Provider string `mapstructure:"provider"` Provider string `mapstructure:"provider"`
ProviderOpts map[string]string `mapstructure:"provider_opts"` ProviderOpts map[string]string `mapstructure:"provider_opts"`
UsersWhitelist []string `mapstructure:"users_whitelist"`
} }
// SSH holds the configuration specific to signing ssh keys. // SSH holds the configuration specific to signing ssh keys.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment