Repository: oauth2-proxy/oauth2-proxy (go)

Issue:
404 page not found, after upgrade to latest oauth2-proxy v6.1.0
Hi @JoelSpeed 

I have been using latest image in oauth2-proxy deployment file. 
After the new release, Im seeing '404 page not found', after login and redirect to backend.
I have used the v6.0.0 in the image which solved the issue.

expected behaviour: redirect to backend application after login.
current behaviour: redirect to backend is not happening instead it shows below

![image](https://user-images.githubusercontent.com/62635671/91642300-da0bb780-ea47-11ea-88e1-2a3112a50b6b.png)

when accessing app url, It shows login page, after entering the credentials and submit, it shows 404 page not found.

below is oauthproxy deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: oauth2-proxy
  name: oauth2-proxy-si
  namespace: myns
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: oauth2-proxy
  template:
    metadata:
      labels:
        k8s-app: oauth2-proxy
    spec:
      containers:
      - args:
        - --provider=oidc
        - --email-domain=*
        - --cookie-domain=.appdomain.com
        - --http-address=0.0.0.0:4180
        - --pass-access-token=true
        - --pass-authorization-header=false
        - --set-authorization-header=true
        - --pass-user-headers=true
        - --set-xauthrequest=true
        - --skip-oidc-discovery=true
        - --login-url=https://idphost:443/oauth2/rest/authorize
        - --insecure-oidc-skip-issuer-verification=true
        - --oidc-issuer-url=https://idphost:443/oauth2
        - --oidc-jwks-url=http://idphost/oauth2/rest/security
        - --redeem-url=http://idphost/oauth2/rest/token
        - --validate-url=http://idphost/oauth2/rest/userinfo
        - --cookie-refresh=1h0m0s
        - --whitelist-domain="idphost"
        - --cookie-httponly=false
        - --cookie-secure=false
        - --standard-logging=true
        - --auth-logging=true
        - --request-logging=true
        - --skip-provider-button=true
        - --upstream=static://200
        - --redis-connection-url=redis://redis-master.default.svc.cluster.local:6379
        - --session-store-type=redis
        env:
        - name: OAUTH2_PROXY_CLIENT_ID
          value: <client id>
        - name: OAUTH2_PROXY_CLIENT_SECRET
          value: <secret>
        - name: OAUTH2_PROXY_COOKIE_SECRET
          value: 
        - name: OAUTH2_PROXY_COOKIE_DOMAIN
          value: .example.com
        image: quay.io/oauth2-proxy/oauth2-proxy:latest
        imagePullPolicy: Always
        name: oauth2-proxy
        ports:
        - containerPort: 4180
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: oauth2-proxy
  name: oauthproxy-service-si
  namespace: myns
spec:
  ports:
  - name: http
    port: 4180
    protocol: TCP
    targetPort: 4180
  selector:
    k8s-app: oauth2-proxy
---

using istio envoy filter, let me know if this file is needed 

Pull request:
Fix conversion of static responses in upstreams
<!--- Provide a general summary of your changes in the Title above -->

## Description

<!--- Describe your changes in detail -->
Fix a bug in the conversion of the static upstream type

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
Fixes #745 

## How Has This Been Tested?

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
Manual testing using the local test environment shows this works.

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [x] My change requires a change to the documentation or CHANGELOG.
- [x] I have updated the documentation/CHANGELOG accordingly.
- [x] I have created a feature (non-master) branch for my PR.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dbec2b12..f723eeca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
 ## Changes since v6.1.0
 
 - [#729](https://github.com/oauth2-proxy/oauth2-proxy/pull/729) Use X-Forwarded-Host consistently when set (@NickMeves)
+- [#746](https://github.com/oauth2-proxy/oauth2-proxy/pull/746) Fix conversion of static responses in upstreams (@JoelSpeed)
 
 # v6.1.0
 
diff --git a/pkg/apis/options/legacy_options.go b/pkg/apis/options/legacy_options.go
index d7f13e59..a2256daf 100644
--- a/pkg/apis/options/legacy_options.go
+++ b/pkg/apis/options/legacy_options.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"net/url"
 	"strconv"
+	"strings"
 	"time"
 
 	"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
@@ -87,6 +88,8 @@ func (l *LegacyUpstreams) convert() (Upstreams, error) {
 			if u.Fragment != "" {
 				upstream.ID = u.Fragment
 				upstream.Path = u.Fragment
+				// Trim the fragment from the end of the URI
+				upstream.URI = strings.SplitN(upstreamString, "#", 2)[0]
 			}
 		case "static":
 			responseCode, err := strconv.Atoi(u.Host)
@@ -97,17 +100,18 @@ func (l *LegacyUpstreams) convert() (Upstreams, error) {
 			upstream.Static = true
 			upstream.StaticCode = &responseCode
 
-			// These are not allowed to be empty and must be unique
+			// This is not allowed to be empty and must be unique
 			upstream.ID = upstreamString
-			upstream.Path = upstreamString
+
+			// We only support the root path in the legacy config
+			upstream.Path = "/"
 
 			// Force defaults compatible with static responses
 			upstream.URI = ""
 			upstream.InsecureSkipTLSVerify = false
 			upstream.PassHostHeader = nil
 			upstream.ProxyWebSockets = nil
-			flush := 1 * time.Second
-			upstream.FlushInterval = &flush
+			upstream.FlushInterval = nil
 		}
 
 		upstreams = append(upstreams, upstream)
diff --git a/pkg/upstream/proxy.go b/pkg/upstream/proxy.go
index a6abc305..9197944b 100644
--- a/pkg/upstream/proxy.go
+++ b/pkg/upstream/proxy.go
@@ -56,6 +56,7 @@ func (m *multiUpstreamProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request
 
 // registerStaticResponseHandler registers a static response handler with at the given path.
 func (m *multiUpstreamProxy) registerStaticResponseHandler(upstream options.Upstream) {
+	logger.Printf("mapping path %q => static response %d", upstream.Path, derefStaticCode(upstream.StaticCode))
 	m.serveMux.Handle(upstream.Path, newStaticResponseHandler(upstream.ID, upstream.StaticCode))
 }
 
diff --git a/pkg/upstream/static.go b/pkg/upstream/static.go
index 0a061421..d53d3d09 100644
--- a/pkg/upstream/static.go
+++ b/pkg/upstream/static.go
@@ -10,12 +10,8 @@ const defaultStaticResponseCode = 200
 // newStaticResponseHandler creates a new staticResponseHandler that serves a
 // a static response code.
 func newStaticResponseHandler(upstream string, code *int) http.Handler {
-	if code == nil {
-		c := defaultStaticResponseCode
-		code = &c
-	}
 	return &staticResponseHandler{
-		code:     *code,
+		code:     derefStaticCode(code),
 		upstream: upstream,
 	}
 }
@@ -32,3 +28,11 @@ func (s *staticResponseHandler) ServeHTTP(rw http.ResponseWriter, req *http.Requ
 	rw.WriteHeader(s.code)
 	fmt.Fprintf(rw, "Authenticated")
 }
+
+// derefStaticCode returns the derefenced value, or the default if the value is nil
+func derefStaticCode(code *int) int {
+	if code != nil {
+		return *code
+	}
+	return defaultStaticResponseCode
+}


Test patch:
diff --git a/pkg/apis/options/legacy_options_test.go b/pkg/apis/options/legacy_options_test.go
index 4223a293..80ad17b9 100644
--- a/pkg/apis/options/legacy_options_test.go
+++ b/pkg/apis/options/legacy_options_test.go
@@ -21,9 +21,10 @@ var _ = Describe("Legacy Options", func() {
 			legacyOpts.LegacyUpstreams.PassHostHeader = true
 			legacyOpts.LegacyUpstreams.ProxyWebSockets = true
 			legacyOpts.LegacyUpstreams.SSLUpstreamInsecureSkipVerify = true
-			legacyOpts.LegacyUpstreams.Upstreams = []string{"http://foo.bar/baz", "file://var/lib/website#/bar"}
+			legacyOpts.LegacyUpstreams.Upstreams = []string{"http://foo.bar/baz", "file:///var/lib/website#/bar", "static://204"}
 
 			truth := true
+			staticCode := 204
 			opts.UpstreamServers = Upstreams{
 				{
 					ID:                    "/baz",
@@ -37,12 +38,23 @@ var _ = Describe("Legacy Options", func() {
 				{
 					ID:                    "/bar",
 					Path:                  "/bar",
-					URI:                   "file://var/lib/website#/bar",
+					URI:                   "file:///var/lib/website",
 					FlushInterval:         &flushInterval,
 					InsecureSkipTLSVerify: true,
 					PassHostHeader:        &truth,
 					ProxyWebSockets:       &truth,
 				},
+				{
+					ID:                    "static://204",
+					Path:                  "/",
+					URI:                   "",
+					Static:                true,
+					StaticCode:            &staticCode,
+					FlushInterval:         nil,
+					InsecureSkipTLSVerify: false,
+					PassHostHeader:        nil,
+					ProxyWebSockets:       nil,
+				},
 			}
 
 			converted, err := legacyOpts.ToOptions()
@@ -58,8 +70,6 @@ var _ = Describe("Legacy Options", func() {
 			errMsg            string
 		}
 
-		defaultFlushInterval := 1 * time.Second
-
 		// Non defaults for these options
 		skipVerify := true
 		passHostHeader := false
@@ -90,11 +100,11 @@ var _ = Describe("Legacy Options", func() {
 			FlushInterval:         &flushInterval,
 		}
 
-		validFileWithFragment := "file://var/lib/website#/bar"
+		validFileWithFragment := "file:///var/lib/website#/bar"
 		validFileWithFragmentUpstream := Upstream{
 			ID:                    "/bar",
 			Path:                  "/bar",
-			URI:                   validFileWithFragment,
+			URI:                   "file:///var/lib/website",
 			InsecureSkipTLSVerify: skipVerify,
 			PassHostHeader:        &passHostHeader,
 			ProxyWebSockets:       &proxyWebSockets,
@@ -105,28 +115,28 @@ var _ = Describe("Legacy Options", func() {
 		validStaticCode := 204
 		validStaticUpstream := Upstream{
 			ID:                    validStatic,
-			Path:                  validStatic,
+			Path:                  "/",
 			URI:                   "",
 			Static:                true,
 			StaticCode:            &validStaticCode,
 			InsecureSkipTLSVerify: false,
 			PassHostHeader:        nil,
 			ProxyWebSockets:       nil,
-			FlushInterval:         &defaultFlushInterval,
+			FlushInterval:         nil,
 		}
 
 		invalidStatic := "static://abc"
 		invalidStaticCode := 200
 		invalidStaticUpstream := Upstream{
 			ID:                    invalidStatic,
-			Path:                  invalidStatic,
+			Path:                  "/",
 			URI:                   "",
 			Static:                true,
 			StaticCode:            &invalidStaticCode,
 			InsecureSkipTLSVerify: false,
 			PassHostHeader:        nil,
 			ProxyWebSockets:       nil,
-			FlushInterval:         &defaultFlushInterval,
+			FlushInterval:         nil,
 		}
 
 		invalidHTTP := ":foo"