From cf4010b4fb36d97aebf349b08be5e66c54c75e2f Mon Sep 17 00:00:00 2001 From: James Elliott Date: Sun, 8 Jan 2023 07:04:06 +1100 Subject: [PATCH] fix(oidc): csp blocks form_post response form submit (#4719) This fixes an issue where the form_post response never gets submitted. Fixes #4669 --- internal/commands/context.go | 2 +- .../handlers/handler_oidc_authorization.go | 4 +++ internal/middlewares/const.go | 20 ++++++----- internal/middlewares/headers.go | 16 +++++++++ internal/oidc/config.go | 12 +++++-- internal/oidc/provider.go | 5 +-- internal/oidc/provider_test.go | 12 +++---- internal/server/handlers.go | 36 +++++++++---------- internal/templates/const.go | 3 ++ internal/templates/provider.go | 26 +++++++++++--- .../src/oidc/AuthorizeResponseFormPost.html | 20 +++++++++++ internal/templates/types.go | 11 ++++-- 12 files changed, 124 insertions(+), 43 deletions(-) create mode 100644 internal/templates/src/oidc/AuthorizeResponseFormPost.html diff --git a/internal/commands/context.go b/internal/commands/context.go index a0f2df2b2..9a9e367d1 100644 --- a/internal/commands/context.go +++ b/internal/commands/context.go @@ -172,7 +172,7 @@ func (ctx *CmdCtx) LoadProviders() (warns, errs []error) { ctx.providers.Notifier = notification.NewFileNotifier(*ctx.config.Notifier.FileSystem) } - if ctx.providers.OpenIDConnect, err = oidc.NewOpenIDConnectProvider(ctx.config.IdentityProviders.OIDC, ctx.providers.StorageProvider); err != nil { + if ctx.providers.OpenIDConnect, err = oidc.NewOpenIDConnectProvider(ctx.config.IdentityProviders.OIDC, ctx.providers.StorageProvider, ctx.providers.Templates); err != nil { errs = append(errs, err) } diff --git a/internal/handlers/handler_oidc_authorization.go b/internal/handlers/handler_oidc_authorization.go index 73e821927..887f11088 100644 --- a/internal/handlers/handler_oidc_authorization.go +++ b/internal/handlers/handler_oidc_authorization.go @@ -111,5 +111,9 @@ func OpenIDConnectAuthorization(ctx *middlewares.AutheliaCtx, rw http.ResponseWr return } + if requester.GetResponseMode() == oidc.ResponseModeFormPost { + ctx.SetUserValueBytes(middlewares.UserValueKeyFormPost, true) + } + ctx.Providers.OpenIDConnect.WriteAuthorizeResponse(ctx, rw, requester, responder) } diff --git a/internal/middlewares/const.go b/internal/middlewares/const.go index ee2c49955..dc5519f2e 100644 --- a/internal/middlewares/const.go +++ b/internal/middlewares/const.go @@ -47,14 +47,15 @@ var ( ) var ( - headerValueFalse = []byte("false") - headerValueTrue = []byte("true") - headerValueMaxAge = []byte("100") - headerValueVary = []byte("Accept-Encoding, Origin") - headerValueVaryWildcard = []byte("Accept-Encoding") - headerValueOriginWildcard = []byte("*") - headerValueZero = []byte("0") - headerValueCSPNone = []byte("default-src 'none';") + headerValueFalse = []byte("false") + headerValueTrue = []byte("true") + headerValueMaxAge = []byte("100") + headerValueVary = []byte("Accept-Encoding, Origin") + headerValueVaryWildcard = []byte("Accept-Encoding") + headerValueOriginWildcard = []byte("*") + headerValueZero = []byte("0") + headerValueCSPNone = []byte("default-src 'none'") + headerValueCSPNoneFormPost = []byte("default-src 'none'; script-src 'sha256-skflBqA90WuHvoczvimLdj49ExKdizFjX2Itd6xKZdU='") headerValueNoSniff = []byte("nosniff") headerValueStrictOriginCrossOrigin = []byte("strict-origin-when-cross-origin") @@ -83,6 +84,9 @@ var ( // UserValueKeyBaseURL is the User Value key where we store the Base URL. UserValueKeyBaseURL = []byte("base_url") + // UserValueKeyFormPost is the User Value key where we indicate the form_post response mode. + UserValueKeyFormPost = []byte("form_post") + headerSeparator = []byte(", ") contentTypeTextPlain = []byte("text/plain; charset=utf-8") diff --git a/internal/middlewares/headers.go b/internal/middlewares/headers.go index cd71440c2..176ad658e 100644 --- a/internal/middlewares/headers.go +++ b/internal/middlewares/headers.go @@ -26,6 +26,22 @@ func SecurityHeadersCSPNone(next fasthttp.RequestHandler) fasthttp.RequestHandle } } +// SecurityHeadersCSPNoneOpenIDConnect middleware adds the Content-Security-Policy header with the value +// "default-src 'none'" except in special circumstances. +func SecurityHeadersCSPNoneOpenIDConnect(next fasthttp.RequestHandler) fasthttp.RequestHandler { + return func(ctx *fasthttp.RequestCtx) { + ctx.SetUserValueBytes(UserValueKeyFormPost, false) + + next(ctx) + + if modeFormPost, ok := ctx.UserValueBytes(UserValueKeyFormPost).(bool); ok && modeFormPost { + ctx.Response.Header.SetBytesKV(headerContentSecurityPolicy, headerValueCSPNoneFormPost) + } else { + ctx.Response.Header.SetBytesKV(headerContentSecurityPolicy, headerValueCSPNone) + } + } +} + // SecurityHeadersNoStore middleware adds the Pragma no-cache and Cache-Control no-store headers. func SecurityHeadersNoStore(next fasthttp.RequestHandler) fasthttp.RequestHandler { return func(ctx *fasthttp.RequestCtx) { diff --git a/internal/oidc/config.go b/internal/oidc/config.go index 0146899bf..7a5110b09 100644 --- a/internal/oidc/config.go +++ b/internal/oidc/config.go @@ -19,10 +19,11 @@ import ( "github.com/ory/fosite/token/jwt" "github.com/authelia/authelia/v4/internal/configuration/schema" + "github.com/authelia/authelia/v4/internal/templates" "github.com/authelia/authelia/v4/internal/utils" ) -func NewConfig(config *schema.OpenIDConnectConfiguration) *Config { +func NewConfig(config *schema.OpenIDConnectConfiguration, templates *templates.Provider) *Config { c := &Config{ GlobalSecret: []byte(utils.HashSHA256FromString(config.HMACSecret)), SendDebugMessagesToClients: config.EnableClientDebugMessages, @@ -38,6 +39,7 @@ func NewConfig(config *schema.OpenIDConnectConfiguration) *Config { EnforcePublicClients: config.EnforcePKCE != "never", AllowPlainChallengeMethod: config.EnablePKCEPlainChallenge, }, + Templates: templates, } c.Strategy.Core = &HMACCoreStrategy{ @@ -85,6 +87,8 @@ type Config struct { HTTPClient *retryablehttp.Client FormPostHTMLTemplate *template.Template MessageCatalog i18n.MessageCatalog + + Templates *templates.Provider } type HashConfig struct { @@ -502,7 +506,11 @@ func (c *Config) GetMessageCatalog(ctx context.Context) (catalog i18n.MessageCat // GetFormPostHTMLTemplate returns the form post HTML template. func (c *Config) GetFormPostHTMLTemplate(ctx context.Context) (tmpl *template.Template) { - return c.FormPostHTMLTemplate + if c.Templates == nil { + return nil + } + + return c.Templates.GetOpenIDConnectAuthorizeResponseFormPostTemplate() } // GetTokenURL returns the token URL. diff --git a/internal/oidc/provider.go b/internal/oidc/provider.go index 32b95a61a..fd2581661 100644 --- a/internal/oidc/provider.go +++ b/internal/oidc/provider.go @@ -9,10 +9,11 @@ import ( "github.com/authelia/authelia/v4/internal/configuration/schema" "github.com/authelia/authelia/v4/internal/storage" + "github.com/authelia/authelia/v4/internal/templates" ) // NewOpenIDConnectProvider new-ups a OpenIDConnectProvider. -func NewOpenIDConnectProvider(config *schema.OpenIDConnectConfiguration, store storage.Provider) (provider *OpenIDConnectProvider, err error) { +func NewOpenIDConnectProvider(config *schema.OpenIDConnectConfiguration, store storage.Provider, templates *templates.Provider) (provider *OpenIDConnectProvider, err error) { if config == nil { return nil, nil } @@ -20,7 +21,7 @@ func NewOpenIDConnectProvider(config *schema.OpenIDConnectConfiguration, store s provider = &OpenIDConnectProvider{ JSONWriter: herodot.NewJSONWriter(nil), Store: NewStore(config, store), - Config: NewConfig(config), + Config: NewConfig(config, templates), } provider.OAuth2Provider = fosite.NewOAuth2Provider(provider.Store, provider.Config) diff --git a/internal/oidc/provider_test.go b/internal/oidc/provider_test.go index e4a486eb5..85ab216ac 100644 --- a/internal/oidc/provider_test.go +++ b/internal/oidc/provider_test.go @@ -16,7 +16,7 @@ import ( var exampleIssuerPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAvcMVMB2vEbqI6PlSNJ4HmUyMxBDJ5iY7FS+zDDAHOZBg9S3S\nKcAn1CZcnyL0VvJ7wcdhR6oTnOwR94eKvzUyJZ+GL2hTMm27dubEYsNdhoCl6N3X\nyEEohNfoxiiCYraVauX8X3M9jFzbEz9+pacaDbHB2syaJ1qFmMNR+HSu2jPzOo7M\nlqKIOgUzA0741MaYNt47AEVg4XU5ORLdolbAkItmYg1QbyFndg9H5IvwKkYaXTGE\nlgDBcPUC0yVjAC15Mguquq+jZeQay+6PSbHTD8PQMOkLjyChI2xEhVNbdCXe676R\ncMW2R/gjrcK23zmtmTWRfdC1iZLSlHO+bJj9vQIDAQABAoIBAEZvkP/JJOCJwqPn\nV3IcbmmilmV4bdi1vByDFgyiDyx4wOSA24+PubjvfFW9XcCgRPuKjDtTj/AhWBHv\nB7stfa2lZuNV7/u562mZArA+IAr62Zp0LdIxDV8x3T8gbjVB3HhPYbv0RJZDKTYd\nzV6jhfIrVu9mHpoY6ZnodhapCPYIyk/d49KBIHZuAc25CUjMXgTeaVtf0c996036\nUxW6ef33wAOJAvW0RCvbXAJfmBeEq2qQlkjTIlpYx71fhZWexHifi8Ouv3Zonc+1\n/P2Adq5uzYVBT92f9RKHg9QxxNzVrLjSMaxyvUtWQCAQfW0tFIRdqBGsHYsQrFtI\nF4yzv8ECgYEA7ntpyN9HD9Z9lYQzPCR73sFCLM+ID99aVij0wHuxK97bkSyyvkLd\n7MyTaym3lg1UEqWNWBCLvFULZx7F0Ah6qCzD4ymm3Bj/ADpWWPgljBI0AFml+HHs\nhcATmXUrj5QbLyhiP2gmJjajp1o/rgATx6ED66seSynD6JOH8wUhhZUCgYEAy7OA\n06PF8GfseNsTqlDjNF0K7lOqd21S0prdwrsJLiVzUlfMM25MLE0XLDUutCnRheeh\nIlcuDoBsVTxz6rkvFGD74N+pgXlN4CicsBq5ofK060PbqCQhSII3fmHobrZ9Cr75\nHmBjAxHx998SKaAAGbBbcYGUAp521i1pH5CEPYkCgYEAkUd1Zf0+2RMdZhwm6hh/\nrW+l1I6IoMK70YkZsLipccRNld7Y9LbfYwYtODcts6di9AkOVfueZJiaXbONZfIE\nZrb+jkAteh9wGL9xIrnohbABJcV3Kiaco84jInUSmGDtPokncOENfHIEuEpuSJ2b\nbx1TuhmAVuGWivR0+ULC7RECgYEAgS0cDRpWc9Xzh9Cl7+PLsXEvdWNpPsL9OsEq\n0Ep7z9+/+f/jZtoTRCS/BTHUpDvAuwHglT5j3p5iFMt5VuiIiovWLwynGYwrbnNS\nqfrIrYKUaH1n1oDS+oBZYLQGCe9/7EifAjxtjYzbvSyg//SPG7tSwfBCREbpZXj2\nqSWkNsECgYA/mCDzCTlrrWPuiepo6kTmN+4TnFA+hJI6NccDVQ+jvbqEdoJ4SW4L\nzqfZSZRFJMNpSgIqkQNRPJqMP0jQ5KRtJrjMWBnYxktwKz9fDg2R2MxdFgMF2LH2\nHEMMhFHlv8NDjVOXh1KwRoltNGVWYsSrD9wKU9GhRCEfmNCGrvBcEg==\n-----END RSA PRIVATE KEY-----" func TestOpenIDConnectProvider_NewOpenIDConnectProvider_NotConfigured(t *testing.T) { - provider, err := NewOpenIDConnectProvider(nil, nil) + provider, err := NewOpenIDConnectProvider(nil, nil, nil) assert.NoError(t, err) assert.Nil(t, provider) @@ -39,7 +39,7 @@ func TestNewOpenIDConnectProvider_ShouldEnableOptionalDiscoveryValues(t *testing }, }, }, - }, nil) + }, nil, nil) assert.NoError(t, err) @@ -88,7 +88,7 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GoodConfiguration(t *tes }, }, }, - }, nil) + }, nil, nil) assert.NotNil(t, provider) assert.NoError(t, err) @@ -109,7 +109,7 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOpenIDConnectWellKnow }, }, }, - }, nil) + }, nil, nil) assert.NoError(t, err) @@ -199,7 +199,7 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOAuth2WellKnownConfig }, }, }, - }, nil) + }, nil, nil) assert.NoError(t, err) @@ -278,7 +278,7 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOpenIDConnectWellKnow }, }, }, - }, nil) + }, nil, nil) assert.NoError(t, err) diff --git a/internal/server/handlers.go b/internal/server/handlers.go index e88621545..277cb16f9 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -226,27 +226,27 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers) } if providers.OpenIDConnect != nil { - middlewareOIDC := middlewares.NewBridgeBuilder(config, providers).WithPreMiddlewares( - middlewares.SecurityHeaders, middlewares.SecurityHeadersCSPNone, middlewares.SecurityHeadersNoStore, + bridgeOIDC := middlewares.NewBridgeBuilder(config, providers).WithPreMiddlewares( + middlewares.SecurityHeaders, middlewares.SecurityHeadersCSPNoneOpenIDConnect, middlewares.SecurityHeadersNoStore, ).Build() - r.GET("/api/oidc/consent", middlewareOIDC(handlers.OpenIDConnectConsentGET)) - r.POST("/api/oidc/consent", middlewareOIDC(handlers.OpenIDConnectConsentPOST)) + r.GET("/api/oidc/consent", bridgeOIDC(handlers.OpenIDConnectConsentGET)) + r.POST("/api/oidc/consent", bridgeOIDC(handlers.OpenIDConnectConsentPOST)) allowedOrigins := utils.StringSliceFromURLs(config.IdentityProviders.OIDC.CORS.AllowedOrigins) r.OPTIONS(oidc.EndpointPathWellKnownOpenIDConfiguration, policyCORSPublicGET.HandleOPTIONS) - r.GET(oidc.EndpointPathWellKnownOpenIDConfiguration, policyCORSPublicGET.Middleware(middlewareOIDC(handlers.OpenIDConnectConfigurationWellKnownGET))) + r.GET(oidc.EndpointPathWellKnownOpenIDConfiguration, policyCORSPublicGET.Middleware(bridgeOIDC(handlers.OpenIDConnectConfigurationWellKnownGET))) r.OPTIONS(oidc.EndpointPathWellKnownOAuthAuthorizationServer, policyCORSPublicGET.HandleOPTIONS) - r.GET(oidc.EndpointPathWellKnownOAuthAuthorizationServer, policyCORSPublicGET.Middleware(middlewareOIDC(handlers.OAuthAuthorizationServerWellKnownGET))) + r.GET(oidc.EndpointPathWellKnownOAuthAuthorizationServer, policyCORSPublicGET.Middleware(bridgeOIDC(handlers.OAuthAuthorizationServerWellKnownGET))) r.OPTIONS(oidc.EndpointPathJWKs, policyCORSPublicGET.HandleOPTIONS) r.GET(oidc.EndpointPathJWKs, policyCORSPublicGET.Middleware(middlewareAPI(handlers.JSONWebKeySetGET))) // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. r.OPTIONS("/api/oidc/jwks", policyCORSPublicGET.HandleOPTIONS) - r.GET("/api/oidc/jwks", policyCORSPublicGET.Middleware(middlewareOIDC(handlers.JSONWebKeySetGET))) + r.GET("/api/oidc/jwks", policyCORSPublicGET.Middleware(bridgeOIDC(handlers.JSONWebKeySetGET))) policyCORSAuthorization := middlewares.NewCORSPolicyBuilder(). WithAllowedMethods(fasthttp.MethodOptions, fasthttp.MethodGet, fasthttp.MethodPost). @@ -255,13 +255,13 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers) Build() r.OPTIONS(oidc.EndpointPathAuthorization, policyCORSAuthorization.HandleOnlyOPTIONS) - r.GET(oidc.EndpointPathAuthorization, policyCORSAuthorization.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization)))) - r.POST(oidc.EndpointPathAuthorization, policyCORSAuthorization.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization)))) + r.GET(oidc.EndpointPathAuthorization, policyCORSAuthorization.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization)))) + r.POST(oidc.EndpointPathAuthorization, policyCORSAuthorization.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization)))) // TODO (james-d-elliott): Remove in GA. This is a legacy endpoint. r.OPTIONS("/api/oidc/authorize", policyCORSAuthorization.HandleOnlyOPTIONS) - r.GET("/api/oidc/authorize", policyCORSAuthorization.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization)))) - r.POST("/api/oidc/authorize", policyCORSAuthorization.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization)))) + r.GET("/api/oidc/authorize", policyCORSAuthorization.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization)))) + r.POST("/api/oidc/authorize", policyCORSAuthorization.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization)))) policyCORSToken := middlewares.NewCORSPolicyBuilder(). WithAllowCredentials(true). @@ -271,7 +271,7 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers) Build() r.OPTIONS(oidc.EndpointPathToken, policyCORSToken.HandleOPTIONS) - r.POST(oidc.EndpointPathToken, policyCORSToken.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectTokenPOST)))) + r.POST(oidc.EndpointPathToken, policyCORSToken.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectTokenPOST)))) policyCORSUserinfo := middlewares.NewCORSPolicyBuilder(). WithAllowCredentials(true). @@ -281,8 +281,8 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers) Build() r.OPTIONS(oidc.EndpointPathUserinfo, policyCORSUserinfo.HandleOPTIONS) - r.GET(oidc.EndpointPathUserinfo, policyCORSUserinfo.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) - r.POST(oidc.EndpointPathUserinfo, policyCORSUserinfo.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) + r.GET(oidc.EndpointPathUserinfo, policyCORSUserinfo.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) + r.POST(oidc.EndpointPathUserinfo, policyCORSUserinfo.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) policyCORSIntrospection := middlewares.NewCORSPolicyBuilder(). WithAllowCredentials(true). @@ -292,11 +292,11 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers) Build() r.OPTIONS(oidc.EndpointPathIntrospection, policyCORSIntrospection.HandleOPTIONS) - r.POST(oidc.EndpointPathIntrospection, policyCORSIntrospection.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) + r.POST(oidc.EndpointPathIntrospection, policyCORSIntrospection.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. r.OPTIONS("/api/oidc/introspect", policyCORSIntrospection.HandleOPTIONS) - r.POST("/api/oidc/introspect", policyCORSIntrospection.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) + r.POST("/api/oidc/introspect", policyCORSIntrospection.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) policyCORSRevocation := middlewares.NewCORSPolicyBuilder(). WithAllowCredentials(true). @@ -306,11 +306,11 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers) Build() r.OPTIONS(oidc.EndpointPathRevocation, policyCORSRevocation.HandleOPTIONS) - r.POST(oidc.EndpointPathRevocation, policyCORSRevocation.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) + r.POST(oidc.EndpointPathRevocation, policyCORSRevocation.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. r.OPTIONS("/api/oidc/revoke", policyCORSRevocation.HandleOPTIONS) - r.POST("/api/oidc/revoke", policyCORSRevocation.Middleware(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) + r.POST("/api/oidc/revoke", policyCORSRevocation.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) } r.HandleMethodNotAllowed = true diff --git a/internal/templates/const.go b/internal/templates/const.go index 755807c44..4457a9660 100644 --- a/internal/templates/const.go +++ b/internal/templates/const.go @@ -9,9 +9,12 @@ const ( const ( TemplateNameEmailIdentityVerification = "IdentityVerification" TemplateNameEmailEvent = "Event" + + TemplateNameOIDCAuthorizeFormPost = "AuthorizeResponseFormPost.html" ) // Template Category Names. const ( TemplateCategoryNotifications = "notification" + TemplateCategoryOpenIDConnect = "oidc" ) diff --git a/internal/templates/provider.go b/internal/templates/provider.go index 08ce6701c..10235dca6 100644 --- a/internal/templates/provider.go +++ b/internal/templates/provider.go @@ -3,7 +3,9 @@ package templates import ( "embed" "fmt" - "text/template" + th "html/template" + "path" + tt "text/template" ) // New creates a new templates' provider. @@ -35,7 +37,7 @@ func (p *Provider) LoadTemplatedAssets(fs embed.FS) (err error) { return err } - if p.templates.asset.index, err = template. + if p.templates.asset.index, err = tt. New("assets/public_html/index.html"). Funcs(FuncMap()). Parse(string(data)); err != nil { @@ -46,7 +48,7 @@ func (p *Provider) LoadTemplatedAssets(fs embed.FS) (err error) { return err } - if p.templates.asset.api.index, err = template. + if p.templates.asset.api.index, err = tt. New("assets/public_html/api/index.html"). Funcs(FuncMap()). Parse(string(data)); err != nil { @@ -57,7 +59,7 @@ func (p *Provider) LoadTemplatedAssets(fs embed.FS) (err error) { return err } - if p.templates.asset.api.spec, err = template. + if p.templates.asset.api.spec, err = tt. New("api/public_html/openapi.yaml"). Funcs(FuncMap()). Parse(string(data)); err != nil { @@ -92,6 +94,11 @@ func (p *Provider) GetIdentityVerificationEmailTemplate() (t *EmailTemplate) { return p.templates.notification.identityVerification } +// GetOpenIDConnectAuthorizeResponseFormPostTemplate returns a Template used to generate the OpenID Connect 1.0 Form Post Authorize Response. +func (p *Provider) GetOpenIDConnectAuthorizeResponseFormPostTemplate() (t *th.Template) { + return p.templates.oidc.formpost +} + func (p *Provider) load() (err error) { var errs []error @@ -103,6 +110,17 @@ func (p *Provider) load() (err error) { errs = append(errs, err) } + var data []byte + + if data, err = embedFS.ReadFile(path.Join("src", TemplateCategoryOpenIDConnect, TemplateNameOIDCAuthorizeFormPost)); err != nil { + errs = append(errs, err) + } else if p.templates.oidc.formpost, err = th. + New("oidc/AuthorizeResponseFormPost.html"). + Funcs(FuncMap()). + Parse(string(data)); err != nil { + errs = append(errs, err) + } + if len(errs) != 0 { for i, e := range errs { if i == 0 { diff --git a/internal/templates/src/oidc/AuthorizeResponseFormPost.html b/internal/templates/src/oidc/AuthorizeResponseFormPost.html new file mode 100644 index 000000000..93569b59b --- /dev/null +++ b/internal/templates/src/oidc/AuthorizeResponseFormPost.html @@ -0,0 +1,20 @@ + + + + Submit This Form + + + +
+ {{ range $key,$value := .Parameters }} + {{ range $parameter:= $value}} + + {{end}} + {{ end }} +
+ + diff --git a/internal/templates/types.go b/internal/templates/types.go index 51c5b254c..e1337cf6f 100644 --- a/internal/templates/types.go +++ b/internal/templates/types.go @@ -10,14 +10,21 @@ import ( type Templates struct { notification NotificationTemplates asset AssetTemplates + oidc OpenIDConnectTemplates } +type OpenIDConnectTemplates struct { + formpost *th.Template +} + +// AssetTemplates are templates for specific key assets. type AssetTemplates struct { index *tt.Template - api APIAssetTemplates + api OpenAPIAssetTemplates } -type APIAssetTemplates struct { +// OpenAPIAssetTemplates are asset templates for the OpenAPI specification. +type OpenAPIAssetTemplates struct { index *tt.Template spec *tt.Template }