Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/sso-proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func main() {

err = opts.Validate()
if err != nil {
logger.Error(err, "error validing options")
logger.Error(err, "error validating options")
os.Exit(1)
}

Expand Down
4 changes: 3 additions & 1 deletion docs/sso_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ For example, the following config would have the following environment variables
* **type** declares the type of route to use, right now there is just *simple* and *rewrite*.
* **options** are a set of options that can be added to your configuration.
* **allowed groups** optional list of authorized google groups that can access the service. If not specified, anyone within an email domain is allowed to access the service. *Note*: We do not support nested group authentication at this time. Groups must be made up of email addresses associated with individual's accounts. See [#133](https://github.com/buzzfeed/sso/issues/133).
* **allowed_email_domains** optional list of authorized email domains that can access the service.
* **allowed_email_addresses** optional list of authorized email addresses that can access the service.
* **skip_auth_regex** skips authentication for paths matching these regular expressions. NOTE: Use with extreme caution.
* **header_overrides** overrides any heads set either by SSO proxy itself or upstream applications. Useful for modifying browser security headers.
* **inject_request_headers** adds headers to the request before the request is sent to the proxied service. Useful for adding basic auth headers if needed.
Expand Down Expand Up @@ -192,4 +194,4 @@ share the same paths.
![sso_request_flow](https://user-images.githubusercontent.com/10510566/44476373-8ae34e80-a605-11e8-93da-d876f7e48d84.png)


<!-- diagram source: http://sequencediagram.org/index.html#initialData=C4S2BsFMAIGVYPLQEqQI4FdIGdjQGLgD2A7gFBkB2RwMRAbpAE7QbbMA00AxAA4iUA1gC5oAFWYBbAUWIBzAJ4A6FdAA6lDQCotqbEQxMAxjAQlKzHeotK5S1uxYkAFkXbQAJgENgX6CGxoACNIATloLyMTbHYPa20tAGFwEEhKPABBXl4Uox8QIkorDUhbe0d6EBNoC0gPMIionEDgIgdmAHJA7194oq0MjGBXJhAAL3zCuGZGJmKbO2g5NOYfHAihkfHJymgjIg8YAAovSjjI6JaiQTSASj6dPQNjGFgZyy1rUsW0j14iAR4YY+aC8JgMECHQJsTrdHxeCjUWjQBjMdpMLjcABmOKCHg8wgAkrthjBgEwvPVQIUvOBoAhBsNoEx0FhcNAscQSNZSej-C1nDAAERPQzVMwWJhCpQaDRiQXQDos-RiyAdfwk5wBPZedwhMIaXkwpiBeQCfyHdJgZQUY0AWgAfDE2mCiAAPBTCADiAFExNBnMBgLxsMIAPRhrFEIhKZ1KSBurySHKlfaSMOImh0WbQZ2g8EezE4rF4gnymAszA4PDa2lcurBSB5GHQXnwJAVKrrLws0EYIK5cAKRqXEAD0qyyjE1sK8mUsAFSi0+mM5zM1nVjlcuCIaAABQLw+1vKFyVS6WgWRyVR20sn+CILHb0BIMGcXkY0AjwBIRAj0DPNJMmyXIdlDaAhTzV0PSFCIzggvMvE2ICb1aKV7DlLVAm1EJm3cdsuk8HAQDkXYYUCPwhQ8AxxxRJDhlgnsjC1WgjGAQxSgoKDDztR1uPdT1mKbQQOUffMBNzZpFz2aNBFSChaTwahxI9SSYmk-Zrnk6Bc30FSFD4vT6MFK08jQ70-QDIMQ3DMNnTtYz40TZMoCUNMMyoLMURzRDkNMnxHyLXF8WEcsdyQVcULMsScJoNdeQ0U8UiAy8QNQxdGPgk9V0fbZqV2N4mFmO9NEoB8n13V8Aw-GBv1-f9AIvK9QPyij4Lqv8w0vTZcomfLpiK5hAg0XCkPcMBumI0j+QiCDqP7KA6M2RjjBYpt2JZJQyB0nTtp23zSX8tDeKdIy-NAaKmGEISjBEqMWGMqKApYdh1KmTS5MgPbdp2lFeCUtpHqOsTXuwDTZO037dMB87UMfR0iGM8TKkOK7fX9QNg1DCNEc2JRXRR5g3KIdMvjKaAvWjORFoZTYACZ93BQmmG+nbWZ0pFszRXGmQJyFOB4YtS1EMKebXPnUZm04IJy0Y+ukwriusc1eTnKlF2XWmmUrNk8E5Ugtqh6B2b+gGlt5pn+ZeqTChNnSxeRq2TodiXmFEY1oHkbDKBNk2Xct1HnaR12rr2Fk1nN8WA7RUHwa0r6jbtyPHcDhHg+j0OPa8bIme7JoYnXKtcBN35faN-2IUD06YcOi7ntEFl6hZNjoAAakk+DjN6nYZMOCgjYOky6+Oh0K+ZhuN3ZC5mlba40msI42AaIxkvSAB9SEuBX89gDX9gjBZPB267uWe-2Q5bjLqHOe8mOztruGMUF4KCR0begI3jwrFOOI39X3f96H2-r2ZYko1hxA0C4ee0stZrkangbO14zLSSOAIBcdYFD3A0JIU4GAMHrjkAEWgJp-DAHYOALEL4wBrhgauRmlciaTh0NOYY2o8juF5CHGalMiDU1KDoK+v0x5OzTpsFObtoCzBAFiYcJ88rg0OBoH+SwVgUmRNPAurQbg+3LunBhTBDI1yHo-UQGirjaMEfte+xjLqOmVM8EwE8i54A9ocXwIBwDYEsRzLyqIWD2NVEFEsIUwoBJeDNE8opwmK2YLBDQKtZwUnVjSOksDC66y3AbScAARSAvBfgNCmLyJia02IcSImDUiHBDRYRkhgcAcQQgzhgNgJMMBdTNO6sMbu-UYlMBlKVZhmo2G6jJAqMJ1RjwKmNIRfmVpgDKAEYnI2EzICGI2A-S67tHBEXcZ47x0MNk2OeidQeT1zKSOYNI4cHt3yBH2EwZueBIA4I8REfEyphqUBAPGew5FZpBAwGMMYWJIB1GJpITwJMvACAOYpSRtJITolZmc4GBj1lA2Ho+a64d1Gw0umpMG70IYJyhpATxMABD0ERXEY0JtUVYoMdwRuDpjSiAACwAAYADMEFiTUpSHEDIUQDDpCFCXM4e1S6-RRdY858Nq76Qnk3dabcO7nB6qffq59SU-SsS6HiirMUmPSZuMxs9tELyXpQcI7916bz2P-PeTZD5qrkfLYlF8Dk3z8Yc6CCggnCz-jvT+394LBo-oAyAwBgEwFAasWgEDKBQN2LQsR8CIhpWQVMVB3zQAYKwZQHBlA8HgCHAQohQ1SHkMoSQahcEVxiIPPogZCQWG1PYWMmAXCpmvF3JFNFSgllQ3pXKtFpyx2MtEFImRRyekKMgEo+C8a1HtPzuYtIo6jHyoMYq-1pj10Ws3csqG-EPQYvxfXU17JXHRphfsk9v0fU+UnY-QNISFTPgHYyiJCoRQ4Aca8d4UplaajJEkhcKTG3a0nnrLkraypiWfFVd8n4Or-iidUPpXzRotgmhUkiuxaxzRootMWK1mJgHWhxBDuT8lnEKWBiIq0qNlN7FCQj1T0gKllvIqYfS4JxF5JhoDg0WAaDyLsIgWJaC7CabyVpkgxlhAQ2FLEIATR4FWZJMTGpOk603Prbkv56lxFQzAEIaQNA8L4dAI4KbOkMsftexNnSZnYUtKABZtxDYjoHq+2xe7DzbLRG4+9XjH36v0hOg1AlhAzpuTsyofgMiJAADLet8S+2LhZn7BIJJ01LaWKK9iCF4G4cRARtAU3pf1OnKjVCUfcwo6m5CGB7upqAAoQRpEIbUEhxbS3lowLwHonFIs6Xhe6uosqcsGXWfusOkAI51djsS+OJcKU1BoHOuWM3-NzbtMyuorLHAcp5XyygAqkXCv2BgMVmXkS+rPQGng-AhCiFYYEbAIw8BGA00YDA+HeRRjLaQBojcNPrV879UupcyAvcdICZgS46SdkceuFVLcPatHq12aAvx-iAkzE9nMyOmCo7xyYd9ZZxmwalmD18HguAdLANVL5aYYBYnBJCvw6OYB1tYUx0Y4QABqe5EgIYQKSJgdb3B+AM+yNMDQsd4A0NzkmbmdkmYaY2dcAArdadQgA -->
<!-- diagram source: http://sequencediagram.org/index.html#initialData=C4S2BsFMAIGVYPLQEqQI4FdIGdjQGLgD2A7gFBkB2RwMRAbpAE7QbbMA00AxAA4iUA1gC5oAFWYBbAUWIBzAJ4A6FdAA6lDQCotqbEQxMAxjAQlKzHeotK5S1uxYkAFkXbQAJgENgX6CGxoACNIATloLyMTbHYPa20tAGFwEEhKPABBXl4Uox8QIkorDUhbe0d6EBNoC0gPMIionEDgIgdmAHJA7194oq0MjGBXJhAAL3zCuGZGJmKbO2g5NOYfHAihkfHJymgjIg8YAAovSjjI6JaiQTSASj6dPQNjGFgZyy1rUsW0j14iAR4YY+aC8JgMECHQJsTrdHxeCjUWjQBjMdpMLjcABmOKCHg8wgAkrthjBgEwvPVQIUvOBoAhBsNoEx0FhcNAscQSNZSej-C1nDAAERPQzVMwWJhCpQaDRiQXQDos-RiyAdfwk5wBPZedwhMIaXkwpiBeQCfyHdJgZQUY0AWgAfDE2mCiAAPBTCADiAFExNBnMBgLxsMIAPRhrFEIhKZ1KSBurySHKlfaSMOImh0WbQZ2g8EezE4rF4gnymAszA4PDa2lcurBSB5GHQXnwJAVKrrLws0EYIK5cAKRqXEAD0qyyjE1sK8mUsAFSi0+mM5zM1nVjlcuCIaAABQLw+1vKFyVS6WgWRyVR20sn+CILHb0BIMGcXkY0AjwBIRAj0DPNJMmyXIdlDaAhTzV0PSFCIzggvMvE2ICb1aKV7DlLVAm1EJm3cdsuk8HAQDkXYYUCPwhQ8AxxxRJDhlgnsjC1WgjGAQxSgoKDDztR1uPdT1mKbQQOUffMBNzZpFz2aNBFSChaTwahxI9SSYmk-Zrnk6Bc30FSFD4vT6MFK08jQ70-QDIMQ3DMNnTtYz40TZMoCUNMMyoLMURzRDkNMnxHyLXF8WEcsdyQVcULMsScJoNdeQ0U8UiAy8QNQxdGPgk9V0fbZqV2N4mFmO9NEoB8n13V8Aw-GBv1-f9AIvK9QPyij4Lqv8w0vTZcomfLpiK5hAg0XCkPcMBumI0j+QiCDqP7KA6M2RjjBYpt2JZJQyB0nTtp23zSX8tDeKdIy-NAaKmGEISjBEqMWGMqKApYdh1KmTS5MgPbdp2lFeCUtpHqOsTXuwDTZO037dMB87UMfR0iGM8TKkOK7fX9QNg1DCNEc2JRXRR5g3KIdMvjKaAvWjORFoZTYACZ93BQmmG+nbWZ0pFszRXGmQJyFOB4YtS1EMKebXPnUZm04IJy0Y+ukwriusc1eTnKlF2XWmmUrNk8E5Ugtqh6B2b+gGlt5pn+ZeqTChNnSxeRq2TodiXmFEY1oHkbDKBNk2Xct1HnaR12rr2Fk1nN8WA7RUHwa0r6jbtyPHcDhHg+j0OPa8bIme7JoYnXKtcBN35faN-2IUD06YcOi7ntEFl6hZNjoAAakk+DjN6nYZMOCgjYOky6+Oh0K+ZhuN3ZC5mlba40msI42AaIxkvSAB9SEuBX89gDX9gjBZPB267uWe-2Q5bjLqHOe8mOztruGMUF4KCR0begI3jwrFOOI39X3f96H2-r2ZYko1hxA0C4ee0stZrkangbO14zLSSOAIBcdYFD3A0JIU4GAMHrjkAEWgJp-DAHYOALEL4wBrhgauRmlciaTh0NOYY2o8juF5CHGalMiDU1KDoK+v0x5OzTpsFObtoCzBAFiYcJ88rg0OBoH+SwVgUmRNPAurQbg+3LunBhTBDI1yHo-UQGirjaMEfte+xjLqOmVM8EwE8i54A9ocXwIBwDYEsRzLyqIWD2NVEFEsIUwoBJeDNE8opwmK2YLBDQKtZwUnVjSOksDC66y3AbScAARSAvBfgNCmLyJia02IcSImDUiHBDRYRkhgcAcQQgzhgNgJMMBdTNO6sMbu-UYlMBlKVZhmo2G6jJAqMJ1RjwKmNIRfmVpgDKAEYnI2EzICGI2A-S67tHBEXcZ47x0MNk2OeidQeT1zKSOYNI4cHt3yBH2EwZueBIA4I8REfEyphqUBAPGew5FZpBAwGMMYWJIB1GJpITwJMvACAOYpSRtJITolZmc4GBj1lA2Ho+a64d1Gw0umpMG70IYJyhpATxMABD0ERXEY0JtUVYoMdwRuDpjSiAACwAAYADMEFiTUpSHEDIUQDDpCFCXM4e1S6-RRdY858Nq76Qnk3dabcO7nB6qffq59SU-SsS6HiirMUmPSZuMxs9tELyXpQcI7916bz2P-PeTZD5qrkfLYlF8Dk3z8Yc6CCggnCz-jvT+394LBo-oAyAwBgEwFAasWgEDKBQN2LQsR8CIhpWQVMVB3zQAYKwZQHBlA8HgCHAQohQ1SHkMoSQahcEVxiIPPogZCQWG1PYWMmAXCpmvF3JFNFSgllQ3pXKtFpyx2MtEFImRRyekKMgEo+C8a1HtPzuYtIo6jHyoMYq-1pj10Ws3csqG-EPQYvxfXU17JXHRphfsk9v0fU+UnY-QNISFTPgHYyiJCoRQ4Aca8d4UplaajJEkhcKTG3a0nnrLkraypiWfFVd8n4Or-iidUPpXzRotgmhUkiuxaxzRootMWK1mJgHWhxBDuT8lnEKWBiIq0qNlN7FCQj1T0gKllvIqYfS4JxF5JhoDg0WAaDyLsIgWJaC7CabyVpkgxlhAQ2FLEIATR4FWZJMTGpOk603Prbkv56lxFQzAEIaQNA8L4dAI4KbOkMsftexNnSZnYUtKABZtxDYjoHq+2xe7DzbLRG4+9XjH36v0hOg1AlhAzpuTsyofgMiJAADLet8S+2LhZn7BIJJ01LaWKK9iCF4G4cRARtAU3pf1OnKjVCUfcwo6m5CGB7upqAAoQRpEIbUEhxbS3lowLwHonFIs6Xhe6uosqcsGXWfusOkAI51djsS+OJcKU1BoHOuWM3-NzbtMyuorLHAcp5XyygAqkXCv2BgMVmXkS+rPQGng-AhCiFYYEbAIw8BGA00YDA+HeRRjLaQBojcNPrV879UupcyAvcdICZgS46SdkceuFVLcPatHq12aAvx-iAkzE9nMyOmCo7xyYd9ZZxmwalmD18HguAdLANVL5aYYBYnBJCvw6OYB1tYUx0Y4QABqe5EgIYQKSJgdb3B+AM+yNMDQsd4A0NzkmbmdkmYaY2dcAArdadQgA -->
9 changes: 6 additions & 3 deletions internal/pkg/options/email_address_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ import (
// of email addresses. The address "*" is a wild card that matches any non-empty email.
func NewEmailAddressValidator(emails []string) func(string) bool {
allowAll := false
for i, email := range emails {
var emailAddresses []string

for _, email := range emails {
if email == "*" {
allowAll = true
}
emails[i] = fmt.Sprintf("%s", strings.ToLower(email))
emailAddress := fmt.Sprintf("%s", strings.ToLower(email))
emailAddresses = append(emailAddresses, emailAddress)
}

if allowAll {
Expand All @@ -25,7 +28,7 @@ func NewEmailAddressValidator(emails []string) func(string) bool {
return false
}
email = strings.ToLower(email)
for _, emailItem := range emails {
for _, emailItem := range emailAddresses {
if email == emailItem {
return true
}
Expand Down
9 changes: 6 additions & 3 deletions internal/pkg/options/email_domain_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ import (
// of domains. The domain "*" is a wild card that matches any non-empty email.
func NewEmailDomainValidator(domains []string) func(string) bool {
allowAll := false
for i, domain := range domains {
var emailDomains []string

for _, domain := range domains {
if domain == "*" {
allowAll = true
}
domains[i] = fmt.Sprintf("@%s", strings.ToLower(domain))
emailDomain := fmt.Sprintf("@%s", strings.ToLower(domain))
emailDomains = append(emailDomains, emailDomain)
}

if allowAll {
Expand All @@ -25,7 +28,7 @@ func NewEmailDomainValidator(domains []string) func(string) bool {
return false
}
email = strings.ToLower(email)
for _, domain := range domains {
for _, domain := range emailDomains {
if strings.HasSuffix(email, domain) {
return true
}
Expand Down
41 changes: 26 additions & 15 deletions internal/proxy/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import (
// Cluster - the cluster in which this is running, used for upstream configs
// Scheme - the default scheme, used for upstream configs
// SkipAuthPreflight - will skip authentication for OPTIONS requests, default false
// EmailDomains - csv list of emails with the specified domain to authenticate. Use * to authenticate any email
// EmailAddresses - []string - authenticate emails with the specified email address (may be given multiple times). Use * to authenticate any email
// DefaultAllowedEmailDomains - csv list of emails with the specified domain to authenticate. Use * to authenticate any email
// DefaultAllowedEmailAddresses - []string - authenticate emails with the specified email address (may be given multiple times). Use * to authenticate any email
// DefaultAllowedGroups - csv list of default allowed groups that are applied to authorize access to upstreams. Will be overridden by groups specified in upstream configs.
// ClientID - the OAuth Client ID: ie: "123456.apps.googleusercontent.com"
// ClientSecret - The OAuth Client Secret
Expand Down Expand Up @@ -60,9 +60,9 @@ type Options struct {

SkipAuthPreflight bool `envconfig:"SKIP_AUTH_PREFLIGHT"`

EmailDomains []string `envconfig:"EMAIL_DOMAIN"`
EmailAddresses []string `envconfig:"EMAIL_ADDRESSES"`
DefaultAllowedGroups []string `envconfig:"DEFAULT_ALLOWED_GROUPS"`
DefaultAllowedEmailDomains []string `envconfig:"DEFAULT_ALLOWED_EMAIL_DOMAINS"`
DefaultAllowedEmailAddresses []string `envconfig:"DEFAULT_ALLOWED_EMAIL_ADDRESSES"`
DefaultAllowedGroups []string `envconfig:"DEFAULT_ALLOWED_GROUPS"`

ClientID string `envconfig:"CLIENT_ID"`
ClientSecret string `envconfig:"CLIENT_SECRET"`
Expand Down Expand Up @@ -121,8 +121,10 @@ func NewOptions() *Options {
DefaultUpstreamTimeout: time.Duration(1) * time.Second,
DefaultUpstreamTCPResetDeadline: time.Duration(1) * time.Minute,

DefaultAllowedGroups: []string{},
PassAccessToken: false,
DefaultAllowedEmailAddresses: []string{},
DefaultAllowedEmailDomains: []string{},
DefaultAllowedGroups: []string{},
PassAccessToken: false,
}
}

Expand All @@ -147,9 +149,6 @@ func (o *Options) Validate() error {
if o.ClientSecret == "" {
msgs = append(msgs, "missing setting: client-secret")
}
if len(o.EmailDomains) == 0 && len(o.EmailAddresses) == 0 {
msgs = append(msgs, "missing setting: email-domain or email-address")
}

if o.StatsdHost == "" {
msgs = append(msgs, "missing setting: statsd-host")
Expand Down Expand Up @@ -178,11 +177,13 @@ func (o *Options) Validate() error {
}

defaultUpstreamOptionsConfig := &OptionsConfig{
AllowedGroups: o.DefaultAllowedGroups,
Timeout: o.DefaultUpstreamTimeout,
ResetDeadline: o.DefaultUpstreamTCPResetDeadline,
ProviderSlug: o.DefaultProviderSlug,
CookieName: o.CookieName,
AllowedEmailAddresses: o.DefaultAllowedEmailAddresses,
AllowedEmailDomains: o.DefaultAllowedEmailDomains,
AllowedGroups: o.DefaultAllowedGroups,
Timeout: o.DefaultUpstreamTimeout,
ResetDeadline: o.DefaultUpstreamTCPResetDeadline,
ProviderSlug: o.DefaultProviderSlug,
CookieName: o.CookieName,
}

o.upstreamConfigs, err = loadServiceConfigs(rawBytes, o.Cluster, o.Scheme, templateVars, defaultUpstreamOptionsConfig)
Expand All @@ -192,10 +193,20 @@ func (o *Options) Validate() error {
}

if o.upstreamConfigs != nil {
invalidUpstreams := []string{}
for _, uc := range o.upstreamConfigs {
if uc.Timeout > o.TCPWriteTimeout {
o.TCPWriteTimeout = uc.Timeout
}

if len(uc.AllowedEmailDomains) == 0 && len(uc.AllowedEmailAddresses) == 0 {
invalidUpstreams = append(invalidUpstreams, uc.Service)
}
}
if len(invalidUpstreams) != 0 {
msgs = append(msgs, fmt.Sprintf(
"missing setting: DEFAULT_ALLOWED_EMAIL_DOMAINS or DEFAULT_ALLOWED_EMAIL_ADDRESSES in either environment or upstream config in the following upstreams: %v",
invalidUpstreams))
}
}

Expand Down
10 changes: 8 additions & 2 deletions internal/proxy/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func testOptions() *Options {
o.CookieSecret = testEncodedCookieSecret
o.ClientID = "bazquux"
o.ClientSecret = "xyzzyplugh"
o.EmailDomains = []string{"*"}
o.DefaultAllowedEmailDomains = []string{"*"}
o.DefaultProviderSlug = "idp"
o.ProviderURLString = "https://www.example.com"
o.UpstreamConfigsFile = "testdata/upstream_configs.yml"
Expand All @@ -41,7 +41,12 @@ func errorMsg(msgs []string) string {

func TestNewOptions(t *testing.T) {
o := NewOptions()
o.EmailDomains = []string{"*"}

upstreamConfig := &UpstreamConfig{
Service: "testService",
}
o.upstreamConfigs = []*UpstreamConfig{upstreamConfig}

err := o.Validate()
testutil.NotEqual(t, nil, err)

Expand All @@ -54,6 +59,7 @@ func TestNewOptions(t *testing.T) {
"missing setting: client-secret",
"missing setting: statsd-host",
"missing setting: statsd-port",
"missing setting: DEFAULT_ALLOWED_EMAIL_DOMAINS or DEFAULT_ALLOWED_EMAIL_ADDRESSES in either environment or upstream config in the following upstreams: [testService]",
"Invalid value for COOKIE_SECRET; must decode to 32 or 64 bytes, but decoded to 0 bytes",
})
testutil.Equal(t, expected, err.Error())
Expand Down
12 changes: 6 additions & 6 deletions internal/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ func New(opts *Options) (*SSOProxy, error) {
optFuncs = append(optFuncs, SetRequestSigner(requestSigner))
}

if len(opts.EmailAddresses) != 0 {
optFuncs = append(optFuncs, SetValidator(options.NewEmailAddressValidator(opts.EmailAddresses)))
} else {
optFuncs = append(optFuncs, SetValidator(options.NewEmailDomainValidator(opts.EmailDomains)))
}

hostRouter := hostmux.NewRouter()
for _, upstreamConfig := range opts.upstreamConfigs {
provider, err := newProvider(opts, upstreamConfig)
Expand All @@ -43,6 +37,12 @@ func New(opts *Options) (*SSOProxy, error) {
return nil, err
}

if len(upstreamConfig.AllowedEmailAddresses) != 0 {
optFuncs = append(optFuncs, SetValidator(options.NewEmailAddressValidator(upstreamConfig.AllowedEmailAddresses)))
} else if len(upstreamConfig.AllowedEmailDomains) != 0 {
optFuncs = append(optFuncs, SetValidator(options.NewEmailDomainValidator(upstreamConfig.AllowedEmailDomains)))
}

optFuncs = append(optFuncs,
SetProvider(provider),
SetCookieStore(opts),
Expand Down
28 changes: 17 additions & 11 deletions internal/proxy/proxy_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ type UpstreamConfig struct {

SkipAuthCompiledRegex []*regexp.Regexp
AllowedGroups []string
AllowedEmailDomains []string
AllowedEmailAddresses []string
TLSSkipVerify bool
PreserveHost bool
HMACAuth hmacauth.HmacAuth
Expand Down Expand Up @@ -88,17 +90,19 @@ type RouteConfig struct {
// * skip_request_signing - skip request signing if this behavior is problematic or undesired. For requests with large http bodies
// this maybe useful to unset as http bodies are read into memory in order to sign.
type OptionsConfig struct {
HeaderOverrides map[string]string `yaml:"header_overrides"`
InjectRequestHeaders map[string]string `yaml:"inject_request_headers"`
SkipAuthRegex []string `yaml:"skip_auth_regex"`
AllowedGroups []string `yaml:"allowed_groups"`
TLSSkipVerify bool `yaml:"tls_skip_verify"`
PreserveHost bool `yaml:"preserve_host"`
Timeout time.Duration `yaml:"timeout"`
ResetDeadline time.Duration `yaml:"reset_deadline"`
FlushInterval time.Duration `yaml:"flush_interval"`
SkipRequestSigning bool `yaml:"skip_request_signing"`
ProviderSlug string `yaml:"provider_slug"`
HeaderOverrides map[string]string `yaml:"header_overrides"`
InjectRequestHeaders map[string]string `yaml:"inject_request_headers"`
SkipAuthRegex []string `yaml:"skip_auth_regex"`
AllowedGroups []string `yaml:"allowed_groups"`
AllowedEmailDomains []string `yaml:"allowed_email_domains"`
AllowedEmailAddresses []string `yaml:"allowed_email_addresses"`
TLSSkipVerify bool `yaml:"tls_skip_verify"`
PreserveHost bool `yaml:"preserve_host"`
Timeout time.Duration `yaml:"timeout"`
ResetDeadline time.Duration `yaml:"reset_deadline"`
FlushInterval time.Duration `yaml:"flush_interval"`
SkipRequestSigning bool `yaml:"skip_request_signing"`
ProviderSlug string `yaml:"provider_slug"`

// CookieName is still set globally, so we do not provide override behavior
CookieName string
Expand Down Expand Up @@ -396,6 +400,8 @@ func parseOptionsConfig(proxy *UpstreamConfig, defaultOpts *OptionsConfig) error
}

proxy.AllowedGroups = dst.AllowedGroups
proxy.AllowedEmailDomains = dst.AllowedEmailDomains
proxy.AllowedEmailAddresses = dst.AllowedEmailAddresses
proxy.Timeout = dst.Timeout
proxy.ResetDeadline = dst.ResetDeadline
proxy.FlushInterval = dst.FlushInterval
Expand Down
6 changes: 3 additions & 3 deletions quickstart/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ services:
entrypoint: /bin/sso-proxy
environment:
# Allow any google account to log in for demo purposes
- EMAIL_DOMAIN=*
- DEFAULT_ALLOWED_EMAIL_DOMAINS=*

# (Optional) Allow specific google email address to log in for demo purposes
# This overrides EMAIL_DOMAIN
# - EMAIL_ADDRESSES=*
# This overrides DEFAULT_ALLOWED_EMAIL_DOMAIN
# - DEFAULT_ALLOWED_EMAIL_ADDRESSES=*

- UPSTREAM_CONFIGS=/sso/upstream_configs.yml
- PROVIDER_URL=http://sso-auth.localtest.me
Expand Down
2 changes: 1 addition & 1 deletion quickstart/kubernetes/sso-proxy-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ spec:
ports:
- containerPort: 4180
env:
- name: EMAIL_DOMAIN
- name: DEFAULT_ALLOWED_EMAIL_DOMAINS
value: 'mydomain.com'
- name: UPSTREAM_CONFIGS
value: /sso/upstream_configs.yml
Expand Down