GithubHelp home page GithubHelp logo

canonical / identity-platform-admin-ui Goto Github PK

View Code? Open in Web Editor NEW
6.0 15.0 4.0 2.1 MB

Admin UI for the Canonical identity broker and identity provider solution

License: Other

Makefile 0.17% Go 91.56% SCSS 0.14% Shell 0.04% JavaScript 0.13% HTML 0.05% TypeScript 7.91%

identity-platform-admin-ui's Introduction

Identity Platform Admin UI

CI codecov OpenSSF Scorecard pre-commit Conventional Commits

GitHub Release Go Reference

This is the Admin UI for the Canonical Identity Platform.

Environment Variables

  • OTEL_GRPC_ENDPOINT: address of the open telemetry grpc endpoint, used for tracing
  • OTEL_HTTP_ENDPOINT: address of the open telemetry http endpoint, used for tracing (grpc endpoint takes precedence)
  • TRACING_ENABLED: flag enabling tracing
  • LOG_LEVEL: log level, one of info,warn,error,debug, defaults to error
  • LOG_FILE: file where to dump logs, defaults to log.txt
  • PORT: http server port, defaults to 8080
  • CONTEXT_PATH: the context path that the application will be served on, needed to perform redirection correctly
  • DEBUG: debugging flag for hydra and kratos clients
  • KUBECONFIG_FILE: optional path of kube config file, default to empty string
  • KRATOS_PUBLIC_URL: Kratos public endpoints address
  • KRATOS_ADMIN_URL: Kratos admin endpoints address
  • HYDRA_ADMIN_URL: Hydra admin endpoints address
  • IDP_CONFIGMAP_NAME: name of the k8s config map containing Identity Providers
  • IDP_CONFIGMAP_NAMESPACE: namespace of the k8s config map containing Identity Providers
  • SCHEMAS_CONFIGMAP_NAME: name of the k8s config map containing Identity Schemas
  • SCHEMAS_CONFIGMAP_NAMESPACE: namespace of the k8s config map containing Identity Schemas
  • OPENFGA_API_SCHEME: scheme for the OpenFGA host variable, either http or https
  • OPENFGA_API_HOST: host of the OpenFGA server
  • OPENFGA_API_TOKEN: token used to interact with OpenFGA server, dictated by OpenFGA server
  • OPENFGA_STORE_ID: ID of the OpenFGA store the application will talk to
  • OPENFGA_AUTHORIZATION_MODEL_ID: ID of the OpenFGA authorization model the application will talk to
  • AUTHORIZATION_ENABLED: flag defining if the OpenFGA authorization middleware is enabled default to false
  • PAYLOAD_VALIDATION_ENABLED: flag defining if the Payload Validation middleware is enabled default to true
  • AUTHENTICATION_ENABLED: flag defining if the OAuth authentication middleware is enabled, default to false
  • OIDC_ISSUER: URL of the OIDC provider
  • OAUTH2_CLIENT_ID: OAuth2 client ID used for authentication purposes
  • OAUTH2_CLIENT_SECRET: OAuth2 client secret used for authentication purposes
  • OAUTH2_REDIRECT_URI: URI used by the Oauth2 provider for the redirecting callback
  • OAUTH2_CODEGRANT_SCOPES: OAuth2 scopes, defaults to openid,offline_access
  • OAUTH2_AUTH_COOKIES_ENCRYPTION_KEY: 32 bytes string used for encrypting cookies
  • ACCESS_TOKEN_VERIFICATION_STRATEGY: OAuth2 verification startegy, one of jwks or `userinfo``

Development setup

As a requirement, please make sure to:

  • have rockcraft, yq, and make installed
snap install rockcraft
snap install yq
apt install make
# Ensure skopeo is in the path
sudo ln -s /snap/rockcraft/current/bin/skopeo /usr/local/bin/skopeo
  • Microk8s is installed with the registry addon operating at localhost:32000 and kubectl configured to use it
snap install microk8s --classic
microk8s status --wait-ready
microk8s enable registry
# ensure kubectl is configured to use microk8s
microk8s.kubectl config view --raw > $HOME/.kube/config
# Alias kubectl so that it can be used by Skaffold
snap alias microk8s.kubectl kubectl
sudo lxd init --auto

Run make dev to get a working environment in k8s.

To stop any running containers and wipe the container state, run skaffold delete from the top of the repository.

Image rebuild and redeployment

To avoid a continuos redeployment of the whole setup, there is always the manual process of building the admin-ui image

$ SKAFFOLD_DEFAULT_REPO=localhost:32000 skaffold build --push=true --cache-artifacts=false

Generating tags...
 - identity-platform-admin-ui -> localhost:32000/identity-platform-admin-ui:v1.5.0-181-g1107165-dirty
Starting build...
Building [identity-platform-admin-ui]...
Target platforms: [linux/amd64]
Starting rockcraft, version 1.2.3
Logging execution to '/home/shipperizer/.local/state/rockcraft/log/rockcraft-20240424-135944.672894.log'
Launching managed ubuntu 22.04 instance...
.
.
v1.5.0-181-g1107165-dirty: digest: sha256:027745f048faddda78b4cd7b9c7dbb59bec8b446941b163006da32f29b9eb377 size: 943

and then substituting the final artifact in the deployment via kubectl with

kubectl edit deployments.apps identity-platform-admin-ui

where you will swap whatever is in spec.template.spec.containers.0.image with the new image tag (with sha)

OpenFGA initialization

The Admin Service comes up with authorization disabled ( see AUTHORIZATION_ENABLED env var), The env vars OPENFGA_AUTHORIZATION_MODEL_ID and OPENFGA_STORE_ID which are needed for the correct functioning of the RBAC APIs get set by the job admin-ui-openfga-setup, after this has completed a developer is supposed to bounce the deployment to get the application to source the new env vars If AUTHORIZATION_ENABLED is set to false, the user context passed to OpenFGA will default to user:anonymous, which will make every call to roles and groups API return an empty response (unless model is populated with relationship linked to user:anonymous)

# Wait for the openfga setup job to complete
kubectl wait --for=condition=complete job/admin-ui-openfga-setup

# Edit the configmap to enable authorization by setting AUTHORIZATION_ENABLED=true
kubectl edit configmap identity-platform-admin-ui

# Restart the admin UI apply the changes
kubectl rollout restart deployment identity-platform-admin-ui

K8s jobs don't get deleted on their own so if you wish to make changes to the openfga model, you need to make sure that the job for setting up openfga is deleted before redeploying the admin UI:

kubectl delete job admin-ui-openfga-setup
make dev

ensure environment variables in the identity-platform-admin-ui configmap reflect the status you want.

Endpoint examples

$ http :8000/api/v0/identities

HTTP/1.1 200 OK
Content-Length: 86
Content-Type: application/json
Date: Wed, 11 Oct 2023 10:05:37 GMT
Vary: Origin

{
    "_meta": {
        "page": 1,
        "size": 100
    },
    "data": [],
    "message": "List of identities",
    "status": 200
}
$ http :8000/api/v0/idps

HTTP/1.1 200 OK
Content-Length: 1520
Content-Type: application/json
Date: Wed, 11 Oct 2023 10:05:43 GMT
Vary: Origin

{
    "_meta": null,
    "data": [
        {
            "apple_private_key": "",
            "apple_private_key_id": "",
            "apple_team_id": "",
            "auth_url": "",
            "client_id": "af675f35-3bd7-4515-88e2-b8032e315f6f",
            "client_secret": "3y38Q~aslkdhaskjhd~W0xWDB.123u98asd",
            "id": "microsoft_af675f353bd7451588e2b8032e315f6f",
            "issuer_url": "",
            "label": "",
            "mapper_url": "file:///etc/config/kratos/microsoft_schema.jsonnet",
            "microsoft_tenant": "e1574293-28de-4e94-87d5-b61c76fc14e1",
            "provider": "microsoft",
            "requested_claims": null,
            "scope": [
                "profile",
                "email",
                "address",
                "phone"
            ],
            "subject_source": "",
            "token_url": ""
        },
        {
            "apple_private_key": "",
            "apple_private_key_id": "",
            "apple_team_id": "",
            "auth_url": "",
            "client_id": "18fa2999-e6c9-475a-a495-15d933d8e8ce",
            "client_secret": "3y38Q~aslkdhaskjhd~W0xWDB.123u98asd",
            "id": "google_18fa2999e6c9475aa49515d933d8e8ce",
            "issuer_url": "",
            "label": "",
            "mapper_url": "file:///etc/config/kratos/google_schema.jsonnet",
            "microsoft_tenant": "",
            "provider": "google",
            "requested_claims": null,
            "scope": [
                "profile",
                "email",
                "address",
                "phone"
            ],
            "subject_source": "",
            "token_url": ""
        },
        {
            "apple_private_key": "",
            "apple_private_key_id": "",
            "apple_team_id": "",
            "auth_url": "",
            "client_id": "18fa2999-e6c9-475a-a495-89d941d8e1zy",
            "client_secret": "3y38Q~aslkdhaskjhd~W0xWDB.123u98asd",
            "id": "aws_18fa2999e6c9475aa49589d941d8e1zy",
            "issuer_url": "",
            "label": "",
            "mapper_url": "file:///etc/config/kratos/google_schema.jsonnet",
            "microsoft_tenant": "",
            "provider": "aws",
            "requested_claims": null,
            "scope": [
                "profile",
                "email",
                "address",
                "phone"
            ],
            "subject_source": "",
            "token_url": ""
        }
    ],
    "message": "List of IDPs",
    "status": 200
}
$ http :8000/api/v0/clients

HTTP/1.1 200 OK
Content-Length: 316
Content-Type: application/json
Date: Wed, 11 Oct 2023 10:05:47 GMT
Vary: Origin

{
    "_links": {
        "first": "/api/v0/clients?page=eyJvZmZzZXQiOiIwIiwidiI6Mn0&size=200",
        "next": "/api/v0/clients?page=eyJvZmZzZXQiOiIyMDAiLCJ2IjoyfQ&size=200",
        "prev": "/api/v0/clients?page=eyJvZmZzZXQiOiItMjAwIiwidiI6Mn0&size=200"
    },
    "_meta": {
        "total_count": "0"
    },
    "data": [],
    "message": "List of clients",
    "status": 200
}

identity-platform-admin-ui's People

Contributors

barcomasile avatar shipperizer avatar renovate[bot] avatar nsklikas avatar canonical-iam avatar huwshimi avatar edlerd avatar bencekov avatar wood-push-melon avatar

Stargazers

Abanoub Hanna avatar Denis Balan avatar Trieu Duong avatar  avatar  avatar 3JoB SRA avatar

Watchers

 avatar James Cloos avatar José Tapadas Alves avatar Peter Balazs Polgar avatar  avatar Martin Storey avatar Ales Stimec avatar  avatar Giulia Zanchi avatar  avatar  avatar MariaPaula Trujillo avatar Amy Pattanasethanon avatar  avatar  avatar

identity-platform-admin-ui's Issues

Add `chi` side validation for URLs + small fixes needed in `converters.go`

Description

In internal/authorization/converters.go, L228, one thing we don't do here is actually check for the first id (group_id) to be non-blank, may raise issues at runtime if we don't validate endpoints path variables before this middleware is run, otherwise we would need to first check after parameter retrieval if the group_id is empty and the method allows for an empty parameter, like GET ( -> can_view) or POST ( -> can_edit).

Using regexp URL parameters to validate that selected endpoints have an ID path variable populated is the best way to fix this.
From the doc:

  // Regexp url parameters:
  r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug) // GET /articles/home-is-toronto

Bonus nitpick

/entitlements suffixed endpoints for group don't support POST operations in this PR, only GET, PATCH and DELETE

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update dependency autoprefixer to v10.4.15
  • fix(deps): update module github.com/google/uuid to v1.3.1
  • chore(deps): update dependency @testing-library/jest-dom to v5.17.0
  • chore(deps): update dependency eslint-config-prettier to v8.10.0
  • chore(deps): update dependency eslint-plugin-react to v7.33.2
  • chore(deps): update golang docker tag to v1.21
  • fix(deps): update dependency sass-embedded to v1.66.1
  • fix(deps): update kubernetes packages to v0.28.0 (k8s.io/apimachinery, k8s.io/client-go)
  • fix(deps): update module go.uber.org/zap to v1.25.0
  • chore(deps): update dependency @testing-library/jest-dom to v6
  • chore(deps): update dependency @typescript-eslint/eslint-plugin to v6
  • chore(deps): update dependency eslint-config-prettier to v9
  • chore(deps): update dependency eslint-plugin-prettier to v5
  • 🔐 Create all rate-limited PRs at once 🔐

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

dockerfile
Dockerfile
  • golang 1.20
github-actions
.github/workflows/build.yaml
  • actions/checkout v3
  • actions/upload-artifact v3
  • actions/upload-artifact v3
.github/workflows/codeql-analysis.yaml
  • actions/checkout v3
  • github/codeql-action v2
  • github/codeql-action v2
  • github/codeql-action v2
.github/workflows/ossf.yaml
  • actions/checkout v3.5.3@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
  • ossf/scorecard-action v2.1.3@80e868c13c90f172d68d1f4501dee99e2479f7af
  • actions/upload-artifact v3.1.2@0b7f8abb1508181956e8e162db84b466c27e18ce
  • github/codeql-action v2.3.6@83f0fe6c4988d98a455712a27f0255212bba9bd4
.github/workflows/publish.yaml
  • actions/checkout v3
  • actions/download-artifact v3
.github/workflows/release.yaml
  • google-github-actions/release-please-action v3
  • actions/checkout v3
.github/workflows/scan.yaml
  • github/codeql-action v2
.github/workflows/unittest.yaml
  • actions/checkout v3
  • actions/setup-go v4
  • actions/setup-node v3
  • codecov/codecov-action v3
  • actions/upload-artifact v3
gomod
go.mod
  • go 1.19
  • github.com/go-chi/chi/v5 v5.0.10
  • github.com/go-chi/cors v1.2.1
  • github.com/golang/mock v1.6.0
  • github.com/google/uuid v1.3.0
  • github.com/kelseyhightower/envconfig v1.4.0
  • github.com/ory/hydra-client-go/v2 v2.1.1
  • github.com/ory/kratos-client-go v0.13.1
  • github.com/prometheus/client_golang v1.16.0
  • github.com/stretchr/testify v1.8.4
  • go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0
  • go.opentelemetry.io/contrib/propagators/jaeger v1.17.0
  • go.opentelemetry.io/otel v1.16.0
  • go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0
  • go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0
  • go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0
  • go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0
  • go.opentelemetry.io/otel/sdk v1.16.0
  • go.opentelemetry.io/otel/trace v1.16.0
  • go.uber.org/zap v1.24.0
  • gopkg.in/natefinch/lumberjack.v2 v2.2.1
  • gopkg.in/yaml.v3 v3.0.1
  • k8s.io/apimachinery v0.27.4
  • k8s.io/client-go v0.27.4
npm
ui/package.json
  • @canonical/react-components 0.42.0
  • react 18.2.0
  • react-toastify 9.1.3
  • sass-embedded 1.63.6
  • vanilla-framework 3.14.0
  • @testing-library/jest-dom 5.16.5
  • @testing-library/react 14.0.0
  • @testing-library/user-event 14.4.3
  • @typescript-eslint/eslint-plugin 5.60.0
  • autoprefixer 10.4.14
  • eslint 8.43.0
  • eslint-config-prettier 8.8.0
  • eslint-plugin-prettier 4.2.1
  • eslint-plugin-react 7.32.2
  • postcss 8.4.24
  • postcss-cli 10.1.0
  • prettier 2.8.8
  • typescript 5.1.3
  • node 18

  • Check this box to trigger a request for Renovate to run again on this repository

Generate id when creating an identity provider if id field is not provided within the POST payload

When establishing an identity provider using the POST /api/v0/idps endpoint, specifying an empty id field can lead to the newly created identity provider lacking an id field altogether. If multiple identity providers are created this way then it becomes impossible to differentiate between those entities via the GET /api/v0/idps/{id} endpoint.

Propose we should generate the id field within the POST handler for an identity provider if id field is not provided in the payload.

Error on creation of a schema via POST

Environment:
Running latest/edge of the juju deployment of the identity platform with the admin-ui build from current master.

We created a new schema via API


curl -d '{
   "schema":{
      "$id":"https://schemas.canonical.com/presets/kratos/test_v0.json",
      "$schema":"http://json-schema.org/draft-07/schema#",
      "title":"Admin Account",
      "type":"object",
      "properties":{
         "traits":{
            "type":"object",
            "properties":{
               "username":{
                  "type":"string",
                  "title":"Username",
                  "ory.sh/kratos":{
                     "credentials":{
                        "password":{
                           "identifier":true
                        }
                     }
                  }
               }
            }
         }
      },
      "additionalProperties":true
   }
}' -X POST -H 'Content-Type: application/json' http://127.0.0.1:8000/api/v0/schemas

Got an empty response from the API. The logs of admin-ui revealed this trace:

2024/03/28 11:36:59 http: panic serving 127.0.0.1:41558: assignment to entry in nil map
goroutine 39 [running]:
net/http.(*conn).serve.func1()
        /snap/go/10554/src/net/http/server.go:1868 +0xb9
panic({0x19dbb00?, 0x1f425f0?})
        /snap/go/10554/src/runtime/panic.go:920 +0x270
github.com/canonical/identity-platform-admin-ui/pkg/schemas.(*Service).CreateSchema(0xc0004b4cb0, {0x1f62930?, 0xc000d04360?}, 0xc00098a060)
        /root/parts/go-build/build/pkg/schemas/service.go:200 +0x448
github.com/canonical/identity-platform-admin-ui/pkg/schemas.(*API).handleCreate(0xc0005a34c0, {0x1f56f00, 0xc0005c4240}, 0xc0000b8b00)
        /root/parts/go-build/build/pkg/schemas/handlers.go:189 +0x30d
net/http.HandlerFunc.ServeHTTP(0xc0000b8900?, {0x1f56f00?, 0xc0005c4240?}, 0x1f417f0?)
        /snap/go/10554/src/net/http/server.go:2136 +0x29
github.com/canonical/identity-platform-admin-ui/pkg/web.NewRouter.(*Middleware).Authorize.func4.1({0x1f56f00, 0xc0005c4240}, 0x0?)
        /root/parts/go-build/build/internal/authorization/middlewares.go:193 +0x28b
net/http.HandlerFunc.ServeHTTP(0xc000626c80?, {0x1f56f00?, 0xc0005c4240?}, 0x0?)
        /snap/go/10554/src/net/http/server.go:2136 +0x29
github.com/go-chi/chi/v5.(*ChainHandler).ServeHTTP(0x19c2940?, {0x1f56f00?, 0xc0005c4240?}, 0xc000d0e005?)
        /root/go/pkg/mod/github.com/go-chi/chi/[email protected]/chain.go:31 +0x26
github.com/go-chi/chi/v5.(*Mux).routeHTTP(0xc0005c4360, {0x1f56f00, 0xc0005c4240}, 0xc0000b8900)
        /root/go/pkg/mod/github.com/go-chi/chi/[email protected]/mux.go:444 +0x2b4
net/http.HandlerFunc.ServeHTTP(0x1f62930?, {0x1f56f00?, 0xc0005c4240?}, 0x2e63c70?)
        /snap/go/10554/src/net/http/server.go:2136 +0x29
github.com/go-chi/chi/v5.(*Mux).ServeHTTP(0xc0005c4360, {0x1f56f00, 0xc0005c4240}, 0xc0000b8700)
        /root/go/pkg/mod/github.com/go-chi/chi/[email protected]/mux.go:90 +0x315
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp.(*middleware).serveHTTP(0xc000aa9c30, {0x1f553b8?, 0xc0007fe0e0}, 0xc0000b8500, {0x1f454a0, 0xc0005c4360})
        /root/go/pkg/mod/go.opentelemetry.io/contrib/instrumentation/net/http/[email protected]/handler.go:217 +0x1202
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp.NewMiddleware.func1.1({0x1f553b8?, 0xc0007fe0e0?}, 0xc0004b6090?)
        /root/go/pkg/mod/go.opentelemetry.io/contrib/instrumentation/net/http/[email protected]/handler.go:81 +0x35
net/http.HandlerFunc.ServeHTTP(0x410965?, {0x1f553b8?, 0xc0007fe0e0?}, 0xc0007fe001?)
        /snap/go/10554/src/net/http/server.go:2136 +0x29
net/http.serverHandler.ServeHTTP({0x1f4ea10?}, {0x1f553b8?, 0xc0007fe0e0?}, 0x6?)
        /snap/go/10554/src/net/http/server.go:2938 +0x8e
net/http.(*conn).serve(0xc00081c000, {0x1f62930, 0xc000800210})
        /snap/go/10554/src/net/http/server.go:2009 +0x5f4
created by net/http.(*Server).Serve in goroutine 11
        /snap/go/10554/src/net/http/server.go:3086 +0x5cb

Identity provider creation without a mapper url

Description

The POST /api/v0/idps endpoint should inject the correct mapper_url value based on the provider in the payload, in case the mapper_url is empty in the payload.

Motivation

On POST /api/v0/idps a mapper_url field is needed in the payload. The mapper relates to a jsonnet file that needs to be present on the backend. A user can't be expected to know the right value when adding a new identity provider. We should allow idp creation with empty mapper_url and things should "just work".

address Skaffold bypassing

the change introduced in 0d81544 bypasses skaffold

this needs to be corrected and lead to a refactoring of the skaffold.yaml to move dependencies into a specific profile and then run 2 separate commands inside the dev Makefile target so that we can create a sequenced deployment

Deleted roles can't be created again

If we delete my-role-id role by accessing the DELETE */roles/my-role-id endpoint, then we are not able to create it back with the POST */roles endpoint. We get the following error:

Unable to create role: Write validation error for POST Write with body {"code":"write_failed_due_to_invalid_input","message":"cannot write a tuple which already exists: user: 'user:shipperizer', relation: 'assignee', object: 'role:my-role-id': invalid write input"} with error code write_failed_due_to_invalid_input error message: cannot write a tuple which already exists: user: 'user:shipperizer', relation: 'assignee', object: 'role:my-role-id': invalid write input

Looked into all the available created tuples using fga tuple read --simple-output --api-url http://127.0.0.1:8080 --store-id $STORE_ID and there is one tuple related to my-role-id that was not removed:

{
  "object":"role:my-role-id",
  "relation":"assignee",
  "user":"user:shipperizer"
}

Spoke with @shipperizer earlier today and it is confirmed that this is a bug, cause, in DeleteRole, we remove only privileged tuple and all those assigned to role:x#assignee not simple assignee.

Note: This issue might be present for groups as well, but haven't tested it there.

Can't remove roles or identities from a group

When doing a DELETE to /groups/group1/roles/role1 or /groups/group1/identities/identity1 to remove the role or identity from a group I get a 403 response with this error:

{"data":null,"message":"insufficient permissions to execute operation","status":403,"_meta":null}

I'm on latest main (commit: 0cc2bce).

I have reset my tuples to those from the seeding doc and appear to have delete permissions (I'm passing the token johndoe as the auth header):

$ fga query check --store-id=$STORE_ID user:johndoe can_delete identity:global --model-id=$MODEL_ID
{
  "allowed":true,
  "resolution":""
}
$ fga query check --store-id=$STORE_ID user:johndoe can_delete role:global --model-id=$MODEL_ID
{
  "allowed":true,
  "resolution":""
}

I can DELETE entitlements from the group (/groups/group1/entitlements/entitlement1).

Adjust endpoints request payload and responses according to current OpenAPI spec.

Description

We need to edit current endpoints request payloads and responses to match the currect OpenAPI spec (repo) as of March 18th 2024.

Endpoints changes

  • remove entitlements endpoints with DELETE /.../{e_id} where e_id is the entitlement ID
  • remove all DELETE operations that perform the removal entities added with PATCH operations (so basically merge PATCH and cooresponding DELETE operations)

Response payload changes

  • all detail endpoints now return the single entity that has been queried
  • all POST endpoints now return the single created entity
  • all PUT endpoints now return the single updated entity

Request payload changes

  • All PATCH endpoints must handle the following formats, examples:
    • PATCH /identity/{id}/groups
    • PATCH /identity/{id}/roles
    • PATCH /identity/{id}/entitlements
    • ...
    {
      "patches": [
          {
              "op": "add",
              "group": "group-A",
          }
      ]
    }
    
    {
      "patches": [
          {
              "op": "remove",
              "role": "role-A",
          }
      ]
    }
    
    {
      "patches": [
          {
              "op": "add",
              "entitlement": {
                  "entity_type": "entity-type",
                  "entity_name": "entity-name",
                  "entitlement_type": "entitlement-type"
              }
          }
      ]
    }

Evaluate how to deal with network or service errors when removing a role in the background via goroutines

current implementation of background tasks and concurrency for removing roles and listing permissions is not scaleable

a new solution should be drafted to deal with the loose goroutines and the potential limit in file descriptors on mid to heavy load

Perhaps it is an unrealistic case, but I am a little worried that this may error if too many permissions are returned. I mean that openfga chooses not to return the permissions all at once, it is possible that it will not be able to handle them all at once either. In the API docs there is no mention of a limit, but I think that we should test it. 

Disregard this if it does not make sense or leave a TODO to look into it in the future. 

If this could cause an issue we could create a go routine for deleting the permissions for every continuation token we get, eg:
"""
for {
 // Get the permissions using the continuation token
 permissions, error := getPermissions(continuationToken)
 // Delete permissions without blocking
 go deletePermissions(permissions)
 cToken = permissions.ContinuationToken
 if cToken == "" {
   break
 }
 // wait for all routines to return
}
"""

Originally posted by @nsklikas in #189 (comment)

Uniform definitions and use of `Response` struct

Description

Right now there are 3 structs definend as Response in the whole codebase.
Their location:

  • internal/responses/responses.go
  • internal/http/types/generic.go
  • pkg/responses/responses.go

If possible, let get rid of unused one/s and stick to the bare minimum amount of definitions needed.

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Location: renovate.json
Error type: Invalid JSON (parsing failed)
Message: Syntax error near ",
],

OpenFGA store and model creation via CLI and k8s configmap update

Current implementation of the dev setup works really nice until we have to start tweaking the model

it doesn't allow for an easy way to change values for store and model ID, writing on the volume can be quite tricky

Plan is to change the cli call to update the configmap if a modifier is set

app create-fga-model --fga-api-token <1234> --fga-api-url <localhost> --store-k8s-cm <admin-ui-cm>

Avoid apple specific fields in responses

The apple_private_key and other apple_ fields are always in the identity provider response (list and single get). I think those fields should be avoided if the "provider" does not equal "apple".

List Identity Schemas needs pagination memory

kratos public endpoints /schema and /schema/{id} return successfully:

shipperizer in ~/shipperizer/identity-platform-admin-ui on IAM-366 ● ● λ http :4433/schemas page==0 page_size==2 
HTTP/1.1 200 OK
Cache-Control: private, no-cache, no-store, must-revalidate
Content-Length: 1751
Content-Type: application/json; charset=utf-8
Date: Thu, 24 Aug 2023 13:09:38 GMT
Link: <https://10.64.140.43/iam-kratos/schemas?page=0&per_page=2>; rel="first"
Set-Cookie: csrf_token_c172ca5a6cb7f832a9b8b4e40baf9b6219f6491e8bcb19122e8e335690c83c10=3P70sWIWF3DSCF6NgVdJlCXhvakFWyiI6TVeYyR2RH0=; Path=/; Max-Age=31536000; HttpOnly; Secure; SameSite=Lax
Vary: Origin
Vary: Cookie
X-Total-Count: 2

[
    {
        "id": "social_user_v0",
        "schema": {
            "$id": "https://schemas.canonical.com/presets/kratos/user_v0.json",
            "$schema": "http://json-schema.org/draft-07/schema#",
            "properties": {
                "additionalProperties": true,
                "traits": {
                    "properties": {
                        "address": {
                            "title": "Address",
                            "type": "string"
                        },
                        "birthdate": {
                            "title": "Birthdate",
                            "type": "string"
                        },
                        "email": {
                            "format": "email",
                            "title": "E-Mail",
                            "type": "string"
                        },
                        "family_name": {
                            "title": "Family Name",
                            "type": "string"
                        },
                        "gender": {
                            "title": "Gender",
                            "type": "string"
                        },
                        "given_name": {
                            "title": "Given Name",
                            "type": "string"
                        },
                        "last_name": {
                            "title": "Last Name",
                            "type": "string"
                        },
                        "locale": {
                            "title": "Locale",
                            "type": "string"
                        },
                        "middle_name": {
                            "title": "Middle Name",
                            "type": "string"
                        },
                        "name": {
                            "title": "Name",
                            "type": "string"
                        },
                        "nickname": {
                            "title": "Nickname",
                            "type": "string"
                        },
                        "phone_number": {
                            "title": "Phone Number",
                            "type": "string"
                        },
                        "picture": {
                            "title": "Picture",
                            "type": "string"
                        },
                        "preferred_username": {
                            "title": "Preferred Username",
                            "type": "string"
                        },
                        "profile": {
                            "title": "Profile",
                            "type": "string"
                        },
                        "website": {
                            "title": "Website",
                            "type": "string"
                        },
                        "zoneinfo": {
                            "title": "Zoneinfo",
                            "type": "string"
                        }
                    },
                    "required": [
                        "email"
                    ],
                    "type": "object"
                }
            },
            "title": "Person",
            "type": "object"
        }
    },
    {
        "id": "admin_v0",
        "schema": {
            "$id": "https://schemas.canonical.com/presets/kratos/admin_v0.json",
            "$schema": "http://json-schema.org/draft-07/schema#",
            "properties": {
                "additionalProperties": true,
                "traits": {
                    "properties": {
                        "email": {
                            "format": "email",
                            "minLength": 3,
                            "ory.sh/kratos": {
                                "verification": {
                                    "via": "email"
                                }
                            },
                            "title": "E-Mail",
                            "type": "string"
                        },
                        "name": {
                            "title": "Name",
                            "type": "string"
                        },
                        "phone_number": {
                            "title": "Phone Number",
                            "type": "string"
                        },
                        "username": {
                            "ory.sh/kratos": {
                                "credentials": {
                                    "password": {
                                        "identifier": true
                                    }
                                }
                            },
                            "title": "Username",
                            "type": "string"
                        }
                    },
                    "type": "object"
                }
            },
            "title": "Admin Account",
            "type": "object"
        }
    }
]

shipperizer in ~/shipperizer/identity-platform-admin-ui on IAM-366 ● λ http :4433/schemas/admin_v0
HTTP/1.1 200 OK
Cache-Control: private, no-cache, no-store, must-revalidate
Content-Length: 1003
Content-Type: application/json
Date: Thu, 24 Aug 2023 11:02:55 GMT
Vary: Origin
Vary: Cookie

{
    "$id": "https://schemas.canonical.com/presets/kratos/admin_v0.json",
    "$schema": "http://json-schema.org/draft-07/schema#",
    "properties": {
        "additionalProperties": true,
        "traits": {
            "properties": {
                "email": {
                    "format": "email",
                    "minLength": 3,
                    "ory.sh/kratos": {
                        "verification": {
                            "via": "email"
                        }
                    },
                    "title": "E-Mail",
                    "type": "string"
                },
                "name": {
                    "title": "Name",
                    "type": "string"
                },
                "phone_number": {
                    "title": "Phone Number",
                    "type": "string"
                },
                "username": {
                    "ory.sh/kratos": {
                        "credentials": {
                            "password": {
                                "identifier": true
                            }
                        }
                    },
                    "title": "Username",
                    "type": "string"
                }
            },
            "type": "object"
        }
    },
    "title": "Admin Account",
    "type": "object"
}


the proxied /api/v0/schema is always empty unless you pass the size==1:

shipperizer in ~/shipperizer/identity-platform-admin-ui on IAM-366 ● λ http :8000/api/v0/schemas
HTTP/1.1 200 OK
Content-Length: 75
Content-Type: application/json
Date: Thu, 24 Aug 2023 11:12:26 GMT
Vary: Origin

{
    "_meta": null,
    "data": [],
    "message": "List of Identity Schemas",
    "status": 200
}

shipperizer in ~/shipperizer/kratos-operator on IAM-362-add-configmap λ http :8000/api/v0/schemas page==1 size==1
HTTP/1.1 200 OK
Content-Length: 679
Content-Type: application/json
Date: Thu, 24 Aug 2023 13:11:17 GMT
Vary: Origin

{
    "_meta": null,
    "data": [
        {
            "id": "admin_v0",
            "schema": {
                "$id": "https://schemas.canonical.com/presets/kratos/admin_v0.json",
                "$schema": "http://json-schema.org/draft-07/schema#",
                "properties": {
                    "additionalProperties": true,
                    "traits": {
                        "properties": {
                            "email": {
                                "format": "email",
                                "minLength": 3,
                                "ory.sh/kratos": {
                                    "verification": {
                                        "via": "email"
                                    }
                                },
                                "title": "E-Mail",
                                "type": "string"
                            },
                            "name": {
                                "title": "Name",
                                "type": "string"
                            },
                            "phone_number": {
                                "title": "Phone Number",
                                "type": "string"
                            },
                            "username": {
                                "ory.sh/kratos": {
                                    "credentials": {
                                        "password": {
                                            "identifier": true
                                        }
                                    }
                                },
                                "title": "Username",
                                "type": "string"
                            }
                        },
                        "type": "object"
                    }
                },
                "title": "Admin Account",
                "type": "object"
            }
        }
    ],
    "message": "List of Identity Schemas",
    "status": 200
}


shipperizer in ~/shipperizer/kratos-operator on IAM-362-add-configmap λ http :8000/api/v0/schemas page==2 size==1
HTTP/1.1 200 OK
Content-Length: 75
Content-Type: application/json
Date: Thu, 24 Aug 2023 13:11:20 GMT
Vary: Origin

{
    "_meta": null,
    "data": [],
    "message": "List of Identity Schemas",
    "status": 200
}


the detailed view works all the time for all the schemas

shipperizer in ~/shipperizer/kratos-operator on IAM-362-add-configmap λ http :8000/api/v0/schemas/admin_v0         
HTTP/1.1 200 OK
Content-Length: 681
Content-Type: application/json
Date: Thu, 24 Aug 2023 13:18:01 GMT
Vary: Origin

{
    "_meta": null,
    "data": [
        {
            "id": "admin_v0",
            "schema": {
                "$id": "https://schemas.canonical.com/presets/kratos/admin_v0.json",
                "$schema": "http://json-schema.org/draft-07/schema#",
                "properties": {
                    "additionalProperties": true,
                    "traits": {
                        "properties": {
                            "email": {
                                "format": "email",
                                "minLength": 3,
                                "ory.sh/kratos": {
                                    "verification": {
                                        "via": "email"
                                    }
                                },
                                "title": "E-Mail",
                                "type": "string"
                            },
                            "name": {
                                "title": "Name",
                                "type": "string"
                            },
                            "phone_number": {
                                "title": "Phone Number",
                                "type": "string"
                            },
                            "username": {
                                "ory.sh/kratos": {
                                    "credentials": {
                                        "password": {
                                            "identifier": true
                                        }
                                    }
                                },
                                "title": "Username",
                                "type": "string"
                            }
                        },
                        "type": "object"
                    }
                },
                "title": "Admin Account",
                "type": "object"
            }
        }
    ],
    "message": "Detail of Identity Schemas",
    "status": 200
}


shipperizer in ~/shipperizer/kratos-operator on IAM-362-add-configmap λ http :8000/api/v0/schemas/social_user_v0
HTTP/1.1 200 OK
Content-Length: 1220
Content-Type: application/json
Date: Thu, 24 Aug 2023 13:18:07 GMT
Vary: Origin

{
    "_meta": null,
    "data": [
        {
            "id": "social_user_v0",
            "schema": {
                "$id": "https://schemas.canonical.com/presets/kratos/user_v0.json",
                "$schema": "http://json-schema.org/draft-07/schema#",
                "properties": {
                    "additionalProperties": true,
                    "traits": {
                        "properties": {
                            "address": {
                                "title": "Address",
                                "type": "string"
                            },
                            "birthdate": {
                                "title": "Birthdate",
                                "type": "string"
                            },
                            "email": {
                                "format": "email",
                                "title": "E-Mail",
                                "type": "string"
                            },
                            "family_name": {
                                "title": "Family Name",
                                "type": "string"
                            },
                            "gender": {
                                "title": "Gender",
                                "type": "string"
                            },
                            "given_name": {
                                "title": "Given Name",
                                "type": "string"
                            },
                            "last_name": {
                                "title": "Last Name",
                                "type": "string"
                            },
                            "locale": {
                                "title": "Locale",
                                "type": "string"
                            },
                            "middle_name": {
                                "title": "Middle Name",
                                "type": "string"
                            },
                            "name": {
                                "title": "Name",
                                "type": "string"
                            },
                            "nickname": {
                                "title": "Nickname",
                                "type": "string"
                            },
                            "phone_number": {
                                "title": "Phone Number",
                                "type": "string"
                            },
                            "picture": {
                                "title": "Picture",
                                "type": "string"
                            },
                            "preferred_username": {
                                "title": "Preferred Username",
                                "type": "string"
                            },
                            "profile": {
                                "title": "Profile",
                                "type": "string"
                            },
                            "website": {
                                "title": "Website",
                                "type": "string"
                            },
                            "zoneinfo": {
                                "title": "Zoneinfo",
                                "type": "string"
                            }
                        },
                        "required": [
                            "email"
                        ],
                        "type": "object"
                    }
                },
                "title": "Person",
                "type": "object"
            }
        }
    ],
    "message": "Detail of Identity Schemas",
    "status": 200
}

as docs go https://github.com/ory/kratos-client-go/blob/v0.13.1/api_identity.go#L2188 pages don't necessarily follow each and i was not able to fund the second schema

investigate a solution on how to get a reliable behaviour

Let users specify `name` instead of `ID` for Groups and Roles

In some cases the field needs to be added. UI team needs to be alerted about this so they can uniform the use of the API.
Plus the following resources suffer from "ID overwrite" in case of update:

  • Identities
  • IdPs

For the Rules the ID check is performed in the service layer instead of the controller.

Standardize rules API pagination strategy

at the moment the /api/v0/rules API follows the page|size pagination strategy

this goes against what is being used in

  • api/v0/identities
  • api/v0/clients
  • api/v0/schemas

plan is to standardzie around a page_token strategy like the APIs above, using a base64 json representation of an offset:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "offset": {
      "type": "string"
    }
  },
  "required": [
    "offset"
  ]
}
shipperizer in ~/shipperizer/identity-platform-admin-ui/pkg/rules on IAM-782 ● λ echo -n '{"offset":"250"}' | base64 | base64 -d
{"offset":"250"}%                                                                                                                           
shipperizer in ~/shipperizer/identity-platform-admin-ui/pkg/rules on IAM-782 ● λ echo -n '{"offset":"250"}' | base64            
eyJvZmZzZXQiOiIyNTAifQ==

this is the same token schema used by the /api/v0/schemas

once we get the offset and the page size, we should be more than able to interpolate the page

Fix pagination token generation to remove "old" pages

Description

When settting tokens for new paginated response, we also need to delete pageTokens that don't have a following page, otherwise the last token for a page would always be present and the PaginationHeader method would never find the exiting condition to return "".

Example: pkg/groups/handlers.go

  for apiType, token := range pageTokens {
    paginator.SetToken(r.Context(), apiType, token)
  }

Old tokens would remain in the paginator and still end up in the base64 digest.

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Location: renovate/internal
Error type: Renovate branch is protected
Message: Renovate cannot push to its branch because branch protection has been enabled.

500 response when adding identities to a group

Doing a PATCH request to /api/v0/groups/group1/identities gets a 500 response with payload: {identities: ["johndoe"]}.

The API responds with:

{
    "data": null,
    "message": "Write validation error for POST Write with body {\"code\":\"validation_error\",\"message\":\"Invalid tuple 'group:group1#member#member@user:johndoe'. Reason: invalid 'object' field format\"}\n with error code validation_error error message: Invalid tuple 'group:group1#member#member@user:johndoe'. Reason: invalid 'object' field format",
    "status": 500,
    "_meta": null
}

I double checked that I'm doing a PATCH request, even though the error message mentions "POST".

Could there be some kind of internal issue with how it's constructing the tuple? There seems to be a double "#member#member".

403 when creating roles/groups

This may be user error, but when I try to create a role or a group (e.g. POST to /api/v0/groups with {id: "newgroup"}) I get a 403 response:

{"data":null,"message":"insufficient permissions to execute operation","status":403,"_meta":null}

I only started getting this error once I enabled authorisation in my configmap.

I'm setting the auth header to the superuser "johndoe" (see tuples below):
X-Authorization: am9obmRvZQ==

The tuples are set to the same values as the seeding doc.

fga tuple read --output-format=simple-json --max-pages 0 --store-id $STORE_ID
[
  {
    "object":"group:c-level",
    "relation":"member",
    "user":"user:joe"
  },
  {
    "object":"role:administrator",
    "relation":"assignee",
    "user":"user:joe"
  },
  {
    "object":"privileged:superuser",
    "relation":"admin",
    "user":"user:shipperizer"
  },
  {
    "object":"group:c-level",
    "relation":"privileged",
    "user":"privileged:superuser"
  },
  {
    "object":"role:administrator",
    "relation":"privileged",
    "user":"privileged:superuser"
  },
  {
    "object":"identity:user-1",
    "relation":"privileged",
    "user":"privileged:superuser"
  },
  {
    "object":"identity:user-2",
    "relation":"privileged",
    "user":"privileged:superuser"
  },
  {
    "object":"scheme:identity-social",
    "relation":"privileged",
    "user":"privileged:superuser"
  },
  {
    "object":"client:github-canonical",
    "relation":"privileged",
    "user":"privileged:superuser"
  },
  {
    "object":"privileged:superuser",
    "relation":"admin",
    "user":"user:johndoe"
  },
  {
    "object":"identity:user-1",
    "relation":"can_delete",
    "user":"user:joe"
  },
  {
    "object":"client:github-canonical",
    "relation":"can_view",
    "user":"role:administrator#assignee"
  },
  {
    "object":"client:okta",
    "relation":"can_delete",
    "user":"role:administrator#assignee"
  },
  {
    "object":"client:github-canonical",
    "relation":"can_edit",
    "user":"group:c-level#member"
  },
  {
    "object":"client:okta",
    "relation":"can_view",
    "user":"group:c-level#member"
  },
  {
    "object":"role:janitor",
    "relation":"assignee",
    "user":"group:c-level#member"
  },
  {
    "object":"role:administrator",
    "relation":"assignee",
    "user":"group:c-level#member"
  },
  {
    "object":"client:okta",
    "relation":"can_delete",
    "user":"group:c-level#member"
  },
  {
    "object":"client:okta",
    "relation":"can_edit",
    "user":"group:c-level#member"
  },
  {
    "object":"role:global",
    "relation":"can_view",
    "user":"user:*"
  },
  {
    "object":"provider:global",
    "relation":"can_view",
    "user":"user:*"
  },
  {
    "object":"group:global",
    "relation":"can_view",
    "user":"user:*"
  },
  {
    "object":"client:global",
    "relation":"can_view",
    "user":"user:*"
  },
  {
    "object":"identity:global",
    "relation":"can_view",
    "user":"user:*"
  },
  {
    "object":"scheme:global",
    "relation":"can_view",
    "user":"user:*"
  }
]

My model is:

$ fga model get --store-id=$STORE_ID
model
  schema 1.1

type user

type privileged
  relations
    define admin: [user]

type role
  relations
    define assignee: [user, group#member] or admin from privileged
    define can_create: [user, role#assignee, group#member] or admin from privileged
    define can_delete: [user, role#assignee, group#member] or admin from privileged
    define can_edit: [user, role#assignee, group#member] or admin from privileged
    define can_view: [user, user:*, role#assignee, group#member] or admin from privileged
    define privileged: [privileged]

type group
  relations
    define can_create: [user, role#assignee, group#member] or admin from privileged
    define can_delete: [user, role#assignee, group#member] or admin from privileged
    define can_edit: [user, role#assignee, group#member] or admin from privileged
    define can_view: [user, user:*, role#assignee, group#member] or admin from privileged
    define member: [user, group#member]
    define privileged: [privileged]

type identity
  relations
    define can_create: [user, role#assignee, group#member] or admin from privileged
    define can_delete: [user, role#assignee, group#member] or admin from privileged
    define can_edit: [user, role#assignee, group#member] or admin from privileged
    define can_view: [user, user:*, role#assignee, group#member] or admin from privileged
    define privileged: [privileged]

type scheme
  relations
    define can_create: [user, role#assignee, group#member] or admin from privileged
    define can_delete: [user, role#assignee, group#member] or admin from privileged
    define can_edit: [user, role#assignee, group#member] or admin from privileged
    define can_view: [user, user:*, role#assignee, group#member] or admin from privileged
    define privileged: [privileged]

type client
  relations
    define can_create: [user, role#assignee, group#member] or admin from privileged
    define can_delete: [user, role#assignee, group#member] or admin from privileged
    define can_edit: [user, role#assignee, group#member] or admin from privileged
    define can_view: [user, user:*, role#assignee, group#member] or admin from privileged
    define privileged: [privileged]

type provider
  relations
    define can_create: [user, role#assignee, group#member] or admin from privileged
    define can_delete: [user, role#assignee, group#member] or admin from privileged
    define can_edit: [user, role#assignee, group#member] or admin from privileged
    define can_view: [user, user:*, role#assignee, group#member] or admin from privileged
    define privileged: [privileged]

type rule
  relations
    define can_create: [user, role#assignee, group#member] or admin from privileged
    define can_delete: [user, role#assignee, group#member] or admin from privileged
    define can_edit: [user, role#assignee, group#member] or admin from privileged
    define can_view: [user, user:*, role#assignee, group#member] or admin from privileged
    define privileged: [privileged]

type application
  relations
    define can_create: [user, role#assignee, group#member] or admin from privileged
    define can_delete: [user, role#assignee, group#member] or admin from privileged
    define can_edit: [user, role#assignee, group#member] or admin from privileged
    define can_view: [user, user:*, role#assignee, group#member] or admin from privileged
    define privileged: [privileged]

Broken status API

When I navigate to the status page I get this response
image

In server throws this error every time a call is made to the status API:

http: superfluous response.WriteHeader call from go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp.(*respWriterWrapper).WriteHeader (wrap.go:98)

(The span.End is not deferred, but that's not what is causing this issue)

Refactor NewRouter function arguments

The NewRouter func is quite overloaded with parameters and following issue #221, not fit for purpose, we should bundle together arguments that belong to the same domain type, like external clients, and provide the function with composite config objects

Add basic entitlements to `privileged` OpenFGA user to allow real administrator/superuser privileges on all resources

When creating the authorization model in OpenFGA, populate the store with the following tuples to allow a newly run instance of admin ui to work without additional setup needed in OpenFGA.
This allows to have a "super user" from the get go.

  - user: privileged:superuser
    relation: privileged
    object: provider:global
  - user: privileged:superuser
    relation: privileged
    object: role:global
  - user: privileged:superuser
    relation: privileged
    object: group:global
  - user: privileged:superuser
    relation: privileged
    object: client:global
  - user: privileged:superuser
    relation: privileged
    object: identity:global
  - user: privileged:superuser
    relation: privileged
    object: scheme:global

List identities endpoint missing first page

Description

When reading the GET /api/v0/identities endpoints, the page=1 is requested from kratos. There is also a page=0, but there is no way to read it via the admin ui endpoint at the moment.

I'd expect to be able to read my own writes on identities endpoints. This is currently broken, as a created identity is not included in the response of a read request. See [1] and [2] below for examples.

Pagination is also broken for GET /api/v0/schemas in exactly the same way. This is another issue described in the comments of #44

[1] create identity request

curl -d '
{
  "credentials": {
    "oidc": {
      "config": {
        "config": {
          "hashed_password": "string",
          "password": "string"
        },
        "providers": [
          {
            "provider": "string",
            "subject": "string"
          }
        ]
      }
    },
    "password": {
      "config": {
        "hashed_password": "string",
        "password": "string"
      }
    }
  },
  "metadata_admin": null,
  "metadata_public": null,
  "recovery_addresses": [
    {
      "created_at": "2019-08-24T14:15:22Z",
      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
      "updated_at": "2019-08-24T14:15:22Z",
      "value": "string",
      "via": "string"
    }
  ],
  "schema_id": "social_user_v0",
  "state": "active",
  "traits": {"email": "[email protected]"},
  "verifiable_addresses": [
    {
      "created_at": "2014-01-01T23:28:56.782Z",
      "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
      "status": "string",
      "updated_at": "2014-01-01T23:28:56.782Z",
      "value": "string",
      "verified": true,
      "verified_at": "2019-08-24T14:15:22Z",
      "via": "email"
    }
  ]
}
' -X POST -H 'Content-Type: application/json' http://127.0.0.1:8000/api/v0/identities

[2] read identities, gives empty result

curl http://127.0.0.1:8000/api/v0/identities
{"data":[],"message":"List of identities","status":200,"_meta":{"page":1,"size":100}}

there is no way to read page 0, even if we specify it

curl http://127.0.0.1:8000/api/v0/identities?page=0
{"data":[],"message":"List of identities","status":200,"_meta":{"page":1,"size":100}}

request to kratos directly returns the identity on page 0

curl "http://127.0.0.1:4434/admin/identities?page=0&size=100"
[{"id":"079de71e-62eb-400a-bfbc-d6b77d04c290","schema_id":"social_user_v0","schema_url":"https://10.64.140.43/iam-kratos/schemas/c29jaWFsX3VzZXJfdjA","state":"active","state_changed_at":"2024-03-28T11:47:27.24283Z","traits":{"email":"[email protected]"},"metadata_public":null,"metadata_admin":null,"created_at":"2024-03-28T11:47:27.24456Z","updated_at":"2024-03-28T11:47:27.24456Z","organization_id":null}]

kratos does not include the identity on page 1:

curl "http://127.0.0.1:4434/admin/identities?page=1&size=100"
[]

Document OpenFGA setup and seeding

create a wiki page or a README section dumping all the information needed to setup and seed OpenFGA with valid data useable by the Groups and Roles API

use the draft below and enhance/make prettier


fetch MODEL_ID and STORE_ID from openfga server (the one running inside k8s should be perfect, if u have it running on docker fine as well), the following will pick the latest model from the first store (hopefully u dont have any more than that)

STORE_ID=$(fga --api-url http://127.0.0.1:8080 store list | jq '.stores[0].id' -r)                                                                         
MODEL_ID=$(fga --api-url http://127.0.0.1:8080 model list --store-id $STORE_ID | jq '.authorization_models[0].id' -r)

populate the model with data

fga --api-url http://127.0.0.1:8080 tuple write --model-id $MODEL_ID --store-id $STORE_ID --file openfga-tuples.yml

where openfga-tuples.yaml is

# tuples
- object: privileged:superuser
  user: user:johndoe
  relation: admin
- object: privileged:superuser
  user: user:shipperizer
  relation: admin
- object: role:administrator
  user: privileged:superuser
  relation: privileged
- object: role:administrator
  user: user:joe
  relation: assignee
- object: group:c-level
  user: user:joe
  relation: member
- object: group:c-level
  user: privileged:superuser
  relation: privileged
- object: identity:user-1
  user: privileged:superuser
  relation: privileged
- object: identity:user-2
  user: privileged:superuser
  relation: privileged
- object: scheme:identity-social
  user: privileged:superuser
  relation: privileged
- object: client:github-canonical
  user: privileged:superuser
  relation: privileged
- object: identity:user-1
  user: user:joe
  relation: can_delete
- object: client:github-canonical
  user: role:administrator#assignee
  relation: can_view
- object: client:okta
  user: role:administrator#assignee
  relation: can_delete
- object: client:github-canonical
  user: group:c-level#member
  relation: can_edit
- object: client:okta
  user: group:c-level#member
  relation: can_delete  
- object: client:okta
  user: group:c-level#member
  relation: can_view  
- object: client:okta
  user: group:c-level#member
  relation: can_edit    
- object: role:administrator
  user: group:c-level#member
  relation: assignee
- object: role:janitor
  user: group:c-level#member
  relation: assignee
#### global view  
- user: user:*
  relation: can_view
  object: provider:global
- user: user:*
  relation: can_view
  object: role:global
- user: user:*
  relation: can_view
  object: group:global
- user: user:*
  relation: can_view
  object: client:global
- user: user:*
  relation: can_view
  object: identity:global
- user: user:*
  relation: can_view
  object: scheme:global  

in terms of API (rudimentary) authorization this

- object: privileged:superuser
  user: user:shipperizer
  relation: admin

is what enables to get the full list of roles and groups as an admin user, what u do on the API is to set X-Authorization to a base64 encoded of the string "huw" or , no need for "user:"

shipperizer in ~/shipperizer/identity-platform-admin-ui on IAM-726 ● λ echo -n shipperizer | base64     
c2hpcHBlcml6ZXI=

PRIVILEGED_USER=c2hpcHBlcml6ZXI=
http :8000/api/v0/roles X-Authorization:$PRIVILEGED_USER
---

publish workflow syntax standardization

Description

Admin UI publish workflow has a different syntax to the one in Login UI

Aim is to standardize this and use the same boilerplate in here

Definition of Done

Admin UI workflow is the same as Login UI

Frontend pathing is broken

Frontend uses absolute paths for routing as well as for making calls to the backend API. This means that when the app is served behind a reverse proxy both the URLs used for routing and all calls to the backend do not work.

Bonus: Some api calls use an env var with an invalid path (https://github.com/canonical/identity-platform-admin-ui/blob/main/ui/src/api/client.tsx#L10) and some use a correct path that is hardcoded (https://github.com/canonical/identity-platform-admin-ui/blob/main/ui/src/api/identities.tsx#L9). It looks like that same is true for the rebac components (https://github.com/canonical/rebac-admin/blob/main/src/api/authentication/authentication.ts#L43)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.