git.iko.soy/typeable/oauth2-proxy
on master help sign in
Create LegacyHeaders struct and conversion to new Headers
commit2dc0d1e7ee914be1fc3d4d2fd3a95a179e00a2ac authorJoel Speed <joel.speed@hotmail.co.uk> dateWed 29 Jul 2020, 20:08 (6 years ago) parentab3cd58
3 files changed+314−28
pkg/apis/options/legacy_options.go+261 pkg/apis/options/legacy_options_test.go+49 pkg/apis/options/options.go+4−28
pkg/apis/options/legacy_options.go+261
@@ -1,6 +1,7 @@
11package options
22
33import (
4+ "encoding/base64"
45 "fmt"
56 "net/url"
67 "strconv"
@@ -15,6 +16,9 @@ type LegacyOptions struct {
1516 // Legacy options related to upstream servers
1617 LegacyUpstreams LegacyUpstreams `cfg:",squash"`
1718
19+ // Legacy options for injecting request/response headers
20+ LegacyHeaders LegacyHeaders `cfg:",squash"`
21+
1822 Options Options `cfg:",squash"`
1923}
2024
@@ -26,6 +30,11 @@ func NewLegacyOptions() *LegacyOptions {
2630 FlushInterval: time.Duration(1) * time.Second,
2731 },
2832
33+ LegacyHeaders: LegacyHeaders{
34+ PassBasicAuth: true,
35+ PassUserHeaders: true,
36+ },
37+
2938 Options: *NewOptions(),
3039 }
3140}
@@ -37,6 +46,7 @@ func (l *LegacyOptions) ToOptions() (*Options, error) {
3746 }
3847 l.Options.UpstreamServers = upstreams
3948
49+ l.Options.InjectRequestHeaders, l.Options.InjectResponseHeaders = l.LegacyHeaders.convert()
4050 return &l.Options, nil
4151}
4252
@@ -119,3 +129,254 @@ func (l *LegacyUpstreams) convert() (Upstreams, error) {
119129
120130 return upstreams, nil
121131}
132+
133+type LegacyHeaders struct {
134+ PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"`
135+ PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"`
136+ PassUserHeaders bool `flag:"pass-user-headers" cfg:"pass_user_headers"`
137+ PassAuthorization bool `flag:"pass-authorization-header" cfg:"pass_authorization_header"`
138+
139+ SetBasicAuth bool `flag:"set-basic-auth" cfg:"set_basic_auth"`
140+ SetXAuthRequest bool `flag:"set-xauthrequest" cfg:"set_xauthrequest"`
141+ SetAuthorization bool `flag:"set-authorization-header" cfg:"set_authorization_header"`
142+
143+ PreferEmailToUser bool `flag:"prefer-email-to-user" cfg:"prefer_email_to_user"`
144+ BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password"`
145+ SkipAuthStripHeaders bool `flag:"skip-auth-strip-headers" cfg:"skip_auth_strip_headers"`
146+}
147+
148+func legacyHeadersFlagSet() *pflag.FlagSet {
149+ flagSet := pflag.NewFlagSet("headers", pflag.ExitOnError)
150+
151+ flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
152+ flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
153+ flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream")
154+ flagSet.Bool("pass-authorization-header", false, "pass the Authorization Header to upstream")
155+
156+ flagSet.Bool("set-basic-auth", false, "set HTTP Basic Auth information in response (useful in Nginx auth_request mode)")
157+ flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)")
158+ flagSet.Bool("set-authorization-header", false, "set Authorization response headers (useful in Nginx auth_request mode)")
159+
160+ flagSet.Bool("prefer-email-to-user", false, "Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, eg. htaccess authentication. Used in conjunction with -pass-basic-auth and -pass-user-headers")
161+ flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
162+ flagSet.Bool("skip-auth-strip-headers", false, "strips X-Forwarded-* style authentication headers & Authorization header if they would be set by oauth2-proxy for request paths in --skip-auth-regex")
163+
164+ return flagSet
165+}
166+
167+// convert takes the legacy request/response headers and converts them to
168+// the new format for InjectRequestHeaders and InjectResponseHeaders
169+func (l *LegacyHeaders) convert() ([]Header, []Header) {
170+ return l.getRequestHeaders(), l.getResponseHeaders()
171+}
172+
173+func (l *LegacyHeaders) getRequestHeaders() []Header {
174+ requestHeaders := []Header{}
175+
176+ if l.PassBasicAuth && l.BasicAuthPassword != "" {
177+ requestHeaders = append(requestHeaders, getBasicAuthHeader(l.PreferEmailToUser, l.BasicAuthPassword))
178+ }
179+
180+ // In the old implementation, PassUserHeaders is a subset of PassBasicAuth
181+ if l.PassBasicAuth || l.PassUserHeaders {
182+ requestHeaders = append(requestHeaders, getPassUserHeaders(l.PreferEmailToUser)...)
183+ requestHeaders = append(requestHeaders, getPreferredUsernameHeader())
184+ }
185+
186+ if l.PassAccessToken {
187+ requestHeaders = append(requestHeaders, getPassAccessTokenHeader())
188+ }
189+
190+ if l.PassAuthorization {
191+ requestHeaders = append(requestHeaders, getAuthorizationHeader())
192+ }
193+
194+ for i := range requestHeaders {
195+ requestHeaders[i].PreserveRequestValue = !l.SkipAuthStripHeaders
196+ }
197+
198+ return requestHeaders
199+}
200+
201+func (l *LegacyHeaders) getResponseHeaders() []Header {
202+ responseHeaders := []Header{}
203+
204+ if l.SetXAuthRequest {
205+ responseHeaders = append(responseHeaders, getXAuthRequestHeaders(l.PassAccessToken)...)
206+ }
207+
208+ if l.SetBasicAuth {
209+ responseHeaders = append(responseHeaders, getBasicAuthHeader(l.PreferEmailToUser, l.BasicAuthPassword))
210+ }
211+
212+ if l.SetAuthorization {
213+ responseHeaders = append(responseHeaders, getAuthorizationHeader())
214+ }
215+
216+ return responseHeaders
217+}
218+
219+func getBasicAuthHeader(preferEmailToUser bool, basicAuthPassword string) Header {
220+ claim := "user"
221+ if preferEmailToUser {
222+ claim = "email"
223+ }
224+
225+ return Header{
226+ Name: "Authorization",
227+ Values: []HeaderValue{
228+ {
229+ ClaimSource: &ClaimSource{
230+ Claim: claim,
231+ BasicAuthPassword: &SecretSource{
232+ Value: []byte(base64.StdEncoding.EncodeToString([]byte(basicAuthPassword))),
233+ },
234+ },
235+ },
236+ },
237+ }
238+}
239+
240+func getPassUserHeaders(preferEmailToUser bool) []Header {
241+ headers := []Header{
242+ {
243+ Name: "X-Forwarded-Groups",
244+ Values: []HeaderValue{
245+ {
246+ ClaimSource: &ClaimSource{
247+ Claim: "groups",
248+ },
249+ },
250+ },
251+ },
252+ }
253+
254+ if preferEmailToUser {
255+ return append(headers,
256+ Header{
257+ Name: "X-Forwarded-User",
258+ Values: []HeaderValue{
259+ {
260+ ClaimSource: &ClaimSource{
261+ Claim: "email",
262+ },
263+ },
264+ },
265+ },
266+ )
267+ }
268+
269+ return append(headers,
270+ Header{
271+ Name: "X-Forwarded-User",
272+ Values: []HeaderValue{
273+ {
274+ ClaimSource: &ClaimSource{
275+ Claim: "user",
276+ },
277+ },
278+ },
279+ },
280+ Header{
281+ Name: "X-Forwarded-Email",
282+ Values: []HeaderValue{
283+ {
284+ ClaimSource: &ClaimSource{
285+ Claim: "email",
286+ },
287+ },
288+ },
289+ },
290+ )
291+}
292+
293+func getPassAccessTokenHeader() Header {
294+ return Header{
295+ Name: "X-Forwarded-Access-Token",
296+ Values: []HeaderValue{
297+ {
298+ ClaimSource: &ClaimSource{
299+ Claim: "access_token",
300+ },
301+ },
302+ },
303+ }
304+}
305+
306+func getAuthorizationHeader() Header {
307+ return Header{
308+ Name: "Authorization",
309+ Values: []HeaderValue{
310+ {
311+ ClaimSource: &ClaimSource{
312+ Claim: "id_token",
313+ Prefix: "Bearer ",
314+ },
315+ },
316+ },
317+ }
318+}
319+
320+func getPreferredUsernameHeader() Header {
321+ return Header{
322+ Name: "X-Forwarded-Preferred-Username",
323+ Values: []HeaderValue{
324+ {
325+ ClaimSource: &ClaimSource{
326+ Claim: "preferred_username",
327+ },
328+ },
329+ },
330+ }
331+}
332+
333+func getXAuthRequestHeaders(passAccessToken bool) []Header {
334+ headers := []Header{
335+ {
336+ Name: "X-Auth-Request-User",
337+ Values: []HeaderValue{
338+ {
339+ ClaimSource: &ClaimSource{
340+ Claim: "user",
341+ },
342+ },
343+ },
344+ },
345+ {
346+ Name: "X-Auth-Request-Email",
347+ Values: []HeaderValue{
348+ {
349+ ClaimSource: &ClaimSource{
350+ Claim: "email",
351+ },
352+ },
353+ },
354+ },
355+ getPreferredUsernameHeader(),
356+ {
357+ Name: "X-Auth-Request-Groups",
358+ Values: []HeaderValue{
359+ {
360+ ClaimSource: &ClaimSource{
361+ Claim: "groups",
362+ },
363+ },
364+ },
365+ },
366+ }
367+
368+ if passAccessToken {
369+ headers = append(headers, Header{
370+ Name: "X-Auth-Request-Access-Token",
371+ Values: []HeaderValue{
372+ {
373+ ClaimSource: &ClaimSource{
374+ Claim: "access_token",
375+ },
376+ },
377+ },
378+ })
379+ }
380+
381+ return headers
382+}
pkg/apis/options/legacy_options_test.go+49
@@ -57,6 +57,55 @@ var _ = Describe("Legacy Options", func() {
5757 },
5858 }
5959
60+ opts.InjectRequestHeaders = []Header{
61+ {
62+ Name: "X-Forwarded-Groups",
63+ PreserveRequestValue: true,
64+ Values: []HeaderValue{
65+ {
66+ ClaimSource: &ClaimSource{
67+ Claim: "groups",
68+ },
69+ },
70+ },
71+ },
72+ {
73+ Name: "X-Forwarded-User",
74+ PreserveRequestValue: true,
75+ Values: []HeaderValue{
76+ {
77+ ClaimSource: &ClaimSource{
78+ Claim: "user",
79+ },
80+ },
81+ },
82+ },
83+ {
84+ Name: "X-Forwarded-Email",
85+ PreserveRequestValue: true,
86+ Values: []HeaderValue{
87+ {
88+ ClaimSource: &ClaimSource{
89+ Claim: "email",
90+ },
91+ },
92+ },
93+ },
94+ {
95+ Name: "X-Forwarded-Preferred-Username",
96+ PreserveRequestValue: true,
97+ Values: []HeaderValue{
98+ {
99+ ClaimSource: &ClaimSource{
100+ Claim: "preferred_username",
101+ },
102+ },
103+ },
104+ },
105+ }
106+
107+ opts.InjectResponseHeaders = []Header{}
108+
60109 converted, err := legacyOpts.ToOptions()
61110 Expect(err).ToNot(HaveOccurred())
62111 Expect(converted).To(Equal(opts))
pkg/apis/options/options.go+4−28
@@ -65,22 +65,15 @@ type Options struct {
6565 // TODO(JoelSpeed): Rename when legacy config is removed
6666 UpstreamServers Upstreams `cfg:",internal"`
6767
68+ InjectRequestHeaders []Header `cfg:",internal"`
69+ InjectResponseHeaders []Header `cfg:",internal"`
70+
6871 SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"`
6972 SkipAuthRoutes []string `flag:"skip-auth-route" cfg:"skip_auth_routes"`
70− SkipAuthStripHeaders bool `flag:"skip-auth-strip-headers" cfg:"skip_auth_strip_headers"`
7173 SkipJwtBearerTokens bool `flag:"skip-jwt-bearer-tokens" cfg:"skip_jwt_bearer_tokens"`
7274 ExtraJwtIssuers []string `flag:"extra-jwt-issuers" cfg:"extra_jwt_issuers"`
73− PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"`
74− SetBasicAuth bool `flag:"set-basic-auth" cfg:"set_basic_auth"`
75− PreferEmailToUser bool `flag:"prefer-email-to-user" cfg:"prefer_email_to_user"`
76− BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password"`
77− PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"`
7875 SkipProviderButton bool `flag:"skip-provider-button" cfg:"skip_provider_button"`
79− PassUserHeaders bool `flag:"pass-user-headers" cfg:"pass_user_headers"`
8076 SSLInsecureSkipVerify bool `flag:"ssl-insecure-skip-verify" cfg:"ssl_insecure_skip_verify"`
81− SetXAuthRequest bool `flag:"set-xauthrequest" cfg:"set_xauthrequest"`
82− SetAuthorization bool `flag:"set-authorization-header" cfg:"set_authorization_header"`
83− PassAuthorization bool `flag:"pass-authorization-header" cfg:"pass_authorization_header"`
8477 SkipAuthPreflight bool `flag:"skip-auth-preflight" cfg:"skip_auth_preflight"`
8578
8679 // These options allow for other providers besides Google, with
@@ -151,15 +144,7 @@ func NewOptions() *Options {
151144 Cookie: cookieDefaults(),
152145 Session: sessionOptionsDefaults(),
153146 AzureTenant: "common",
154− SetXAuthRequest: false,
155147 SkipAuthPreflight: false,
156− PassBasicAuth: true,
157− SetBasicAuth: false,
158− PassUserHeaders: true,
159− PassAccessToken: false,
160− SetAuthorization: false,
161− PassAuthorization: false,
162− PreferEmailToUser: false,
163148 Prompt: "", // Change to "login" when ApprovalPrompt officially deprecated
164149 ApprovalPrompt: "force",
165150 UserIDClaim: "email",
@@ -183,18 +168,8 @@ func NewFlagSet() *pflag.FlagSet {
183168 flagSet.String("tls-cert-file", "", "path to certificate file")
184169 flagSet.String("tls-key-file", "", "path to private key file")
185170 flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"")
186− flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)")
187− flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
188− flagSet.Bool("set-basic-auth", false, "set HTTP Basic Auth information in response (useful in Nginx auth_request mode)")
189− flagSet.Bool("prefer-email-to-user", false, "Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, eg. htaccess authentication. Used in conjunction with -pass-basic-auth and -pass-user-headers")
190− flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream")
191− flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
192− flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
193− flagSet.Bool("pass-authorization-header", false, "pass the Authorization Header to upstream")
194− flagSet.Bool("set-authorization-header", false, "set Authorization response headers (useful in Nginx auth_request mode)")
195171 flagSet.StringSlice("skip-auth-regex", []string{}, "(DEPRECATED for --skip-auth-route) bypass authentication for requests path's that match (may be given multiple times)")
196172 flagSet.StringSlice("skip-auth-route", []string{}, "bypass authentication for requests that match the method & path. Format: method=path_regex OR path_regex alone for all methods")
197− flagSet.Bool("skip-auth-strip-headers", false, "strips `X-Forwarded-*` style authentication headers & `Authorization` header if they would be set by oauth2-proxy for allowlisted requests (`--skip-auth-route`, `--skip-auth-regex`, `--skip-auth-preflight`, `--trusted-ip`)")
198173 flagSet.Bool("skip-provider-button", false, "will skip sign-in-page to directly reach the next step: oauth/start")
199174 flagSet.Bool("skip-auth-preflight", false, "will skip authentication for OPTIONS requests")
200175 flagSet.Bool("ssl-insecure-skip-verify", false, "skip validation of certificates presented when using HTTPS providers")
@@ -272,6 +247,7 @@ func NewFlagSet() *pflag.FlagSet {
272247 flagSet.AddFlagSet(cookieFlagSet())
273248 flagSet.AddFlagSet(loggingFlagSet())
274249 flagSet.AddFlagSet(legacyUpstreamsFlagSet())
250+ flagSet.AddFlagSet(legacyHeadersFlagSet())
275251
276252 return flagSet
277253}