Skip to content

Commit

Permalink
fix: enforce content type header for API requests (#16860) (Cherry-pi…
Browse files Browse the repository at this point in the history
…ck release-2.8) (#16879)

* chore: skip server certificate verification for http requests in e2e tests (#15733)

* chore: skip verifying server certificate for http requests in e2e tests

Signed-off-by: Chris Fry <christopherfry@google.com>

* chore: skip certificate verification only for remote tests

Signed-off-by: Chris Fry <christopherfry@google.com>

---------

Signed-off-by: Chris Fry <christopherfry@google.com>

* fix: enforce content type header for API requests (#16860)

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

---------

Signed-off-by: Chris Fry <christopherfry@google.com>
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Christopher Fry <ChristopherFry2008@gmail.com>
  • Loading branch information
alexmt and ChristopherFry committed Jan 16, 2024
1 parent c80e771 commit 0b459f2
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 1 deletion.
4 changes: 4 additions & 0 deletions cmd/argocd-server/commands/argocd_server.go
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math"
"strings"
"time"

"github.com/argoproj/pkg/stats"
Expand Down Expand Up @@ -62,6 +63,7 @@ func NewCommand() *cobra.Command {
repoServerAddress string
dexServerAddress string
disableAuth bool
contentTypes string
enableGZip bool
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
cacheSrc func() (*servercache.Cache, error)
Expand Down Expand Up @@ -181,6 +183,7 @@ func NewCommand() *cobra.Command {
DexServerAddr: dexServerAddress,
DexTLSConfig: dexTlsConfig,
DisableAuth: disableAuth,
ContentTypes: strings.Split(contentTypes, ";"),
EnableGZip: enableGZip,
TLSConfigCustomizer: tlsConfigCustomizer,
Cache: cache,
Expand Down Expand Up @@ -228,6 +231,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_SERVER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address")
command.Flags().StringVar(&dexServerAddress, "dex-server", env.StringFromEnv("ARGOCD_SERVER_DEX_SERVER", common.DefaultDexServerAddr), "Dex server address")
command.Flags().BoolVar(&disableAuth, "disable-auth", env.ParseBoolFromEnv("ARGOCD_SERVER_DISABLE_AUTH", false), "Disable client authentication")
command.Flags().StringVar(&contentTypes, "api-content-types", "application/json", "Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty.")
command.Flags().BoolVar(&enableGZip, "enable-gzip", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_GZIP", true), "Enable GZIP compression")
command.AddCommand(cli.NewVersionCmd(cliName))
command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_SERVER_LISTEN_ADDRESS", common.DefaultAddressAPIServer), "Listen on given address")
Expand Down
1 change: 1 addition & 0 deletions docs/operator-manual/server-commands/argocd-server.md
Expand Up @@ -14,6 +14,7 @@ argocd-server [flags]

```
--address string Listen on given address (default "0.0.0.0")
--api-content-types string Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty. (default "application/json")
--app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s)
--application-namespaces strings List of additional namespaces where application resources can be managed in
--as string Username to impersonate for the operation
Expand Down
18 changes: 18 additions & 0 deletions server/server.go
Expand Up @@ -199,6 +199,7 @@ type ArgoCDServer struct {

type ArgoCDServerOpts struct {
DisableAuth bool
ContentTypes []string
EnableGZip bool
Insecure bool
StaticAssetsDir string
Expand Down Expand Up @@ -974,6 +975,9 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
if a.EnableGZip {
handler = compressHandler(handler)
}
if len(a.ContentTypes) > 0 {
handler = enforceContentTypes(handler, a.ContentTypes)
}
mux.Handle("/api/", handler)

terminal := application.NewHandler(a.appLister, a.Namespace, a.ApplicationNamespaces, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells, *a.sessionMgr).
Expand Down Expand Up @@ -1040,6 +1044,20 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
return &httpS
}

func enforceContentTypes(handler http.Handler, types []string) http.Handler {
allowedTypes := map[string]bool{}
for _, t := range types {
allowedTypes[strings.ToLower(t)] = true
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet || allowedTypes[strings.ToLower(r.Header.Get("Content-Type"))] {
handler.ServeHTTP(w, r)
} else {
http.Error(w, "Invalid content type", http.StatusUnsupportedMediaType)
}
})
}

// registerExtensions will try to register all configured extensions
// in the given mux. If any error is returned while registering
// extensions handlers, no route will be added in the given mux.
Expand Down
11 changes: 10 additions & 1 deletion test/e2e/fixture/http.go
Expand Up @@ -2,6 +2,7 @@ package fixture

import (
"bytes"
"crypto/tls"
"encoding/json"
"io"
"net/http"
Expand All @@ -27,7 +28,15 @@ func DoHttpRequest(method string, path string, data ...byte) (*http.Response, er
return nil, err
}
req.AddCookie(&http.Cookie{Name: common.AuthCookieName, Value: token})
return http.DefaultClient.Do(req)
req.Header.Set("Content-Type", "application/json")

httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: IsRemote()},
},
}

return httpClient.Do(req)
}

// DoHttpJsonRequest executes a http request against the Argo CD API server and unmarshals the response body as JSON
Expand Down

0 comments on commit 0b459f2

Please sign in to comment.