@@ -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}
@@ -119,3 +128,250 @@ func (l *LegacyUpstreams) convert() (Upstreams, error) {
119128
120129 return upstreams, nil
121130}
131+
132+type LegacyHeaders struct {
133+ PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"`
134+ PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"`
135+ PassUserHeaders bool `flag:"pass-user-headers" cfg:"pass_user_headers"`
136+ PassAuthorization bool `flag:"pass-authorization-header" cfg:"pass_authorization_header"`
137+
138+ SetBasicAuth bool `flag:"set-basic-auth" cfg:"set_basic_auth"`
139+ SetXAuthRequest bool `flag:"set-xauthrequest" cfg:"set_xauthrequest"`
140+ SetAuthorization bool `flag:"set-authorization-header" cfg:"set_authorization_header"`
141+
142+ PreferEmailToUser bool `flag:"prefer-email-to-user" cfg:"prefer_email_to_user"`
143+ BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password"`
144+ SkipAuthStripHeaders bool `flag:"skip-auth-strip-headers" cfg:"skip_auth_strip_headers"`
145+}
146+
147+func legacyHeadersFlagSet() *pflag.FlagSet {
148+ flagSet := pflag.NewFlagSet("headers", pflag.ExitOnError)
149+
150+ flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
151+ flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
152+ flagSet.Bool("pass-user-headers", true, "pass X-Forwarded-User and X-Forwarded-Email information to upstream")
153+ flagSet.Bool("pass-authorization-header", false, "pass the Authorization Header to upstream")
154+
155+ flagSet.Bool("set-basic-auth", false, "set HTTP Basic Auth information in response (useful in Nginx auth_request mode)")
156+ flagSet.Bool("set-xauthrequest", false, "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)")
157+ flagSet.Bool("set-authorization-header", false, "set Authorization response headers (useful in Nginx auth_request mode)")
158+
159+ 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")
160+ flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
161+ 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")
162+
163+ return flagSet
164+}
165+
166+// convert takes the legacy request/response headers and converts them to
167+// the new format for InjectRequestHeaders and InjectResponseHeaders
168+func (l *LegacyHeaders) convert() ([]Header, []Header) {
169+ return l.getRequestHeaders(), l.getResponseHeaders()
170+}
171+
172+func (l *LegacyHeaders) getRequestHeaders() []Header {
173+ requestHeaders := []Header{}
174+
175+ if l.PassBasicAuth {
176+ requestHeaders = append(requestHeaders, getBasicAuthHeader(l.PreferEmailToUser, l.BasicAuthPassword))
177+ }
178+
179+ // In the old implementation, PassUserHeaders is a subset of PassBasicAuth
180+ if l.PassBasicAuth || l.PassUserHeaders {
181+ requestHeaders = append(requestHeaders, getPassUserHeaders(l.PreferEmailToUser)...)
182+ requestHeaders = append(requestHeaders, getPreferredUsernameHeader())
183+ }
184+
185+ if l.PassAccessToken {
186+ requestHeaders = append(requestHeaders, getPassAccessTokenHeader())
187+ }
188+
189+ if l.PassAuthorization {
190+ requestHeaders = append(requestHeaders, getAuthorizationHeader())
191+ }
192+
193+ return requestHeaders
194+}
195+
196+func (l *LegacyHeaders) getResponseHeaders() []Header {
197+ responseHeaders := []Header{}
198+
199+ if l.SetXAuthRequest {
200+ responseHeaders = append(responseHeaders, getXAuthRequestHeaders(l.PassAccessToken)...)
201+ }
202+
203+ if l.SetBasicAuth {
204+ responseHeaders = append(responseHeaders, getBasicAuthHeader(l.PreferEmailToUser, l.BasicAuthPassword))
205+ }
206+
207+ if l.SetAuthorization {
208+ responseHeaders = append(responseHeaders, getAuthorizationHeader())
209+ }
210+
211+ return responseHeaders
212+}
213+
214+func getBasicAuthHeader(preferEmailToUser bool, basicAuthPassword string) Header {
215+ claim := "user"
216+ if preferEmailToUser {
217+ claim = "email"
218+ }
219+
220+ return Header{
221+ Name: "Authorization",
222+ Values: []HeaderValue{
223+ {
224+ ClaimSource: &ClaimSource{
225+ Claim: claim,
226+ BasicAuthPassword: &SecretSource{
227+ Value: []byte(base64.StdEncoding.EncodeToString([]byte(basicAuthPassword))),
228+ },
229+ },
230+ },
231+ },
232+ }
233+}
234+
235+func getPassUserHeaders(preferEmailToUser bool) []Header {
236+ headers := []Header{
237+ {
238+ Name: "X-Forwarded-Groups",
239+ Values: []HeaderValue{
240+ {
241+ ClaimSource: &ClaimSource{
242+ Claim: "groups",
243+ },
244+ },
245+ },
246+ },
247+ }
248+
249+ if preferEmailToUser {
250+ return append(headers,
251+ Header{
252+ Name: "X-Forwarded-User",
253+ Values: []HeaderValue{
254+ {
255+ ClaimSource: &ClaimSource{
256+ Claim: "email",
257+ },
258+ },
259+ },
260+ },
261+ )
262+ } else {
263+ return append(headers,
264+ Header{
265+ Name: "X-Forwarded-User",
266+ Values: []HeaderValue{
267+ {
268+ ClaimSource: &ClaimSource{
269+ Claim: "user",
270+ },
271+ },
272+ },
273+ },
274+ Header{
275+ Name: "X-Forwarded-Email",
276+ Values: []HeaderValue{
277+ {
278+ ClaimSource: &ClaimSource{
279+ Claim: "email",
280+ },
281+ },
282+ },
283+ },
284+ )
285+ }
286+}
287+
288+func getPassAccessTokenHeader() Header {
289+ return Header{
290+ Name: "X-Forwarded-Access-Token",
291+ Values: []HeaderValue{
292+ {
293+ ClaimSource: &ClaimSource{
294+ Claim: "access_token",
295+ },
296+ },
297+ },
298+ }
299+}
300+
301+func getAuthorizationHeader() Header {
302+ return Header{
303+ Name: "Authorization",
304+ Values: []HeaderValue{
305+ {
306+ ClaimSource: &ClaimSource{
307+ Claim: "id_token",
308+ Prefix: "Bearer ",
309+ },
310+ },
311+ },
312+ }
313+}
314+
315+func getPreferredUsernameHeader() Header {
316+ return Header{
317+ Name: "X-Forwarded-Preferred-Username",
318+ Values: []HeaderValue{
319+ {
320+ ClaimSource: &ClaimSource{
321+ Claim: "preferred_username",
322+ },
323+ },
324+ },
325+ }
326+}
327+
328+func getXAuthRequestHeaders(passAccessToken bool) []Header {
329+ headers := []Header{
330+ {
331+ Name: "X-Auth-Request-User",
332+ Values: []HeaderValue{
333+ {
334+ ClaimSource: &ClaimSource{
335+ Claim: "user",
336+ },
337+ },
338+ },
339+ },
340+ {
341+ Name: "X-Auth-Request-Email",
342+ Values: []HeaderValue{
343+ {
344+ ClaimSource: &ClaimSource{
345+ Claim: "email",
346+ },
347+ },
348+ },
349+ },
350+ getPreferredUsernameHeader(),
351+ {
352+ Name: "X-Auth-Request-Groups",
353+ Values: []HeaderValue{
354+ {
355+ ClaimSource: &ClaimSource{
356+ Claim: "groups",
357+ },
358+ },
359+ },
360+ },
361+ }
362+
363+ if passAccessToken {
364+ headers = append(headers, Header{
365+ Name: "X-Auth-Request-Access-Token",
366+ Values: []HeaderValue{
367+ {
368+ ClaimSource: &ClaimSource{
369+ Claim: "access_token",
370+ },
371+ },
372+ },
373+ })
374+ }
375+
376+ return headers
377+}