git.iko.soy/typeable/oauth2-proxy
on master help sign in
Move SignIn page rendering to app pkg
commitdba6989054e58f931fbffcd692d51b91fc8f979f authorJoel Speed <joel.speed@hotmail.co.uk> dateFri 12 Feb 2021, 17:53 (6 years ago) parent1e3d854
3 files changed+188−80
oauthproxy.go+61−80 pkg/app/sign_in_page.go+66 pkg/app/sign_in_page_test.go+61
oauthproxy.go+61−80
@@ -5,7 +5,6 @@ import (
55 "encoding/json"
66 "errors"
77 "fmt"
8− "html/template"
98 "net"
109 "net/http"
1110 "net/url"
@@ -76,39 +75,34 @@ type OAuthProxy struct {
7675 AuthOnlyPath string
7776 UserInfoPath string
7877
79− allowedRoutes []allowedRoute
80− redirectURL *url.URL // the url to receive requests at
81− whitelistDomains []string
82− provider providers.Provider
83− providerNameOverride string
84− sessionStore sessionsapi.SessionStore
85− ProxyPrefix string
86− SignInMessage string
87− basicAuthValidator basic.Validator
88− displayHtpasswdForm bool
89− serveMux http.Handler
90− SetXAuthRequest bool
91− PassBasicAuth bool
92− SetBasicAuth bool
93− SkipProviderButton bool
94− PassUserHeaders bool
95− BasicAuthPassword string
96− PassAccessToken bool
97− SetAuthorization bool
98− PassAuthorization bool
99− PreferEmailToUser bool
100− skipAuthPreflight bool
101− skipJwtBearerTokens bool
102− templates *template.Template
103− realClientIPParser ipapi.RealClientIPParser
104− trustedIPs *ip.NetSet
105− Banner string
106− Footer string
78+ allowedRoutes []allowedRoute
79+ redirectURL *url.URL // the url to receive requests at
80+ whitelistDomains []string
81+ provider providers.Provider
82+ sessionStore sessionsapi.SessionStore
83+ ProxyPrefix string
84+ basicAuthValidator basic.Validator
85+ serveMux http.Handler
86+ SetXAuthRequest bool
87+ PassBasicAuth bool
88+ SetBasicAuth bool
89+ SkipProviderButton bool
90+ PassUserHeaders bool
91+ BasicAuthPassword string
92+ PassAccessToken bool
93+ SetAuthorization bool
94+ PassAuthorization bool
95+ PreferEmailToUser bool
96+ skipAuthPreflight bool
97+ skipJwtBearerTokens bool
98+ realClientIPParser ipapi.RealClientIPParser
99+ trustedIPs *ip.NetSet
107100
108101 sessionChain alice.Chain
109102 headersChain alice.Chain
110103 preAuthChain alice.Chain
111104 errorPage *app.ErrorPage
105+ signInPage *app.SignInPage
112106}
113107
114108// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
@@ -174,6 +168,17 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
174168 }
175169 }
176170
171+ signInPage := &app.SignInPage{
172+ Template: templates.Lookup("sign_in.html"),
173+ ErrorPage: errorPage,
174+ ProxyPrefix: opts.ProxyPrefix,
175+ ProviderName: buildProviderName(opts.GetProvider(), opts.ProviderName),
176+ SignInMessage: buildSignInMessage(opts),
177+ Footer: opts.Templates.Footer,
178+ Version: VERSION,
179+ DisplayLoginForm: basicAuthValidator != nil && opts.Templates.DisplayLoginForm,
180+ }
181+
177182 allowedRoutes, err := buildRoutesAllowlist(opts)
178183 if err != nil {
179184 return nil, err
@@ -210,30 +215,25 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
210215 AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix),
211216 UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
212217
213− ProxyPrefix: opts.ProxyPrefix,
214− provider: opts.GetProvider(),
215− providerNameOverride: opts.ProviderName,
216− sessionStore: sessionStore,
217− serveMux: upstreamProxy,
218− redirectURL: redirectURL,
219− allowedRoutes: allowedRoutes,
220− whitelistDomains: opts.WhitelistDomains,
221− skipAuthPreflight: opts.SkipAuthPreflight,
222− skipJwtBearerTokens: opts.SkipJwtBearerTokens,
223− realClientIPParser: opts.GetRealClientIPParser(),
224− SkipProviderButton: opts.SkipProviderButton,
225− templates: templates,
226− trustedIPs: trustedIPs,
227− Banner: opts.Templates.Banner,
228− Footer: opts.Templates.Footer,
229− SignInMessage: buildSignInMessage(opts),
230−
231− basicAuthValidator: basicAuthValidator,
232− displayHtpasswdForm: basicAuthValidator != nil && opts.Templates.DisplayLoginForm,
233− sessionChain: sessionChain,
234− headersChain: headersChain,
235− preAuthChain: preAuthChain,
236− errorPage: errorPage,
218+ ProxyPrefix: opts.ProxyPrefix,
219+ provider: opts.GetProvider(),
220+ sessionStore: sessionStore,
221+ serveMux: upstreamProxy,
222+ redirectURL: redirectURL,
223+ allowedRoutes: allowedRoutes,
224+ whitelistDomains: opts.WhitelistDomains,
225+ skipAuthPreflight: opts.SkipAuthPreflight,
226+ skipJwtBearerTokens: opts.SkipJwtBearerTokens,
227+ realClientIPParser: opts.GetRealClientIPParser(),
228+ SkipProviderButton: opts.SkipProviderButton,
229+ trustedIPs: trustedIPs,
230+
231+ basicAuthValidator: basicAuthValidator,
232+ sessionChain: sessionChain,
233+ headersChain: headersChain,
234+ preAuthChain: preAuthChain,
235+ errorPage: errorPage,
236+ signInPage: signInPage,
237237 }, nil
238238}
239239
@@ -331,6 +331,13 @@ func buildSignInMessage(opts *options.Options) string {
331331 return msg
332332}
333333
334+func buildProviderName(p providers.Provider, override string) string {
335+ if override != "" {
336+ return override
337+ }
338+ return p.Data().ProviderName
339+}
340+
334341// buildRoutesAllowlist builds an []allowedRoute list from either the legacy
335342// SkipAuthRegex option (paths only support) or newer SkipAuthRoutes option
336343// (method=path support)
@@ -594,33 +601,7 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code
594601 redirectURL = "/"
595602 }
596603
597− // We allow unescaped template.HTML since it is user configured options
598− /* #nosec G203 */
599− t := struct {
600− ProviderName string
601− SignInMessage template.HTML
602− CustomLogin bool
603− Redirect string
604− Version string
605− ProxyPrefix string
606− Footer template.HTML
607− }{
608− ProviderName: p.provider.Data().ProviderName,
609− SignInMessage: template.HTML(p.SignInMessage),
610− CustomLogin: p.displayHtpasswdForm,
611− Redirect: redirectURL,
612− Version: VERSION,
613− ProxyPrefix: p.ProxyPrefix,
614− Footer: template.HTML(p.Footer),
615− }
616− if p.providerNameOverride != "" {
617− t.ProviderName = p.providerNameOverride
618− }
619− err = p.templates.ExecuteTemplate(rw, "sign_in.html", t)
620− if err != nil {
621− logger.Printf("Error rendering sign_in.html template: %v", err)
622− p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
623− }
604+ p.signInPage.Render(rw, redirectURL)
624605}
625606
626607// ManualSignIn handles basic auth logins to the proxy
pkg/app/sign_in_page.gonew file+66
@@ -0,0 +1,66 @@
1+package app
2+
3+import (
4+ "html/template"
5+ "net/http"
6+
7+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
8+)
9+
10+// SignInPage is used to render sign-in pages.
11+type SignInPage struct {
12+ // Template is the sign-in page HTML template.
13+ Template *template.Template
14+
15+ // ErrorPage is used to render an error if there are problems with rendering the sign-in page.
16+ ErrorPage *ErrorPage
17+
18+ // ProxyPrefix is the prefix under which OAuth2 Proxy pages are served.
19+ ProxyPrefix string
20+
21+ // ProviderName is the name of the provider that should be displayed on the login button.
22+ ProviderName string
23+
24+ // SignInMessage is the messge displayed above the login button.
25+ SignInMessage string
26+
27+ // Footer is the footer to be displayed at the bottom of the page.
28+ // If not set, a default footer will be used.
29+ Footer string
30+
31+ // Version is the OAuth2 Proxy version to be used in the default footer.
32+ Version string
33+
34+ // DisplayLoginForm determines whether or not the basic auth password form is displayed on the sign-in page.
35+ DisplayLoginForm bool
36+}
37+
38+// Render writes the sign-in page to the given response writer.
39+// It uses the redirectURL to be able to set the final destination for the user post login.
40+func (s *SignInPage) Render(rw http.ResponseWriter, redirectURL string) {
41+ // We allow unescaped template.HTML since it is user configured options
42+ /* #nosec G203 */
43+ t := struct {
44+ ProviderName string
45+ SignInMessage template.HTML
46+ CustomLogin bool
47+ Redirect string
48+ Version string
49+ ProxyPrefix string
50+ Footer template.HTML
51+ }{
52+ ProviderName: s.ProviderName,
53+ SignInMessage: template.HTML(s.SignInMessage),
54+ CustomLogin: s.DisplayLoginForm,
55+ Redirect: redirectURL,
56+ Version: s.Version,
57+ ProxyPrefix: s.ProxyPrefix,
58+ Footer: template.HTML(s.Footer),
59+ }
60+
61+ err := s.Template.Execute(rw, t)
62+ if err != nil {
63+ logger.Printf("Error rendering sign-in template: %v", err)
64+ s.ErrorPage.Render(rw, http.StatusInternalServerError, redirectURL, err.Error())
65+ }
66+}
pkg/app/sign_in_page_test.gonew file+61
@@ -0,0 +1,61 @@
1+package app
2+
3+import (
4+ "html/template"
5+ "io/ioutil"
6+ "net/http/httptest"
7+
8+ . "github.com/onsi/ginkgo"
9+ . "github.com/onsi/gomega"
10+)
11+
12+var _ = Describe("SignIn Page", func() {
13+ var signInPage *SignInPage
14+
15+ BeforeEach(func() {
16+ errorTmpl, err := template.New("").Parse("{{.Title}}")
17+ Expect(err).ToNot(HaveOccurred())
18+ errorPage := &ErrorPage{
19+ Template: errorTmpl,
20+ }
21+
22+ tmpl, err := template.New("").Parse("{{.ProxyPrefix}} {{.ProviderName}} {{.SignInMessage}} {{.Footer}} {{.Version}} {{.Redirect}} {{.CustomLogin}}")
23+ Expect(err).ToNot(HaveOccurred())
24+
25+ signInPage = &SignInPage{
26+ Template: tmpl,
27+ ErrorPage: errorPage,
28+ ProxyPrefix: "/prefix/",
29+ ProviderName: "My Provider",
30+ SignInMessage: "Sign In Here",
31+ Footer: "Custom Footer Text",
32+ Version: "v0.0.0-test",
33+ DisplayLoginForm: true,
34+ }
35+ })
36+
37+ Context("Render", func() {
38+ It("Writes the template to the response writer", func() {
39+ recorder := httptest.NewRecorder()
40+ signInPage.Render(recorder, "/redirect")
41+
42+ body, err := ioutil.ReadAll(recorder.Result().Body)
43+ Expect(err).ToNot(HaveOccurred())
44+ Expect(string(body)).To(Equal("/prefix/ My Provider Sign In Here Custom Footer Text v0.0.0-test /redirect true"))
45+ })
46+
47+ It("Writes an error if the template can't be rendered", func() {
48+ // Overwrite the template with something bad
49+ tmpl, err := template.New("").Parse("{{.Unknown}}")
50+ Expect(err).ToNot(HaveOccurred())
51+ signInPage.Template = tmpl
52+
53+ recorder := httptest.NewRecorder()
54+ signInPage.Render(recorder, "/redirect")
55+
56+ body, err := ioutil.ReadAll(recorder.Result().Body)
57+ Expect(err).ToNot(HaveOccurred())
58+ Expect(string(body)).To(Equal("Internal Server Error"))
59+ })
60+ })
61+})