fix: add interceptors for console (#255)

* add interceptors for console

* add interceptors for console to env.json
This commit is contained in:
Livio Amstutz 2020-06-22 13:17:29 +02:00 committed by GitHub
parent 66cca48b62
commit f68a5e63b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 32 deletions

View File

@ -205,6 +205,10 @@ Admin:
Console:
Port: 50050
EnvOverwriteDir: $ZITADEL_CONSOLE_ENV_DIR
Cache:
MaxAge: $ZITADEL_CACHE_MAXAGE
SharedMaxAge: $ZITADEL_CACHE_SHARED_MAXAGE
CSPDomain: $ZITADEL_DEFAULT_DOMAIN
Notification:

View File

@ -6,29 +6,31 @@ import (
)
type CSP struct {
DefaultSrc CSPSourceOptions
ScriptSrc CSPSourceOptions
ObjectSrc CSPSourceOptions
StyleSrc CSPSourceOptions
ImgSrc CSPSourceOptions
MediaSrc CSPSourceOptions
FrameSrc CSPSourceOptions
FontSrc CSPSourceOptions
ConnectSrc CSPSourceOptions
FormAction CSPSourceOptions
DefaultSrc CSPSourceOptions
ScriptSrc CSPSourceOptions
ObjectSrc CSPSourceOptions
StyleSrc CSPSourceOptions
ImgSrc CSPSourceOptions
MediaSrc CSPSourceOptions
FrameSrc CSPSourceOptions
FontSrc CSPSourceOptions
ManifestSrc CSPSourceOptions
ConnectSrc CSPSourceOptions
FormAction CSPSourceOptions
}
var (
DefaultSCP = CSP{
DefaultSrc: CSPSourceOptsNone(),
ScriptSrc: CSPSourceOptsSelf(),
ObjectSrc: CSPSourceOptsNone(),
StyleSrc: CSPSourceOptsSelf(),
ImgSrc: CSPSourceOptsSelf(),
MediaSrc: CSPSourceOptsNone(),
FrameSrc: CSPSourceOptsNone(),
FontSrc: CSPSourceOptsSelf(),
ConnectSrc: CSPSourceOptsSelf(),
DefaultSrc: CSPSourceOptsNone(),
ScriptSrc: CSPSourceOptsSelf(),
ObjectSrc: CSPSourceOptsNone(),
StyleSrc: CSPSourceOptsSelf(),
ImgSrc: CSPSourceOptsSelf(),
MediaSrc: CSPSourceOptsNone(),
FrameSrc: CSPSourceOptsNone(),
FontSrc: CSPSourceOptsSelf(),
ManifestSrc: CSPSourceOptsSelf(),
ConnectSrc: CSPSourceOptsSelf(),
}
)
@ -49,16 +51,17 @@ func (csp *CSP) Value(nonce string) string {
func (csp *CSP) asMap() map[string]CSPSourceOptions {
return map[string]CSPSourceOptions{
"default-src": csp.DefaultSrc,
"script-src": csp.ScriptSrc,
"object-src": csp.ObjectSrc,
"style-src": csp.StyleSrc,
"img-src": csp.ImgSrc,
"media-src": csp.MediaSrc,
"frame-src": csp.FrameSrc,
"font-src": csp.FontSrc,
"connect-src": csp.ConnectSrc,
"form-action": csp.FormAction,
"default-src": csp.DefaultSrc,
"script-src": csp.ScriptSrc,
"object-src": csp.ObjectSrc,
"style-src": csp.StyleSrc,
"img-src": csp.ImgSrc,
"media-src": csp.MediaSrc,
"frame-src": csp.FrameSrc,
"font-src": csp.FontSrc,
"manifest-src": csp.ManifestSrc,
"connect-src": csp.ConnectSrc,
"form-action": csp.FormAction,
}
}

View File

@ -48,7 +48,16 @@ func (h *headers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var err error
nonce, err = generateNonce(h.nonceLength)
if err != nil {
h.errorHandler(err).ServeHTTP(w, r)
errorHandler := h.errorHandler
if errorHandler == nil {
errorHandler = func(err error) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
})
}
}
errorHandler(err).ServeHTTP(w, r)
return
}
r = saveContext(r, nonceKey, nonce)

View File

@ -5,15 +5,20 @@ import (
"net/http"
"os"
"path"
"strings"
"time"
"github.com/rakyll/statik/fs"
"github.com/caos/zitadel/internal/api/http/middleware"
_ "github.com/caos/zitadel/pkg/console/statik"
)
type Config struct {
Port string
EnvOverwriteDir string
Cache middleware.CacheConfig
CSPDomain string
}
type spaHandler struct {
@ -23,6 +28,8 @@ type spaHandler struct {
const (
envRequestPath = "/assets/environment.json"
envDefaultDir = "/console/"
manifestFile = "/manifest.webmanifest"
)
func (i *spaHandler) Open(name string) (http.File, error) {
@ -43,7 +50,33 @@ func Start(ctx context.Context, config Config) error {
if config.EnvOverwriteDir != "" {
envDir = config.EnvOverwriteDir
}
http.Handle("/", http.FileServer(&spaHandler{statikFS}))
http.Handle(envRequestPath, http.StripPrefix("/assets", http.FileServer(http.Dir(envDir))))
cache := AssetsCacheInterceptorIgnoreManifest(config.Cache.MaxAge.Duration, config.Cache.SharedMaxAge.Duration)
security := middleware.SecurityHeaders(csp(config.CSPDomain), nil)
http.Handle("/", cache(security(http.FileServer(&spaHandler{statikFS}))))
http.Handle(envRequestPath, cache(security(http.StripPrefix("/assets", http.FileServer(http.Dir(envDir))))))
return http.ListenAndServe(":"+config.Port, nil)
}
func csp(zitadelDomain string) *middleware.CSP {
if !strings.HasPrefix(zitadelDomain, "*.") {
zitadelDomain = "*." + zitadelDomain
}
csp := middleware.DefaultSCP
csp.StyleSrc = csp.StyleSrc.AddInline().AddHost("fonts.googleapis.com").AddHost("maxst.icons8.com") //TODO: host it
csp.FontSrc = csp.FontSrc.AddHost("fonts.gstatic.com").AddHost("maxst.icons8.com") //TODO: host it
csp.ScriptSrc = csp.ScriptSrc.AddEval()
csp.ConnectSrc = csp.ConnectSrc.AddHost(zitadelDomain)
return &csp
}
func AssetsCacheInterceptorIgnoreManifest(maxAge, sharedMaxAge time.Duration) func(http.Handler) http.Handler {
return func(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == manifestFile {
middleware.NoCacheInterceptor(handler).ServeHTTP(w, r)
return
}
middleware.AssetsCacheInterceptor(maxAge, sharedMaxAge, handler).ServeHTTP(w, r)
})
}
}