mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 07:57:32 +00:00
feat: enable iframe use (#4766)
* feat: enable iframe use * cleanup * fix mocks * fix linting * docs: add iframe usage to solution scenarios configurations * improve api * feat(console): security policy * description * remove unnecessary line * disable input button and urls when not enabled * add image to docs Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Fabi <38692350+hifabienne@users.noreply.github.com>
This commit is contained in:
@@ -19,6 +19,7 @@ type Instance interface {
|
||||
RequestedHost() string
|
||||
DefaultLanguage() language.Tag
|
||||
DefaultOrganisationID() string
|
||||
SecurityPolicyAllowedOrigins() []string
|
||||
}
|
||||
|
||||
type InstanceVerifier interface {
|
||||
@@ -66,6 +67,10 @@ func (i *instance) DefaultOrganisationID() string {
|
||||
return i.orgID
|
||||
}
|
||||
|
||||
func (i *instance) SecurityPolicyAllowedOrigins() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetInstance(ctx context.Context) Instance {
|
||||
instance, ok := ctx.Value(instanceKey).(Instance)
|
||||
if !ok {
|
||||
|
@@ -99,3 +99,7 @@ func (m *mockInstance) RequestedDomain() string {
|
||||
func (m *mockInstance) RequestedHost() string {
|
||||
return "zitadel.cloud:443"
|
||||
}
|
||||
|
||||
func (m *mockInstance) SecurityPolicyAllowedOrigins() []string {
|
||||
return nil
|
||||
}
|
||||
|
@@ -106,3 +106,23 @@ func (s *Server) UpdateSMTPConfigPassword(ctx context.Context, req *admin_pb.Upd
|
||||
details.ResourceOwner),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetSecurityPolicy(ctx context.Context, req *admin_pb.GetSecurityPolicyRequest) (*admin_pb.GetSecurityPolicyResponse, error) {
|
||||
policy, err := s.query.SecurityPolicy(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.GetSecurityPolicyResponse{
|
||||
Policy: SecurityPolicyToPb(policy),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetSecurityPolicy(ctx context.Context, req *admin_pb.SetSecurityPolicyRequest) (*admin_pb.SetSecurityPolicyResponse, error) {
|
||||
details, err := s.command.SetSecurityPolicy(ctx, req.EnableIframeEmbedding, req.AllowedOrigins)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.SetSecurityPolicyResponse{
|
||||
Details: object.DomainToChangeDetailsPb(details),
|
||||
}, nil
|
||||
}
|
||||
|
@@ -149,3 +149,11 @@ func SMTPConfigToPb(smtp *query.SMTPConfig) *settings_pb.SMTPConfig {
|
||||
}
|
||||
return mapped
|
||||
}
|
||||
|
||||
func SecurityPolicyToPb(policy *query.SecurityPolicy) *settings_pb.SecurityPolicy {
|
||||
return &settings_pb.SecurityPolicy{
|
||||
Details: obj_grpc.ToViewDetailsPb(policy.Sequence, policy.CreationDate, policy.ChangeDate, policy.AggregateID),
|
||||
EnableIframeEmbedding: policy.Enabled,
|
||||
AllowedOrigins: policy.AllowedOrigins,
|
||||
}
|
||||
}
|
||||
|
@@ -193,3 +193,7 @@ func (m *mockInstance) RequestedDomain() string {
|
||||
func (m *mockInstance) RequestedHost() string {
|
||||
return "localhost:8080"
|
||||
}
|
||||
|
||||
func (m *mockInstance) SecurityPolicyAllowedOrigins() []string {
|
||||
return nil
|
||||
}
|
||||
|
@@ -6,36 +6,38 @@ import (
|
||||
)
|
||||
|
||||
type CSP struct {
|
||||
DefaultSrc CSPSourceOptions
|
||||
ScriptSrc CSPSourceOptions
|
||||
ObjectSrc CSPSourceOptions
|
||||
StyleSrc CSPSourceOptions
|
||||
ImgSrc CSPSourceOptions
|
||||
MediaSrc CSPSourceOptions
|
||||
FrameSrc CSPSourceOptions
|
||||
FontSrc CSPSourceOptions
|
||||
ManifestSrc CSPSourceOptions
|
||||
ConnectSrc CSPSourceOptions
|
||||
FormAction CSPSourceOptions
|
||||
DefaultSrc CSPSourceOptions
|
||||
ScriptSrc CSPSourceOptions
|
||||
ObjectSrc CSPSourceOptions
|
||||
StyleSrc CSPSourceOptions
|
||||
ImgSrc CSPSourceOptions
|
||||
MediaSrc CSPSourceOptions
|
||||
FrameSrc CSPSourceOptions
|
||||
FrameAncestors 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(),
|
||||
ManifestSrc: CSPSourceOptsSelf(),
|
||||
ConnectSrc: CSPSourceOptsSelf(),
|
||||
DefaultSrc: CSPSourceOptsNone(),
|
||||
ScriptSrc: CSPSourceOptsSelf(),
|
||||
ObjectSrc: CSPSourceOptsNone(),
|
||||
StyleSrc: CSPSourceOptsSelf(),
|
||||
ImgSrc: CSPSourceOptsSelf(),
|
||||
MediaSrc: CSPSourceOptsNone(),
|
||||
FrameSrc: CSPSourceOptsNone(),
|
||||
FrameAncestors: CSPSourceOptsNone(),
|
||||
FontSrc: CSPSourceOptsSelf(),
|
||||
ManifestSrc: CSPSourceOptsSelf(),
|
||||
ConnectSrc: CSPSourceOptsSelf(),
|
||||
}
|
||||
)
|
||||
|
||||
func (csp *CSP) Value(nonce string, host string) string {
|
||||
valuesMap := csp.asMap()
|
||||
func (csp *CSP) Value(nonce, host string, iframe []string) string {
|
||||
valuesMap := csp.asMap(iframe)
|
||||
|
||||
values := make([]string, 0, len(valuesMap))
|
||||
for k, v := range valuesMap {
|
||||
@@ -49,19 +51,24 @@ func (csp *CSP) Value(nonce string, host string) string {
|
||||
return strings.Join(values, ";")
|
||||
}
|
||||
|
||||
func (csp *CSP) asMap() map[string]CSPSourceOptions {
|
||||
func (csp *CSP) asMap(iframe []string) map[string]CSPSourceOptions {
|
||||
frameAncestors := csp.FrameAncestors
|
||||
if len(iframe) > 0 {
|
||||
frameAncestors = CSPSourceOpts().AddHost(iframe...)
|
||||
}
|
||||
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,
|
||||
"manifest-src": csp.ManifestSrc,
|
||||
"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,
|
||||
"frame-ancestors": frameAncestors,
|
||||
"font-src": csp.FontSrc,
|
||||
"manifest-src": csp.ManifestSrc,
|
||||
"connect-src": csp.ConnectSrc,
|
||||
"form-action": csp.FormAction,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -277,3 +277,7 @@ func (m *mockInstance) RequestedDomain() string {
|
||||
func (m *mockInstance) RequestedHost() string {
|
||||
return "zitadel.cloud:443"
|
||||
}
|
||||
|
||||
func (m *mockInstance) SecurityPolicyAllowedOrigins() []string {
|
||||
return nil
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_utils "github.com/zitadel/zitadel/internal/api/http"
|
||||
)
|
||||
|
||||
@@ -62,11 +63,14 @@ func (h *headers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
r = saveContext(r, nonceKey, nonce)
|
||||
}
|
||||
allowedHosts := authz.GetInstance(r.Context()).SecurityPolicyAllowedOrigins()
|
||||
headers := w.Header()
|
||||
headers.Set(http_utils.ContentSecurityPolicy, h.csp.Value(nonce, r.Host))
|
||||
headers.Set(http_utils.ContentSecurityPolicy, h.csp.Value(nonce, r.Host, allowedHosts))
|
||||
headers.Set(http_utils.XXSSProtection, "1; mode=block")
|
||||
headers.Set(http_utils.StrictTransportSecurity, "max-age=31536000; includeSubDomains")
|
||||
headers.Set(http_utils.XFrameOptions, "DENY")
|
||||
if len(allowedHosts) == 0 {
|
||||
headers.Set(http_utils.XFrameOptions, "DENY")
|
||||
}
|
||||
headers.Set(http_utils.XContentTypeOptions, "nosniff")
|
||||
headers.Set(http_utils.ReferrerPolicy, "same-origin")
|
||||
headers.Set(http_utils.FeaturePolicy, "payment 'none'")
|
||||
|
@@ -99,7 +99,7 @@ func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, inst
|
||||
|
||||
handler := mux.NewRouter()
|
||||
|
||||
handler.Use(security, instanceHandler)
|
||||
handler.Use(instanceHandler, security)
|
||||
handler.Handle(envRequestPath, middleware.TelemetryHandler()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
url := http_util.BuildOrigin(r.Host, externalSecure)
|
||||
environmentJSON, err := createEnvironmentJSON(url, issuer(r), authz.GetInstance(r.Context()).ConsoleClientID(), customerPortal)
|
||||
|
Reference in New Issue
Block a user