mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-09 07:35:13 +00:00
Merge commit from fork
* Add DenyLists parsing * Remove unneeded returned error * Plug global denylist into Command * app creation: apply denylist to backchannel logout URI * Inject denylist to backchannel logout worker * webhook config: validate against blocked URLs * Add notificationsWebhook denylist target * command: Add SMTP endpoint validation against blocklist * command: Add SMS endpoint validation against blocklist * Validate webhook endpoint against denylist on channel notification * Remove unused tests * handle deprecated denylists * remove unintended denylist entry in deprecated list * use single http client * fix tests * update comments * fixes * cleanup * address comments * fix merge --------- Co-authored-by: Livio Spring <[email protected]>
This commit is contained in:
@@ -9,9 +9,7 @@ import (
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -22,7 +20,6 @@ import (
|
||||
zhttp "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/api/oidc/sign"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/denylist"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
target_domain "github.com/zitadel/zitadel/internal/execution/target"
|
||||
"github.com/zitadel/zitadel/internal/repository/execution"
|
||||
@@ -46,7 +43,7 @@ func CallTargets(
|
||||
info ContextInfo,
|
||||
alg crypto.EncryptionAlgorithm,
|
||||
activeSigningKey GetActiveSigningWebKey,
|
||||
deniedIPList []denylist.AddressChecker,
|
||||
client *http.Client,
|
||||
) (_ any, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -58,7 +55,7 @@ func CallTargets(
|
||||
|
||||
for _, target := range targets {
|
||||
// call the type of target
|
||||
resp, err := CallTarget(ctx, target, info, alg, signerOnce, encrypters, deniedIPList)
|
||||
resp, err := CallTarget(ctx, target, info, alg, signerOnce, encrypters, client)
|
||||
// handle error if interrupt is set
|
||||
logging.WithFields("instanceID", authz.GetInstance(ctx).InstanceID(), "target", target.GetTargetID()).OnError(err).Error("error calling target")
|
||||
if err != nil && target.IsInterruptOnError() {
|
||||
@@ -86,7 +83,7 @@ func CallTarget(
|
||||
alg crypto.EncryptionAlgorithm,
|
||||
signerOnce sign.SignerFunc,
|
||||
encrypters *sync.Map,
|
||||
deniedIPList []denylist.AddressChecker,
|
||||
client *http.Client,
|
||||
) (res []byte, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -96,16 +93,6 @@ func CallTarget(
|
||||
return nil, zerrors.ThrowInternal(err, "EXEC-thiiCh5b", "Errors.Internal")
|
||||
}
|
||||
|
||||
if target.GetEndpoint() != "" {
|
||||
endpointURL, err := url.Parse(target.GetEndpoint())
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "EXEC-N5lu09", "Errors.Endpoint.Invalid")
|
||||
}
|
||||
if err := denylist.IsHostBlocked(deniedIPList, endpointURL, net.LookupIP); err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "EXEC-N5lu09", "Errors.Endpoint.Denied")
|
||||
}
|
||||
}
|
||||
|
||||
body, err := payload(ctx, info.GetHTTPRequestBody(), target, signerOnce, encrypters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -114,13 +101,13 @@ func CallTarget(
|
||||
switch target.GetTargetType() {
|
||||
// get request, ignore response and return request and error for handling in list of targets
|
||||
case target_domain.TargetTypeWebhook:
|
||||
return nil, webhook(ctx, target.GetEndpoint(), target.GetTimeout(), body, signingKey)
|
||||
return nil, webhook(ctx, target.GetEndpoint(), target.GetTimeout(), body, signingKey, client)
|
||||
// get request, return response and error
|
||||
case target_domain.TargetTypeCall:
|
||||
return Call(ctx, target.GetEndpoint(), target.GetTimeout(), body, signingKey)
|
||||
return Call(ctx, target.GetEndpoint(), target.GetTimeout(), body, signingKey, client)
|
||||
case target_domain.TargetTypeAsync:
|
||||
go func(ctx context.Context, target target_domain.Target, info []byte) {
|
||||
if _, err := Call(ctx, target.GetEndpoint(), target.GetTimeout(), info, signingKey); err != nil {
|
||||
if _, err := Call(ctx, target.GetEndpoint(), target.GetTimeout(), info, signingKey, client); err != nil {
|
||||
logging.WithFields("target", target.GetTargetID()).OnError(err).Info(err)
|
||||
}
|
||||
}(context.WithoutCancel(ctx), target, body)
|
||||
@@ -238,13 +225,13 @@ func publicKeyFromBytes(data []byte) (any, jose.KeyAlgorithm, error) {
|
||||
}
|
||||
|
||||
// webhook call a webhook, ignore the response but return the errror
|
||||
func webhook(ctx context.Context, url string, timeout time.Duration, body []byte, signingKey string) error {
|
||||
_, err := Call(ctx, url, timeout, body, signingKey)
|
||||
func webhook(ctx context.Context, url string, timeout time.Duration, body []byte, signingKey string, client *http.Client) error {
|
||||
_, err := Call(ctx, url, timeout, body, signingKey, client)
|
||||
return err
|
||||
}
|
||||
|
||||
// Call function to do a post HTTP request to a desired url with timeout
|
||||
func Call(ctx context.Context, url string, timeout time.Duration, body []byte, signingKey string) (_ []byte, err error) {
|
||||
func Call(ctx context.Context, url string, timeout time.Duration, body []byte, signingKey string, client *http.Client) (_ []byte, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() {
|
||||
@@ -261,7 +248,6 @@ func Call(ctx context.Context, url string, timeout time.Duration, body []byte, s
|
||||
req.Header.Set(actions.SigningHeader, actions.ComputeSignatureHeader(time.Now(), body, signingKey))
|
||||
}
|
||||
|
||||
client := http.DefaultClient
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -423,9 +423,7 @@ func Test_CallTarget(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_CallTargets(t *testing.T) {
|
||||
deniedLocalhost, err := denylist.NewHostChecker("127.0.0.1")
|
||||
require.NoError(t, err)
|
||||
deniedIPs := []denylist.AddressChecker{deniedLocalhost}
|
||||
deniedIPs := []denylist.AddressChecker{denylist.NewHostChecker("127.0.0.1")}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
info *middleware.ContextInfoRequest
|
||||
@@ -720,7 +718,7 @@ func checkRequest(t *testing.T, sent *http.Request, method string, checkExpected
|
||||
|
||||
func testCall(ctx context.Context, timeout time.Duration, body []byte, signingKey string) func(string) ([]byte, error) {
|
||||
return func(url string) ([]byte, error) {
|
||||
return execution.Call(ctx, url, timeout, body, signingKey)
|
||||
return execution.Call(ctx, url, timeout, body, signingKey, http.DefaultClient)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,7 +732,7 @@ func testCallTarget(ctx context.Context,
|
||||
) func(string) ([]byte, error) {
|
||||
return func(url string) (r []byte, err error) {
|
||||
target.Endpoint = url
|
||||
return execution.CallTarget(ctx, target, info, alg, signerOnce, encrypters, actionsDenyList)
|
||||
return execution.CallTarget(ctx, target, info, alg, signerOnce, encrypters, &http.Client{Transport: denylist.NewHTTPTransport(actionsDenyList)})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,7 +749,7 @@ func testCallTargets(ctx context.Context,
|
||||
t.Endpoint = urls[i]
|
||||
targets[i] = t
|
||||
}
|
||||
return execution.CallTargets(ctx, targets, info, alg, activeSigningKey, actionsDenyList)
|
||||
return execution.CallTargets(ctx, targets, info, alg, activeSigningKey, &http.Client{Transport: denylist.NewHTTPTransport(actionsDenyList)})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
@@ -16,12 +17,13 @@ var (
|
||||
func Register(
|
||||
ctx context.Context,
|
||||
workerConfig WorkerConfig,
|
||||
httpClient *http.Client,
|
||||
queue *queue.Queue,
|
||||
targetEncAlg crypto.EncryptionAlgorithm,
|
||||
activeSigningKey GetActiveSigningWebKey,
|
||||
) {
|
||||
queue.ShouldStart()
|
||||
queue.AddWorkers(ctx, NewWorker(workerConfig, targetEncAlg, activeSigningKey, time.Now))
|
||||
queue.AddWorkers(ctx, NewWorker(workerConfig, targetEncAlg, activeSigningKey, time.Now, httpClient))
|
||||
}
|
||||
|
||||
func Start(ctx context.Context) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/riverqueue/river"
|
||||
@@ -18,8 +19,9 @@ import (
|
||||
type Worker struct {
|
||||
river.WorkerDefaults[*exec_repo.Request]
|
||||
|
||||
config WorkerConfig
|
||||
now NowFunc
|
||||
config WorkerConfig
|
||||
httpClient *http.Client
|
||||
now NowFunc
|
||||
|
||||
targetEncAlg crypto.EncryptionAlgorithm
|
||||
activeSigningKey GetActiveSigningWebKey
|
||||
@@ -47,7 +49,7 @@ func (w *Worker) Work(ctx context.Context, job *river.Job[*exec_repo.Request]) e
|
||||
return river.JobCancel(fmt.Errorf("unable to unmarshal targets because %w", err))
|
||||
}
|
||||
|
||||
_, err = CallTargets(ctx, targets, exec_repo.ContextInfoFromRequest(job.Args), w.targetEncAlg, w.activeSigningKey, w.config.DenyList)
|
||||
_, err = CallTargets(ctx, targets, exec_repo.ContextInfoFromRequest(job.Args), w.targetEncAlg, w.activeSigningKey, w.httpClient)
|
||||
if err != nil {
|
||||
// If there is an error returned from the targets, it means that the execution was interrupted
|
||||
return river.JobCancel(fmt.Errorf("interruption during call of targets because %w", err))
|
||||
@@ -70,9 +72,11 @@ func NewWorker(
|
||||
targetEncAlg crypto.EncryptionAlgorithm,
|
||||
activeSigningKey GetActiveSigningWebKey,
|
||||
now NowFunc,
|
||||
httpClient *http.Client,
|
||||
) *Worker {
|
||||
return &Worker{
|
||||
config: config,
|
||||
httpClient: httpClient,
|
||||
now: now,
|
||||
targetEncAlg: targetEncAlg,
|
||||
activeSigningKey: activeSigningKey,
|
||||
|
||||
@@ -61,6 +61,7 @@ func newExecutionWorker(f fieldsWorker) *execution.Worker {
|
||||
nil,
|
||||
mockGetActiveSigningWebKey,
|
||||
f.now,
|
||||
http.DefaultClient,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user