git.iko.soy/typeable/oauth2-proxy
on master help sign in
Wrap templates and page rendering in PageWriter interface
commite8e2af73df818772cc743c3006033332bab1b1c9 authorJoel Speed <joel.speed@hotmail.co.uk> dateFri 12 Feb 2021, 18:25 (6 years ago) parentdba6989
9 files changed+325−126
oauthproxy.go+25−37 pkg/app/error_page.go+23−23 pkg/app/error_page_test.go+15−15 pkg/app/pagewriter.go+85 pkg/app/pagewriter_test.go+126 pkg/app/sign_in_page.go+21−21 pkg/app/sign_in_page_test.go+17−17 pkg/app/templates.go+2−2 pkg/app/templates_test.go+11−11
oauthproxy.go+25−37
@@ -101,8 +101,7 @@ type OAuthProxy struct {
101101 sessionChain alice.Chain
102102 headersChain alice.Chain
103103 preAuthChain alice.Chain
104− errorPage *app.ErrorPage
105− signInPage *app.SignInPage
104+ pageWriter app.PageWriter
106105}
107106
108107// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
@@ -112,20 +111,31 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
112111 return nil, fmt.Errorf("error initialising session store: %v", err)
113112 }
114113
115− templates, err := app.LoadTemplates(opts.Templates.Path)
116− if err != nil {
117− return nil, fmt.Errorf("error loading templates: %v", err)
114+ var basicAuthValidator basic.Validator
115+ if opts.HtpasswdFile != "" {
116+ logger.Printf("using htpasswd file: %s", opts.HtpasswdFile)
117+ var err error
118+ basicAuthValidator, err = basic.NewHTPasswdValidator(opts.HtpasswdFile)
119+ if err != nil {
120+ return nil, fmt.Errorf("could not load htpasswdfile: %v", err)
121+ }
118122 }
119123
120− errorPage := &app.ErrorPage{
121− Template: templates.Lookup("error.html"),
122− ProxyPrefix: opts.ProxyPrefix,
123− Footer: opts.Templates.Footer,
124− Version: VERSION,
125− Debug: opts.Templates.Debug,
124+ pageWriter, err := app.NewPageWriter(app.PageWriterOpts{
125+ TemplatesPath: opts.Templates.Path,
126+ ProxyPrefix: opts.ProxyPrefix,
127+ Footer: opts.Templates.Footer,
128+ Version: VERSION,
129+ Debug: opts.Templates.Debug,
130+ ProviderName: buildProviderName(opts.GetProvider(), opts.ProviderName),
131+ SignInMessage: buildSignInMessage(opts),
132+ DisplayLoginForm: basicAuthValidator != nil && opts.Templates.DisplayLoginForm,
133+ })
134+ if err != nil {
135+ return nil, fmt.Errorf("error initialising page writer: %v", err)
126136 }
127137
128− upstreamProxy, err := upstream.NewProxy(opts.UpstreamServers, opts.GetSignatureData(), errorPage.ProxyErrorHandler)
138+ upstreamProxy, err := upstream.NewProxy(opts.UpstreamServers, opts.GetSignatureData(), pageWriter.ProxyErrorHandler)
129139 if err != nil {
130140 return nil, fmt.Errorf("error initialising upstream proxy: %v", err)
131141 }
@@ -158,27 +168,6 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
158168 }
159169 }
160170
161− var basicAuthValidator basic.Validator
162− if opts.HtpasswdFile != "" {
163− logger.Printf("using htpasswd file: %s", opts.HtpasswdFile)
164− var err error
165− basicAuthValidator, err = basic.NewHTPasswdValidator(opts.HtpasswdFile)
166− if err != nil {
167− return nil, fmt.Errorf("could not load htpasswdfile: %v", err)
168− }
169− }
170−
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−
182171 allowedRoutes, err := buildRoutesAllowlist(opts)
183172 if err != nil {
184173 return nil, err
@@ -232,8 +221,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
232221 sessionChain: sessionChain,
233222 headersChain: headersChain,
234223 preAuthChain: preAuthChain,
235− errorPage: errorPage,
236− signInPage: signInPage,
224+ pageWriter: pageWriter,
237225 }, nil
238226}
239227
@@ -540,7 +528,7 @@ func (p *OAuthProxy) ErrorPage(rw http.ResponseWriter, req *http.Request, code i
540528 redirectURL = "/"
541529 }
542530
543− p.errorPage.Render(rw, code, redirectURL, appError, messages...)
531+ p.pageWriter.WriteErrorPage(rw, code, redirectURL, appError, messages...)
544532}
545533
546534// IsAllowedRequest is used to check if auth should be skipped for this request
@@ -601,7 +589,7 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code
601589 redirectURL = "/"
602590 }
603591
604− p.signInPage.Render(rw, redirectURL)
592+ p.pageWriter.WriteSignInPage(rw, redirectURL)
605593}
606594
607595// ManualSignIn handles basic auth logins to the proxy
pkg/app/error_page.go+23−23
@@ -17,30 +17,30 @@ var errorMessages = map[int]string{
1717 http.StatusUnauthorized: "You need to be logged in to access this resource.",
1818}
1919
20−// ErrorPage is used to render error pages.
21−type ErrorPage struct {
22− // Template is the error page HTML template.
23− Template *template.Template
20+// errorPageWriter is used to render error pages.
21+type errorPageWriter struct {
22+ // template is the error page HTML template.
23+ template *template.Template
2424
25− // ProxyPrefix is the prefix under which OAuth2 Proxy pages are served.
26− ProxyPrefix string
25+ // proxyPrefix is the prefix under which OAuth2 Proxy pages are served.
26+ proxyPrefix string
2727
28− // Footer is the footer to be displayed at the bottom of the page.
28+ // footer is the footer to be displayed at the bottom of the page.
2929 // If not set, a default footer will be used.
30− Footer string
30+ footer string
3131
32− // Version is the OAuth2 Proxy version to be used in the default footer.
33− Version string
32+ // version is the OAuth2 Proxy version to be used in the default footer.
33+ version string
3434
35− // Debug determines whether errors pages should be rendered with detailed
35+ // debug determines whether errors pages should be rendered with detailed
3636 // errors.
37− Debug bool
37+ debug bool
3838}
3939
40−// Render writes an error page to the given response writer.
40+// WriteErrorPage writes an error page to the given response writer.
4141// It uses the passed redirectURL to give users the option to go back to where
4242// they originally came from or try signing in again.
43−func (e *ErrorPage) Render(rw http.ResponseWriter, status int, redirectURL string, appError string, messages ...interface{}) {
43+func (e *errorPageWriter) WriteErrorPage(rw http.ResponseWriter, status int, redirectURL string, appError string, messages ...interface{}) {
4444 rw.WriteHeader(status)
4545
4646 // We allow unescaped template.HTML since it is user configured options
@@ -56,14 +56,14 @@ func (e *ErrorPage) Render(rw http.ResponseWriter, status int, redirectURL strin
5656 }{
5757 Title: http.StatusText(status),
5858 Message: e.getMessage(status, appError, messages...),
59− ProxyPrefix: e.ProxyPrefix,
59+ ProxyPrefix: e.proxyPrefix,
6060 StatusCode: status,
6161 Redirect: redirectURL,
62− Footer: template.HTML(e.Footer),
63− Version: e.Version,
62+ Footer: template.HTML(e.footer),
63+ Version: e.version,
6464 }
6565
66− if err := e.Template.Execute(rw, data); err != nil {
66+ if err := e.template.Execute(rw, data); err != nil {
6767 logger.Printf("Error rendering error template: %v", err)
6868 http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
6969 }
@@ -72,18 +72,18 @@ func (e *ErrorPage) Render(rw http.ResponseWriter, status int, redirectURL strin
7272// ProxyErrorHandler is used by the upstream ReverseProxy to render error pages
7373// when there are issues with upstream servers.
7474// It is expected to always render a bad gateway error.
75−func (e *ErrorPage) ProxyErrorHandler(rw http.ResponseWriter, req *http.Request, proxyErr error) {
75+func (e *errorPageWriter) ProxyErrorHandler(rw http.ResponseWriter, req *http.Request, proxyErr error) {
7676 logger.Errorf("Error proxying to upstream server: %v", proxyErr)
77− e.Render(rw, http.StatusBadGateway, "", proxyErr.Error(), "There was a problem connecting to the upstream server.")
77+ e.WriteErrorPage(rw, http.StatusBadGateway, "", proxyErr.Error(), "There was a problem connecting to the upstream server.")
7878}
7979
8080// getMessage creates the message for the template parameters.
81−// If the ErrorPage.Debug is enabled, the application error takes precedence.
81+// If the errorPagewriter.Debug is enabled, the application error takes precedence.
8282// Otherwise, any messages will be used.
8383// The first message is expected to be a format string.
8484// If no messages are supplied, a default error message will be used.
85−func (e *ErrorPage) getMessage(status int, appError string, messages ...interface{}) string {
86− if e.Debug {
85+func (e *errorPageWriter) getMessage(status int, appError string, messages ...interface{}) string {
86+ if e.debug {
8787 return appError
8888 }
8989 if len(messages) > 0 {
pkg/app/error_page_test.go+15−15
@@ -10,25 +10,25 @@ import (
1010 . "github.com/onsi/gomega"
1111)
1212
13−var _ = Describe("Error Page", func() {
14− var errorPage *ErrorPage
13+var _ = Describe("Error Page Writer", func() {
14+ var errorPage *errorPageWriter
1515
1616 BeforeEach(func() {
1717 tmpl, err := template.New("").Parse("{{.Title}} {{.Message}} {{.ProxyPrefix}} {{.StatusCode}} {{.Redirect}} {{.Footer}} {{.Version}}")
1818 Expect(err).ToNot(HaveOccurred())
1919
20− errorPage = &ErrorPage{
21− Template: tmpl,
22− ProxyPrefix: "/prefix/",
23− Footer: "Custom Footer Text",
24− Version: "v0.0.0-test",
20+ errorPage = &errorPageWriter{
21+ template: tmpl,
22+ proxyPrefix: "/prefix/",
23+ footer: "Custom Footer Text",
24+ version: "v0.0.0-test",
2525 }
2626 })
2727
28− Context("Render", func() {
28+ Context("WriteErrorPage", func() {
2929 It("Writes the template to the response writer", func() {
3030 recorder := httptest.NewRecorder()
31− errorPage.Render(recorder, 403, "/redirect", "Access Denied")
31+ errorPage.WriteErrorPage(recorder, 403, "/redirect", "Access Denied")
3232
3333 body, err := ioutil.ReadAll(recorder.Result().Body)
3434 Expect(err).ToNot(HaveOccurred())
@@ -37,7 +37,7 @@ var _ = Describe("Error Page", func() {
3737
3838 It("With a different code, uses the stock message for the correct code", func() {
3939 recorder := httptest.NewRecorder()
40− errorPage.Render(recorder, 500, "/redirect", "Access Denied")
40+ errorPage.WriteErrorPage(recorder, 500, "/redirect", "Access Denied")
4141
4242 body, err := ioutil.ReadAll(recorder.Result().Body)
4343 Expect(err).ToNot(HaveOccurred())
@@ -46,7 +46,7 @@ var _ = Describe("Error Page", func() {
4646
4747 It("With a message override, uses the message", func() {
4848 recorder := httptest.NewRecorder()
49− errorPage.Render(recorder, 403, "/redirect", "Access Denied", "An extra message: %s", "with more context.")
49+ errorPage.WriteErrorPage(recorder, 403, "/redirect", "Access Denied", "An extra message: %s", "with more context.")
5050
5151 body, err := ioutil.ReadAll(recorder.Result().Body)
5252 Expect(err).ToNot(HaveOccurred())
@@ -71,14 +71,14 @@ var _ = Describe("Error Page", func() {
7171 tmpl, err := template.New("").Parse("{{.Message}}")
7272 Expect(err).ToNot(HaveOccurred())
7373
74− errorPage.Template = tmpl
75− errorPage.Debug = true
74+ errorPage.template = tmpl
75+ errorPage.debug = true
7676 })
7777
78− Context("Render", func() {
78+ Context("WriteErrorPage", func() {
7979 It("Writes the detailed error in place of the message", func() {
8080 recorder := httptest.NewRecorder()
81− errorPage.Render(recorder, 403, "/redirect", "Debug error")
81+ errorPage.WriteErrorPage(recorder, 403, "/redirect", "Debug error")
8282
8383 body, err := ioutil.ReadAll(recorder.Result().Body)
8484 Expect(err).ToNot(HaveOccurred())
pkg/app/pagewriter.gonew file+85
@@ -0,0 +1,85 @@
1+package app
2+
3+import (
4+ "fmt"
5+ "net/http"
6+)
7+
8+// PageWriter is an interface for rendering html templates for both sign-in and
9+// error pages.
10+// It can also be used to write errors for the http.ReverseProxy used in the
11+// upstream package.
12+type PageWriter interface {
13+ WriteSignInPage(rw http.ResponseWriter, redirectURL string)
14+ WriteErrorPage(rw http.ResponseWriter, status int, redirectURL string, appError string, messages ...interface{})
15+ ProxyErrorHandler(rw http.ResponseWriter, req *http.Request, proxyErr error)
16+}
17+
18+// pageWriter implements the PageWriter interface
19+type pageWriter struct {
20+ *errorPageWriter
21+ *signInPageWriter
22+}
23+
24+// PageWriterOpts contains all options required to configure the template
25+// rendering within OAuth2 Proxy.
26+type PageWriterOpts struct {
27+ // TemplatesPath is the path from which to load custom templates for the sign-in and error pages.
28+ TemplatesPath string
29+
30+ // ProxyPrefix is the prefix under which OAuth2 Proxy pages are served.
31+ ProxyPrefix string
32+
33+ // Footer is the footer to be displayed at the bottom of the page.
34+ // If not set, a default footer will be used.
35+ Footer string
36+
37+ // Version is the OAuth2 Proxy version to be used in the default footer.
38+ Version string
39+
40+ // Debug determines whether errors pages should be rendered with detailed
41+ // errors.
42+ Debug bool
43+
44+ // DisplayLoginForm determines whether or not the basic auth password form is displayed on the sign-in page.
45+ DisplayLoginForm bool
46+
47+ // ProviderName is the name of the provider that should be displayed on the login button.
48+ ProviderName string
49+
50+ // SignInMessage is the messge displayed above the login button.
51+ SignInMessage string
52+}
53+
54+// NewPageWriter constructs a PageWriter from the options given to allow
55+// rendering of sign-in and error pages.
56+func NewPageWriter(opts PageWriterOpts) (PageWriter, error) {
57+ templates, err := loadTemplates(opts.TemplatesPath)
58+ if err != nil {
59+ return nil, fmt.Errorf("error loading templates: %v", err)
60+ }
61+
62+ errorPage := &errorPageWriter{
63+ template: templates.Lookup("error.html"),
64+ proxyPrefix: opts.ProxyPrefix,
65+ footer: opts.Footer,
66+ version: opts.Version,
67+ debug: opts.Debug,
68+ }
69+
70+ signInPage := &signInPageWriter{
71+ template: templates.Lookup("sign_in.html"),
72+ errorPageWriter: errorPage,
73+ proxyPrefix: opts.ProxyPrefix,
74+ providerName: opts.ProviderName,
75+ signInMessage: opts.SignInMessage,
76+ footer: opts.Footer,
77+ version: opts.Version,
78+ displayLoginForm: opts.DisplayLoginForm,
79+ }
80+
81+ return &pageWriter{
82+ errorPageWriter: errorPage,
83+ signInPageWriter: signInPage,
84+ }, nil
85+}
pkg/app/pagewriter_test.gonew file+126
@@ -0,0 +1,126 @@
1+package app
2+
3+import (
4+ "io/ioutil"
5+ "net/http/httptest"
6+ "os"
7+ "path/filepath"
8+
9+ . "github.com/onsi/ginkgo"
10+ . "github.com/onsi/gomega"
11+)
12+
13+var _ = Describe("PageWriter", func() {
14+ Context("NewPageWriter", func() {
15+ var writer PageWriter
16+ var opts PageWriterOpts
17+
18+ BeforeEach(func() {
19+ opts = PageWriterOpts{
20+ TemplatesPath: "",
21+ ProxyPrefix: "/prefix",
22+ Footer: "<Footer>",
23+ Version: "<Version>",
24+ Debug: false,
25+ DisplayLoginForm: false,
26+ ProviderName: "<ProviderName>",
27+ SignInMessage: "<SignInMessage>",
28+ }
29+ })
30+
31+ Context("With no custom templates", func() {
32+ BeforeEach(func() {
33+ var err error
34+ writer, err = NewPageWriter(opts)
35+ Expect(err).ToNot(HaveOccurred())
36+ })
37+
38+ It("Writes the default error template", func() {
39+ recorder := httptest.NewRecorder()
40+ writer.WriteErrorPage(recorder, 500, "/redirect", "Some debug error")
41+
42+ body, err := ioutil.ReadAll(recorder.Result().Body)
43+ Expect(err).ToNot(HaveOccurred())
44+ Expect(string(body)).To(HavePrefix("\n<!DOCTYPE html>"))
45+ })
46+
47+ It("Writes the default sign in template", func() {
48+ recorder := httptest.NewRecorder()
49+ writer.WriteSignInPage(recorder, "/redirect")
50+
51+ body, err := ioutil.ReadAll(recorder.Result().Body)
52+ Expect(err).ToNot(HaveOccurred())
53+ Expect(string(body)).To(HavePrefix("\n<!DOCTYPE html>"))
54+ })
55+ })
56+
57+ Context("With custom templates", func() {
58+ var customDir string
59+
60+ BeforeEach(func() {
61+ var err error
62+ customDir, err = ioutil.TempDir("", "oauth2-proxy-pagewriter-test")
63+ Expect(err).ToNot(HaveOccurred())
64+
65+ templateHTML := `Custom Template`
66+ signInFile := filepath.Join(customDir, signInTemplateName)
67+ Expect(ioutil.WriteFile(signInFile, []byte(templateHTML), 0600)).To(Succeed())
68+ errorFile := filepath.Join(customDir, errorTemplateName)
69+ Expect(ioutil.WriteFile(errorFile, []byte(templateHTML), 0600)).To(Succeed())
70+
71+ opts.TemplatesPath = customDir
72+
73+ writer, err = NewPageWriter(opts)
74+ Expect(err).ToNot(HaveOccurred())
75+ })
76+
77+ AfterEach(func() {
78+ Expect(os.RemoveAll(customDir)).To(Succeed())
79+ })
80+
81+ It("Writes the custom error template", func() {
82+ recorder := httptest.NewRecorder()
83+ writer.WriteErrorPage(recorder, 500, "/redirect", "Some debug error")
84+
85+ body, err := ioutil.ReadAll(recorder.Result().Body)
86+ Expect(err).ToNot(HaveOccurred())
87+ Expect(string(body)).To(Equal("Custom Template"))
88+ })
89+
90+ It("Writes the custom sign in template", func() {
91+ recorder := httptest.NewRecorder()
92+ writer.WriteSignInPage(recorder, "/redirect")
93+
94+ body, err := ioutil.ReadAll(recorder.Result().Body)
95+ Expect(err).ToNot(HaveOccurred())
96+ Expect(string(body)).To(Equal("Custom Template"))
97+ })
98+ })
99+
100+ Context("With an invalid custom template", func() {
101+ var customDir string
102+
103+ BeforeEach(func() {
104+ var err error
105+ customDir, err = ioutil.TempDir("", "oauth2-proxy-pagewriter-test")
106+ Expect(err).ToNot(HaveOccurred())
107+
108+ templateHTML := `{{ Custom Broken Template`
109+ signInFile := filepath.Join(customDir, signInTemplateName)
110+ Expect(ioutil.WriteFile(signInFile, []byte(templateHTML), 0600)).To(Succeed())
111+
112+ opts.TemplatesPath = customDir
113+ })
114+
115+ AfterEach(func() {
116+ Expect(os.RemoveAll(customDir)).To(Succeed())
117+ })
118+
119+ It("Should return an error", func() {
120+ writer, err := NewPageWriter(opts)
121+ Expect(err).To(MatchError(ContainSubstring("template: sign_in.html:1: function \"Custom\" not defined")))
122+ Expect(writer).To(BeNil())
123+ })
124+ })
125+ })
126+})
pkg/app/sign_in_page.go+21−21
@@ -7,37 +7,37 @@ import (
77 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
88)
99
10−// SignInPage is used to render sign-in pages.
11−type SignInPage struct {
10+// signInPageWriter is used to render sign-in pages.
11+type signInPageWriter struct {
1212 // Template is the sign-in page HTML template.
13− Template *template.Template
13+ template *template.Template
1414
15− // ErrorPage is used to render an error if there are problems with rendering the sign-in page.
16− ErrorPage *ErrorPage
15+ // errorPageWriter is used to render an error if there are problems with rendering the sign-in page.
16+ errorPageWriter *errorPageWriter
1717
1818 // ProxyPrefix is the prefix under which OAuth2 Proxy pages are served.
19− ProxyPrefix string
19+ proxyPrefix string
2020
2121 // ProviderName is the name of the provider that should be displayed on the login button.
22− ProviderName string
22+ providerName string
2323
2424 // SignInMessage is the messge displayed above the login button.
25− SignInMessage string
25+ signInMessage string
2626
2727 // Footer is the footer to be displayed at the bottom of the page.
2828 // If not set, a default footer will be used.
29− Footer string
29+ footer string
3030
3131 // Version is the OAuth2 Proxy version to be used in the default footer.
32− Version string
32+ version string
3333
3434 // DisplayLoginForm determines whether or not the basic auth password form is displayed on the sign-in page.
35− DisplayLoginForm bool
35+ displayLoginForm bool
3636}
3737
38−// Render writes the sign-in page to the given response writer.
38+// WriteSignInPage writes the sign-in page to the given response writer.
3939// 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) {
40+func (s *signInPageWriter) WriteSignInPage(rw http.ResponseWriter, redirectURL string) {
4141 // We allow unescaped template.HTML since it is user configured options
4242 /* #nosec G203 */
4343 t := struct {
@@ -49,18 +49,18 @@ func (s *SignInPage) Render(rw http.ResponseWriter, redirectURL string) {
4949 ProxyPrefix string
5050 Footer template.HTML
5151 }{
52− ProviderName: s.ProviderName,
53− SignInMessage: template.HTML(s.SignInMessage),
54− CustomLogin: s.DisplayLoginForm,
52+ ProviderName: s.providerName,
53+ SignInMessage: template.HTML(s.signInMessage),
54+ CustomLogin: s.displayLoginForm,
5555 Redirect: redirectURL,
56− Version: s.Version,
57− ProxyPrefix: s.ProxyPrefix,
58− Footer: template.HTML(s.Footer),
56+ Version: s.version,
57+ ProxyPrefix: s.proxyPrefix,
58+ Footer: template.HTML(s.footer),
5959 }
6060
61− err := s.Template.Execute(rw, t)
61+ err := s.template.Execute(rw, t)
6262 if err != nil {
6363 logger.Printf("Error rendering sign-in template: %v", err)
64− s.ErrorPage.Render(rw, http.StatusInternalServerError, redirectURL, err.Error())
64+ s.errorPageWriter.WriteErrorPage(rw, http.StatusInternalServerError, redirectURL, err.Error())
6565 }
6666}
pkg/app/sign_in_page_test.go+17−17
@@ -9,35 +9,35 @@ import (
99 . "github.com/onsi/gomega"
1010)
1111
12−var _ = Describe("SignIn Page", func() {
13− var signInPage *SignInPage
12+var _ = Describe("SignIn Page Writer", func() {
13+ var signInPage *signInPageWriter
1414
1515 BeforeEach(func() {
1616 errorTmpl, err := template.New("").Parse("{{.Title}}")
1717 Expect(err).ToNot(HaveOccurred())
18− errorPage := &ErrorPage{
19− Template: errorTmpl,
18+ errorPage := &errorPageWriter{
19+ template: errorTmpl,
2020 }
2121
2222 tmpl, err := template.New("").Parse("{{.ProxyPrefix}} {{.ProviderName}} {{.SignInMessage}} {{.Footer}} {{.Version}} {{.Redirect}} {{.CustomLogin}}")
2323 Expect(err).ToNot(HaveOccurred())
2424
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,
25+ signInPage = &signInPageWriter{
26+ template: tmpl,
27+ errorPageWriter: 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,
3434 }
3535 })
3636
37− Context("Render", func() {
37+ Context("WriteSignInPage", func() {
3838 It("Writes the template to the response writer", func() {
3939 recorder := httptest.NewRecorder()
40− signInPage.Render(recorder, "/redirect")
40+ signInPage.WriteSignInPage(recorder, "/redirect")
4141
4242 body, err := ioutil.ReadAll(recorder.Result().Body)
4343 Expect(err).ToNot(HaveOccurred())
@@ -48,10 +48,10 @@ var _ = Describe("SignIn Page", func() {
4848 // Overwrite the template with something bad
4949 tmpl, err := template.New("").Parse("{{.Unknown}}")
5050 Expect(err).ToNot(HaveOccurred())
51− signInPage.Template = tmpl
51+ signInPage.template = tmpl
5252
5353 recorder := httptest.NewRecorder()
54− signInPage.Render(recorder, "/redirect")
54+ signInPage.WriteSignInPage(recorder, "/redirect")
5555
5656 body, err := ioutil.ReadAll(recorder.Result().Body)
5757 Expect(err).ToNot(HaveOccurred())
pkg/app/templates.go+2−2
@@ -206,10 +206,10 @@ const (
206206{{end}}`
207207)
208208
209−// LoadTemplates adds the Sign In and Error templates from the custom template
209+// loadTemplates adds the Sign In and Error templates from the custom template
210210// directory, or uses the defaults if they do not exist or the custom directory
211211// is not provided.
212−func LoadTemplates(customDir string) (*template.Template, error) {
212+func loadTemplates(customDir string) (*template.Template, error) {
213213 t := template.New("").Funcs(template.FuncMap{
214214 "ToUpper": strings.ToUpper,
215215 "ToLower": strings.ToLower,
pkg/app/templates_test.go+11−11
@@ -21,16 +21,16 @@ var _ = Describe("Templates", func() {
2121
2222 templateHTML := `{{.TestString}} {{.TestString | ToLower}} {{.TestString | ToUpper}}`
2323 signInFile := filepath.Join(customDir, signInTemplateName)
24− Expect(ioutil.WriteFile(signInFile, []byte(templateHTML), 0666)).To(Succeed())
24+ Expect(ioutil.WriteFile(signInFile, []byte(templateHTML), 0600)).To(Succeed())
2525 errorFile := filepath.Join(customDir, errorTemplateName)
26− Expect(ioutil.WriteFile(errorFile, []byte(templateHTML), 0666)).To(Succeed())
26+ Expect(ioutil.WriteFile(errorFile, []byte(templateHTML), 0600)).To(Succeed())
2727 })
2828
2929 AfterEach(func() {
3030 Expect(os.RemoveAll(customDir)).To(Succeed())
3131 })
3232
33− Context("LoadTemplates", func() {
33+ Context("loadTemplates", func() {
3434 var data interface{}
3535 var t *template.Template
3636
@@ -73,7 +73,7 @@ var _ = Describe("Templates", func() {
7373 Context("With no custom directory", func() {
7474 BeforeEach(func() {
7575 var err error
76− t, err = LoadTemplates("")
76+ t, err = loadTemplates("")
7777 Expect(err).ToNot(HaveOccurred())
7878 })
7979
@@ -94,7 +94,7 @@ var _ = Describe("Templates", func() {
9494 Context("With both templates", func() {
9595 BeforeEach(func() {
9696 var err error
97− t, err = LoadTemplates(customDir)
97+ t, err = loadTemplates(customDir)
9898 Expect(err).ToNot(HaveOccurred())
9999 })
100100
@@ -116,7 +116,7 @@ var _ = Describe("Templates", func() {
116116 Expect(os.Remove(filepath.Join(customDir, errorTemplateName))).To(Succeed())
117117
118118 var err error
119− t, err = LoadTemplates(customDir)
119+ t, err = loadTemplates(customDir)
120120 Expect(err).ToNot(HaveOccurred())
121121 })
122122
@@ -138,7 +138,7 @@ var _ = Describe("Templates", func() {
138138 Expect(os.Remove(filepath.Join(customDir, signInTemplateName))).To(Succeed())
139139
140140 var err error
141− t, err = LoadTemplates(customDir)
141+ t, err = loadTemplates(customDir)
142142 Expect(err).ToNot(HaveOccurred())
143143 })
144144
@@ -158,11 +158,11 @@ var _ = Describe("Templates", func() {
158158 Context("With an invalid sign_in template", func() {
159159 BeforeEach(func() {
160160 signInFile := filepath.Join(customDir, signInTemplateName)
161− Expect(ioutil.WriteFile(signInFile, []byte("{{"), 0666))
161+ Expect(ioutil.WriteFile(signInFile, []byte("{{"), 0600))
162162 })
163163
164164 It("Should return an error when loading templates", func() {
165− t, err := LoadTemplates(customDir)
165+ t, err := loadTemplates(customDir)
166166 Expect(err).To(MatchError(HavePrefix("could not add Sign In template:")))
167167 Expect(t).To(BeNil())
168168 })
@@ -171,11 +171,11 @@ var _ = Describe("Templates", func() {
171171 Context("With an invalid error template", func() {
172172 BeforeEach(func() {
173173 errorFile := filepath.Join(customDir, errorTemplateName)
174− Expect(ioutil.WriteFile(errorFile, []byte("{{"), 0666))
174+ Expect(ioutil.WriteFile(errorFile, []byte("{{"), 0600))
175175 })
176176
177177 It("Should return an error when loading templates", func() {
178− t, err := LoadTemplates(customDir)
178+ t, err := loadTemplates(customDir)
179179 Expect(err).To(MatchError(HavePrefix("could not add Error template:")))
180180 Expect(t).To(BeNil())
181181 })