[#1689] ape: Fix validation for overrides in bearer
All checks were successful
Tests and linters / Run gofumpt (push) Successful in 32s
Vulncheck / Vulncheck (push) Successful in 1m33s
Build / Build Components (push) Successful in 2m21s
Pre-commit hooks / Pre-commit (push) Successful in 2m29s
Tests and linters / Staticcheck (push) Successful in 2m48s
Tests and linters / Tests (push) Successful in 3m18s
Tests and linters / Lint (push) Successful in 3m49s
Tests and linters / Tests with -race (push) Successful in 4m37s
OCI image / Build container images (push) Successful in 4m57s
Tests and linters / gopls check (push) Successful in 5m7s
All checks were successful
Tests and linters / Run gofumpt (push) Successful in 32s
Vulncheck / Vulncheck (push) Successful in 1m33s
Build / Build Components (push) Successful in 2m21s
Pre-commit hooks / Pre-commit (push) Successful in 2m29s
Tests and linters / Staticcheck (push) Successful in 2m48s
Tests and linters / Tests (push) Successful in 3m18s
Tests and linters / Lint (push) Successful in 3m49s
Tests and linters / Tests with -race (push) Successful in 4m37s
OCI image / Build container images (push) Successful in 4m57s
Tests and linters / gopls check (push) Successful in 5m7s
* APE-overrides are optional for bearer. So, it should validate only set override; * Bearer can set overrides for containers, not only the one container - validation expects for any target type for set override. Basically, APE-overrides for all container must be set for namespace target; * Add unit-test cases to check bearer token validation. Change-Id: I6b8e19eb73d24f8cd8799bf99b6c551287da67d9 Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
This commit is contained in:
parent
8e2f919df0
commit
64b46746e4
2 changed files with 78 additions and 15 deletions
|
@ -20,7 +20,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errInvalidTargetType = errors.New("bearer token defines non-container target override")
|
|
||||||
errBearerExpired = errors.New("bearer token has expired")
|
errBearerExpired = errors.New("bearer token has expired")
|
||||||
errBearerInvalidSignature = errors.New("bearer token has invalid signature")
|
errBearerInvalidSignature = errors.New("bearer token has invalid signature")
|
||||||
errBearerInvalidContainerID = errors.New("bearer token was created for another container")
|
errBearerInvalidContainerID = errors.New("bearer token was created for another container")
|
||||||
|
@ -81,7 +80,10 @@ func (c *checkerCoreImpl) CheckAPE(ctx context.Context, prm CheckPrm) error {
|
||||||
if prm.BearerToken.Impersonate() {
|
if prm.BearerToken.Impersonate() {
|
||||||
cr = policyengine.NewDefaultChainRouterWithLocalOverrides(c.MorphChainStorage, c.LocalOverrideStorage)
|
cr = policyengine.NewDefaultChainRouterWithLocalOverrides(c.MorphChainStorage, c.LocalOverrideStorage)
|
||||||
} else {
|
} else {
|
||||||
override, _ := prm.BearerToken.APEOverride()
|
override, isSet := prm.BearerToken.APEOverride()
|
||||||
|
if !isSet {
|
||||||
|
return errors.New("expected for override within bearer")
|
||||||
|
}
|
||||||
cr, err = router.BearerChainFeedRouter(c.LocalOverrideStorage, c.MorphChainStorage, override)
|
cr, err = router.BearerChainFeedRouter(c.LocalOverrideStorage, c.MorphChainStorage, override)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create chain router error: %w", err)
|
return fmt.Errorf("create chain router error: %w", err)
|
||||||
|
@ -131,19 +133,19 @@ func isValidBearer(token *bearer.Token, ownerCnr user.ID, cntID cid.ID, publicKe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for ape overrides defined in the bearer token.
|
// Check for ape overrides defined in the bearer token.
|
||||||
apeOverride, _ := token.APEOverride()
|
if apeOverride, isSet := token.APEOverride(); isSet {
|
||||||
if len(apeOverride.Chains) > 0 && apeOverride.Target.TargetType != ape.TargetTypeContainer {
|
switch apeOverride.Target.TargetType {
|
||||||
return fmt.Errorf("%w: %s", errInvalidTargetType, apeOverride.Target.TargetType.ToV2().String())
|
case ape.TargetTypeContainer:
|
||||||
}
|
var targetCnr cid.ID
|
||||||
|
err := targetCnr.DecodeString(apeOverride.Target.Name)
|
||||||
// Then check if container is either empty or equal to the container in the request.
|
if err != nil {
|
||||||
var targetCnr cid.ID
|
return fmt.Errorf("invalid cid format: %s", apeOverride.Target.Name)
|
||||||
err := targetCnr.DecodeString(apeOverride.Target.Name)
|
}
|
||||||
if err != nil {
|
if !cntID.Equals(targetCnr) {
|
||||||
return fmt.Errorf("invalid cid format: %s", apeOverride.Target.Name)
|
return errBearerInvalidContainerID
|
||||||
}
|
}
|
||||||
if !cntID.Equals(targetCnr) {
|
default:
|
||||||
return errBearerInvalidContainerID
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then check if container owner signed this token.
|
// Then check if container owner signed this token.
|
||||||
|
|
|
@ -235,6 +235,48 @@ func TestMessageSign(t *testing.T) {
|
||||||
require.Error(t, s.verifyClient(context.Background(), req, cid1, versionTreeID, req.GetBody().GetBearerToken(), acl.OpObjectPut))
|
require.Error(t, s.verifyClient(context.Background(), req, cid1, versionTreeID, req.GetBody().GetBearerToken(), acl.OpObjectPut))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("omit override within bt", func(t *testing.T) {
|
||||||
|
t.Run("personated", func(t *testing.T) {
|
||||||
|
bt := testBearerTokenNoOverride()
|
||||||
|
require.NoError(t, bt.Sign(privs[0].PrivateKey))
|
||||||
|
req.Body.BearerToken = bt.Marshal()
|
||||||
|
|
||||||
|
require.NoError(t, SignMessage(req, &privs[1].PrivateKey))
|
||||||
|
require.ErrorContains(t, s.verifyClient(context.Background(), req, cid1, versionTreeID, req.GetBody().GetBearerToken(), acl.OpObjectPut), "expected for override")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("impersonated", func(t *testing.T) {
|
||||||
|
bt := testBearerTokenNoOverride()
|
||||||
|
bt.SetImpersonate(true)
|
||||||
|
require.NoError(t, bt.Sign(privs[0].PrivateKey))
|
||||||
|
req.Body.BearerToken = bt.Marshal()
|
||||||
|
|
||||||
|
require.NoError(t, SignMessage(req, &privs[0].PrivateKey))
|
||||||
|
require.NoError(t, s.verifyClient(context.Background(), req, cid1, versionTreeID, req.GetBody().GetBearerToken(), acl.OpObjectPut))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid override within bearer token", func(t *testing.T) {
|
||||||
|
t.Run("personated", func(t *testing.T) {
|
||||||
|
bt := testBearerTokenCorruptOverride(privs[1].PublicKey(), privs[2].PublicKey())
|
||||||
|
require.NoError(t, bt.Sign(privs[0].PrivateKey))
|
||||||
|
req.Body.BearerToken = bt.Marshal()
|
||||||
|
|
||||||
|
require.NoError(t, SignMessage(req, &privs[1].PrivateKey))
|
||||||
|
require.ErrorContains(t, s.verifyClient(context.Background(), req, cid1, versionTreeID, req.GetBody().GetBearerToken(), acl.OpObjectPut), "invalid cid")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("impersonated", func(t *testing.T) {
|
||||||
|
bt := testBearerTokenCorruptOverride(privs[1].PublicKey(), privs[2].PublicKey())
|
||||||
|
bt.SetImpersonate(true)
|
||||||
|
require.NoError(t, bt.Sign(privs[0].PrivateKey))
|
||||||
|
req.Body.BearerToken = bt.Marshal()
|
||||||
|
|
||||||
|
require.NoError(t, SignMessage(req, &privs[0].PrivateKey))
|
||||||
|
require.ErrorContains(t, s.verifyClient(context.Background(), req, cid1, versionTreeID, req.GetBody().GetBearerToken(), acl.OpObjectPut), "invalid cid")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("impersonate", func(t *testing.T) {
|
t.Run("impersonate", func(t *testing.T) {
|
||||||
cnr.Value.SetBasicACL(acl.PublicRWExtended)
|
cnr.Value.SetBasicACL(acl.PublicRWExtended)
|
||||||
var bt bearer.Token
|
var bt bearer.Token
|
||||||
|
@ -311,6 +353,25 @@ func testBearerToken(cid cid.ID, forPutGet, forGet *keys.PublicKey) bearer.Token
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testBearerTokenCorruptOverride(forPutGet, forGet *keys.PublicKey) bearer.Token {
|
||||||
|
var b bearer.Token
|
||||||
|
b.SetExp(currentEpoch + 1)
|
||||||
|
b.SetAPEOverride(bearer.APEOverride{
|
||||||
|
Target: ape.ChainTarget{
|
||||||
|
TargetType: ape.TargetTypeContainer,
|
||||||
|
},
|
||||||
|
Chains: []ape.Chain{{Raw: testChain(forPutGet, forGet).Bytes()}},
|
||||||
|
})
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func testBearerTokenNoOverride() bearer.Token {
|
||||||
|
var b bearer.Token
|
||||||
|
b.SetExp(currentEpoch + 1)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
func testChain(forPutGet, forGet *keys.PublicKey) *chain.Chain {
|
func testChain(forPutGet, forGet *keys.PublicKey) *chain.Chain {
|
||||||
ruleGet := chain.Rule{
|
ruleGet := chain.Rule{
|
||||||
Status: chain.Allow,
|
Status: chain.Allow,
|
||||||
|
|
Loading…
Add table
Reference in a new issue