mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 21:17:58 +08:00
fix: parse public key as fallback for certificate for bearer authentication (#3180)
* fix: parse public key as fallback for bearer auth Signed-off-by: evanebb <git@evanus.nl> * fix: use correct error message Signed-off-by: evanebb <git@evanus.nl> --------- Signed-off-by: evanebb <git@evanus.nl>
This commit is contained in:
+1
-1
@@ -179,7 +179,7 @@ var (
|
|||||||
ErrNoBearerToken = errors.New("no bearer token given")
|
ErrNoBearerToken = errors.New("no bearer token given")
|
||||||
ErrInvalidBearerToken = errors.New("invalid bearer token given")
|
ErrInvalidBearerToken = errors.New("invalid bearer token given")
|
||||||
ErrInsufficientScope = errors.New("bearer token does not have sufficient scope")
|
ErrInsufficientScope = errors.New("bearer token does not have sufficient scope")
|
||||||
ErrCouldNotLoadCertificate = errors.New("failed to load certificate")
|
ErrCouldNotLoadPublicKey = errors.New("failed to load public key")
|
||||||
ErrEventTypeEmpty = errors.New("event type empty")
|
ErrEventTypeEmpty = errors.New("event type empty")
|
||||||
ErrEventSinkIsNil = errors.New("event sink is nil")
|
ErrEventSinkIsNil = errors.New("event sink is nil")
|
||||||
ErrUnsupportedEventSink = errors.New("event sink is not supported")
|
ErrUnsupportedEventSink = errors.New("event sink is not supported")
|
||||||
|
|||||||
+24
-12
@@ -2,6 +2,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
@@ -402,15 +403,17 @@ func (amw *AuthnMiddleware) tryAuthnHandlers(ctlr *Controller) mux.MiddlewareFun
|
|||||||
}
|
}
|
||||||
|
|
||||||
func bearerAuthHandler(ctlr *Controller) mux.MiddlewareFunc {
|
func bearerAuthHandler(ctlr *Controller) mux.MiddlewareFunc {
|
||||||
certificate, err := loadCertificateFromFile(ctlr.Config.HTTP.Auth.Bearer.Cert)
|
// although the configuration option is called 'cert', this function will also parse a public key directly
|
||||||
|
// see https://github.com/project-zot/zot/issues/3173 for info
|
||||||
|
publicKey, err := loadPublicKeyFromFile(ctlr.Config.HTTP.Auth.Bearer.Cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctlr.Log.Panic().Err(err).Msg("failed to load certificate for bearer authentication")
|
ctlr.Log.Panic().Err(err).Msg("failed to load public key for bearer authentication")
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizer := NewBearerAuthorizer(
|
authorizer := NewBearerAuthorizer(
|
||||||
ctlr.Config.HTTP.Auth.Bearer.Realm,
|
ctlr.Config.HTTP.Auth.Bearer.Realm,
|
||||||
ctlr.Config.HTTP.Auth.Bearer.Service,
|
ctlr.Config.HTTP.Auth.Bearer.Service,
|
||||||
certificate.PublicKey,
|
publicKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
@@ -902,21 +905,30 @@ func GenerateAPIKey(uuidGenerator guuid.Generator, log log.Logger,
|
|||||||
return apiKey, apiKeyID.String(), err
|
return apiKey, apiKeyID.String(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadCertificateFromFile(path string) (*x509.Certificate, error) {
|
func loadPublicKeyFromFile(path string) (crypto.PublicKey, error) {
|
||||||
rawCert, err := os.ReadFile(path)
|
raw, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: %w, path %s", zerr.ErrCouldNotLoadCertificate, err, path)
|
return nil, fmt.Errorf("%w: %w, path %s", zerr.ErrCouldNotLoadPublicKey, err, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
block, _ := pem.Decode(rawCert)
|
block, _ := pem.Decode(raw)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return nil, fmt.Errorf("%w: no valid PEM data found", zerr.ErrCouldNotLoadCertificate)
|
return nil, fmt.Errorf("%w: no valid PEM data found", zerr.ErrCouldNotLoadPublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
cert, err := x509.ParseCertificate(block.Bytes)
|
pemBytes := block.Bytes
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("%w: %w", zerr.ErrCouldNotLoadCertificate, err)
|
if cert, err := x509.ParseCertificate(pemBytes); err == nil {
|
||||||
|
return cert.PublicKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return cert, nil
|
if key, err := x509.ParsePKIXPublicKey(pemBytes); err == nil {
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if key, err := x509.ParsePKCS1PublicKey(pemBytes); err == nil {
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("%w: no valid x509 certificate or public key found", zerr.ErrCouldNotLoadPublicKey)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,11 +77,15 @@ import (
|
|||||||
const (
|
const (
|
||||||
ServerCert = "../../test/data/server.cert"
|
ServerCert = "../../test/data/server.cert"
|
||||||
ServerKey = "../../test/data/server.key"
|
ServerKey = "../../test/data/server.key"
|
||||||
|
ServerPublicKey = "../../test/data/server-public.key"
|
||||||
|
ServerPublicKeyPKCS1 = "../../test/data/server-public-pkcs1.key"
|
||||||
CACert = "../../test/data/ca.crt"
|
CACert = "../../test/data/ca.crt"
|
||||||
ServerCertECDSA = "../../test/data/server-ecdsa.cert"
|
ServerCertECDSA = "../../test/data/server-ecdsa.cert"
|
||||||
ServerKeyECDSA = "../../test/data/server-ecdsa.key"
|
ServerKeyECDSA = "../../test/data/server-ecdsa.key"
|
||||||
|
ServerPublicKeyECDSA = "../../test/data/server-public-ecdsa.key"
|
||||||
ServerCertED25519 = "../../test/data/server-ed25519.cert"
|
ServerCertED25519 = "../../test/data/server-ed25519.cert"
|
||||||
ServerKeyED25519 = "../../test/data/server-ed25519.key"
|
ServerKeyED25519 = "../../test/data/server-ed25519.key"
|
||||||
|
ServerPublicKeyED25519 = "../../test/data/server-public-ed25519.key"
|
||||||
UnauthorizedNamespace = "fortknox/notallowed"
|
UnauthorizedNamespace = "fortknox/notallowed"
|
||||||
AuthorizationNamespace = "authz/image"
|
AuthorizationNamespace = "authz/image"
|
||||||
LDAPAddress = "127.0.0.1"
|
LDAPAddress = "127.0.0.1"
|
||||||
@@ -3921,23 +3925,47 @@ func TestBearerAuthMultipleAlgorithms(t *testing.T) {
|
|||||||
alg string
|
alg string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"RSA signing key",
|
"RSA signing key using certificate",
|
||||||
ServerKey,
|
ServerKey,
|
||||||
ServerCert,
|
ServerCert,
|
||||||
"RS256",
|
"RS256",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ECDSA signing key",
|
"RSA signing key using public key",
|
||||||
|
ServerKey,
|
||||||
|
ServerPublicKey,
|
||||||
|
"RS256",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"RSA signing key using public key in PKCS1 format",
|
||||||
|
ServerKey,
|
||||||
|
ServerPublicKeyPKCS1,
|
||||||
|
"RS256",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ECDSA signing key using certificate",
|
||||||
ServerKeyECDSA,
|
ServerKeyECDSA,
|
||||||
ServerCertECDSA,
|
ServerCertECDSA,
|
||||||
"ES256",
|
"ES256",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ED25519 signing key",
|
"ECDSA signing key using public key",
|
||||||
|
ServerKeyECDSA,
|
||||||
|
ServerPublicKeyECDSA,
|
||||||
|
"ES256",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ED25519 signing key using certificate",
|
||||||
ServerKeyED25519,
|
ServerKeyED25519,
|
||||||
ServerCertED25519,
|
ServerCertED25519,
|
||||||
"EdDSA",
|
"EdDSA",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ED25519 signing key using public key",
|
||||||
|
ServerKeyED25519,
|
||||||
|
ServerPublicKeyED25519,
|
||||||
|
"EdDSA",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
|
|||||||
@@ -19,6 +19,16 @@ openssl req \
|
|||||||
-out server.csr \
|
-out server.csr \
|
||||||
-subj "/OU=TestServer/CN=*"
|
-subj "/OU=TestServer/CN=*"
|
||||||
|
|
||||||
|
openssl rsa \
|
||||||
|
-in server.key \
|
||||||
|
-pubout \
|
||||||
|
-out server-public.key
|
||||||
|
|
||||||
|
openssl rsa \
|
||||||
|
-in server.key \
|
||||||
|
-RSAPublicKey_out \
|
||||||
|
-out server-public-pkcs1.key
|
||||||
|
|
||||||
openssl x509 \
|
openssl x509 \
|
||||||
-req \
|
-req \
|
||||||
-days 3650 \
|
-days 3650 \
|
||||||
@@ -76,6 +86,11 @@ openssl req \
|
|||||||
-out server-ecdsa.csr \
|
-out server-ecdsa.csr \
|
||||||
-subj "/OU=TestServer/CN=*"
|
-subj "/OU=TestServer/CN=*"
|
||||||
|
|
||||||
|
openssl ec \
|
||||||
|
-in server-ecdsa.key \
|
||||||
|
-pubout \
|
||||||
|
-out server-public-ecdsa.key
|
||||||
|
|
||||||
openssl x509 \
|
openssl x509 \
|
||||||
-req \
|
-req \
|
||||||
-days 3650 \
|
-days 3650 \
|
||||||
@@ -112,6 +127,11 @@ openssl req \
|
|||||||
-out server-ed25519.csr \
|
-out server-ed25519.csr \
|
||||||
-subj "/OU=TestServer/CN=*"
|
-subj "/OU=TestServer/CN=*"
|
||||||
|
|
||||||
|
openssl pkey \
|
||||||
|
-in server-ed25519.key \
|
||||||
|
-pubout \
|
||||||
|
-out server-public-ed25519.key
|
||||||
|
|
||||||
openssl x509 \
|
openssl x509 \
|
||||||
-req \
|
-req \
|
||||||
-days 3650 \
|
-days 3650 \
|
||||||
|
|||||||
Reference in New Issue
Block a user