Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions net/secureservice/admission.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package secureservice

import "context"

const (
DefaultAdmissionIdentityClaim = "anytype_identity"
DefaultAdmissionNetworkClaim = "network_id"
DefaultAdmissionSubjectClaim = "sub"
DefaultAdmissionClockSkewSec = 60
)

type AdmissionConfig struct {
Enabled bool `yaml:"enabled"`
Required bool `yaml:"required"`
Issuer string `yaml:"issuer"`
Audience string `yaml:"audience"`
JWKSURL string `yaml:"jwksUrl"`
RequiredClaims map[string]any `yaml:"requiredClaims"`
IdentityClaim string `yaml:"identityClaim"`
NetworkClaim string `yaml:"networkClaim"`
SubjectClaim string `yaml:"subjectClaim"`
ClockSkewSec int `yaml:"clockSkewSec"`
}

func (c AdmissionConfig) WithDefaults() AdmissionConfig {
if c.IdentityClaim == "" {
c.IdentityClaim = DefaultAdmissionIdentityClaim
}
if c.NetworkClaim == "" {
c.NetworkClaim = DefaultAdmissionNetworkClaim
}
if c.SubjectClaim == "" {
c.SubjectClaim = DefaultAdmissionSubjectClaim
}
if c.ClockSkewSec == 0 {
c.ClockSkewSec = DefaultAdmissionClockSkewSec
}
return c
}

type AdmissionRequest struct {
Token string
Identity []byte
NetworkID string
PeerID string
ClientVersion string
}

type AdmissionClaims struct {
Subject string
Issuer string
Audience []string
NetworkID string
Identity []byte
Claims map[string]any
}

type AdmissionDecision struct {
Allowed bool
Reason string
Claims AdmissionClaims
}

type AdmissionVerifier interface {
VerifyAdmission(ctx context.Context, req AdmissionRequest) (AdmissionDecision, error)
}

type NoopAdmissionVerifier struct{}

func (NoopAdmissionVerifier) VerifyAdmission(ctx context.Context, req AdmissionRequest) (AdmissionDecision, error) {
return AdmissionDecision{
Allowed: true,
Reason: "admission disabled",
}, nil
}
78 changes: 78 additions & 0 deletions net/secureservice/admission_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package secureservice

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)

func TestAdmissionConfig_WithDefaults(t *testing.T) {
conf := AdmissionConfig{}.WithDefaults()

assert.False(t, conf.Enabled)
assert.False(t, conf.Required)
assert.Equal(t, DefaultAdmissionIdentityClaim, conf.IdentityClaim)
assert.Equal(t, DefaultAdmissionNetworkClaim, conf.NetworkClaim)
assert.Equal(t, DefaultAdmissionSubjectClaim, conf.SubjectClaim)
assert.Equal(t, DefaultAdmissionClockSkewSec, conf.ClockSkewSec)
}

func TestAdmissionConfig_WithDefaultsPreservesConfiguredValues(t *testing.T) {
conf := AdmissionConfig{
Enabled: true,
Required: true,
IdentityClaim: "identity",
NetworkClaim: "network",
SubjectClaim: "subject",
ClockSkewSec: 120,
}.WithDefaults()

assert.True(t, conf.Enabled)
assert.True(t, conf.Required)
assert.Equal(t, "identity", conf.IdentityClaim)
assert.Equal(t, "network", conf.NetworkClaim)
assert.Equal(t, "subject", conf.SubjectClaim)
assert.Equal(t, 120, conf.ClockSkewSec)
}

func TestAdmissionConfig_YAML(t *testing.T) {
var conf Config
err := yaml.Unmarshal([]byte(`
admission:
enabled: true
required: true
issuer: https://issuer.example
audience: any-sync
jwksUrl: https://issuer.example/.well-known/jwks.json
requiredClaims:
group: docs-users
identityClaim: anytype_id
networkClaim: sync_network
subjectClaim: user
clockSkewSec: 30
`), &conf)
require.NoError(t, err)

assert.True(t, conf.Admission.Enabled)
assert.True(t, conf.Admission.Required)
assert.Equal(t, "https://issuer.example", conf.Admission.Issuer)
assert.Equal(t, "any-sync", conf.Admission.Audience)
assert.Equal(t, "https://issuer.example/.well-known/jwks.json", conf.Admission.JWKSURL)
assert.Equal(t, map[string]any{"group": "docs-users"}, conf.Admission.RequiredClaims)
assert.Equal(t, "anytype_id", conf.Admission.IdentityClaim)
assert.Equal(t, "sync_network", conf.Admission.NetworkClaim)
assert.Equal(t, "user", conf.Admission.SubjectClaim)
assert.Equal(t, 30, conf.Admission.ClockSkewSec)
}

func TestNoopAdmissionVerifier_AllowsRequests(t *testing.T) {
verifier := NoopAdmissionVerifier{}
decision, err := verifier.VerifyAdmission(context.Background(), AdmissionRequest{})

require.NoError(t, err)
assert.True(t, decision.Allowed)
assert.Equal(t, "admission disabled", decision.Reason)
}
5 changes: 3 additions & 2 deletions net/secureservice/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ type configGetter interface {
}

type Config struct {
RequireClientAuth bool `yaml:"requireClientAuth"`
CompatibleVersions []uint32 `yaml:"compatibleVersions"`
RequireClientAuth bool `yaml:"requireClientAuth"`
CompatibleVersions []uint32 `yaml:"compatibleVersions"`
Admission AdmissionConfig `yaml:"admission"`
}

// CtxAllowAccountCheck upgrades the context to allow identity check on handshake
Expand Down
Loading