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: Console:
Port: 50050 Port: 50050
EnvOverwriteDir: $ZITADEL_CONSOLE_ENV_DIR EnvOverwriteDir: $ZITADEL_CONSOLE_ENV_DIR
Cache:
MaxAge: $ZITADEL_CACHE_MAXAGE
SharedMaxAge: $ZITADEL_CACHE_SHARED_MAXAGE
CSPDomain: $ZITADEL_DEFAULT_DOMAIN
Notification: Notification:

View File

@ -6,29 +6,31 @@ import (
) )
type CSP struct { type CSP struct {
DefaultSrc CSPSourceOptions DefaultSrc CSPSourceOptions
ScriptSrc CSPSourceOptions ScriptSrc CSPSourceOptions
ObjectSrc CSPSourceOptions ObjectSrc CSPSourceOptions
StyleSrc CSPSourceOptions StyleSrc CSPSourceOptions
ImgSrc CSPSourceOptions ImgSrc CSPSourceOptions
MediaSrc CSPSourceOptions MediaSrc CSPSourceOptions
FrameSrc CSPSourceOptions FrameSrc CSPSourceOptions
FontSrc CSPSourceOptions FontSrc CSPSourceOptions
ConnectSrc CSPSourceOptions ManifestSrc CSPSourceOptions
FormAction CSPSourceOptions ConnectSrc CSPSourceOptions
FormAction CSPSourceOptions
} }
var ( var (
DefaultSCP = CSP{ DefaultSCP = CSP{
DefaultSrc: CSPSourceOptsNone(), DefaultSrc: CSPSourceOptsNone(),
ScriptSrc: CSPSourceOptsSelf(), ScriptSrc: CSPSourceOptsSelf(),
ObjectSrc: CSPSourceOptsNone(), ObjectSrc: CSPSourceOptsNone(),
StyleSrc: CSPSourceOptsSelf(), StyleSrc: CSPSourceOptsSelf(),
ImgSrc: CSPSourceOptsSelf(), ImgSrc: CSPSourceOptsSelf(),
MediaSrc: CSPSourceOptsNone(), MediaSrc: CSPSourceOptsNone(),
FrameSrc: CSPSourceOptsNone(), FrameSrc: CSPSourceOptsNone(),
FontSrc: CSPSourceOptsSelf(), FontSrc: CSPSourceOptsSelf(),
ConnectSrc: CSPSourceOptsSelf(), ManifestSrc: CSPSourceOptsSelf(),
ConnectSrc: CSPSourceOptsSelf(),
} }
) )
@ -49,16 +51,17 @@ func (csp *CSP) Value(nonce string) string {
func (csp *CSP) asMap() map[string]CSPSourceOptions { func (csp *CSP) asMap() map[string]CSPSourceOptions {
return map[string]CSPSourceOptions{ return map[string]CSPSourceOptions{
"default-src": csp.DefaultSrc, "default-src": csp.DefaultSrc,
"script-src": csp.ScriptSrc, "script-src": csp.ScriptSrc,
"object-src": csp.ObjectSrc, "object-src": csp.ObjectSrc,
"style-src": csp.StyleSrc, "style-src": csp.StyleSrc,
"img-src": csp.ImgSrc, "img-src": csp.ImgSrc,
"media-src": csp.MediaSrc, "media-src": csp.MediaSrc,
"frame-src": csp.FrameSrc, "frame-src": csp.FrameSrc,
"font-src": csp.FontSrc, "font-src": csp.FontSrc,
"connect-src": csp.ConnectSrc, "manifest-src": csp.ManifestSrc,
"form-action": csp.FormAction, "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 var err error
nonce, err = generateNonce(h.nonceLength) nonce, err = generateNonce(h.nonceLength)
if err != nil { 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 return
} }
r = saveContext(r, nonceKey, nonce) r = saveContext(r, nonceKey, nonce)

View File

@ -5,15 +5,20 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"strings"
"time"
"github.com/rakyll/statik/fs" "github.com/rakyll/statik/fs"
"github.com/caos/zitadel/internal/api/http/middleware"
_ "github.com/caos/zitadel/pkg/console/statik" _ "github.com/caos/zitadel/pkg/console/statik"
) )
type Config struct { type Config struct {
Port string Port string
EnvOverwriteDir string EnvOverwriteDir string
Cache middleware.CacheConfig
CSPDomain string
} }
type spaHandler struct { type spaHandler struct {
@ -23,6 +28,8 @@ type spaHandler struct {
const ( const (
envRequestPath = "/assets/environment.json" envRequestPath = "/assets/environment.json"
envDefaultDir = "/console/" envDefaultDir = "/console/"
manifestFile = "/manifest.webmanifest"
) )
func (i *spaHandler) Open(name string) (http.File, error) { func (i *spaHandler) Open(name string) (http.File, error) {
@ -43,7 +50,33 @@ func Start(ctx context.Context, config Config) error {
if config.EnvOverwriteDir != "" { if config.EnvOverwriteDir != "" {
envDir = config.EnvOverwriteDir envDir = config.EnvOverwriteDir
} }
http.Handle("/", http.FileServer(&spaHandler{statikFS})) cache := AssetsCacheInterceptorIgnoreManifest(config.Cache.MaxAge.Duration, config.Cache.SharedMaxAge.Duration)
http.Handle(envRequestPath, http.StripPrefix("/assets", http.FileServer(http.Dir(envDir)))) 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) 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)
})
}
}