@@ -108,6 +108,7 @@ type OAuthProxy struct {
108108 sessionChain alice.Chain
109109 headersChain alice.Chain
110110 preAuthChain alice.Chain
111+ errorPage *app.ErrorPage
111112}
112113
113114// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
@@ -224,6 +225,12 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
224225 sessionChain: sessionChain,
225226 headersChain: headersChain,
226227 preAuthChain: preAuthChain,
228+ errorPage: &app.ErrorPage{
229+ Template: templates.Lookup("error.html"),
230+ ProxyPrefix: opts.ProxyPrefix,
231+ Footer: opts.Templates.Footer,
232+ Version: VERSION,
233+ },
227234 }, nil
228235}
229236
@@ -507,14 +514,14 @@ func (p *OAuthProxy) RobotsTxt(rw http.ResponseWriter, req *http.Request) {
507514 _, err := fmt.Fprintf(rw, "User-agent: *\nDisallow: /")
508515 if err != nil {
509516 logger.Printf("Error writing robots.txt: %v", err)
510− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
517+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
511518 return
512519 }
513520 rw.WriteHeader(http.StatusOK)
514521}
515522
516523// ErrorPage writes an error response
517−func (p *OAuthProxy) ErrorPage(rw http.ResponseWriter, req *http.Request, code int, title string, message string) {
524+func (p *OAuthProxy) ErrorPage(rw http.ResponseWriter, req *http.Request, code int, appError string) {
518525 redirectURL, err := p.getAppRedirect(req)
519526 if err != nil {
520527 logger.Errorf("Error obtaining redirect: %v", err)
@@ -523,32 +530,7 @@ func (p *OAuthProxy) ErrorPage(rw http.ResponseWriter, req *http.Request, code i
523530 redirectURL = "/"
524531 }
525532
526− rw.WriteHeader(code)
527−
528− // We allow unescaped template.HTML since it is user configured options
529− /* #nosec G203 */
530− t := struct {
531− Title string
532− Message string
533− ProxyPrefix string
534− StatusCode int
535− Redirect string
536− Footer template.HTML
537− Version string
538− }{
539− Title: title,
540− Message: message,
541− ProxyPrefix: p.ProxyPrefix,
542− StatusCode: code,
543− Redirect: redirectURL,
544− Footer: template.HTML(p.Footer),
545− Version: VERSION,
546− }
547−
548− if err := p.templates.ExecuteTemplate(rw, "error.html", t); err != nil {
549− logger.Printf("Error rendering error.html template: %v", err)
550− http.Error(rw, "Internal Server Error", http.StatusInternalServerError)
551− }
533+ p.errorPage.Render(rw, code, redirectURL, appError)
552534}
553535
554536// IsAllowedRequest is used to check if auth should be skipped for this request
@@ -593,7 +575,7 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code
593575 err := p.ClearSessionCookie(rw, req)
594576 if err != nil {
595577 logger.Printf("Error clearing session cookie: %v", err)
596− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
578+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
597579 return
598580 }
599581 rw.WriteHeader(code)
@@ -601,7 +583,7 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code
601583 redirectURL, err := p.getAppRedirect(req)
602584 if err != nil {
603585 logger.Errorf("Error obtaining redirect: %v", err)
604− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
586+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
605587 return
606588 }
607589
@@ -634,7 +616,7 @@ func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code
634616 err = p.templates.ExecuteTemplate(rw, "sign_in.html", t)
635617 if err != nil {
636618 logger.Printf("Error rendering sign_in.html template: %v", err)
637− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
619+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
638620 }
639621}
640622
@@ -662,7 +644,7 @@ func (p *OAuthProxy) SignIn(rw http.ResponseWriter, req *http.Request) {
662644 redirect, err := p.getAppRedirect(req)
663645 if err != nil {
664646 logger.Errorf("Error obtaining redirect: %v", err)
665− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
647+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
666648 return
667649 }
668650
@@ -672,7 +654,7 @@ func (p *OAuthProxy) SignIn(rw http.ResponseWriter, req *http.Request) {
672654 err = p.SaveSession(rw, req, session)
673655 if err != nil {
674656 logger.Printf("Error saving session: %v", err)
675− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
657+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
676658 return
677659 }
678660 http.Redirect(rw, req, redirect, http.StatusFound)
@@ -711,7 +693,7 @@ func (p *OAuthProxy) UserInfo(rw http.ResponseWriter, req *http.Request) {
711693 err = json.NewEncoder(rw).Encode(userInfo)
712694 if err != nil {
713695 logger.Printf("Error encoding user info: %v", err)
714− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
696+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
715697 }
716698}
717699
@@ -720,13 +702,13 @@ func (p *OAuthProxy) SignOut(rw http.ResponseWriter, req *http.Request) {
720702 redirect, err := p.getAppRedirect(req)
721703 if err != nil {
722704 logger.Errorf("Error obtaining redirect: %v", err)
723− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
705+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
724706 return
725707 }
726708 err = p.ClearSessionCookie(rw, req)
727709 if err != nil {
728710 logger.Errorf("Error clearing session cookie: %v", err)
729− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
711+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
730712 return
731713 }
732714 http.Redirect(rw, req, redirect, http.StatusFound)
@@ -738,14 +720,14 @@ func (p *OAuthProxy) OAuthStart(rw http.ResponseWriter, req *http.Request) {
738720 nonce, err := encryption.Nonce()
739721 if err != nil {
740722 logger.Errorf("Error obtaining nonce: %v", err)
741− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
723+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
742724 return
743725 }
744726 p.SetCSRFCookie(rw, req, nonce)
745727 redirect, err := p.getAppRedirect(req)
746728 if err != nil {
747729 logger.Errorf("Error obtaining redirect: %v", err)
748− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
730+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
749731 return
750732 }
751733 redirectURI := p.getOAuthRedirectURI(req)
@@ -761,34 +743,34 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
761743 err := req.ParseForm()
762744 if err != nil {
763745 logger.Errorf("Error while parsing OAuth2 callback: %v", err)
764− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
746+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
765747 return
766748 }
767749 errorString := req.Form.Get("error")
768750 if errorString != "" {
769751 logger.Errorf("Error while parsing OAuth2 callback: %s", errorString)
770− p.ErrorPage(rw, req, http.StatusForbidden, "Permission Denied", errorString)
752+ p.ErrorPage(rw, req, http.StatusForbidden, errorString)
771753 return
772754 }
773755
774756 session, err := p.redeemCode(req)
775757 if err != nil {
776758 logger.Errorf("Error redeeming code during OAuth2 callback: %v", err)
777− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", "Internal Error")
759+ p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Error")
778760 return
779761 }
780762
781763 err = p.enrichSessionState(req.Context(), session)
782764 if err != nil {
783765 logger.Errorf("Error creating session during OAuth2 callback: %v", err)
784− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", "Internal Error")
766+ p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Error")
785767 return
786768 }
787769
788770 state := strings.SplitN(req.Form.Get("state"), ":", 2)
789771 if len(state) != 2 {
790772 logger.Error("Error while parsing OAuth2 state: invalid length")
791− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", "Invalid State")
773+ p.ErrorPage(rw, req, http.StatusInternalServerError, "Invalid State")
792774 return
793775 }
794776 nonce := state[0]
@@ -796,13 +778,13 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
796778 c, err := req.Cookie(p.CSRFCookieName)
797779 if err != nil {
798780 logger.PrintAuthf(session.Email, req, logger.AuthFailure, "Invalid authentication via OAuth2: unable to obtain CSRF cookie")
799− p.ErrorPage(rw, req, http.StatusForbidden, "Permission Denied", err.Error())
781+ p.ErrorPage(rw, req, http.StatusForbidden, err.Error())
800782 return
801783 }
802784 p.ClearCSRFCookie(rw, req)
803785 if c.Value != nonce {
804786 logger.PrintAuthf(session.Email, req, logger.AuthFailure, "Invalid authentication via OAuth2: CSRF token mismatch, potential attack")
805− p.ErrorPage(rw, req, http.StatusForbidden, "Permission Denied", "CSRF Failed")
787+ p.ErrorPage(rw, req, http.StatusForbidden, "CSRF Failed")
806788 return
807789 }
808790
@@ -820,13 +802,13 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
820802 err := p.SaveSession(rw, req, session)
821803 if err != nil {
822804 logger.Errorf("Error saving session state for %s: %v", remoteAddr, err)
823− p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Server Error", err.Error())
805+ p.ErrorPage(rw, req, http.StatusInternalServerError, err.Error())
824806 return
825807 }
826808 http.Redirect(rw, req, redirect, http.StatusFound)
827809 } else {
828810 logger.PrintAuthf(session.Email, req, logger.AuthFailure, "Invalid authentication via OAuth2: unauthorized")
829− p.ErrorPage(rw, req, http.StatusForbidden, "Permission Denied", "Invalid Account")
811+ p.ErrorPage(rw, req, http.StatusForbidden, "Invalid Account")
830812 }
831813}
832814
@@ -908,13 +890,12 @@ func (p *OAuthProxy) Proxy(rw http.ResponseWriter, req *http.Request) {
908890 }
909891
910892 case ErrAccessDenied:
911− p.ErrorPage(rw, req, http.StatusUnauthorized, "Permission Denied", "Unauthorized")
893+ p.ErrorPage(rw, req, http.StatusUnauthorized, "Unauthorized")
912894
913895 default:
914896 // unknown error
915897 logger.Errorf("Unexpected internal error: %v", err)
916− p.ErrorPage(rw, req, http.StatusInternalServerError,
917− "Internal Error", "Internal Error")
898+ p.ErrorPage(rw, req, http.StatusInternalServerError, "Internal Error")
918899 }
919900}
920901