feat: project v2beta resource API (#9742)

# Which Problems Are Solved

Resource management of projects and sub-resources was before limited by
the context provided by the management API, which would mean you could
only manage resources belonging to a specific organization.

# How the Problems Are Solved

With the addition of a resource-based API, it is now possible to manage
projects and sub-resources on the basis of the resources themselves,
which means that as long as you have the permission for the resource,
you can create, read, update and delete it.

- CreateProject to create a project under an organization
- UpdateProject to update an existing project
- DeleteProject to delete an existing project
- DeactivateProject and ActivateProject to change the status of a
project
- GetProject to query for a specific project with an identifier
- ListProject to query for projects and granted projects
- CreateProjectGrant to create a project grant with project and granted
organization
- UpdateProjectGrant to update the roles of a project grant
- DeactivateProjectGrant and ActivateProjectGrant to change the status
of a project grant
- DeleteProjectGrant to delete an existing project grant
- ListProjectGrants to query for project grants
- AddProjectRole to add a role to an existing project
- UpdateProjectRole to change texts of an existing role
- RemoveProjectRole to remove an existing role
- ListProjectRoles to query for project roles

# Additional Changes

- Changes to ListProjects, which now contains granted projects as well
- Changes to messages as defined in the
[API_DESIGN](https://github.com/zitadel/zitadel/blob/main/API_DESIGN.md)
- Permission checks for project functionality on query and command side
- Added testing to unit tests on command side
- Change update endpoints to no error returns if nothing changes in the
resource
- Changed all integration test utility to the new service
- ListProjects now also correctly lists `granted projects`
- Permission checks for project grant and project role functionality on
query and command side
- Change existing pre checks so that they also work resource specific
without resourceowner
- Added the resourceowner to the grant and role if no resourceowner is
provided
- Corrected import tests with project grants and roles
- Added testing to unit tests on command side
- Change update endpoints to no error returns if nothing changes in the
resource
- Changed all integration test utility to the new service
- Corrected some naming in the proto files to adhere to the API_DESIGN

# Additional Context

Closes #9177

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Stefan Benz
2025-05-21 14:40:47 +02:00
committed by GitHub
parent 6889d6a1da
commit 7eb45c6cfd
64 changed files with 9821 additions and 1037 deletions

View File

@@ -7,6 +7,7 @@ import (
"testing"
"time"
"github.com/brianvoe/gofakeit/v6"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/pkg/client"
@@ -24,8 +25,7 @@ import (
)
func TestServer_Introspect(t *testing.T) {
project, err := Instance.CreateProject(CTX)
require.NoError(t, err)
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
app, err := Instance.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), false)
require.NoError(t, err)
@@ -188,10 +188,8 @@ func assertIntrospection(
// with clients that have different authentication methods.
func TestServer_VerifyClient(t *testing.T) {
sessionID, sessionToken, startTime, changeTime := Instance.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
project, err := Instance.CreateProject(CTX)
require.NoError(t, err)
projectInactive, err := Instance.CreateProject(CTX)
require.NoError(t, err)
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
projectInactive := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
inactiveClient, err := Instance.CreateOIDCInactivateClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
require.NoError(t, err)

View File

@@ -421,21 +421,20 @@ type clientOpts struct {
func createClientWithOpts(t testing.TB, instance *integration.Instance, opts clientOpts) (clientID, projectID string) {
ctx := instance.WithAuthorization(CTX, integration.UserTypeOrgOwner)
project, err := instance.CreateProject(ctx)
require.NoError(t, err)
project := instance.CreateProject(ctx, t.(*testing.T), "", gofakeit.AppName(), false, false)
app, err := instance.CreateOIDCClientLoginVersion(ctx, opts.redirectURI, opts.logoutURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, opts.devMode, opts.LoginVersion)
require.NoError(t, err)
return app.GetClientId(), project.GetId()
}
func createImplicitClient(t testing.TB) string {
app, err := Instance.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit, nil)
app, err := Instance.CreateOIDCImplicitFlowClient(CTX, t.(*testing.T), redirectURIImplicit, nil)
require.NoError(t, err)
return app.GetClientId()
}
func createImplicitClientNoLoginClientHeader(t testing.TB) string {
app, err := Instance.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit, &app.LoginVersion{Version: &app.LoginVersion_LoginV2{LoginV2: &app.LoginV2{BaseUri: nil}}})
app, err := Instance.CreateOIDCImplicitFlowClient(CTX, t.(*testing.T), redirectURIImplicit, &app.LoginVersion{Version: &app.LoginVersion_LoginV2{LoginV2: &app.LoginV2{BaseUri: nil}}})
require.NoError(t, err)
return app.GetClientId()
}

View File

@@ -8,6 +8,7 @@ import (
"testing"
"time"
"github.com/brianvoe/gofakeit/v6"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/oidc/v3/pkg/client/rp"
@@ -21,8 +22,7 @@ import (
)
func TestServer_DeviceAuth(t *testing.T) {
project, err := Instance.CreateProject(CTX)
require.NoError(t, err)
project := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false)
client, err := Instance.CreateOIDCClient(CTX, redirectURI, logoutRedirectURI, project.GetId(), app.OIDCAppType_OIDC_APP_TYPE_NATIVE, app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE, false, app.OIDCGrantType_OIDC_GRANT_TYPE_DEVICE_CODE)
require.NoError(t, err)

View File

@@ -147,7 +147,7 @@ func TestServer_TokenExchange(t *testing.T) {
ctx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
userResp := instance.CreateHumanUser(ctx)
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx)
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx, t)
require.NoError(t, err)
signer, err := rp.SignerFromKeyFile(keyData)()
require.NoError(t, err)
@@ -371,7 +371,7 @@ func TestServer_TokenExchangeImpersonation(t *testing.T) {
setTokenExchangeFeature(t, instance, true)
setImpersonationPolicy(t, instance, true)
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx)
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx, t)
require.NoError(t, err)
signer, err := rp.SignerFromKeyFile(keyData)()
require.NoError(t, err)
@@ -591,7 +591,7 @@ func TestImpersonation_API_Call(t *testing.T) {
instance := integration.NewInstance(CTX)
ctx := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx)
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx, t)
require.NoError(t, err)
signer, err := rp.SignerFromKeyFile(keyData)()
require.NoError(t, err)

View File

@@ -309,9 +309,7 @@ func TestServer_UserInfo_Issue6662(t *testing.T) {
roleBar = "bar"
)
project, err := Instance.CreateProject(CTX)
projectID := project.GetId()
require.NoError(t, err)
projectID := Instance.CreateProject(CTX, t, "", gofakeit.AppName(), false, false).GetId()
user, _, clientID, clientSecret, err := Instance.CreateOIDCCredentialsClient(CTX)
require.NoError(t, err)
addProjectRolesGrants(t, user.GetUserId(), projectID, roleFoo, roleBar)