Skip to content

Commit

Permalink
feature: Introduce auth type aliases, fixes #7
Browse files Browse the repository at this point in the history
STUNner' current terminology is doubly confusing: (1) what we call plaintext is not plain-text at
all, and (2) we reuse the name longterm from the STUN spec to mean the time-windowed authentication
mode but in fact both what we call plaintext and longterm use the STUN "long-term" authentication
mechanism.

This commit introduces the following aliases in the GatewayConfig authType field: (1) static as an
alias for plaintext, and (2) timewindowed and ephemeral as aliases for longterm.

For backward compatibility, the dataplane API does not change.
  • Loading branch information
rg0now committed Apr 11, 2023
1 parent 8d6c153 commit 11487bd
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 19 deletions.
2 changes: 1 addition & 1 deletion api/v1alpha1/gatewayconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type GatewayConfigSpec struct {
// AuthType is the type of the STUN/TURN authentication mechanism.
//
// +optional
// +kubebuilder:validation:Pattern=`^plaintext|longterm$`
// +kubebuilder:validation:Pattern=`^plaintext|static|longterm|ephemeral|timewindowed$`
// +kubebuilder:default:="plaintext"
AuthType *string `json:"authType,omitempty"`

Expand Down
2 changes: 1 addition & 1 deletion config/crd/bases/stunner.l7mp.io_gatewayconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ spec:
default: plaintext
description: AuthType is the type of the STUN/TURN authentication
mechanism.
pattern: ^plaintext|longterm$
pattern: ^plaintext|static|longterm|ephemeral|timewindowed$
type: string
healthCheckEndpoint:
description: HealthCheckEndpoint is the URI of the form `http://address:port`
Expand Down
50 changes: 37 additions & 13 deletions internal/renderer/auth_render.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,9 @@ func (r *Renderer) renderInlineAuth(c *RenderContext) (*stnrconfv1a1.AuthConfig,
Credentials: make(map[string]string),
}

authType := stnrconfv1a1.DefaultAuthType
if gwConf.Spec.AuthType != nil {
authType = *gwConf.Spec.AuthType
}

atype, err := stnrconfv1a1.NewAuthType(authType)
atype, err := getAuthType(gwConf.Spec.AuthType)
if err != nil {
return nil, NewCriticalError(InvalidAuthType)
return nil, err
}

switch atype {
Expand Down Expand Up @@ -111,15 +106,15 @@ func (r *Renderer) renderExternalAuth(c *RenderContext) (*stnrconfv1a1.AuthConfi
"gateway-config", store.GetObjectKey(c.gwConf), "secret", n.String())
}

// allow default type
authType := stnrconfv1a1.DefaultAuthType
if atype, ok := secret.Data["type"]; ok {
authType = string(atype)
var hint *string
if stype, ok := secret.Data["type"]; ok {
stype := string(stype)
hint = &stype
}

atype, err := stnrconfv1a1.NewAuthType(authType)
atype, err := getAuthType(hint)
if err != nil {
return nil, NewCriticalError(InvalidAuthType)
return nil, err
}

switch atype {
Expand Down Expand Up @@ -160,3 +155,32 @@ func (r *Renderer) renderExternalAuth(c *RenderContext) (*stnrconfv1a1.AuthConfi

return &auth, nil
}

func getAuthType(hint *string) (stnrconfv1a1.AuthType, error) {
authType := stnrconfv1a1.DefaultAuthType
if hint != nil {
authType = *hint
}

// aliases
switch authType {
// plaintext
case "static":
fallthrough
case "plaintext":
authType = "plaintext"
case "ephemeral":
fallthrough
case "timewindowed":
fallthrough
case "longterm":
authType = "longterm"
}

atype, err := stnrconfv1a1.NewAuthType(authType)
if err != nil {
return stnrconfv1a1.AuthTypeUnknown, NewCriticalError(InvalidAuthType)
}

return atype, nil
}
94 changes: 94 additions & 0 deletions internal/renderer/auth_render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,36 @@ func TestRenderAuthRender(t *testing.T) {
assert.True(t, IsCritical(err), "critical err")
},
},
{
name: "auth type alias: static - ok",
cls: []gwapiv1a2.GatewayClass{testutils.TestGwClass},
cfs: []stnrv1a1.GatewayConfig{testutils.TestGwConfig},
gws: []gwapiv1a2.Gateway{},
rs: []gwapiv1a2.UDPRoute{},
svcs: []corev1.Service{},
prep: func(c *renderTestConfig) {
w := testutils.TestGwConfig.DeepCopy()
*w.Spec.AuthType = "static"
u, p := "testuser", "testpasswd"
w.Spec.Username = &u
w.Spec.Password = &p
c.cfs = []stnrv1a1.GatewayConfig{*w}
},
tester: func(t *testing.T, r *Renderer) {
gc, err := r.getGatewayClass()
assert.NoError(t, err, "gw-class found")
c := &RenderContext{gc: gc, log: logr.Discard()}
c.gwConf, err = r.getGatewayConfig4Class(c)
assert.NoError(t, err, "gw-conf found")

auth, err := r.renderAuth(c)
assert.NoError(t, err, "renderAuth")

assert.Equal(t, "plaintext", auth.Type, "auth-type")
assert.Equal(t, "testuser", auth.Credentials["username"], "username")
assert.Equal(t, "testpasswd", auth.Credentials["password"], "password")
},
},
{
name: "lonterm no-secret errs",
cls: []gwapiv1a2.GatewayClass{testutils.TestGwClass},
Expand All @@ -180,6 +210,70 @@ func TestRenderAuthRender(t *testing.T) {
assert.True(t, IsCritical(err), "critical err")
},
},
{
name: "auth type alias: timewindowed - ok",
cls: []gwapiv1a2.GatewayClass{testutils.TestGwClass},
cfs: []stnrv1a1.GatewayConfig{testutils.TestGwConfig},
gws: []gwapiv1a2.Gateway{},
rs: []gwapiv1a2.UDPRoute{},
svcs: []corev1.Service{},
prep: func(c *renderTestConfig) {
w := testutils.TestGwConfig.DeepCopy()
*w.Spec.StunnerConfig = "dummy"
*w.Spec.Realm = "dummy"
*w.Spec.AuthType = "timewindowed"
s := "dummy"
w.Spec.SharedSecret = &s
c.cfs = []stnrv1a1.GatewayConfig{*w}
},
tester: func(t *testing.T, r *Renderer) {
gc, err := r.getGatewayClass()
assert.NoError(t, err, "gw-class found")
c := &RenderContext{gc: gc, log: logr.Discard()}
c.gwConf, err = r.getGatewayConfig4Class(c)
assert.NoError(t, err, "gw-conf found")

auth, err := r.renderAuth(c)
assert.NoError(t, err, "renderAuth")

assert.Equal(t, "dummy", auth.Realm, "realm")
assert.Equal(t, "longterm", auth.Type, "auth-type")
assert.Equal(t, "dummy", auth.Credentials["secret"], "secret")

},
},
{
name: "auth type alias: ephemeral - ok",
cls: []gwapiv1a2.GatewayClass{testutils.TestGwClass},
cfs: []stnrv1a1.GatewayConfig{testutils.TestGwConfig},
gws: []gwapiv1a2.Gateway{},
rs: []gwapiv1a2.UDPRoute{},
svcs: []corev1.Service{},
prep: func(c *renderTestConfig) {
w := testutils.TestGwConfig.DeepCopy()
*w.Spec.StunnerConfig = "dummy"
*w.Spec.Realm = "dummy"
*w.Spec.AuthType = "timewindowed"
s := "dummy"
w.Spec.SharedSecret = &s
c.cfs = []stnrv1a1.GatewayConfig{*w}
},
tester: func(t *testing.T, r *Renderer) {
gc, err := r.getGatewayClass()
assert.NoError(t, err, "gw-class found")
c := &RenderContext{gc: gc, log: logr.Discard()}
c.gwConf, err = r.getGatewayConfig4Class(c)
assert.NoError(t, err, "gw-conf found")

auth, err := r.renderAuth(c)
assert.NoError(t, err, "renderAuth")

assert.Equal(t, "dummy", auth.Realm, "realm")
assert.Equal(t, "longterm", auth.Type, "auth-type")
assert.Equal(t, "dummy", auth.Credentials["secret"], "secret")

},
},
// external auth tests
{
name: "default external auth ok",
Expand Down
8 changes: 4 additions & 4 deletions test/integration_test_cases.go
Original file line number Diff line number Diff line change
Expand Up @@ -1723,7 +1723,7 @@ var _ = Describe("Integration test:", func() {
})

It("changing the auth type", func() {
atype := "longterm"
atype := "ephemeral" // use alias -> longterm
secret := "dummy"

ctrl.Log.Info("re-loading original UDPRoute")
Expand Down Expand Up @@ -1777,7 +1777,7 @@ var _ = Describe("Integration test:", func() {
ctrl.Log.Info("re-loading gateway-config")
namespace := gwapiv1b1.Namespace("testnamespace")
recreateOrUpdateGatewayConfig(func(current *stnrv1a1.GatewayConfig) {
atype := "longterm"
atype := "timewindowed" // use alias -> longterm
current.Spec.AuthType = &atype
current.Spec.Username = nil
current.Spec.Password = nil
Expand Down Expand Up @@ -1912,7 +1912,7 @@ var _ = Describe("Integration test:", func() {
It("cnanging the external auth ref type should re-generate the config", func() {
ctrl.Log.Info("re-loading the external auth Secret")
recreateOrUpdateAuthSecret(func(current *corev1.Secret) {
current.Data["type"] = []byte("longterm")
current.Data["type"] = []byte("ephemeral")
current.Data["secret"] = []byte("dummy")
delete(current.Data, "username")
delete(current.Data, "password")
Expand Down Expand Up @@ -1981,7 +1981,7 @@ var _ = Describe("Integration test:", func() {
It("fallback to inline auth defs", func() {
ctrl.Log.Info("re-loading gateway-config with inline auth")
recreateOrUpdateGatewayConfig(func(current *stnrv1a1.GatewayConfig) {
atype := "longterm"
atype := "timewindowed" // use alias -> longterm
secret := "dummy"
current.Spec.AuthType = &atype
current.Spec.SharedSecret = &secret
Expand Down

0 comments on commit 11487bd

Please sign in to comment.