mirror of
https://github.com/portainer/portainer.git
synced 2025-07-24 15:59:41 +02:00
fix(docker-desktop): support auth cookies [BE-11134] (#12108)
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
This commit is contained in:
parent
8cd53a4b7a
commit
f016b31388
8 changed files with 70 additions and 38 deletions
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/rand"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/portainer/portainer/api/http/security"
|
||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
|
@ -13,6 +14,13 @@ import (
|
|||
)
|
||||
|
||||
func WithProtect(handler http.Handler) (http.Handler, error) {
|
||||
// IsDockerDesktopExtension is used to check if we should skip csrf checks in the request bouncer (ShouldSkipCSRFCheck)
|
||||
// DOCKER_EXTENSION is set to '1' in build/docker-extension/docker-compose.yml
|
||||
isDockerDesktopExtension := false
|
||||
if val, ok := os.LookupEnv("DOCKER_EXTENSION"); ok && val == "1" {
|
||||
isDockerDesktopExtension = true
|
||||
}
|
||||
|
||||
handler = withSendCSRFToken(handler)
|
||||
|
||||
token := make([]byte, 32)
|
||||
|
@ -26,7 +34,7 @@ func WithProtect(handler http.Handler) (http.Handler, error) {
|
|||
gorillacsrf.Secure(false),
|
||||
)(handler)
|
||||
|
||||
return withSkipCSRF(handler), nil
|
||||
return withSkipCSRF(handler, isDockerDesktopExtension), nil
|
||||
}
|
||||
|
||||
func withSendCSRFToken(handler http.Handler) http.Handler {
|
||||
|
@ -45,9 +53,9 @@ func withSendCSRFToken(handler http.Handler) http.Handler {
|
|||
})
|
||||
}
|
||||
|
||||
func withSkipCSRF(handler http.Handler) http.Handler {
|
||||
func withSkipCSRF(handler http.Handler, isDockerDesktopExtension bool) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
skip, err := security.ShouldSkipCSRFCheck(r)
|
||||
skip, err := security.ShouldSkipCSRFCheck(r, isDockerDesktopExtension)
|
||||
if err != nil {
|
||||
httperror.WriteError(w, http.StatusForbidden, err.Error(), err)
|
||||
|
||||
|
|
|
@ -528,7 +528,12 @@ func (bouncer *RequestBouncer) EdgeComputeOperation(next http.Handler) http.Hand
|
|||
// - public routes
|
||||
// - kubectl - a bearer token is needed, and no csrf token can be sent
|
||||
// - api token
|
||||
func ShouldSkipCSRFCheck(r *http.Request) (bool, error) {
|
||||
// - docker desktop extension
|
||||
func ShouldSkipCSRFCheck(r *http.Request, isDockerDesktopExtension bool) (bool, error) {
|
||||
if isDockerDesktopExtension {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
cookie, _ := r.Cookie(portainer.AuthCookieKey)
|
||||
hasCookie := cookie != nil && cookie.Value != ""
|
||||
|
||||
|
|
|
@ -386,40 +386,52 @@ func Test_apiKeyLookup(t *testing.T) {
|
|||
func Test_ShouldSkipCSRFCheck(t *testing.T) {
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
cookieValue string
|
||||
apiKey string
|
||||
authHeader string
|
||||
expectedResult bool
|
||||
expectedError bool
|
||||
name string
|
||||
cookieValue string
|
||||
apiKey string
|
||||
authHeader string
|
||||
isDockerDesktopExtension bool
|
||||
expectedResult bool
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "Should return false when cookie is present",
|
||||
cookieValue: "test-cookie",
|
||||
name: "Should return false (not skip) when cookie is present",
|
||||
cookieValue: "test-cookie",
|
||||
isDockerDesktopExtension: false,
|
||||
},
|
||||
{
|
||||
name: "Should return true when cookie is not present",
|
||||
cookieValue: "",
|
||||
expectedResult: true,
|
||||
name: "Should return true (skip) when cookie is present and docker desktop extension is true",
|
||||
cookieValue: "test-cookie",
|
||||
isDockerDesktopExtension: true,
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Should return true when api key is present",
|
||||
cookieValue: "",
|
||||
apiKey: "test-api-key",
|
||||
expectedResult: true,
|
||||
name: "Should return true (skip) when cookie is not present",
|
||||
cookieValue: "",
|
||||
isDockerDesktopExtension: false,
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Should return true when auth header is present",
|
||||
cookieValue: "",
|
||||
authHeader: "test-auth-header",
|
||||
expectedResult: true,
|
||||
name: "Should return true (skip) when api key is present",
|
||||
cookieValue: "",
|
||||
apiKey: "test-api-key",
|
||||
isDockerDesktopExtension: false,
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Should return false and error when both api key and auth header are present",
|
||||
cookieValue: "",
|
||||
apiKey: "test-api-key",
|
||||
authHeader: "test-auth-header",
|
||||
expectedError: true,
|
||||
name: "Should return true (skip) when auth header is present",
|
||||
cookieValue: "",
|
||||
authHeader: "test-auth-header",
|
||||
isDockerDesktopExtension: false,
|
||||
expectedResult: true,
|
||||
},
|
||||
{
|
||||
name: "Should return false (not skip) and error when both api key and auth header are present",
|
||||
cookieValue: "",
|
||||
apiKey: "test-api-key",
|
||||
authHeader: "test-auth-header",
|
||||
isDockerDesktopExtension: false,
|
||||
expectedError: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -437,7 +449,7 @@ func Test_ShouldSkipCSRFCheck(t *testing.T) {
|
|||
req.Header.Set(jwtTokenHeader, test.authHeader)
|
||||
}
|
||||
|
||||
result, err := ShouldSkipCSRFCheck(req)
|
||||
result, err := ShouldSkipCSRFCheck(req, test.isDockerDesktopExtension)
|
||||
is.Equal(test.expectedResult, result)
|
||||
if test.expectedError {
|
||||
is.Error(err)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue