1
0
mirror of https://github.com/oauth2-proxy/oauth2-proxy.git synced 2024-11-24 08:52:25 +02:00

Move SignIn page rendering to app pkg

This commit is contained in:
Joel Speed 2021-02-12 17:53:01 +00:00 committed by Joel Speed
parent 1e3d8547d7
commit dba6989054
No known key found for this signature in database
GPG Key ID: 6E80578D6751DEFB
3 changed files with 187 additions and 79 deletions

View File

@ -5,7 +5,6 @@ import (
"encoding/json"
"errors"
"fmt"
"html/template"
"net"
"net/http"
"net/url"
@ -76,39 +75,34 @@ type OAuthProxy struct {
AuthOnlyPath string
UserInfoPath string
allowedRoutes []allowedRoute
redirectURL *url.URL // the url to receive requests at
whitelistDomains []string
provider providers.Provider
providerNameOverride string
sessionStore sessionsapi.SessionStore
ProxyPrefix string
SignInMessage string
basicAuthValidator basic.Validator
displayHtpasswdForm bool
serveMux http.Handler
SetXAuthRequest bool
PassBasicAuth bool
SetBasicAuth bool
SkipProviderButton bool
PassUserHeaders bool
BasicAuthPassword string
PassAccessToken bool
SetAuthorization bool
PassAuthorization bool
PreferEmailToUser bool
skipAuthPreflight bool
skipJwtBearerTokens bool
templates *template.Template
realClientIPParser ipapi.RealClientIPParser
trustedIPs *ip.NetSet
Banner string
Footer string
allowedRoutes []allowedRoute
redirectURL *url.URL // the url to receive requests at
whitelistDomains []string
provider providers.Provider
sessionStore sessionsapi.SessionStore
ProxyPrefix string
basicAuthValidator basic.Validator
serveMux http.Handler
SetXAuthRequest bool
PassBasicAuth bool
SetBasicAuth bool
SkipProviderButton bool
PassUserHeaders bool
BasicAuthPassword string
PassAccessToken bool
SetAuthorization bool
PassAuthorization bool
PreferEmailToUser bool
skipAuthPreflight bool
skipJwtBearerTokens bool
realClientIPParser ipapi.RealClientIPParser
trustedIPs *ip.NetSet
sessionChain alice.Chain
headersChain alice.Chain
preAuthChain alice.Chain
errorPage *app.ErrorPage
signInPage *app.SignInPage
}
// 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
}
}
signInPage := &app.SignInPage{
Template: templates.Lookup("sign_in.html"),
ErrorPage: errorPage,
ProxyPrefix: opts.ProxyPrefix,
ProviderName: buildProviderName(opts.GetProvider(), opts.ProviderName),
SignInMessage: buildSignInMessage(opts),
Footer: opts.Templates.Footer,
Version: VERSION,
DisplayLoginForm: basicAuthValidator != nil && opts.Templates.DisplayLoginForm,
}
allowedRoutes, err := buildRoutesAllowlist(opts)
if err != nil {
return nil, err
@ -210,30 +215,25 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix),
UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
ProxyPrefix: opts.ProxyPrefix,
provider: opts.GetProvider(),
providerNameOverride: opts.ProviderName,
sessionStore: sessionStore,
serveMux: upstreamProxy,
redirectURL: redirectURL,
allowedRoutes: allowedRoutes,
whitelistDomains: opts.WhitelistDomains,
skipAuthPreflight: opts.SkipAuthPreflight,
skipJwtBearerTokens: opts.SkipJwtBearerTokens,
realClientIPParser: opts.GetRealClientIPParser(),
SkipProviderButton: opts.SkipProviderButton,
templates: templates,
trustedIPs: trustedIPs,
Banner: opts.Templates.Banner,
Footer: opts.Templates.Footer,
SignInMessage: buildSignInMessage(opts),
ProxyPrefix: opts.ProxyPrefix,
provider: opts.GetProvider(),
sessionStore: sessionStore,
serveMux: upstreamProxy,
redirectURL: redirectURL,
allowedRoutes: allowedRoutes,
whitelistDomains: opts.WhitelistDomains,
skipAuthPreflight: opts.SkipAuthPreflight,
skipJwtBearerTokens: opts.SkipJwtBearerTokens,
realClientIPParser: opts.GetRealClientIPParser(),
SkipProviderButton: opts.SkipProviderButton,
trustedIPs: trustedIPs,
basicAuthValidator: basicAuthValidator,
displayHtpasswdForm: basicAuthValidator != nil && opts.Templates.DisplayLoginForm,
sessionChain: sessionChain,
headersChain: headersChain,
preAuthChain: preAuthChain,
errorPage: errorPage,
basicAuthValidator: basicAuthValidator,
sessionChain: sessionChain,
headersChain: headersChain,
preAuthChain: preAuthChain,
errorPage: errorPage,
signInPage: signInPage,
}, nil
}
@ -331,6 +331,13 @@ func buildSignInMessage(opts *options.Options) string {
return msg
}
func buildProviderName(p providers.Provider, override string) string {
if override != "" {
return override
}
return p.Data().ProviderName
}
// buildRoutesAllowlist builds an []allowedRoute list from either the legacy
// SkipAuthRegex option (paths only support) or newer SkipAuthRoutes option
// (method=path support)
@ -594,33 +601,7 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code
redirectURL = "/"
}
// We allow unescaped template.HTML since it is user configured options
/* #nosec G203 */
t := struct {
ProviderName string
SignInMessage template.HTML
CustomLogin bool
Redirect string
Version string
ProxyPrefix string
Footer template.HTML
}{
ProviderName: p.provider.Data().ProviderName,
SignInMessage: template.HTML(p.SignInMessage),
CustomLogin: p.displayHtpasswdForm,
Redirect: redirectURL,
Version: VERSION,
ProxyPrefix: p.ProxyPrefix,
Footer: template.HTML(p.Footer),
}
if p.providerNameOverride != "" {
t.ProviderName = p.providerNameOverride
}
err = p.templates.ExecuteTemplate(rw, "sign_in.html", t)
if err != nil {
logger.Printf("Error rendering sign_in.html template: %v", err)
p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
}
p.signInPage.Render(rw, redirectURL)
}
// ManualSignIn handles basic auth logins to the proxy

66
pkg/app/sign_in_page.go Normal file
View File

@ -0,0 +1,66 @@
package app
import (
"html/template"
"net/http"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
)
// SignInPage is used to render sign-in pages.
type SignInPage struct {
// Template is the sign-in page HTML template.
Template *template.Template
// ErrorPage is used to render an error if there are problems with rendering the sign-in page.
ErrorPage *ErrorPage
// ProxyPrefix is the prefix under which OAuth2 Proxy pages are served.
ProxyPrefix string
// ProviderName is the name of the provider that should be displayed on the login button.
ProviderName string
// SignInMessage is the messge displayed above the login button.
SignInMessage string
// Footer is the footer to be displayed at the bottom of the page.
// If not set, a default footer will be used.
Footer string
// Version is the OAuth2 Proxy version to be used in the default footer.
Version string
// DisplayLoginForm determines whether or not the basic auth password form is displayed on the sign-in page.
DisplayLoginForm bool
}
// Render writes the sign-in page to the given response writer.
// It uses the redirectURL to be able to set the final destination for the user post login.
func (s *SignInPage) Render(rw http.ResponseWriter, redirectURL string) {
// We allow unescaped template.HTML since it is user configured options
/* #nosec G203 */
t := struct {
ProviderName string
SignInMessage template.HTML
CustomLogin bool
Redirect string
Version string
ProxyPrefix string
Footer template.HTML
}{
ProviderName: s.ProviderName,
SignInMessage: template.HTML(s.SignInMessage),
CustomLogin: s.DisplayLoginForm,
Redirect: redirectURL,
Version: s.Version,
ProxyPrefix: s.ProxyPrefix,
Footer: template.HTML(s.Footer),
}
err := s.Template.Execute(rw, t)
if err != nil {
logger.Printf("Error rendering sign-in template: %v", err)
s.ErrorPage.Render(rw, http.StatusInternalServerError, redirectURL, err.Error())
}
}

View File

@ -0,0 +1,61 @@
package app
import (
"html/template"
"io/ioutil"
"net/http/httptest"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("SignIn Page", func() {
var signInPage *SignInPage
BeforeEach(func() {
errorTmpl, err := template.New("").Parse("{{.Title}}")
Expect(err).ToNot(HaveOccurred())
errorPage := &ErrorPage{
Template: errorTmpl,
}
tmpl, err := template.New("").Parse("{{.ProxyPrefix}} {{.ProviderName}} {{.SignInMessage}} {{.Footer}} {{.Version}} {{.Redirect}} {{.CustomLogin}}")
Expect(err).ToNot(HaveOccurred())
signInPage = &SignInPage{
Template: tmpl,
ErrorPage: errorPage,
ProxyPrefix: "/prefix/",
ProviderName: "My Provider",
SignInMessage: "Sign In Here",
Footer: "Custom Footer Text",
Version: "v0.0.0-test",
DisplayLoginForm: true,
}
})
Context("Render", func() {
It("Writes the template to the response writer", func() {
recorder := httptest.NewRecorder()
signInPage.Render(recorder, "/redirect")
body, err := ioutil.ReadAll(recorder.Result().Body)
Expect(err).ToNot(HaveOccurred())
Expect(string(body)).To(Equal("/prefix/ My Provider Sign In Here Custom Footer Text v0.0.0-test /redirect true"))
})
It("Writes an error if the template can't be rendered", func() {
// Overwrite the template with something bad
tmpl, err := template.New("").Parse("{{.Unknown}}")
Expect(err).ToNot(HaveOccurred())
signInPage.Template = tmpl
recorder := httptest.NewRecorder()
signInPage.Render(recorder, "/redirect")
body, err := ioutil.ReadAll(recorder.Result().Body)
Expect(err).ToNot(HaveOccurred())
Expect(string(body)).To(Equal("Internal Server Error"))
})
})
})