From 098c27d3da3d27e4a836751636f6247938a48be9 Mon Sep 17 00:00:00 2001 From: Silvan Date: Thu, 11 May 2023 18:02:34 +0200 Subject: [PATCH 1/8] fix: render authrequest id only if possible (#5823) --- internal/api/ui/login/renderer.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/api/ui/login/renderer.go b/internal/api/ui/login/renderer.go index a9b12f19dc..5c20168d35 100644 --- a/internal/api/ui/login/renderer.go +++ b/internal/api/ui/login/renderer.go @@ -327,7 +327,12 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq * func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) { var msg string if err != nil { - logging.WithError(err).WithField("auth_req_id", authReq.ID).Error() + log := logging.WithError(err) + if authReq != nil { + log = log.WithField("auth_req_id", authReq.ID) + } + log.Error() + _, msg = l.getErrorMessage(r, err) } data := l.getBaseData(r, authReq, "Errors.Internal", "", "Internal", msg) From 240b799fd326b6900987a5cb6bff257389ab82a4 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 12 May 2023 07:06:54 +0200 Subject: [PATCH 2/8] chore: bump Helm charts from next (#5815) Co-authored-by: Livio Spring --- .github/workflows/zitadel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zitadel.yml b/.github/workflows/zitadel.yml index 2691109f80..c5512d5290 100644 --- a/.github/workflows/zitadel.yml +++ b/.github/workflows/zitadel.yml @@ -80,7 +80,7 @@ jobs: name: go-codecov - name: Bump Chart Version uses: peter-evans/repository-dispatch@v2 - if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/main' + if: steps.semantic.outputs.new_release_published == 'true' && github.ref == 'refs/heads/next' with: token: ${{ steps.generate-token.outputs.token }} repository: zitadel/zitadel-charts From 99857ff9549a612e36eec09f882834a82e51ead0 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Fri, 12 May 2023 09:36:44 +0200 Subject: [PATCH 3/8] chore: speed up local console docker build (#5824) Co-authored-by: Livio Spring --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.dockerignore b/.dockerignore index 5d4e0f6ced..0fea514232 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,6 +7,7 @@ /k8s/ /node_modules/ /console/src/app/proto/generated/ +/console/.angular /console/tmp/ .releaserc.js changelog.config.js @@ -18,3 +19,4 @@ pkg/grpc/*/*.pb.* pkg/grpc/*/*.swagger.json .goreleaser.yaml .artifacts/ +.vscode From 91431cb451f673efc1d4feb618b37ebf046fe40a Mon Sep 17 00:00:00 2001 From: mffap Date: Fri, 12 May 2023 10:51:17 +0200 Subject: [PATCH 4/8] docs(legal): editorial changes (#5828) * docs(legal): editorial changes * remove from tos --- docs/docs/legal/introduction.mdx | 27 -------- docs/docs/legal/terms-of-service-dedicated.md | 39 ----------- docs/docs/legal/terms-of-service.md | 6 +- docs/docusaurus.config.js | 2 +- docs/sidebars.js | 68 +++++++++++-------- 5 files changed, 42 insertions(+), 100 deletions(-) delete mode 100644 docs/docs/legal/introduction.mdx delete mode 100644 docs/docs/legal/terms-of-service-dedicated.md diff --git a/docs/docs/legal/introduction.mdx b/docs/docs/legal/introduction.mdx deleted file mode 100644 index 00bebc4a6a..0000000000 --- a/docs/docs/legal/introduction.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Overview ---- - -import {ListElement, ListWrapper, ICONTYPE} from '../../src/components/list'; -import Column from '../../src/components/column'; - -This section contains important agreements, policies and appendices relevant for users of our websites and services. - -All documents will be provided in English language. - - - - - - - - - - - - - - - - - diff --git a/docs/docs/legal/terms-of-service-dedicated.md b/docs/docs/legal/terms-of-service-dedicated.md deleted file mode 100644 index d2bae23355..0000000000 --- a/docs/docs/legal/terms-of-service-dedicated.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Dedicated Instance Terms -custom_edit_url: null ---- -## General - -Last revised: June 3, 2022 - -### Background - -Within the scope of the Framework Agreement, the Customer may choose to purchase a subscription that requires a dedicated instance of ZITADEL. These additional terms for dedicated instance ("**Dedicated Instance Terms**") apply in addition to the Framework Agreement. - -### Service - -CAOS operates and manages a **Dedicated Instance** of ZITADEL in a private infrastructure environment dedicated for the Customer and provides support services for the Customer according the Purchase Order, these terms, agreed [**Service Level Description**](service-level-description), and [**Support Service Descriptions**](support-services). - -Each Dedicated Instance consists, except agreed otherwise in writing, of a multi-zonal high-availability configuration that guarantees loads up to the specified [rate limits](rate-limit-policy#what-rate-limits-do-apply). - -### Operations - -CAOS will install and manage the Dedicated Instance on infracstructure provided by preferred cloud providers. Costs for infrastructure or cloud providers are not included in the Subscription, if not agreed otherwise in writing. - -You may choose to provide the required infrastructure yourself. You must comply with the requirements and prerequisites outlined in the purchase order. - -You may not modify, maintain or attempt to modify the Dedicated Instance, except with prior instructions by CAOS. - -CAOS will use the same backup strategy as for ZITADEL Cloud (public cloud) services, except otherwise agreed between you and CAOS in writing. - -### Maintenance and Updates - -We will access, modify, and maintain the Dedicated Instance at times solely determined by CAOS (**"Regular Maintenance"**). - -Under certain subscription plans, the Customer may agree a custom frequency and times for changes and updates. CAOS will coordinate the cadence and the changes with the Customer. To guarantee the quality of service, maintenance will occur on regular basis, typically monthly or sooner for security or performance related patches (**"Emergency Maintenance"**), but no longer than on quarterly basis. - -If you fail to permit CAOS to conduct Regular Maintenance for 3 consecutive months or Emergency Maintenance within 5 days of notification, then CAOS will raise this issue with the Customer via Escalation Process. In case the issue is not resolved 5 days after such an escalation, CAOS may terminate the subscription with 30 days prior written notice to Customer. CAOS is not obligated to provide the service according to the terms and SLA, nor is CAOS liable to any security breach or damages after failure to permit Regular Maintenance for 3 consecutive months, or Emergency Maintenance for 5 days after notification. - -### Incidents - -Incidents are handled as documented in the [**Support Service Descriptions**](support-services). If the Customer choose in Purchase Order to provide the required infrastructure, then any incidents related to the infrastructure of the Dedicated Instance have to be resolved through the Customer directly. diff --git a/docs/docs/legal/terms-of-service.md b/docs/docs/legal/terms-of-service.md index ee2b8be36d..e963ae58d2 100644 --- a/docs/docs/legal/terms-of-service.md +++ b/docs/docs/legal/terms-of-service.md @@ -25,10 +25,6 @@ The following policies complement the TOS. When accepting the TOS, you accept th * [**Acceptable Use Policy**](acceptable-use-policy) - What we understand as acceptable and fair use of our Services * [**Rate Limit Policy**](rate-limit-policy) - How we avoid overloads of our services -This Agreement is extended with additional terms, in case your Subscription requires a Dedicated Instance. When you enter the Agreement with us, you accept these additional agreements. - -* [**Dedicated Instance Terms**](terms-of-service-dedicated) - How we provide our services for a dedicated instance - ### Alterations Any provisions which deviate from these TOS must be agreed in writing between the Customer and us. Such agreements shall take precedence over the TOS outlined in this document. @@ -195,7 +191,7 @@ Should any provision of these TOS be or become invalid, this shall not affect th These TOS shall enter into force as of 15.07.2022. -Last revised: June 14, 2022 +Last revised: May 12, 2023 ### Amendments diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 409f3905e3..058d2c4626 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -83,7 +83,7 @@ module.exports = { }, { type: "doc", - docId: "legal/introduction", + docId: "legal", label: "Legal", position: "right", }, diff --git a/docs/sidebars.js b/docs/sidebars.js index 54ca65bb18..709c99b928 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -540,38 +540,50 @@ module.exports = { support: [ ], legal: [ - "legal/introduction", - "legal/terms-of-service", - "legal/data-processing-agreement", { type: "category", - label: "Service Description", + label: "Legal Agreements", collapsed: false, + link: { + type: "generated-index", + title: "Legal Agreements", + slug: "legal", + description: + "This section contains important agreements, policies and appendices relevant for users of our websites and services. All documents will be provided in English language.", + }, items: [ - "legal/cloud-service-description", - "legal/service-level-description", - "legal/support-services", - ], - }, - { - type: "category", - label: "Additional terms", - collapsed: true, - items: [ - "legal/terms-support-service", - "legal/terms-of-service-dedicated", - ], - }, - { - type: "category", - label: "Policies", - collapsed: false, - items: [ - "legal/privacy-policy", - "legal/acceptable-use-policy", - "legal/rate-limit-policy", - "legal/vulnerability-disclosure-policy", - ], + "legal/terms-of-service", + "legal/data-processing-agreement", + { + type: "category", + label: "Service Description", + collapsed: false, + items: [ + "legal/cloud-service-description", + "legal/service-level-description", + "legal/support-services", + ], + }, + { + type: "category", + label: "Support Program", + collapsed: true, + items: [ + "legal/terms-support-service", + ], + }, + { + type: "category", + label: "Policies", + collapsed: false, + items: [ + "legal/privacy-policy", + "legal/acceptable-use-policy", + "legal/rate-limit-policy", + "legal/vulnerability-disclosure-policy", + ], + }, + ] }, ], }; From b449762aedac4907b697e4b81ec61b8439e1056f Mon Sep 17 00:00:00 2001 From: mffap Date: Fri, 12 May 2023 11:08:22 +0200 Subject: [PATCH 5/8] docs: add generated docs to gitignore (#5827) --- docs/.gitignore | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/.gitignore b/docs/.gitignore index aa32254704..0b04043a5e 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -9,6 +9,18 @@ .cache-loader .artifacts +# Generated by docusaurus-plugin-openapi-docs +docs/apis/auth +docs/apis/mgmt +docs/apis/admin +docs/apis/system +docs/apis/user_service +docs/apis/session_service +docs/apis/system +docs/apis/user_service +docs/apis/session_service +docs/apis/settings_service + # Misc .DS_Store .env.local From 0e251a29c8c6957978a41be3b65e195336807fc1 Mon Sep 17 00:00:00 2001 From: Elio Bischof Date: Mon, 15 May 2023 08:51:02 +0200 Subject: [PATCH 6/8] fix: set exhausted cookie with env json (#5868) * fix: set exhausted cookie with env json * lint --- cmd/start/start.go | 7 +- internal/api/api.go | 48 +++++------ internal/api/grpc/server/gateway.go | 58 ++++++------- .../api/http/middleware/access_interceptor.go | 86 +++++++++++-------- internal/api/ui/console/console.go | 12 ++- 5 files changed, 109 insertions(+), 102 deletions(-) diff --git a/cmd/start/start.go b/cmd/start/start.go index 0d2d973690..efa0e9326f 100644 --- a/cmd/start/start.go +++ b/cmd/start/start.go @@ -306,9 +306,8 @@ func startAPIs( http_util.WithNonHttpOnly(), http_util.WithMaxAge(int(math.Floor(config.Quotas.Access.ExhaustedCookieMaxAge.Seconds()))), ) - limitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, exhaustedCookieHandler, config.Quotas.Access, false) - nonLimitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, nil, config.Quotas.Access, true) - apis, err := api.New(ctx, config.Port, router, queries, verifier, config.InternalAuthZ, tlsConfig, config.HTTP2HostHeader, config.HTTP1HostHeader, accessSvc, exhaustedCookieHandler, config.Quotas.Access) + limitingAccessInterceptor := middleware.NewAccessInterceptor(accessSvc, exhaustedCookieHandler, config.Quotas.Access) + apis, err := api.New(ctx, config.Port, router, queries, verifier, config.InternalAuthZ, tlsConfig, config.HTTP2HostHeader, config.HTTP1HostHeader, limitingAccessInterceptor) if err != nil { return fmt.Errorf("error creating api %w", err) } @@ -376,7 +375,7 @@ func startAPIs( } apis.RegisterHandlerOnPrefix(saml.HandlerPrefix, samlProvider.HttpHandler()) - c, err := console.Start(config.Console, config.ExternalSecure, oidcProvider.IssuerFromRequest, middleware.CallDurationHandler, instanceInterceptor.Handler, nonLimitingAccessInterceptor.Handle, config.CustomerPortal) + c, err := console.Start(config.Console, config.ExternalSecure, oidcProvider.IssuerFromRequest, middleware.CallDurationHandler, instanceInterceptor.Handler, limitingAccessInterceptor, config.CustomerPortal) if err != nil { return fmt.Errorf("unable to start console: %w", err) } diff --git a/internal/api/api.go b/internal/api/api.go index 768f0f1a2e..578bae3a45 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -19,24 +19,22 @@ import ( http_mw "github.com/zitadel/zitadel/internal/api/http/middleware" "github.com/zitadel/zitadel/internal/api/ui/login" "github.com/zitadel/zitadel/internal/errors" - "github.com/zitadel/zitadel/internal/logstore" "github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/telemetry/metrics" "github.com/zitadel/zitadel/internal/telemetry/tracing" ) type API struct { - port uint16 - grpcServer *grpc.Server - verifier *internal_authz.TokenVerifier - health healthCheck - router *mux.Router - http1HostName string - grpcGateway *server.Gateway - healthServer *health.Server - cookieHandler *http_util.CookieHandler - cookieConfig *http_mw.AccessConfig - queries *query.Queries + port uint16 + grpcServer *grpc.Server + verifier *internal_authz.TokenVerifier + health healthCheck + router *mux.Router + http1HostName string + grpcGateway *server.Gateway + healthServer *health.Server + accessInterceptor *http_mw.AccessInterceptor + queries *query.Queries } type healthCheck interface { @@ -51,23 +49,20 @@ func New( verifier *internal_authz.TokenVerifier, authZ internal_authz.Config, tlsConfig *tls.Config, http2HostName, http1HostName string, - accessSvc *logstore.Service, - cookieHandler *http_util.CookieHandler, - cookieConfig *http_mw.AccessConfig, + accessInterceptor *http_mw.AccessInterceptor, ) (_ *API, err error) { api := &API{ - port: port, - verifier: verifier, - health: queries, - router: router, - http1HostName: http1HostName, - cookieConfig: cookieConfig, - cookieHandler: cookieHandler, - queries: queries, + port: port, + verifier: verifier, + health: queries, + router: router, + http1HostName: http1HostName, + queries: queries, + accessInterceptor: accessInterceptor, } - api.grpcServer = server.CreateServer(api.verifier, authZ, queries, http2HostName, tlsConfig, accessSvc) - api.grpcGateway, err = server.CreateGateway(ctx, port, http1HostName, cookieHandler, cookieConfig) + api.grpcServer = server.CreateServer(api.verifier, authZ, queries, http2HostName, tlsConfig, accessInterceptor.AccessService()) + api.grpcGateway, err = server.CreateGateway(ctx, port, http1HostName, accessInterceptor) if err != nil { return nil, err } @@ -90,8 +85,7 @@ func (a *API) RegisterServer(ctx context.Context, grpcServer server.WithGatewayP grpcServer, a.port, a.http1HostName, - a.cookieHandler, - a.cookieConfig, + a.accessInterceptor, a.queries, ) if err != nil { diff --git a/internal/api/grpc/server/gateway.go b/internal/api/grpc/server/gateway.go index 9798e5dbd0..eed0234be9 100644 --- a/internal/api/grpc/server/gateway.go +++ b/internal/api/grpc/server/gateway.go @@ -16,7 +16,6 @@ import ( client_middleware "github.com/zitadel/zitadel/internal/api/grpc/client/middleware" "github.com/zitadel/zitadel/internal/api/grpc/server/middleware" - http_utils "github.com/zitadel/zitadel/internal/api/http" http_mw "github.com/zitadel/zitadel/internal/api/http/middleware" "github.com/zitadel/zitadel/internal/query" ) @@ -66,16 +65,15 @@ var ( ) type Gateway struct { - mux *runtime.ServeMux - http1HostName string - connection *grpc.ClientConn - cookieHandler *http_utils.CookieHandler - cookieConfig *http_mw.AccessConfig - queries *query.Queries + mux *runtime.ServeMux + http1HostName string + connection *grpc.ClientConn + accessInterceptor *http_mw.AccessInterceptor + queries *query.Queries } func (g *Gateway) Handler() http.Handler { - return addInterceptors(g.mux, g.http1HostName, g.cookieHandler, g.cookieConfig, g.queries) + return addInterceptors(g.mux, g.http1HostName, g.accessInterceptor, g.queries) } type CustomHTTPResponse interface { @@ -89,8 +87,7 @@ func CreateGatewayWithPrefix( g WithGatewayPrefix, port uint16, http1HostName string, - cookieHandler *http_utils.CookieHandler, - cookieConfig *http_mw.AccessConfig, + accessInterceptor *http_mw.AccessInterceptor, queries *query.Queries, ) (http.Handler, string, error) { runtimeMux := runtime.NewServeMux(serveMuxOptions...) @@ -106,10 +103,10 @@ func CreateGatewayWithPrefix( if err != nil { return nil, "", fmt.Errorf("failed to register grpc gateway: %w", err) } - return addInterceptors(runtimeMux, http1HostName, cookieHandler, cookieConfig, queries), g.GatewayPathPrefix(), nil + return addInterceptors(runtimeMux, http1HostName, accessInterceptor, queries), g.GatewayPathPrefix(), nil } -func CreateGateway(ctx context.Context, port uint16, http1HostName string, cookieHandler *http_utils.CookieHandler, cookieConfig *http_mw.AccessConfig) (*Gateway, error) { +func CreateGateway(ctx context.Context, port uint16, http1HostName string, accessInterceptor *http_mw.AccessInterceptor) (*Gateway, error) { connection, err := dial(ctx, port, []grpc.DialOption{ @@ -121,11 +118,10 @@ func CreateGateway(ctx context.Context, port uint16, http1HostName string, cooki } runtimeMux := runtime.NewServeMux(append(serveMuxOptions, runtime.WithHealthzEndpoint(healthpb.NewHealthClient(connection)))...) return &Gateway{ - mux: runtimeMux, - http1HostName: http1HostName, - connection: connection, - cookieHandler: cookieHandler, - cookieConfig: cookieConfig, + mux: runtimeMux, + http1HostName: http1HostName, + connection: connection, + accessInterceptor: accessInterceptor, }, nil } @@ -163,8 +159,7 @@ func dial(ctx context.Context, port uint16, opts []grpc.DialOption) (*grpc.Clien func addInterceptors( handler http.Handler, http1HostName string, - cookieHandler *http_utils.CookieHandler, - cookieConfig *http_mw.AccessConfig, + accessInterceptor *http_mw.AccessInterceptor, queries *query.Queries, ) http.Handler { handler = http_mw.CallDurationHandler(handler) @@ -174,7 +169,7 @@ func addInterceptors( handler = http_mw.DefaultTelemetryHandler(handler) // For some non-obvious reason, the exhaustedCookieInterceptor sends the SetCookie header // only if it follows the http_mw.DefaultTelemetryHandler - handler = exhaustedCookieInterceptor(handler, cookieHandler, cookieConfig, queries) + handler = exhaustedCookieInterceptor(handler, accessInterceptor, queries) handler = http_mw.DefaultMetricsHandler(handler) return handler } @@ -193,35 +188,32 @@ func http1Host(next http.Handler, http1HostName string) http.Handler { func exhaustedCookieInterceptor( next http.Handler, - cookieHandler *http_utils.CookieHandler, - cookieConfig *http_mw.AccessConfig, + accessInterceptor *http_mw.AccessInterceptor, queries *query.Queries, ) http.Handler { return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { next.ServeHTTP(&cookieResponseWriter{ - ResponseWriter: writer, - cookieHandler: cookieHandler, - cookieConfig: cookieConfig, - request: request, - queries: queries, + ResponseWriter: writer, + accessInterceptor: accessInterceptor, + request: request, + queries: queries, }, request) }) } type cookieResponseWriter struct { http.ResponseWriter - cookieHandler *http_utils.CookieHandler - cookieConfig *http_mw.AccessConfig - request *http.Request - queries *query.Queries + accessInterceptor *http_mw.AccessInterceptor + request *http.Request + queries *query.Queries } func (r *cookieResponseWriter) WriteHeader(status int) { if status >= 200 && status < 300 { - http_mw.DeleteExhaustedCookie(r.cookieHandler, r.ResponseWriter, r.request, r.cookieConfig) + r.accessInterceptor.DeleteExhaustedCookie(r.ResponseWriter, r.request) } if status == http.StatusTooManyRequests { - http_mw.SetExhaustedCookie(r.cookieHandler, r.ResponseWriter, r.cookieConfig, r.request) + r.accessInterceptor.SetExhaustedCookie(r.ResponseWriter, r.request) } r.ResponseWriter.WriteHeader(status) } diff --git a/internal/api/http/middleware/access_interceptor.go b/internal/api/http/middleware/access_interceptor.go index cf52a597d6..469fdd16d7 100644 --- a/internal/api/http/middleware/access_interceptor.go +++ b/internal/api/http/middleware/access_interceptor.go @@ -1,6 +1,7 @@ package middleware import ( + "context" "net" "net/http" "net/url" @@ -32,15 +33,54 @@ type AccessConfig struct { // NewAccessInterceptor intercepts all requests and stores them to the logstore. // If storeOnly is false, it also checks if requests are exhausted. // If requests are exhausted, it also returns http.StatusTooManyRequests and sets a cookie -func NewAccessInterceptor(svc *logstore.Service, cookieHandler *http_utils.CookieHandler, cookieConfig *AccessConfig, storeOnly bool) *AccessInterceptor { +func NewAccessInterceptor(svc *logstore.Service, cookieHandler *http_utils.CookieHandler, cookieConfig *AccessConfig) *AccessInterceptor { return &AccessInterceptor{ svc: svc, cookieHandler: cookieHandler, limitConfig: cookieConfig, - storeOnly: storeOnly, } } +func (a *AccessInterceptor) WithoutLimiting() *AccessInterceptor { + return &AccessInterceptor{ + svc: a.svc, + cookieHandler: a.cookieHandler, + limitConfig: a.limitConfig, + storeOnly: true, + } +} + +func (a *AccessInterceptor) AccessService() *logstore.Service { + return a.svc +} + +func (a *AccessInterceptor) Limit(ctx context.Context) bool { + if !a.svc.Enabled() || a.storeOnly { + return false + } + instance := authz.GetInstance(ctx) + remaining := a.svc.Limit(ctx, instance.InstanceID()) + return remaining != nil && *remaining <= 0 +} + +func (a *AccessInterceptor) SetExhaustedCookie(writer http.ResponseWriter, request *http.Request) { + cookieValue := "true" + host := request.Header.Get(middleware.HTTP1Host) + domain := host + if strings.ContainsAny(host, ":") { + var err error + domain, _, err = net.SplitHostPort(host) + if err != nil { + logging.WithError(err).WithField("host", host).Warning("failed to extract cookie domain from request host") + } + } + a.cookieHandler.SetCookie(writer, a.limitConfig.ExhaustedCookieKey, domain, cookieValue) +} + +func (a *AccessInterceptor) DeleteExhaustedCookie(writer http.ResponseWriter, request *http.Request) { + a.cookieHandler.DeleteCookie(writer, request, a.limitConfig.ExhaustedCookieKey) +} + func (a *AccessInterceptor) Handle(next http.Handler) http.Handler { if !a.svc.Enabled() { return next @@ -49,23 +89,16 @@ func (a *AccessInterceptor) Handle(next http.Handler) http.Handler { ctx := request.Context() tracingCtx, checkSpan := tracing.NewNamedSpan(ctx, "checkAccess") wrappedWriter := &statusRecorder{ResponseWriter: writer, status: 0} - instance := authz.GetInstance(ctx) - limit := false - if !a.storeOnly { - remaining := a.svc.Limit(tracingCtx, instance.InstanceID()) - limit = remaining != nil && *remaining == 0 - } + limited := a.Limit(tracingCtx) checkSpan.End() - if limit { - // Limit can only be true when storeOnly is false, so set the cookie and the response code - SetExhaustedCookie(a.cookieHandler, wrappedWriter, a.limitConfig, request) + if limited { + a.SetExhaustedCookie(wrappedWriter, request) http.Error(wrappedWriter, "quota for authenticated requests is exhausted", http.StatusTooManyRequests) - } else { - if !a.storeOnly { - // If not limited and not storeOnly, ensure the cookie is deleted - DeleteExhaustedCookie(a.cookieHandler, wrappedWriter, request, a.limitConfig) - } - // Always serve if not limited + } + if !limited && !a.storeOnly { + a.DeleteExhaustedCookie(wrappedWriter, request) + } + if !limited { next.ServeHTTP(wrappedWriter, request) } tracingCtx, writeSpan := tracing.NewNamedSpan(tracingCtx, "writeAccess") @@ -75,6 +108,7 @@ func (a *AccessInterceptor) Handle(next http.Handler) http.Handler { if err != nil { logging.WithError(err).WithField("url", requestURL).Warning("failed to unescape request url") } + instance := authz.GetInstance(tracingCtx) a.svc.Handle(tracingCtx, &access.Record{ LogDate: time.Now(), Protocol: access.HTTP, @@ -90,24 +124,6 @@ func (a *AccessInterceptor) Handle(next http.Handler) http.Handler { }) } -func SetExhaustedCookie(cookieHandler *http_utils.CookieHandler, writer http.ResponseWriter, cookieConfig *AccessConfig, request *http.Request) { - cookieValue := "true" - host := request.Header.Get(middleware.HTTP1Host) - domain := host - if strings.ContainsAny(host, ":") { - var err error - domain, _, err = net.SplitHostPort(host) - if err != nil { - logging.WithError(err).WithField("host", host).Warning("failed to extract cookie domain from request host") - } - } - cookieHandler.SetCookie(writer, cookieConfig.ExhaustedCookieKey, domain, cookieValue) -} - -func DeleteExhaustedCookie(cookieHandler *http_utils.CookieHandler, writer http.ResponseWriter, request *http.Request, cookieConfig *AccessConfig) { - cookieHandler.DeleteCookie(writer, request, cookieConfig.ExhaustedCookieKey) -} - type statusRecorder struct { http.ResponseWriter status int diff --git a/internal/api/ui/console/console.go b/internal/api/ui/console/console.go index 45503ca0c1..1980f6cc5f 100644 --- a/internal/api/ui/console/console.go +++ b/internal/api/ui/console/console.go @@ -91,7 +91,7 @@ func (f *file) Stat() (_ fs.FileInfo, err error) { return f, nil } -func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, callDurationInterceptor, instanceHandler, accessInterceptor func(http.Handler) http.Handler, customerPortal string) (http.Handler, error) { +func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, callDurationInterceptor, instanceHandler func(http.Handler) http.Handler, limitingAccessInterceptor *middleware.AccessInterceptor, customerPortal string) (http.Handler, error) { fSys, err := fs.Sub(static, "static") if err != nil { return nil, err @@ -106,10 +106,11 @@ func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, call handler := mux.NewRouter() - handler.Use(callDurationInterceptor, instanceHandler, security, accessInterceptor) + handler.Use(callDurationInterceptor, instanceHandler, security, limitingAccessInterceptor.WithoutLimiting().Handle) handler.Handle(envRequestPath, middleware.TelemetryHandler()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { url := http_util.BuildOrigin(r.Host, externalSecure) - instance := authz.GetInstance(r.Context()) + ctx := r.Context() + instance := authz.GetInstance(ctx) instanceMgmtURL, err := templateInstanceManagementURL(config.InstanceManagementURL, instance) if err != nil { http.Error(w, fmt.Sprintf("unable to template instance management url for console: %v", err), http.StatusInternalServerError) @@ -120,6 +121,11 @@ func Start(config Config, externalSecure bool, issuer op.IssuerFromRequest, call http.Error(w, fmt.Sprintf("unable to marshal env for console: %v", err), http.StatusInternalServerError) return } + if limitingAccessInterceptor.Limit(ctx) { + limitingAccessInterceptor.SetExhaustedCookie(w, r) + } else { + limitingAccessInterceptor.DeleteExhaustedCookie(w, r) + } _, err = w.Write(environmentJSON) logging.OnError(err).Error("error serving environment.json") }))) From a21d184790548fdb9cca92717df57c35477d1a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kotori=E3=81=AE=E3=81=AD=E3=81=93?= Date: Mon, 15 May 2023 02:23:56 -0500 Subject: [PATCH 7/8] docs(nginx): fix nginx directory, system api proto description (#5809) Co-authored-by: Elio Bischof --- docs/nginx.conf | 6 +++--- proto/zitadel/system.proto | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/nginx.conf b/docs/nginx.conf index 1af667f386..7b64550084 100644 --- a/docs/nginx.conf +++ b/docs/nginx.conf @@ -15,7 +15,7 @@ http { } location /docs { - root /usr/share/nginx/html; + alias /usr/share/nginx/html; index /docs/index.html; try_files $uri $uri/ /docs/index.html?q=$query_string; } @@ -23,7 +23,7 @@ http { location = /docs/proxy/js/script.js { proxy_pass https://plausible.io/js/script.js; proxy_set_header Host plausible.io; - } + } location = /docs/proxy/api/event { proxy_pass https://plausible.io/api/event; @@ -53,4 +53,4 @@ http { application/xml application/json application/ld+json; -} \ No newline at end of file +} diff --git a/proto/zitadel/system.proto b/proto/zitadel/system.proto index b34977e621..4bfec35e6e 100644 --- a/proto/zitadel/system.proto +++ b/proto/zitadel/system.proto @@ -229,7 +229,7 @@ service SystemService { }; } - // Returns the domain of an instance + // Removes the domain of an instance rpc RemoveDomain(RemoveDomainRequest) returns (RemoveDomainResponse) { option (google.api.http) = { delete: "/instances/{instance_id}/domains/{domain}"; @@ -240,7 +240,7 @@ service SystemService { }; } - // Returns the domain of an instance + // Sets the primary domain of an instance rpc SetPrimaryDomain(SetPrimaryDomainRequest) returns (SetPrimaryDomainResponse) { option (google.api.http) = { post: "/instances/{instance_id}/domains/_set_primary"; From d78b273b44dcf70f6f3eb0c4aa13d548f2090647 Mon Sep 17 00:00:00 2001 From: mffap Date: Mon, 15 May 2023 14:30:05 +0200 Subject: [PATCH 8/8] docs(contributing): don't repeat yourself (#5869) --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6d35289418..35c27ef3b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -338,6 +338,7 @@ Please refer to the [README](./docs/README.md) for more information and local te - **Code with variables**: Make sure that code snippets can be used by setting environment variables, instead of manually replacing a placeholder. - **Embedded files**: When embedding mdx files, make sure the template ist prefixed by "_" (lowdash). The content will be rendered inside the parent page, but is not accessible individually (eg, by search). +- **Don't repeat yourself**: When using the same content in multiple places, save and manage the content as separate file and make use of embedded files to import it into other docs pages. - **Embedded code**: You can embed code snippets from a repository. See the [plugin](https://github.com/saucelabs/docusaurus-theme-github-codeblock#usage) for usage. ### Docs Pull Request