From 583ec18fa23e12b8c8b44ff870b754c3bc7b04a4 Mon Sep 17 00:00:00 2001 From: Karel Pokorny Date: Sun, 28 Jul 2019 15:54:39 +0200 Subject: [PATCH 1/7] Add keycloak provider --- main.go | 1 + options.go | 3 + providers/keycloak.go | 86 +++++++++++++++++++++ providers/keycloak_test.go | 148 +++++++++++++++++++++++++++++++++++++ providers/providers.go | 2 + 5 files changed, 240 insertions(+) create mode 100644 providers/keycloak.go create mode 100644 providers/keycloak_test.go diff --git a/main.go b/main.go index 97e2357..60d64d0 100644 --- a/main.go +++ b/main.go @@ -54,6 +54,7 @@ func main() { flagSet.Var(&emailDomains, "email-domain", "authenticate emails with the specified domain (may be given multiple times). Use * to authenticate any email") flagSet.Var(&whitelistDomains, "whitelist-domain", "allowed domains for redirection after authentication. Prefix domain with a . to allow subdomains (eg .example.com)") + flagSet.String("keycloak-group", "", "restrict login to members of this group.") flagSet.String("azure-tenant", "common", "go to a tenant-specific or common (tenant-independent) endpoint.") flagSet.String("github-org", "", "restrict logins to members of this organisation") flagSet.String("github-team", "", "restrict logins to members of this team") diff --git a/options.go b/options.go index 7dcb12b..3c7d078 100644 --- a/options.go +++ b/options.go @@ -41,6 +41,7 @@ type Options struct { TLSKeyFile string `flag:"tls-key-file" cfg:"tls_key_file" env:"OAUTH2_PROXY_TLS_KEY_FILE"` AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file" env:"OAUTH2_PROXY_AUTHENTICATED_EMAILS_FILE"` + KeycloakGroup string `flag:"keycloak-group" cfg:"keycloak_group"` AzureTenant string `flag:"azure-tenant" cfg:"azure_tenant" env:"OAUTH2_PROXY_AZURE_TENANT"` EmailDomains []string `flag:"email-domain" cfg:"email_domains" env:"OAUTH2_PROXY_EMAIL_DOMAINS"` WhitelistDomains []string `flag:"whitelist-domain" cfg:"whitelist_domains" env:"OAUTH2_PROXY_WHITELIST_DOMAINS"` @@ -394,6 +395,8 @@ func parseProviderInfo(o *Options, msgs []string) []string { p.Configure(o.AzureTenant) case *providers.GitHubProvider: p.SetOrgTeam(o.GitHubOrg, o.GitHubTeam) + case *providers.KeycloakProvider: + p.SetGroup(o.KeycloakGroup) case *providers.GoogleProvider: if o.GoogleServiceAccountJSON != "" { file, err := os.Open(o.GoogleServiceAccountJSON) diff --git a/providers/keycloak.go b/providers/keycloak.go new file mode 100644 index 0000000..ae1ef69 --- /dev/null +++ b/providers/keycloak.go @@ -0,0 +1,86 @@ +package providers + +import ( + "github.com/pusher/oauth2_proxy/pkg/apis/sessions" + "log" + "net/http" + "net/url" + + "github.com/bitly/oauth2_proxy/api" +) + +type KeycloakProvider struct { + *ProviderData + Group string +} + +func NewKeycloakProvider(p *ProviderData) *KeycloakProvider { + p.ProviderName = "Keycloak" + if p.LoginURL == nil || p.LoginURL.String() == "" { + p.LoginURL = &url.URL{ + Scheme: "https", + Host: "keycloak.org", + Path: "/oauth/authorize", + } + } + if p.RedeemURL == nil || p.RedeemURL.String() == "" { + p.RedeemURL = &url.URL{ + Scheme: "https", + Host: "keycloak.org", + Path: "/oauth/token", + } + } + if p.ValidateURL == nil || p.ValidateURL.String() == "" { + p.ValidateURL = &url.URL{ + Scheme: "https", + Host: "keycloak.org", + Path: "/api/v3/user", + } + } + if p.Scope == "" { + p.Scope = "api" + } + return &KeycloakProvider{ProviderData: p} +} + +func (p *KeycloakProvider) SetGroup(group string) { + p.Group = group +} + +func (p *KeycloakProvider) GetEmailAddress(s *sessions.SessionState) (string, error) { + + req, err := http.NewRequest("GET", p.ValidateURL.String(), nil) + req.Header.Set("Authorization", "Bearer "+s.AccessToken) + if err != nil { + log.Printf("failed building request %s", err) + return "", err + } + json, err := api.Request(req) + if err != nil { + log.Printf("failed making request %s", err) + return "", err + } + + if p.Group != "" { + var groups, err = json.Get("groups").Array() + if err != nil { + log.Printf("groups not found %s", err) + return "", err + } + + var found = false + for i := range groups { + if groups[i].(string) == p.Group { + found = true + break + } + } + + if found != true { + log.Printf("group not found, access denied") + return "", nil + } + } + + return json.Get("email").String() +} diff --git a/providers/keycloak_test.go b/providers/keycloak_test.go new file mode 100644 index 0000000..f64df12 --- /dev/null +++ b/providers/keycloak_test.go @@ -0,0 +1,148 @@ +package providers + +import ( + "github.com/pusher/oauth2_proxy/pkg/apis/sessions" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/bmizerany/assert" +) + +func testKeycloakProvider(hostname, group string) *KeycloakProvider { + p := NewKeycloakProvider( + &ProviderData{ + ProviderName: "", + LoginURL: &url.URL{}, + RedeemURL: &url.URL{}, + ProfileURL: &url.URL{}, + ValidateURL: &url.URL{}, + Scope: ""}) + + if group != "" { + p.SetGroup(group) + } + + if hostname != "" { + updateURL(p.Data().LoginURL, hostname) + updateURL(p.Data().RedeemURL, hostname) + updateURL(p.Data().ProfileURL, hostname) + updateURL(p.Data().ValidateURL, hostname) + } + return p +} + +func testKeycloakBackend(payload string) *httptest.Server { + path := "/api/v3/user" + + return httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + url := r.URL + if url.Path != path { + w.WriteHeader(404) + } else if r.Header.Get("Authorization") != "Bearer imaginary_access_token" { + w.WriteHeader(403) + } else { + w.WriteHeader(200) + w.Write([]byte(payload)) + } + })) +} + +func TestKeycloakProviderDefaults(t *testing.T) { + p := testKeycloakProvider("", "") + assert.NotEqual(t, nil, p) + assert.Equal(t, "Keycloak", p.Data().ProviderName) + assert.Equal(t, "https://keycloak.org/oauth/authorize", + p.Data().LoginURL.String()) + assert.Equal(t, "https://keycloak.org/oauth/token", + p.Data().RedeemURL.String()) + assert.Equal(t, "https://keycloak.org/api/v3/user", + p.Data().ValidateURL.String()) + assert.Equal(t, "api", p.Data().Scope) +} + +func TestKeycloakProviderOverrides(t *testing.T) { + p := NewKeycloakProvider( + &ProviderData{ + LoginURL: &url.URL{ + Scheme: "https", + Host: "example.com", + Path: "/oauth/auth"}, + RedeemURL: &url.URL{ + Scheme: "https", + Host: "example.com", + Path: "/oauth/token"}, + ValidateURL: &url.URL{ + Scheme: "https", + Host: "example.com", + Path: "/api/v3/user"}, + Scope: "profile"}) + assert.NotEqual(t, nil, p) + assert.Equal(t, "Keycloak", p.Data().ProviderName) + assert.Equal(t, "https://example.com/oauth/auth", + p.Data().LoginURL.String()) + assert.Equal(t, "https://example.com/oauth/token", + p.Data().RedeemURL.String()) + assert.Equal(t, "https://example.com/api/v3/user", + p.Data().ValidateURL.String()) + assert.Equal(t, "profile", p.Data().Scope) +} + +func TestKeycloakProviderGetEmailAddress(t *testing.T) { + b := testKeycloakBackend("{\"email\": \"michael.bland@gsa.gov\"}") + defer b.Close() + + b_url, _ := url.Parse(b.URL) + p := testKeycloakProvider(b_url.Host, "") + + session := &sessions.SessionState{AccessToken: "imaginary_access_token"} + email, err := p.GetEmailAddress(session) + assert.Equal(t, nil, err) + assert.Equal(t, "michael.bland@gsa.gov", email) +} + +func TestKeycloakProviderGetEmailAddressAndGroup(t *testing.T) { + b := testKeycloakBackend("{\"email\": \"michael.bland@gsa.gov\", \"groups\": [\"test-grp1\", \"test-grp2\"]}") + defer b.Close() + + b_url, _ := url.Parse(b.URL) + p := testKeycloakProvider(b_url.Host, "test-grp1") + + session := &sessions.SessionState{AccessToken: "imaginary_access_token"} + email, err := p.GetEmailAddress(session) + assert.Equal(t, nil, err) + assert.Equal(t, "michael.bland@gsa.gov", email) +} + +// Note that trying to trigger the "failed building request" case is not +// practical, since the only way it can fail is if the URL fails to parse. +func TestKeycloakProviderGetEmailAddressFailedRequest(t *testing.T) { + b := testKeycloakBackend("unused payload") + defer b.Close() + + b_url, _ := url.Parse(b.URL) + p := testKeycloakProvider(b_url.Host, "") + + // We'll trigger a request failure by using an unexpected access + // token. Alternatively, we could allow the parsing of the payload as + // JSON to fail. + session := &sessions.SessionState{AccessToken: "unexpected_access_token"} + email, err := p.GetEmailAddress(session) + assert.NotEqual(t, nil, err) + assert.Equal(t, "", email) +} + +func TestKeycloakProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) { + b := testKeycloakBackend("{\"foo\": \"bar\"}") + defer b.Close() + + b_url, _ := url.Parse(b.URL) + p := testKeycloakProvider(b_url.Host, "") + + session := &sessions.SessionState{AccessToken: "imaginary_access_token"} + email, err := p.GetEmailAddress(session) + assert.NotEqual(t, nil, err) + assert.Equal(t, "", email) +} diff --git a/providers/providers.go b/providers/providers.go index baf723d..bbb8675 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -28,6 +28,8 @@ func New(provider string, p *ProviderData) Provider { return NewFacebookProvider(p) case "github": return NewGitHubProvider(p) + case "keycloak": + return NewKeycloakProvider(p) case "azure": return NewAzureProvider(p) case "gitlab": From 800a3694c247bceaf8f9a358fcfeed4d12bccb9c Mon Sep 17 00:00:00 2001 From: Karel Pokorny Date: Sun, 28 Jul 2019 16:26:09 +0200 Subject: [PATCH 2/7] Add docs and record in CHANGELOG --- CHANGELOG.md | 1 + docs/2_auth.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74f09c2..fdbb6d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ ## Changes since v3.2.0 +- [#226](https://github.com/pusher/oauth2_proxy/pull/227) Add Keycloak provider (@Ofinka) - [#178](https://github.com/pusher/outh2_proxy/pull/178) Add Silence Ping Logging and Exclude Logging Paths flags (@kskewes) - [#209](https://github.com/pusher/outh2_proxy/pull/209) Improve docker build caching of layers (@dekimsey) - [#186](https://github.com/pusher/oauth2_proxy/pull/186) Make config consistent (@JoelSpeed) diff --git a/docs/2_auth.md b/docs/2_auth.md index 7a9bebd..2d53e1f 100644 --- a/docs/2_auth.md +++ b/docs/2_auth.md @@ -15,6 +15,7 @@ Valid providers are : - [Azure](#azure-auth-provider) - [Facebook](#facebook-auth-provider) - [GitHub](#github-auth-provider) +- [Keycloak](#keycloak-auth-provider) - [GitLab](#gitlab-auth-provider) - [LinkedIn](#linkedin-auth-provider) - [login.gov](#logingov-provider) @@ -101,6 +102,20 @@ If you are using GitHub enterprise, make sure you set the following to the appro -redeem-url="http(s):///login/oauth/access_token" -validate-url="http(s):///api/v3" +### Keycloak Auth Provider + +1. Create new client in your Keycloak with **Access Type** 'confidental'. +2. Create a mapper with **Mapper Type** 'Group Membership'. + +Make sure you set the following to the appropriate url: + + -provider=keycloak + -client-id= + -client-secret= + -login-url="http(s):///realms//protocol/openid-connect/auth" + -redeem-url="http(s):///realms/master//openid-connect/auth/token" + -validate-url="http(s):///realms/master//openid-connect/userinfo" + ### GitLab Auth Provider Whether you are using GitLab.com or self-hosting GitLab, follow [these steps to add an application](http://doc.gitlab.com/ce/integration/oauth_provider.html) From 53524875d1e62f11485c7cbc6d07967fc0830d8f Mon Sep 17 00:00:00 2001 From: Karel Pokorny Date: Sun, 28 Jul 2019 16:46:16 +0200 Subject: [PATCH 3/7] Get rid of dependencies on bitly/oauth2_proxy/api --- providers/keycloak.go | 16 ++++++++-------- providers/keycloak_test.go | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/providers/keycloak.go b/providers/keycloak.go index ae1ef69..2715372 100644 --- a/providers/keycloak.go +++ b/providers/keycloak.go @@ -1,12 +1,12 @@ package providers import ( - "github.com/pusher/oauth2_proxy/pkg/apis/sessions" - "log" "net/http" "net/url" - "github.com/bitly/oauth2_proxy/api" + "github.com/pusher/oauth2_proxy/pkg/apis/sessions" + "github.com/pusher/oauth2_proxy/pkg/logger" + "github.com/pusher/oauth2_proxy/pkg/requests" ) type KeycloakProvider struct { @@ -52,19 +52,19 @@ func (p *KeycloakProvider) GetEmailAddress(s *sessions.SessionState) (string, er req, err := http.NewRequest("GET", p.ValidateURL.String(), nil) req.Header.Set("Authorization", "Bearer "+s.AccessToken) if err != nil { - log.Printf("failed building request %s", err) + logger.Printf("failed building request %s", err) return "", err } - json, err := api.Request(req) + json, err := requests.Request(req) if err != nil { - log.Printf("failed making request %s", err) + logger.Printf("failed making request %s", err) return "", err } if p.Group != "" { var groups, err = json.Get("groups").Array() if err != nil { - log.Printf("groups not found %s", err) + logger.Printf("groups not found %s", err) return "", err } @@ -77,7 +77,7 @@ func (p *KeycloakProvider) GetEmailAddress(s *sessions.SessionState) (string, er } if found != true { - log.Printf("group not found, access denied") + logger.Printf("group not found, access denied") return "", nil } } diff --git a/providers/keycloak_test.go b/providers/keycloak_test.go index f64df12..ced528b 100644 --- a/providers/keycloak_test.go +++ b/providers/keycloak_test.go @@ -94,8 +94,8 @@ func TestKeycloakProviderGetEmailAddress(t *testing.T) { b := testKeycloakBackend("{\"email\": \"michael.bland@gsa.gov\"}") defer b.Close() - b_url, _ := url.Parse(b.URL) - p := testKeycloakProvider(b_url.Host, "") + bUrl, _ := url.Parse(b.URL) + p := testKeycloakProvider(bUrl.Host, "") session := &sessions.SessionState{AccessToken: "imaginary_access_token"} email, err := p.GetEmailAddress(session) @@ -107,8 +107,8 @@ func TestKeycloakProviderGetEmailAddressAndGroup(t *testing.T) { b := testKeycloakBackend("{\"email\": \"michael.bland@gsa.gov\", \"groups\": [\"test-grp1\", \"test-grp2\"]}") defer b.Close() - b_url, _ := url.Parse(b.URL) - p := testKeycloakProvider(b_url.Host, "test-grp1") + bUrl, _ := url.Parse(b.URL) + p := testKeycloakProvider(bUrl.Host, "test-grp1") session := &sessions.SessionState{AccessToken: "imaginary_access_token"} email, err := p.GetEmailAddress(session) @@ -122,8 +122,8 @@ func TestKeycloakProviderGetEmailAddressFailedRequest(t *testing.T) { b := testKeycloakBackend("unused payload") defer b.Close() - b_url, _ := url.Parse(b.URL) - p := testKeycloakProvider(b_url.Host, "") + bUrl, _ := url.Parse(b.URL) + p := testKeycloakProvider(bUrl.Host, "") // We'll trigger a request failure by using an unexpected access // token. Alternatively, we could allow the parsing of the payload as @@ -138,8 +138,8 @@ func TestKeycloakProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) { b := testKeycloakBackend("{\"foo\": \"bar\"}") defer b.Close() - b_url, _ := url.Parse(b.URL) - p := testKeycloakProvider(b_url.Host, "") + bUrl, _ := url.Parse(b.URL) + p := testKeycloakProvider(bUrl.Host, "") session := &sessions.SessionState{AccessToken: "imaginary_access_token"} email, err := p.GetEmailAddress(session) From 4eab98e65b3247c2fa61340f693d2f958450b7af Mon Sep 17 00:00:00 2001 From: Karel Pokorny Date: Sun, 28 Jul 2019 16:58:11 +0200 Subject: [PATCH 4/7] Fix travis analysis --- providers/keycloak_test.go | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/providers/keycloak_test.go b/providers/keycloak_test.go index ced528b..b5d2625 100644 --- a/providers/keycloak_test.go +++ b/providers/keycloak_test.go @@ -1,15 +1,18 @@ package providers import ( - "github.com/pusher/oauth2_proxy/pkg/apis/sessions" "net/http" "net/http/httptest" "net/url" "testing" "github.com/bmizerany/assert" + "github.com/pusher/oauth2_proxy/pkg/apis/sessions" ) +const imaginaryAccessToken = "imaginary_access_token" +const bearerAccessToken = "Bearer " + imaginaryAccessToken + func testKeycloakProvider(hostname, group string) *KeycloakProvider { p := NewKeycloakProvider( &ProviderData{ @@ -41,7 +44,7 @@ func testKeycloakBackend(payload string) *httptest.Server { url := r.URL if url.Path != path { w.WriteHeader(404) - } else if r.Header.Get("Authorization") != "Bearer imaginary_access_token" { + } else if r.Header.Get("Authorization") != bearerAccessToken { w.WriteHeader(403) } else { w.WriteHeader(200) @@ -94,10 +97,10 @@ func TestKeycloakProviderGetEmailAddress(t *testing.T) { b := testKeycloakBackend("{\"email\": \"michael.bland@gsa.gov\"}") defer b.Close() - bUrl, _ := url.Parse(b.URL) - p := testKeycloakProvider(bUrl.Host, "") + bURL, _ := url.Parse(b.URL) + p := testKeycloakProvider(bURL.Host, "") - session := &sessions.SessionState{AccessToken: "imaginary_access_token"} + session := &sessions.SessionState{AccessToken: imaginaryAccessToken} email, err := p.GetEmailAddress(session) assert.Equal(t, nil, err) assert.Equal(t, "michael.bland@gsa.gov", email) @@ -107,10 +110,10 @@ func TestKeycloakProviderGetEmailAddressAndGroup(t *testing.T) { b := testKeycloakBackend("{\"email\": \"michael.bland@gsa.gov\", \"groups\": [\"test-grp1\", \"test-grp2\"]}") defer b.Close() - bUrl, _ := url.Parse(b.URL) - p := testKeycloakProvider(bUrl.Host, "test-grp1") + bURL, _ := url.Parse(b.URL) + p := testKeycloakProvider(bURL.Host, "test-grp1") - session := &sessions.SessionState{AccessToken: "imaginary_access_token"} + session := &sessions.SessionState{AccessToken: imaginaryAccessToken} email, err := p.GetEmailAddress(session) assert.Equal(t, nil, err) assert.Equal(t, "michael.bland@gsa.gov", email) @@ -122,8 +125,8 @@ func TestKeycloakProviderGetEmailAddressFailedRequest(t *testing.T) { b := testKeycloakBackend("unused payload") defer b.Close() - bUrl, _ := url.Parse(b.URL) - p := testKeycloakProvider(bUrl.Host, "") + bURL, _ := url.Parse(b.URL) + p := testKeycloakProvider(bURL.Host, "") // We'll trigger a request failure by using an unexpected access // token. Alternatively, we could allow the parsing of the payload as @@ -138,10 +141,10 @@ func TestKeycloakProviderGetEmailAddressEmailNotPresentInPayload(t *testing.T) { b := testKeycloakBackend("{\"foo\": \"bar\"}") defer b.Close() - bUrl, _ := url.Parse(b.URL) - p := testKeycloakProvider(bUrl.Host, "") + bURL, _ := url.Parse(b.URL) + p := testKeycloakProvider(bURL.Host, "") - session := &sessions.SessionState{AccessToken: "imaginary_access_token"} + session := &sessions.SessionState{AccessToken: imaginaryAccessToken} email, err := p.GetEmailAddress(session) assert.NotEqual(t, nil, err) assert.Equal(t, "", email) From a025228a6ddea9e563d841426d0d6b93198c5d7c Mon Sep 17 00:00:00 2001 From: Karel Pokorny Date: Wed, 31 Jul 2019 14:36:13 +0200 Subject: [PATCH 5/7] Set env tag appropriately --- options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options.go b/options.go index 3c7d078..8eaf21e 100644 --- a/options.go +++ b/options.go @@ -41,7 +41,7 @@ type Options struct { TLSKeyFile string `flag:"tls-key-file" cfg:"tls_key_file" env:"OAUTH2_PROXY_TLS_KEY_FILE"` AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file" env:"OAUTH2_PROXY_AUTHENTICATED_EMAILS_FILE"` - KeycloakGroup string `flag:"keycloak-group" cfg:"keycloak_group"` + KeycloakGroup string `flag:"keycloak-group" cfg:"keycloak_group" env:"OAUTH2_PROXY_AUTHENTICATED_KEYCLOAK_GROUP"` AzureTenant string `flag:"azure-tenant" cfg:"azure_tenant" env:"OAUTH2_PROXY_AZURE_TENANT"` EmailDomains []string `flag:"email-domain" cfg:"email_domains" env:"OAUTH2_PROXY_EMAIL_DOMAINS"` WhitelistDomains []string `flag:"whitelist-domain" cfg:"whitelist_domains" env:"OAUTH2_PROXY_WHITELIST_DOMAINS"` From 436936836d57cffe2df0b9104f3c5961267fafa6 Mon Sep 17 00:00:00 2001 From: Karel Pokorny Date: Wed, 31 Jul 2019 14:39:34 +0200 Subject: [PATCH 6/7] Fix typo in env tag --- options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options.go b/options.go index 8eaf21e..1b56400 100644 --- a/options.go +++ b/options.go @@ -41,7 +41,7 @@ type Options struct { TLSKeyFile string `flag:"tls-key-file" cfg:"tls_key_file" env:"OAUTH2_PROXY_TLS_KEY_FILE"` AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file" env:"OAUTH2_PROXY_AUTHENTICATED_EMAILS_FILE"` - KeycloakGroup string `flag:"keycloak-group" cfg:"keycloak_group" env:"OAUTH2_PROXY_AUTHENTICATED_KEYCLOAK_GROUP"` + KeycloakGroup string `flag:"keycloak-group" cfg:"keycloak_group" env:"OAUTH2_PROXY_KEYCLOAK_GROUP"` AzureTenant string `flag:"azure-tenant" cfg:"azure_tenant" env:"OAUTH2_PROXY_AZURE_TENANT"` EmailDomains []string `flag:"email-domain" cfg:"email_domains" env:"OAUTH2_PROXY_EMAIL_DOMAINS"` WhitelistDomains []string `flag:"whitelist-domain" cfg:"whitelist_domains" env:"OAUTH2_PROXY_WHITELIST_DOMAINS"` From a122ac60e4862f405e1f7827e7b879d220798e17 Mon Sep 17 00:00:00 2001 From: Dan Bond Date: Wed, 25 Sep 2019 13:33:58 -0700 Subject: [PATCH 7/7] Fix CHANGELOG errors --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f16e75..2c48091 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## Changes since v4.0.0 -- [#226](https://github.com/pusher/oauth2_proxy/pull/227) Add Keycloak provider (@Ofinka) +- [#227](https://github.com/pusher/oauth2_proxy/pull/227) Add Keycloak provider (@Ofinka) # v4.0.0 @@ -51,8 +51,6 @@ reconfigure their proxies. Please read the Breaking Changes below thoroughly. ## Changes since v3.2.0 -- [#178](https://github.com/pusher/outh2_proxy/pull/178) Add Silence Ping Logging and Exclude Logging Paths flags (@kskewes) -- [#209](https://github.com/pusher/outh2_proxy/pull/209) Improve docker build caching of layers (@dekimsey) - [#234](https://github.com/pusher/oauth2_proxy/pull/234) Added option `-ssl-upstream-insecure-skip-validation` to skip validation of upstream SSL certificates (@jansinger) - [#224](https://github.com/pusher/oauth2_proxy/pull/224) Check Google group membership using hasMember to support nested groups and external users (@jpalpant) - [#231](https://github.com/pusher/oauth2_proxy/pull/231) Add optional group membership and email domain checks to the GitLab provider (@Overv)