diff --git a/pkg/server/api/connect/v1/schema.graphql b/pkg/server/api/connect/v1/schema.graphql index 4980573f6..6e4d9d4a0 100644 --- a/pkg/server/api/connect/v1/schema.graphql +++ b/pkg/server/api/connect/v1/schema.graphql @@ -250,6 +250,7 @@ type Organization implements Node { ): SAMLConfigurationConnection @goField(forceResolver: true) scimConfiguration: SCIMConfiguration @goField(forceResolver: true) + googleWorkspaceOAuth2Scopes: [String!]! @goField(forceResolver: true) auditLogEntries( first: Int diff --git a/pkg/server/api/connect/v1/v1_resolver.go b/pkg/server/api/connect/v1/v1_resolver.go index 23d6b6b6e..49457e800 100644 --- a/pkg/server/api/connect/v1/v1_resolver.go +++ b/pkg/server/api/connect/v1/v1_resolver.go @@ -18,6 +18,7 @@ import ( "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/iam" + "go.probo.inc/probo/pkg/iam/scim/bridge/provider/googleworkspace" "go.probo.inc/probo/pkg/mail" "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/server/api/authn" @@ -1333,6 +1334,11 @@ func (r *organizationResolver) ScimConfiguration(ctx context.Context, obj *types return types.NewSCIMConfiguration(config), nil } +// GoogleWorkspaceOAuth2Scopes is the resolver for the googleWorkspaceOAuth2Scopes field. +func (r *organizationResolver) GoogleWorkspaceOAuth2Scopes(ctx context.Context, obj *types.Organization) ([]string, error) { + return googleworkspace.OAuth2Scopes, nil +} + // AuditLogEntries is the resolver for the auditLogEntries field. func (r *organizationResolver) AuditLogEntries(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditLogEntryOrderBy, filter *types.AuditLogEntryFilter) (*types.AuditLogEntryConnection, error) { if err := r.authorize(ctx, obj.ID, iam.ActionAuditLogEntryList); err != nil { diff --git a/pkg/server/api/console/v1/schema.graphql b/pkg/server/api/console/v1/schema.graphql index 45960d734..badc3ce95 100644 --- a/pkg/server/api/console/v1/schema.graphql +++ b/pkg/server/api/console/v1/schema.graphql @@ -1908,6 +1908,7 @@ type Organization implements Node { last: Int before: CursorKey ): SlackConnectionConnection! @goField(forceResolver: true) + slackOAuth2Scopes: [String!]! @goField(forceResolver: true) connectors(filter: ConnectorFilter): [Connector!]! @goField(forceResolver: true) connectorProviderInfos: [ConnectorProviderInfo!]! @goField(forceResolver: true) @@ -2166,6 +2167,7 @@ type ConnectorProviderInfo { oauthConfigured: Boolean! apiKeySupported: Boolean! clientCredentialsSupported: Boolean! + oauth2Scopes: [String!]! extraSettings: [ConnectorProviderSettingInfo!]! } @@ -6802,6 +6804,7 @@ type AccessSource implements Node { needsConfiguration: Boolean! @goField(forceResolver: true) connectionStatus: AccessSourceConnectionStatus! @goField(forceResolver: true) selectedOrganization: String @goField(forceResolver: true) + oauth2Scopes: [String!]! @goField(forceResolver: true) createdAt: Datetime! updatedAt: Datetime! diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index fd9d25d06..4c9559be3 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -18,6 +18,7 @@ import ( "github.com/vikstrous/dataloadgen" "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/accessreview" + "go.probo.inc/probo/pkg/accessreview/drivers" "go.probo.inc/probo/pkg/connector" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" @@ -31,6 +32,7 @@ import ( "go.probo.inc/probo/pkg/server/api/console/v1/types" "go.probo.inc/probo/pkg/server/gqlutils" "go.probo.inc/probo/pkg/server/gqlutils/types/cursor" + "go.probo.inc/probo/pkg/slack" "go.probo.inc/probo/pkg/validator" ) @@ -520,6 +522,30 @@ func (r *accessSourceResolver) SelectedOrganization(ctx context.Context, obj *ty return nil, nil } +// Oauth2Scopes is the resolver for the oauth2Scopes field. +func (r *accessSourceResolver) Oauth2Scopes(ctx context.Context, obj *types.AccessSource) ([]string, error) { + if obj.ConnectorID == nil { + return []string{}, nil + } + + prb := r.ProboService(ctx, obj.ID.TenantID()) + + dbConnector, err := prb.Connectors.Get(ctx, *obj.ConnectorID) + if err != nil { + if errors.Is(err, coredata.ErrResourceNotFound) { + return []string{}, nil + } + r.logger.ErrorCtx(ctx, "cannot get connector for oauth2 scopes", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } + + scopes := drivers.ProviderOAuth2Scopes(dbConnector.Provider) + if scopes == nil { + return []string{}, nil + } + return scopes, nil +} + // Permission is the resolver for the permission field. func (r *accessSourceResolver) Permission(ctx context.Context, obj *types.AccessSource, action string) (bool, error) { return r.Resolver.Permission(ctx, obj, action) @@ -8280,6 +8306,11 @@ func (r *organizationResolver) SlackConnections(ctx context.Context, obj *types. return types.NewSlackConnectionConnection(page), nil } +// SlackOAuth2Scopes is the resolver for the slackOAuth2Scopes field. +func (r *organizationResolver) SlackOAuth2Scopes(ctx context.Context, obj *types.Organization) ([]string, error) { + return slack.OAuth2Scopes, nil +} + // Connectors is the resolver for the connectors field. func (r *organizationResolver) Connectors(ctx context.Context, obj *types.Organization, filter *types.ConnectorFilter) ([]*types.Connector, error) { if err := r.authorize(ctx, obj.ID, probo.ActionConnectorList); err != nil { @@ -8320,12 +8351,17 @@ func (r *organizationResolver) ConnectorProviderInfos(ctx context.Context, obj * var infos []*types.ConnectorProviderInfo for _, provider := range coredata.ConnectorProviders() { _, oauthErr := r.connectorRegistry.Get(string(provider)) + scopes := drivers.ProviderOAuth2Scopes(provider) + if scopes == nil { + scopes = []string{} + } info := &types.ConnectorProviderInfo{ Provider: provider, DisplayName: providerDisplayName(provider), OauthConfigured: oauthErr == nil, APIKeySupported: providerSupportsAPIKey(provider), ClientCredentialsSupported: providerSupportsClientCredentials(provider), + Oauth2Scopes: scopes, ExtraSettings: providerExtraSettings(provider), } infos = append(infos, info)