@@ -50,6 +50,16 @@ type DomainMismatchError struct {
5050 ActualDomain string // The instance from the OIDC token
5151}
5252
53+ // TranslationKey returns the i18n key for translating this error.
54+ func (e * DomainMismatchError ) TranslationKey () string {
55+ return "OIDC Domain Mismatch %s %s"
56+ }
57+
58+ // TranslationArgs returns the arguments for the translation.
59+ func (e * DomainMismatchError ) TranslationArgs () []interface {} {
60+ return []interface {}{e .ExpectedDomain , e .ActualDomain }
61+ }
62+
5363func (e * DomainMismatchError ) Error () string {
5464 return fmt .Sprintf ("OIDC Domain Mismatch %s %s" , e .ExpectedDomain , e .ActualDomain )
5565}
@@ -378,7 +388,18 @@ func Login(c echo.Context) error {
378388 }
379389
380390 if err := checkDomainFromUserInfo (conf , inst , token ); err != nil {
381- return renderError (c , inst , http .StatusBadRequest , err .Error ())
391+ extras := map [string ]interface {}{}
392+ errMsg := err .Error ()
393+ var dmErr * DomainMismatchError
394+ if errors .As (err , & dmErr ) {
395+ extras ["ErrorArgs" ] = dmErr .TranslationArgs ()
396+ errMsg = dmErr .TranslationKey ()
397+ if logoutURL := getOIDCLogoutURL (inst .ContextName ); logoutURL != "" {
398+ extras ["Button" ] = "Disconnect"
399+ extras ["ButtonURL" ] = logoutURL
400+ }
401+ }
402+ return renderError (c , inst , http .StatusBadRequest , errMsg , extras )
382403 }
383404 }
384405
@@ -454,7 +475,17 @@ func TwoFactor(c echo.Context) error {
454475 return renderError (c , inst , http .StatusBadRequest , "No OpenID Connect is configured." )
455476 }
456477 if err := checkDomainFromUserInfo (conf , inst , accessToken ); err != nil {
457- return renderError (c , inst , http .StatusBadRequest , err .Error ())
478+ extras := map [string ]interface {}{}
479+ errMsg := err .Error ()
480+ if dmErr , ok := err .(* DomainMismatchError ); ok {
481+ extras ["ErrorArgs" ] = dmErr .TranslationArgs ()
482+ errMsg = dmErr .TranslationKey ()
483+ if logoutURL := getOIDCLogoutURL (inst .ContextName ); logoutURL != "" {
484+ extras ["Button" ] = "Disconnect"
485+ extras ["ButtonURL" ] = logoutURL
486+ }
487+ }
488+ return renderError (c , inst , http .StatusBadRequest , errMsg , extras )
458489 }
459490
460491 if inst .ValidateTwoFactorTrustedDeviceSecret (c .Request (), trustedDeviceToken ) {
@@ -1270,15 +1301,15 @@ func loadKey(raw *jwKey) (interface{}, error) {
12701301 return & key , nil
12711302}
12721303
1273- func renderError (c echo.Context , inst * instance.Instance , code int , msg string ) error {
1304+ func renderError (c echo.Context , inst * instance.Instance , code int , msg string , extras ... map [ string ] interface {} ) error {
12741305 if inst == nil {
12751306 inst = & instance.Instance {
12761307 Domain : c .Request ().Host ,
12771308 ContextName : config .DefaultInstanceContext ,
12781309 Locale : consts .DefaultLocale ,
12791310 }
12801311 }
1281- return c . Render ( code , "error.html" , echo.Map {
1312+ params := echo.Map {
12821313 "Domain" : inst .ContextualDomain (),
12831314 "ContextName" : inst .ContextName ,
12841315 "Locale" : inst .Locale ,
@@ -1287,7 +1318,22 @@ func renderError(c echo.Context, inst *instance.Instance, code int, msg string)
12871318 "Illustration" : "/images/generic-error.svg" ,
12881319 "Error" : msg ,
12891320 "SupportEmail" : inst .SupportEmailAddress (),
1290- })
1321+ }
1322+ // Merge any extra params (Button, ButtonURL, etc.)
1323+ for _ , extra := range extras {
1324+ for k , v := range extra {
1325+ params [k ] = v
1326+ }
1327+ }
1328+ return c .Render (code , "error.html" , params )
1329+ }
1330+
1331+ func getOIDCLogoutURL (contextName string ) string {
1332+ a := config .GetConfig ().Authentication
1333+ delegated , _ := a [contextName ].(map [string ]interface {})
1334+ oidc , _ := delegated ["oidc" ].(map [string ]interface {})
1335+ u , _ := oidc ["logout_url" ].(string )
1336+ return u
12911337}
12921338
12931339// Routes setup routing for OpenID Connect routes.
0 commit comments