From 34fd36054bae9783f34d170e405d1ae2546fea84 Mon Sep 17 00:00:00 2001 From: shipperizer Date: Fri, 5 Apr 2024 18:06:27 +0200 Subject: [PATCH] feat: adjust identity api to accept page token closes #256 --- cmd/serve.go | 2 +- go.mod | 3 +- go.sum | 6 ++-- internal/kratos/client.go | 4 +-- pkg/identities/handlers.go | 7 ++++- pkg/identities/handlers_test.go | 49 +++++++++++++++++++-------------- pkg/web/router.go | 2 +- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/cmd/serve.go b/cmd/serve.go index 9bdb63c01..8ad7630f4 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -100,7 +100,7 @@ func serve() { schemasConfig := &schemas.Config{ K8s: k8sCoreV1, - Kratos: extCfg.KratosPublic().IdentityApi(), + Kratos: extCfg.KratosPublic().IdentityAPI(), Name: specs.SchemasConfigMapName, Namespace: specs.SchemasConfigMapNamespace, } diff --git a/go.mod b/go.mod index 05bcdf5b2..a2929600f 100644 --- a/go.mod +++ b/go.mod @@ -13,11 +13,12 @@ require ( github.com/openfga/go-sdk v0.3.4 github.com/openfga/language/pkg/go v0.0.0-20240122114256-aaa86ab89379 github.com/ory/hydra-client-go/v2 v2.1.1 - github.com/ory/kratos-client-go v1.0.0 + github.com/ory/kratos-client-go v1.1.0 github.com/ory/oathkeeper-client-go v0.40.6 github.com/prometheus/client_golang v1.17.0 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 + github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 go.opentelemetry.io/contrib/propagators/jaeger v1.20.0 go.opentelemetry.io/otel v1.19.0 diff --git a/go.sum b/go.sum index 04629d1c2..704f11188 100644 --- a/go.sum +++ b/go.sum @@ -117,8 +117,8 @@ github.com/openfga/language/pkg/go v0.0.0-20240122114256-aaa86ab89379 h1:j42rKsj github.com/openfga/language/pkg/go v0.0.0-20240122114256-aaa86ab89379/go.mod h1:dHJaJ7H5tViBCPidTsfl3IOd152FhYxWFQmZXOhZ2pw= github.com/ory/hydra-client-go/v2 v2.1.1 h1:3JatU9uFbw5XhF3lgPCas1l1Kok2v5Mq1p26zZwGHNg= github.com/ory/hydra-client-go/v2 v2.1.1/go.mod h1:IiIwChp/9wRvPoyFQblqPvg78uVishCCrV9+/M7Pl34= -github.com/ory/kratos-client-go v1.0.0 h1:mm32FMJrt4pBv2KEuhuNtiewJApc8c1Kmz0+WFHhOMA= -github.com/ory/kratos-client-go v1.0.0/go.mod h1:a2Tl4cgQAxsjR59w3EfnH5hengabjXUHiEVDzdqiZI0= +github.com/ory/kratos-client-go v1.1.0 h1:mCk5wxNTxjYq/sbZfoEY/JcxuBtuixStHD14Y0sU1E8= +github.com/ory/kratos-client-go v1.1.0/go.mod h1:ultwfjWsBxshnZgopqQ3DrKOe/t6SXsM+KKOd21PaTQ= github.com/ory/oathkeeper-client-go v0.40.6 h1:Qm/odusPn6DTJ8mXXElNzfXYpcD5wqmb/k3dOYKUfTg= github.com/ory/oathkeeper-client-go v0.40.6/go.mod h1:9JUPR04XPH3e53TYbfu+KveCnTIYtlSTJiQ23rEQLJI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -147,6 +147,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= +github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= diff --git a/internal/kratos/client.go b/internal/kratos/client.go index c4a14cb5b..ba39282f4 100644 --- a/internal/kratos/client.go +++ b/internal/kratos/client.go @@ -14,8 +14,8 @@ type Client struct { c *client.APIClient } -func (c *Client) IdentityApi() client.IdentityApi { - return c.c.IdentityApi +func (c *Client) IdentityAPI() client.IdentityAPI { + return c.c.IdentityAPI } func NewClient(url string, debug bool) *Client { diff --git a/pkg/identities/handlers.go b/pkg/identities/handlers.go index 80e26a6f6..7056f6f72 100644 --- a/pkg/identities/handlers.go +++ b/pkg/identities/handlers.go @@ -64,7 +64,7 @@ func (a *API) handleList(w http.ResponseWriter, r *http.Request) { credID := r.URL.Query().Get("credID") - ids, err := a.service.ListIdentities(r.Context(), pagination.Page, pagination.Size, credID) + ids, err := a.service.ListIdentities(r.Context(), pagination.Size, pagination.PageToken, credID) if err != nil { rr := a.error(ids.Error) @@ -75,6 +75,11 @@ func (a *API) handleList(w http.ResponseWriter, r *http.Request) { return } + // TODO @shipperizer improve on this, see if better to stick with link headers + pagination.Next = ids.Tokens.Next + pagination.Prev = ids.Tokens.Prev + pagination.First = ids.Tokens.First + w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode( types.Response{ diff --git a/pkg/identities/handlers_test.go b/pkg/identities/handlers_test.go index cf4cdd08d..cb48fed17 100644 --- a/pkg/identities/handlers_test.go +++ b/pkg/identities/handlers_test.go @@ -7,7 +7,6 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" "net/http" "net/http/httptest" "reflect" @@ -19,6 +18,8 @@ import ( "github.com/canonical/identity-platform-admin-ui/internal/http/types" + "io" + kClient "github.com/ory/kratos-client-go" ) @@ -26,7 +27,7 @@ import ( //go:generate mockgen -build_flags=--mod=mod -package identities -destination ./mock_interfaces.go -source=./interfaces.go //go:generate mockgen -build_flags=--mod=mod -package identities -destination ./mock_monitor.go -source=../../internal/monitoring/interfaces.go //go:generate mockgen -build_flags=--mod=mod -package identities -destination ./mock_tracing.go go.opentelemetry.io/otel/trace Tracer -//go:generate mockgen -build_flags=--mod=mod -package identities -destination ./mock_kratos.go github.com/ory/kratos-client-go IdentityApi +//go:generate mockgen -build_flags=--mod=mod -package identities -destination ./mock_kratos.go github.com/ory/kratos-client-go IdentityAPI func TestHandleListSuccess(t *testing.T) { ctrl := gomock.NewController(t) @@ -43,11 +44,20 @@ func TestHandleListSuccess(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/api/v0/identities", nil) values := req.URL.Query() - values.Add("page", "1") values.Add("size", "100") req.URL.RawQuery = values.Encode() - mockService.EXPECT().ListIdentities(gomock.Any(), int64(1), int64(100), "").Return(&IdentityData{Identities: identities}, nil) + mockService.EXPECT().ListIdentities(gomock.Any(), int64(100), "", "").Return( + &IdentityData{ + Identities: identities, + Tokens: PaginationTokens{ + Next: "eyJvZmZzZXQiOiIyNTAiLCJ2IjoyfQ", + First: "eyJvZmZzZXQiOiIwIiwidiI6Mn0", + Prev: "eyJvZmZzZXQiOiItMjUwIiwidiI6Mn0", + }, + }, + nil, + ) w := httptest.NewRecorder() mux := chi.NewMux() @@ -57,7 +67,7 @@ func TestHandleListSuccess(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -113,7 +123,6 @@ func TestHandleListFailAndPropagatesKratosError(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/api/v0/identities", nil) values := req.URL.Query() - values.Add("page", "1") values.Add("size", "100") req.URL.RawQuery = values.Encode() @@ -122,7 +131,7 @@ func TestHandleListFailAndPropagatesKratosError(t *testing.T) { gerr.SetMessage("teapot error") gerr.SetReason("teapot is broken") - mockService.EXPECT().ListIdentities(gomock.Any(), int64(1), int64(100), "").Return(&IdentityData{Identities: make([]kClient.Identity, 0), Error: gerr}, fmt.Errorf("error")) + mockService.EXPECT().ListIdentities(gomock.Any(), int64(100), "", "").Return(&IdentityData{Identities: make([]kClient.Identity, 0), Error: gerr}, fmt.Errorf("error")) w := httptest.NewRecorder() mux := chi.NewMux() @@ -132,7 +141,7 @@ func TestHandleListFailAndPropagatesKratosError(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -178,7 +187,7 @@ func TestHandleDetailSuccess(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -254,7 +263,7 @@ func TestHandleDetailFailAndPropagatesKratosError(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -304,7 +313,7 @@ func TestHandleCreateSuccess(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -385,7 +394,7 @@ func TestHandleCreateFailAndPropagatesKratosError(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -426,7 +435,7 @@ func TestHandleCreateFailBadRequest(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -457,7 +466,7 @@ func TestHandleUpdateSuccess(t *testing.T) { identity := kClient.NewIdentity(credID, "test.json", "https://test.com/test.json", map[string]string{"name": "name"}) identityBody := kClient.NewUpdateIdentityBodyWithDefaults() identityBody.SchemaId = identity.SchemaId - identityBody.SetState(kClient.IDENTITYSTATE_ACTIVE) + identityBody.SetState("active") identityBody.Traits = map[string]interface{}{"name": "name"} identityBody.AdditionalProperties = map[string]interface{}{"name": "name"} @@ -475,7 +484,7 @@ func TestHandleUpdateSuccess(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -536,7 +545,7 @@ func TestHandleUpdateFailAndPropagatesKratosError(t *testing.T) { identityBody := kClient.NewUpdateIdentityBodyWithDefaults() identityBody.SchemaId = "test.json" identityBody.Traits = map[string]interface{}{"name": "name"} - identityBody.SetState(kClient.IDENTITYSTATE_ACTIVE) + identityBody.SetState("active") identityBody.AdditionalProperties = map[string]interface{}{"name": "name"} payload, err := json.Marshal(identityBody) @@ -557,7 +566,7 @@ func TestHandleUpdateFailAndPropagatesKratosError(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -598,7 +607,7 @@ func TestHandleUpdateFailBadRequest(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -639,7 +648,7 @@ func TestHandleRemoveSuccess(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) @@ -687,7 +696,7 @@ func TestHandleRemoveFailAndPropagatesKratosError(t *testing.T) { res := w.Result() defer res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(io.Reader(res.Body)) if err != nil { t.Errorf("expected error to be nil got %v", err) diff --git a/pkg/web/router.go b/pkg/web/router.go index 050dda8be..b64727330 100644 --- a/pkg/web/router.go +++ b/pkg/web/router.go @@ -65,7 +65,7 @@ func NewRouter(idpConfig *idp.Config, schemasConfig *schemas.Config, rulesConfig metrics.NewAPI(logger).RegisterEndpoints(router) identitiesAPI := identities.NewAPI( - identities.NewService(externalConfig.KratosAdmin().IdentityApi(), tracer, monitor, logger), + identities.NewService(externalConfig.KratosAdmin().IdentityAPI(), tracer, monitor, logger), logger, ) identitiesAPI.RegisterEndpoints(router)