Skip to content

Commit

Permalink
Modify tests to handle new Code type in auth webhook response
Browse files Browse the repository at this point in the history
  • Loading branch information
chacha912 committed Oct 17, 2024
1 parent cdd952e commit b73e95b
Showing 1 changed file with 226 additions and 43 deletions.
269 changes: 226 additions & 43 deletions test/integration/auth_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ func newAuthServer(t *testing.T) (*httptest.Server, string) {
var res types.AuthWebhookResponse
if req.Token == token {
res.Code = types.CodeOK
} else if req.Token == "not allowed token" {
res.Code = types.CodePermissionDenied
} else {
res.Code = types.CodeUnauthenticated
res.Message = "invalid token"
Expand All @@ -62,22 +64,20 @@ func newAuthServer(t *testing.T) (*httptest.Server, string) {
}

func newUnavailableAuthServer(t *testing.T, recoveryCnt uint64) *httptest.Server {
var retries uint64
var requestCount uint64
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := types.NewAuthWebhookRequest(r.Body)
assert.NoError(t, err)

var res types.AuthWebhookResponse
res.Code = types.CodeOK
if retries < recoveryCnt-1 {

if requestCount < recoveryCnt {
w.WriteHeader(http.StatusServiceUnavailable)
retries++
} else {
retries = 0
}

_, err = res.Write(w)
assert.NoError(t, err)
requestCount++
}))
}

Expand All @@ -93,7 +93,7 @@ func TestProjectAuthWebhook(t *testing.T) {
project, err := adminCli.CreateProject(context.Background(), "auth-webhook-test")
assert.NoError(t, err)

t.Run("authorization webhook test", func(t *testing.T) {
t.Run("successful authorization test", func(t *testing.T) {
ctx := context.Background()
authServer, token := newAuthServer(t)

Expand Down Expand Up @@ -121,6 +121,22 @@ func TestProjectAuthWebhook(t *testing.T) {

doc := document.New(helper.TestDocKey(t))
assert.NoError(t, cli.Attach(ctx, doc))
})

t.Run("unauthenticated response test", func(t *testing.T) {
ctx := context.Background()
authServer, _ := newAuthServer(t)

// project with authorization webhook
project.AuthWebhookURL = authServer.URL
_, err := adminCli.UpdateProject(
ctx,
project.ID.String(),
&types.UpdatableProjectFields{
AuthWebhookURL: &project.AuthWebhookURL,
},
)
assert.NoError(t, err)

// client without token
cliWithoutToken, err := client.Dial(
Expand All @@ -131,6 +147,7 @@ func TestProjectAuthWebhook(t *testing.T) {
defer func() { assert.NoError(t, cliWithoutToken.Close()) }()
err = cliWithoutToken.Activate(ctx)
assert.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err))
assert.Equal(t, connecthelper.CodeOf(auth.ErrUnauthenticated), converter.ErrorCodeOf(err))

// client with invalid token
cliWithInvalidToken, err := client.Dial(
Expand All @@ -142,9 +159,38 @@ func TestProjectAuthWebhook(t *testing.T) {
defer func() { assert.NoError(t, cliWithInvalidToken.Close()) }()
err = cliWithInvalidToken.Activate(ctx)
assert.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err))
assert.Equal(t, connecthelper.CodeOf(auth.ErrUnauthenticated), converter.ErrorCodeOf(err))
})

t.Run("Selected method authorization webhook test", func(t *testing.T) {
t.Run("permission denied response test", func(t *testing.T) {
ctx := context.Background()
authServer, _ := newAuthServer(t)

// project with authorization webhook
project.AuthWebhookURL = authServer.URL
_, err := adminCli.UpdateProject(
ctx,
project.ID.String(),
&types.UpdatableProjectFields{
AuthWebhookURL: &project.AuthWebhookURL,
},
)
assert.NoError(t, err)

// client with not allowed token
cliNotAllowed, err := client.Dial(
svr.RPCAddr(),
client.WithAPIKey(project.PublicKey),
client.WithToken("not allowed token"),
)
assert.NoError(t, err)
defer func() { assert.NoError(t, cliNotAllowed.Close()) }()
err = cliNotAllowed.Activate(ctx)
assert.Equal(t, connect.CodePermissionDenied, connect.CodeOf(err))
assert.Equal(t, connecthelper.CodeOf(auth.ErrPermissionDenied), converter.ErrorCodeOf(err))
})

t.Run("selected method authorization webhook test", func(t *testing.T) {
ctx := context.Background()
authServer, _ := newAuthServer(t)

Expand Down Expand Up @@ -186,25 +232,40 @@ func TestProjectAuthWebhook(t *testing.T) {
})
}

func TestAuthWebhook(t *testing.T) {
t.Run("authorization webhook that success after retries test", func(t *testing.T) {
func TestAuthWebhookErrorHandling(t *testing.T) {
var recoveryCnt uint64 = 4

conf := helper.TestConfig()
conf.Backend.AuthWebhookMaxRetries = recoveryCnt
conf.Backend.AuthWebhookMaxWaitInterval = "1000ms"
svr, err := server.New(conf)
assert.NoError(t, err)
assert.NoError(t, svr.Start())
defer func() { assert.NoError(t, svr.Shutdown(true)) }()

adminCli := helper.CreateAdminCli(t, svr.RPCAddr())
defer func() { adminCli.Close() }()

t.Run("unexpected status code test", func(t *testing.T) {
ctx := context.Background()
authServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := types.NewAuthWebhookRequest(r.Body)
assert.NoError(t, err)

var recoveryCnt uint64 = 4
authServer := newUnavailableAuthServer(t, recoveryCnt)
var res types.AuthWebhookResponse
res.Code = types.CodeOK

conf := helper.TestConfig()
conf.Backend.AuthWebhookMaxRetries = recoveryCnt
conf.Backend.AuthWebhookMaxWaitInterval = "1000ms"
svr, err := server.New(conf)
assert.NoError(t, err)
assert.NoError(t, svr.Start())
defer func() { assert.NoError(t, svr.Shutdown(true)) }()
// unexpected status code
w.WriteHeader(http.StatusBadRequest)

adminCli := helper.CreateAdminCli(t, svr.RPCAddr())
defer func() { adminCli.Close() }()
project, err := adminCli.CreateProject(context.Background(), "success-webhook-after-retries")
_, err = res.Write(w)
assert.NoError(t, err)
}))

// project with authorization webhook
project, err := adminCli.CreateProject(context.Background(), "unexpected-status-code")
assert.NoError(t, err)

project.AuthWebhookURL = authServer.URL
_, err = adminCli.UpdateProject(
ctx,
Expand All @@ -217,35 +278,61 @@ func TestAuthWebhook(t *testing.T) {

cli, err := client.Dial(
svr.RPCAddr(),
client.WithToken("token"),
client.WithAPIKey(project.PublicKey),
client.WithToken("token"),
)
assert.NoError(t, err)
defer func() { assert.NoError(t, cli.Close()) }()

err = cli.Activate(ctx)
assert.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err))
assert.Equal(t, connecthelper.CodeOf(auth.ErrUnexpectedStatusCode), converter.ErrorCodeOf(err))
})

t.Run("unexpected webhook response test", func(t *testing.T) {
ctx := context.Background()
authServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := types.NewAuthWebhookRequest(r.Body)
assert.NoError(t, err)

var res types.AuthWebhookResponse
// unexpected response code
res.Code = 555

_, err = res.Write(w)
assert.NoError(t, err)
}))

// project with authorization webhook
project, err := adminCli.CreateProject(context.Background(), "unexpected-response-code")
assert.NoError(t, err)

doc := document.New(helper.TestDocKey(t))
err = cli.Attach(ctx, doc)
project.AuthWebhookURL = authServer.URL
_, err = adminCli.UpdateProject(
ctx,
project.ID.String(),
&types.UpdatableProjectFields{
AuthWebhookURL: &project.AuthWebhookURL,
},
)
assert.NoError(t, err)

cli, err := client.Dial(
svr.RPCAddr(),
client.WithAPIKey(project.PublicKey),
client.WithToken("token"),
)
assert.NoError(t, err)
defer func() { assert.NoError(t, cli.Close()) }()
err = cli.Activate(ctx)
assert.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err))
assert.Equal(t, connecthelper.CodeOf(auth.ErrUnexpectedResponse), converter.ErrorCodeOf(err))
})

t.Run("authorization webhook that fails after retries test", func(t *testing.T) {
t.Run("unavailable authentication server test(timeout)", func(t *testing.T) {
ctx := context.Background()
authServer := newUnavailableAuthServer(t, 4)
authServer := newUnavailableAuthServer(t, recoveryCnt+1)

conf := helper.TestConfig()
conf.Backend.AuthWebhookMaxRetries = 2
conf.Backend.AuthWebhookMaxWaitInterval = "1000ms"
svr, err := server.New(conf)
assert.NoError(t, err)
assert.NoError(t, svr.Start())
defer func() { assert.NoError(t, svr.Shutdown(true)) }()

adminCli := helper.CreateAdminCli(t, svr.RPCAddr())
defer func() { adminCli.Close() }()
project, err := adminCli.CreateProject(context.Background(), "fail-webhook-after-retries")
project, err := adminCli.CreateProject(context.Background(), "unavailable-auth-server")
assert.NoError(t, err)
project.AuthWebhookURL = authServer.URL
_, err = adminCli.UpdateProject(
Expand All @@ -270,7 +357,41 @@ func TestAuthWebhook(t *testing.T) {
assert.Equal(t, connecthelper.CodeOf(auth.ErrWebhookTimeout), converter.ErrorCodeOf(err))
})

t.Run("authorized request cache test", func(t *testing.T) {
t.Run("successful authorization after temporarily unavailable server test", func(t *testing.T) {
ctx := context.Background()
authServer := newUnavailableAuthServer(t, recoveryCnt)

project, err := adminCli.CreateProject(context.Background(), "success-webhook-after-retries")
assert.NoError(t, err)
project.AuthWebhookURL = authServer.URL
_, err = adminCli.UpdateProject(
ctx,
project.ID.String(),
&types.UpdatableProjectFields{
AuthWebhookURL: &project.AuthWebhookURL,
},
)
assert.NoError(t, err)

cli, err := client.Dial(
svr.RPCAddr(),
client.WithToken("token"),
client.WithAPIKey(project.PublicKey),
)
assert.NoError(t, err)
defer func() { assert.NoError(t, cli.Close()) }()

err = cli.Activate(ctx)
assert.NoError(t, err)

doc := document.New(helper.TestDocKey(t))
err = cli.Attach(ctx, doc)
assert.NoError(t, err)
})
}

func TestAuthWebhookCache(t *testing.T) {
t.Run("authorized response cache test", func(t *testing.T) {
ctx := context.Background()
reqCnt := 0
authServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -299,7 +420,7 @@ func TestAuthWebhook(t *testing.T) {

adminCli := helper.CreateAdminCli(t, svr.RPCAddr())
defer func() { adminCli.Close() }()
project, err := adminCli.CreateProject(context.Background(), "auth-request-cache")
project, err := adminCli.CreateProject(context.Background(), "authorized-response-cache")
assert.NoError(t, err)
project.AuthWebhookURL = authServer.URL
_, err = adminCli.UpdateProject(
Expand Down Expand Up @@ -348,7 +469,7 @@ func TestAuthWebhook(t *testing.T) {
assert.Equal(t, 2, reqCnt)
})

t.Run("unauthorized request cache test", func(t *testing.T) {
t.Run("permission denied response cache test", func(t *testing.T) {
ctx := context.Background()
reqCnt := 0
authServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -375,7 +496,7 @@ func TestAuthWebhook(t *testing.T) {

adminCli := helper.CreateAdminCli(t, svr.RPCAddr())
defer func() { adminCli.Close() }()
project, err := adminCli.CreateProject(context.Background(), "unauth-request-cache")
project, err := adminCli.CreateProject(context.Background(), "permission-denied-cache")
assert.NoError(t, err)
project.AuthWebhookURL = authServer.URL
_, err = adminCli.UpdateProject(
Expand Down Expand Up @@ -409,4 +530,66 @@ func TestAuthWebhook(t *testing.T) {
}
assert.Equal(t, 2, reqCnt)
})

t.Run("other response not cached test", func(t *testing.T) {
ctx := context.Background()
reqCnt := 0
authServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := types.NewAuthWebhookRequest(r.Body)
assert.NoError(t, err)

var res types.AuthWebhookResponse
res.Code = types.CodeUnauthenticated

_, err = res.Write(w)
assert.NoError(t, err)

reqCnt++
}))

unauthorizedTTL := 1 * time.Second
conf := helper.TestConfig()
conf.Backend.AuthWebhookCacheUnauthTTL = unauthorizedTTL.String()

svr, err := server.New(conf)
assert.NoError(t, err)
assert.NoError(t, svr.Start())
defer func() { assert.NoError(t, svr.Shutdown(true)) }()

adminCli := helper.CreateAdminCli(t, svr.RPCAddr())
defer func() { adminCli.Close() }()
project, err := adminCli.CreateProject(context.Background(), "other-response-not-cached")
assert.NoError(t, err)
project.AuthWebhookURL = authServer.URL
_, err = adminCli.UpdateProject(
ctx,
project.ID.String(),
&types.UpdatableProjectFields{
AuthWebhookURL: &project.AuthWebhookURL,
},
)
assert.NoError(t, err)

cli, err := client.Dial(
svr.RPCAddr(),
client.WithToken("token"),
client.WithAPIKey(project.PublicKey),
)
assert.NoError(t, err)
defer func() { assert.NoError(t, cli.Close()) }()

// 01. multiple requests.
for i := 0; i < 3; i++ {
err = cli.Activate(ctx)
assert.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err))
}

// 02. multiple requests after eviction by ttl.
time.Sleep(unauthorizedTTL)
for i := 0; i < 3; i++ {
err = cli.Activate(ctx)
assert.Equal(t, connect.CodeUnauthenticated, connect.CodeOf(err))
}
assert.Equal(t, 6, reqCnt)
})
}

0 comments on commit b73e95b

Please sign in to comment.