fix(oidc): csp blocks form_post response form submit (#4719)
This fixes an issue where the form_post response never gets submitted. Fixes #4669pull/4736/head^2
parent
e68e52777a
commit
cf4010b4fb
|
@ -172,7 +172,7 @@ func (ctx *CmdCtx) LoadProviders() (warns, errs []error) {
|
||||||
ctx.providers.Notifier = notification.NewFileNotifier(*ctx.config.Notifier.FileSystem)
|
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)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,5 +111,9 @@ func OpenIDConnectAuthorization(ctx *middlewares.AutheliaCtx, rw http.ResponseWr
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if requester.GetResponseMode() == oidc.ResponseModeFormPost {
|
||||||
|
ctx.SetUserValueBytes(middlewares.UserValueKeyFormPost, true)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Providers.OpenIDConnect.WriteAuthorizeResponse(ctx, rw, requester, responder)
|
ctx.Providers.OpenIDConnect.WriteAuthorizeResponse(ctx, rw, requester, responder)
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,8 @@ var (
|
||||||
headerValueVaryWildcard = []byte("Accept-Encoding")
|
headerValueVaryWildcard = []byte("Accept-Encoding")
|
||||||
headerValueOriginWildcard = []byte("*")
|
headerValueOriginWildcard = []byte("*")
|
||||||
headerValueZero = []byte("0")
|
headerValueZero = []byte("0")
|
||||||
headerValueCSPNone = []byte("default-src 'none';")
|
headerValueCSPNone = []byte("default-src 'none'")
|
||||||
|
headerValueCSPNoneFormPost = []byte("default-src 'none'; script-src 'sha256-skflBqA90WuHvoczvimLdj49ExKdizFjX2Itd6xKZdU='")
|
||||||
|
|
||||||
headerValueNoSniff = []byte("nosniff")
|
headerValueNoSniff = []byte("nosniff")
|
||||||
headerValueStrictOriginCrossOrigin = []byte("strict-origin-when-cross-origin")
|
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 is the User Value key where we store the Base URL.
|
||||||
UserValueKeyBaseURL = []byte("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(", ")
|
headerSeparator = []byte(", ")
|
||||||
|
|
||||||
contentTypeTextPlain = []byte("text/plain; charset=utf-8")
|
contentTypeTextPlain = []byte("text/plain; charset=utf-8")
|
||||||
|
|
|
@ -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.
|
// SecurityHeadersNoStore middleware adds the Pragma no-cache and Cache-Control no-store headers.
|
||||||
func SecurityHeadersNoStore(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
func SecurityHeadersNoStore(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
return func(ctx *fasthttp.RequestCtx) {
|
return func(ctx *fasthttp.RequestCtx) {
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"github.com/ory/fosite/token/jwt"
|
"github.com/ory/fosite/token/jwt"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
|
"github.com/authelia/authelia/v4/internal/templates"
|
||||||
"github.com/authelia/authelia/v4/internal/utils"
|
"github.com/authelia/authelia/v4/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewConfig(config *schema.OpenIDConnectConfiguration) *Config {
|
func NewConfig(config *schema.OpenIDConnectConfiguration, templates *templates.Provider) *Config {
|
||||||
c := &Config{
|
c := &Config{
|
||||||
GlobalSecret: []byte(utils.HashSHA256FromString(config.HMACSecret)),
|
GlobalSecret: []byte(utils.HashSHA256FromString(config.HMACSecret)),
|
||||||
SendDebugMessagesToClients: config.EnableClientDebugMessages,
|
SendDebugMessagesToClients: config.EnableClientDebugMessages,
|
||||||
|
@ -38,6 +39,7 @@ func NewConfig(config *schema.OpenIDConnectConfiguration) *Config {
|
||||||
EnforcePublicClients: config.EnforcePKCE != "never",
|
EnforcePublicClients: config.EnforcePKCE != "never",
|
||||||
AllowPlainChallengeMethod: config.EnablePKCEPlainChallenge,
|
AllowPlainChallengeMethod: config.EnablePKCEPlainChallenge,
|
||||||
},
|
},
|
||||||
|
Templates: templates,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Strategy.Core = &HMACCoreStrategy{
|
c.Strategy.Core = &HMACCoreStrategy{
|
||||||
|
@ -85,6 +87,8 @@ type Config struct {
|
||||||
HTTPClient *retryablehttp.Client
|
HTTPClient *retryablehttp.Client
|
||||||
FormPostHTMLTemplate *template.Template
|
FormPostHTMLTemplate *template.Template
|
||||||
MessageCatalog i18n.MessageCatalog
|
MessageCatalog i18n.MessageCatalog
|
||||||
|
|
||||||
|
Templates *templates.Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
type HashConfig struct {
|
type HashConfig struct {
|
||||||
|
@ -502,7 +506,11 @@ func (c *Config) GetMessageCatalog(ctx context.Context) (catalog i18n.MessageCat
|
||||||
|
|
||||||
// GetFormPostHTMLTemplate returns the form post HTML template.
|
// GetFormPostHTMLTemplate returns the form post HTML template.
|
||||||
func (c *Config) GetFormPostHTMLTemplate(ctx context.Context) (tmpl *template.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.
|
// GetTokenURL returns the token URL.
|
||||||
|
|
|
@ -9,10 +9,11 @@ import (
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
"github.com/authelia/authelia/v4/internal/storage"
|
"github.com/authelia/authelia/v4/internal/storage"
|
||||||
|
"github.com/authelia/authelia/v4/internal/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewOpenIDConnectProvider new-ups a OpenIDConnectProvider.
|
// 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 {
|
if config == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -20,7 +21,7 @@ func NewOpenIDConnectProvider(config *schema.OpenIDConnectConfiguration, store s
|
||||||
provider = &OpenIDConnectProvider{
|
provider = &OpenIDConnectProvider{
|
||||||
JSONWriter: herodot.NewJSONWriter(nil),
|
JSONWriter: herodot.NewJSONWriter(nil),
|
||||||
Store: NewStore(config, store),
|
Store: NewStore(config, store),
|
||||||
Config: NewConfig(config),
|
Config: NewConfig(config, templates),
|
||||||
}
|
}
|
||||||
|
|
||||||
provider.OAuth2Provider = fosite.NewOAuth2Provider(provider.Store, provider.Config)
|
provider.OAuth2Provider = fosite.NewOAuth2Provider(provider.Store, provider.Config)
|
||||||
|
|
|
@ -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-----"
|
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) {
|
func TestOpenIDConnectProvider_NewOpenIDConnectProvider_NotConfigured(t *testing.T) {
|
||||||
provider, err := NewOpenIDConnectProvider(nil, nil)
|
provider, err := NewOpenIDConnectProvider(nil, nil, nil)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, provider)
|
assert.Nil(t, provider)
|
||||||
|
@ -39,7 +39,7 @@ func TestNewOpenIDConnectProvider_ShouldEnableOptionalDiscoveryValues(t *testing
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil, nil)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GoodConfiguration(t *tes
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil, nil)
|
||||||
|
|
||||||
assert.NotNil(t, provider)
|
assert.NotNil(t, provider)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -109,7 +109,7 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOpenIDConnectWellKnow
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil, nil)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOAuth2WellKnownConfig
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil, nil)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ func TestOpenIDConnectProvider_NewOpenIDConnectProvider_GetOpenIDConnectWellKnow
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil, nil)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
|
|
@ -226,27 +226,27 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers)
|
||||||
}
|
}
|
||||||
|
|
||||||
if providers.OpenIDConnect != nil {
|
if providers.OpenIDConnect != nil {
|
||||||
middlewareOIDC := middlewares.NewBridgeBuilder(config, providers).WithPreMiddlewares(
|
bridgeOIDC := middlewares.NewBridgeBuilder(config, providers).WithPreMiddlewares(
|
||||||
middlewares.SecurityHeaders, middlewares.SecurityHeadersCSPNone, middlewares.SecurityHeadersNoStore,
|
middlewares.SecurityHeaders, middlewares.SecurityHeadersCSPNoneOpenIDConnect, middlewares.SecurityHeadersNoStore,
|
||||||
).Build()
|
).Build()
|
||||||
|
|
||||||
r.GET("/api/oidc/consent", middlewareOIDC(handlers.OpenIDConnectConsentGET))
|
r.GET("/api/oidc/consent", bridgeOIDC(handlers.OpenIDConnectConsentGET))
|
||||||
r.POST("/api/oidc/consent", middlewareOIDC(handlers.OpenIDConnectConsentPOST))
|
r.POST("/api/oidc/consent", bridgeOIDC(handlers.OpenIDConnectConsentPOST))
|
||||||
|
|
||||||
allowedOrigins := utils.StringSliceFromURLs(config.IdentityProviders.OIDC.CORS.AllowedOrigins)
|
allowedOrigins := utils.StringSliceFromURLs(config.IdentityProviders.OIDC.CORS.AllowedOrigins)
|
||||||
|
|
||||||
r.OPTIONS(oidc.EndpointPathWellKnownOpenIDConfiguration, policyCORSPublicGET.HandleOPTIONS)
|
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.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.OPTIONS(oidc.EndpointPathJWKs, policyCORSPublicGET.HandleOPTIONS)
|
||||||
r.GET(oidc.EndpointPathJWKs, policyCORSPublicGET.Middleware(middlewareAPI(handlers.JSONWebKeySetGET)))
|
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.
|
// TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint.
|
||||||
r.OPTIONS("/api/oidc/jwks", policyCORSPublicGET.HandleOPTIONS)
|
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().
|
policyCORSAuthorization := middlewares.NewCORSPolicyBuilder().
|
||||||
WithAllowedMethods(fasthttp.MethodOptions, fasthttp.MethodGet, fasthttp.MethodPost).
|
WithAllowedMethods(fasthttp.MethodOptions, fasthttp.MethodGet, fasthttp.MethodPost).
|
||||||
|
@ -255,13 +255,13 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers)
|
||||||
Build()
|
Build()
|
||||||
|
|
||||||
r.OPTIONS(oidc.EndpointPathAuthorization, policyCORSAuthorization.HandleOnlyOPTIONS)
|
r.OPTIONS(oidc.EndpointPathAuthorization, policyCORSAuthorization.HandleOnlyOPTIONS)
|
||||||
r.GET(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(middlewareOIDC(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.
|
// TODO (james-d-elliott): Remove in GA. This is a legacy endpoint.
|
||||||
r.OPTIONS("/api/oidc/authorize", policyCORSAuthorization.HandleOnlyOPTIONS)
|
r.OPTIONS("/api/oidc/authorize", policyCORSAuthorization.HandleOnlyOPTIONS)
|
||||||
r.GET("/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(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization))))
|
r.POST("/api/oidc/authorize", policyCORSAuthorization.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorization))))
|
||||||
|
|
||||||
policyCORSToken := middlewares.NewCORSPolicyBuilder().
|
policyCORSToken := middlewares.NewCORSPolicyBuilder().
|
||||||
WithAllowCredentials(true).
|
WithAllowCredentials(true).
|
||||||
|
@ -271,7 +271,7 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers)
|
||||||
Build()
|
Build()
|
||||||
|
|
||||||
r.OPTIONS(oidc.EndpointPathToken, policyCORSToken.HandleOPTIONS)
|
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().
|
policyCORSUserinfo := middlewares.NewCORSPolicyBuilder().
|
||||||
WithAllowCredentials(true).
|
WithAllowCredentials(true).
|
||||||
|
@ -281,8 +281,8 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers)
|
||||||
Build()
|
Build()
|
||||||
|
|
||||||
r.OPTIONS(oidc.EndpointPathUserinfo, policyCORSUserinfo.HandleOPTIONS)
|
r.OPTIONS(oidc.EndpointPathUserinfo, policyCORSUserinfo.HandleOPTIONS)
|
||||||
r.GET(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(middlewareOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo))))
|
r.POST(oidc.EndpointPathUserinfo, policyCORSUserinfo.Middleware(bridgeOIDC(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo))))
|
||||||
|
|
||||||
policyCORSIntrospection := middlewares.NewCORSPolicyBuilder().
|
policyCORSIntrospection := middlewares.NewCORSPolicyBuilder().
|
||||||
WithAllowCredentials(true).
|
WithAllowCredentials(true).
|
||||||
|
@ -292,11 +292,11 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers)
|
||||||
Build()
|
Build()
|
||||||
|
|
||||||
r.OPTIONS(oidc.EndpointPathIntrospection, policyCORSIntrospection.HandleOPTIONS)
|
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.
|
// TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint.
|
||||||
r.OPTIONS("/api/oidc/introspect", policyCORSIntrospection.HandleOPTIONS)
|
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().
|
policyCORSRevocation := middlewares.NewCORSPolicyBuilder().
|
||||||
WithAllowCredentials(true).
|
WithAllowCredentials(true).
|
||||||
|
@ -306,11 +306,11 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers)
|
||||||
Build()
|
Build()
|
||||||
|
|
||||||
r.OPTIONS(oidc.EndpointPathRevocation, policyCORSRevocation.HandleOPTIONS)
|
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.
|
// TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint.
|
||||||
r.OPTIONS("/api/oidc/revoke", policyCORSRevocation.HandleOPTIONS)
|
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
|
r.HandleMethodNotAllowed = true
|
||||||
|
|
|
@ -9,9 +9,12 @@ const (
|
||||||
const (
|
const (
|
||||||
TemplateNameEmailIdentityVerification = "IdentityVerification"
|
TemplateNameEmailIdentityVerification = "IdentityVerification"
|
||||||
TemplateNameEmailEvent = "Event"
|
TemplateNameEmailEvent = "Event"
|
||||||
|
|
||||||
|
TemplateNameOIDCAuthorizeFormPost = "AuthorizeResponseFormPost.html"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Template Category Names.
|
// Template Category Names.
|
||||||
const (
|
const (
|
||||||
TemplateCategoryNotifications = "notification"
|
TemplateCategoryNotifications = "notification"
|
||||||
|
TemplateCategoryOpenIDConnect = "oidc"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,7 +3,9 @@ package templates
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"text/template"
|
th "html/template"
|
||||||
|
"path"
|
||||||
|
tt "text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
// New creates a new templates' provider.
|
// New creates a new templates' provider.
|
||||||
|
@ -35,7 +37,7 @@ func (p *Provider) LoadTemplatedAssets(fs embed.FS) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.templates.asset.index, err = template.
|
if p.templates.asset.index, err = tt.
|
||||||
New("assets/public_html/index.html").
|
New("assets/public_html/index.html").
|
||||||
Funcs(FuncMap()).
|
Funcs(FuncMap()).
|
||||||
Parse(string(data)); err != nil {
|
Parse(string(data)); err != nil {
|
||||||
|
@ -46,7 +48,7 @@ func (p *Provider) LoadTemplatedAssets(fs embed.FS) (err error) {
|
||||||
return err
|
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").
|
New("assets/public_html/api/index.html").
|
||||||
Funcs(FuncMap()).
|
Funcs(FuncMap()).
|
||||||
Parse(string(data)); err != nil {
|
Parse(string(data)); err != nil {
|
||||||
|
@ -57,7 +59,7 @@ func (p *Provider) LoadTemplatedAssets(fs embed.FS) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.templates.asset.api.spec, err = template.
|
if p.templates.asset.api.spec, err = tt.
|
||||||
New("api/public_html/openapi.yaml").
|
New("api/public_html/openapi.yaml").
|
||||||
Funcs(FuncMap()).
|
Funcs(FuncMap()).
|
||||||
Parse(string(data)); err != nil {
|
Parse(string(data)); err != nil {
|
||||||
|
@ -92,6 +94,11 @@ func (p *Provider) GetIdentityVerificationEmailTemplate() (t *EmailTemplate) {
|
||||||
return p.templates.notification.identityVerification
|
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) {
|
func (p *Provider) load() (err error) {
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
|
@ -103,6 +110,17 @@ func (p *Provider) load() (err error) {
|
||||||
errs = append(errs, err)
|
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 {
|
if len(errs) != 0 {
|
||||||
for i, e := range errs {
|
for i, e := range errs {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Submit This Form</title>
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.onload = function() {
|
||||||
|
document.forms[0].submit();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form method="post" action="{{ .RedirURL }}">
|
||||||
|
{{ range $key,$value := .Parameters }}
|
||||||
|
{{ range $parameter:= $value}}
|
||||||
|
<input type="hidden" name="{{$key}}" value="{{$parameter}}"/>
|
||||||
|
{{end}}
|
||||||
|
{{ end }}
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -10,14 +10,21 @@ import (
|
||||||
type Templates struct {
|
type Templates struct {
|
||||||
notification NotificationTemplates
|
notification NotificationTemplates
|
||||||
asset AssetTemplates
|
asset AssetTemplates
|
||||||
|
oidc OpenIDConnectTemplates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OpenIDConnectTemplates struct {
|
||||||
|
formpost *th.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetTemplates are templates for specific key assets.
|
||||||
type AssetTemplates struct {
|
type AssetTemplates struct {
|
||||||
index *tt.Template
|
index *tt.Template
|
||||||
api APIAssetTemplates
|
api OpenAPIAssetTemplates
|
||||||
}
|
}
|
||||||
|
|
||||||
type APIAssetTemplates struct {
|
// OpenAPIAssetTemplates are asset templates for the OpenAPI specification.
|
||||||
|
type OpenAPIAssetTemplates struct {
|
||||||
index *tt.Template
|
index *tt.Template
|
||||||
spec *tt.Template
|
spec *tt.Template
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue