mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-07-15 21:48:13 +03:00
feat: add description field to oidc clients (#1547)
Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
|
|||||||
type OidcClientMetaDataDto struct {
|
type OidcClientMetaDataDto struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
HasLogo bool `json:"hasLogo"`
|
HasLogo bool `json:"hasLogo"`
|
||||||
HasDarkLogo bool `json:"hasDarkLogo"`
|
HasDarkLogo bool `json:"hasDarkLogo"`
|
||||||
LaunchURL *string `json:"launchURL"`
|
LaunchURL *string `json:"launchURL"`
|
||||||
@@ -36,6 +37,7 @@ type OidcClientWithAllowedGroupsCountDto struct {
|
|||||||
|
|
||||||
type OidcClientUpdateDto struct {
|
type OidcClientUpdateDto struct {
|
||||||
Name string `json:"name" binding:"required,max=50" unorm:"nfc"`
|
Name string `json:"name" binding:"required,max=50" unorm:"nfc"`
|
||||||
|
Description string `json:"description" binding:"omitempty,max=150" unorm:"nfc"`
|
||||||
CallbackURLs []string `json:"callbackURLs" binding:"omitempty,dive,callback_url_pattern"`
|
CallbackURLs []string `json:"callbackURLs" binding:"omitempty,dive,callback_url_pattern"`
|
||||||
LogoutCallbackURLs []string `json:"logoutCallbackURLs" binding:"omitempty,dive,callback_url_pattern"`
|
LogoutCallbackURLs []string `json:"logoutCallbackURLs" binding:"omitempty,dive,callback_url_pattern"`
|
||||||
IsPublic bool `json:"isPublic"`
|
IsPublic bool `json:"isPublic"`
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type OidcClient struct {
|
|||||||
Base
|
Base
|
||||||
|
|
||||||
Name string `sortable:"true"`
|
Name string `sortable:"true"`
|
||||||
|
Description string
|
||||||
Secret string
|
Secret string
|
||||||
CallbackURLs UrlList
|
CallbackURLs UrlList
|
||||||
LogoutCallbackURLs UrlList
|
LogoutCallbackURLs UrlList
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
|
|||||||
ID: "3654a746-35d4-4321-ac61-0bdcff2b4055",
|
ID: "3654a746-35d4-4321-ac61-0bdcff2b4055",
|
||||||
},
|
},
|
||||||
Name: "Nextcloud",
|
Name: "Nextcloud",
|
||||||
|
Description: "This is an example description for Nextcloud",
|
||||||
LaunchURL: new("https://nextcloud.local"),
|
LaunchURL: new("https://nextcloud.local"),
|
||||||
Secret: "$2a$10$9dypwot8nGuCjT6wQWWpJOckZfRprhe2EkwpKizxS/fpVHrOLEJHC", // w2mUeZISmEvIDMEDvpY0PnxQIpj1m3zY
|
Secret: "$2a$10$9dypwot8nGuCjT6wQWWpJOckZfRprhe2EkwpKizxS/fpVHrOLEJHC", // w2mUeZISmEvIDMEDvpY0PnxQIpj1m3zY
|
||||||
CallbackURLs: model.UrlList{"http://nextcloud.localhost/auth/callback"},
|
CallbackURLs: model.UrlList{"http://nextcloud.localhost/auth/callback"},
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ func (s *OidcService) UpdateClient(ctx context.Context, clientID string, input d
|
|||||||
func updateOIDCClientModelFromDto(client *model.OidcClient, input *dto.OidcClientUpdateDto) {
|
func updateOIDCClientModelFromDto(client *model.OidcClient, input *dto.OidcClientUpdateDto) {
|
||||||
// Base fields
|
// Base fields
|
||||||
client.Name = input.Name
|
client.Name = input.Name
|
||||||
|
client.Description = input.Description
|
||||||
client.CallbackURLs = input.CallbackURLs
|
client.CallbackURLs = input.CallbackURLs
|
||||||
client.LogoutCallbackURLs = input.LogoutCallbackURLs
|
client.LogoutCallbackURLs = input.LogoutCallbackURLs
|
||||||
client.IsPublic = input.IsPublic
|
client.IsPublic = input.IsPublic
|
||||||
@@ -594,16 +595,16 @@ func (s *OidcService) ListAccessibleOidcClients(ctx context.Context, userID stri
|
|||||||
// If user has no groups, only return clients with no allowed user groups
|
// If user has no groups, only return clients with no allowed user groups
|
||||||
if len(userGroupIDs) == 0 {
|
if len(userGroupIDs) == 0 {
|
||||||
query = query.Where(`NOT EXISTS (
|
query = query.Where(`NOT EXISTS (
|
||||||
SELECT 1 FROM oidc_clients_allowed_user_groups
|
SELECT 1 FROM oidc_clients_allowed_user_groups
|
||||||
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id)`)
|
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id)`)
|
||||||
} else {
|
} else {
|
||||||
query = query.Where(`
|
query = query.Where(`
|
||||||
NOT EXISTS (
|
NOT EXISTS (
|
||||||
SELECT 1 FROM oidc_clients_allowed_user_groups
|
SELECT 1 FROM oidc_clients_allowed_user_groups
|
||||||
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id
|
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id
|
||||||
) OR EXISTS (
|
) OR EXISTS (
|
||||||
SELECT 1 FROM oidc_clients_allowed_user_groups
|
SELECT 1 FROM oidc_clients_allowed_user_groups
|
||||||
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id
|
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id
|
||||||
AND oidc_clients_allowed_user_groups.user_group_id IN (?))`, userGroupIDs)
|
AND oidc_clients_allowed_user_groups.user_group_id IN (?))`, userGroupIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,6 +633,7 @@ func (s *OidcService) ListAccessibleOidcClients(ctx context.Context, userID stri
|
|||||||
OidcClientMetaDataDto: dto.OidcClientMetaDataDto{
|
OidcClientMetaDataDto: dto.OidcClientMetaDataDto{
|
||||||
ID: client.ID,
|
ID: client.ID,
|
||||||
Name: client.Name,
|
Name: client.Name,
|
||||||
|
Description: client.Description,
|
||||||
LaunchURL: client.LaunchURL,
|
LaunchURL: client.LaunchURL,
|
||||||
HasLogo: client.HasLogo(),
|
HasLogo: client.HasLogo(),
|
||||||
HasDarkLogo: client.HasDarkLogo(),
|
HasDarkLogo: client.HasDarkLogo(),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/common"
|
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/dto"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/model"
|
"github.com/pocket-id/pocket-id/backend/internal/model"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/storage"
|
"github.com/pocket-id/pocket-id/backend/internal/storage"
|
||||||
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
||||||
@@ -449,3 +450,91 @@ func TestOidcService_downloadAndSaveLogoFromURL(t *testing.T) {
|
|||||||
require.ErrorContains(t, err, "failed to look up client")
|
require.ErrorContains(t, err, "failed to look up client")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOidcService_CreateClient_withDescription(t *testing.T) {
|
||||||
|
db := testutils.NewDatabaseForTest(t)
|
||||||
|
|
||||||
|
s, err := NewOidcService(db, nil, nil, nil, nil, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
description := "A test client description"
|
||||||
|
input := dto.OidcClientCreateDto{
|
||||||
|
OidcClientUpdateDto: dto.OidcClientUpdateDto{
|
||||||
|
Name: "Test Client",
|
||||||
|
Description: description,
|
||||||
|
CallbackURLs: []string{"https://example.com/callback"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := s.CreateClient(t.Context(), input, "user-id")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var fetched model.OidcClient
|
||||||
|
err = db.First(&fetched, "id = ?", client.ID).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, fetched.Description)
|
||||||
|
assert.Equal(t, description, fetched.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOidcService_CreateClient_withoutDescription(t *testing.T) {
|
||||||
|
db := testutils.NewDatabaseForTest(t)
|
||||||
|
|
||||||
|
s, err := NewOidcService(db, nil, nil, nil, nil, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
input := dto.OidcClientCreateDto{
|
||||||
|
OidcClientUpdateDto: dto.OidcClientUpdateDto{
|
||||||
|
Name: "Test Client",
|
||||||
|
CallbackURLs: []string{"https://example.com/callback"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := s.CreateClient(t.Context(), input, "user-id")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var fetched model.OidcClient
|
||||||
|
err = db.First(&fetched, "id = ?", client.ID).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Empty(t, fetched.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOidcService_UpdateClient_description(t *testing.T) {
|
||||||
|
db := testutils.NewDatabaseForTest(t)
|
||||||
|
|
||||||
|
s, err := NewOidcService(db, nil, nil, nil, nil, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Create a client without a description
|
||||||
|
client := model.OidcClient{
|
||||||
|
Name: "Test Client",
|
||||||
|
CallbackURLs: model.UrlList{"https://example.com/callback"},
|
||||||
|
}
|
||||||
|
err = db.Create(&client).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Update with a description
|
||||||
|
description := "Updated description"
|
||||||
|
input := dto.OidcClientUpdateDto{
|
||||||
|
Name: "Test Client",
|
||||||
|
Description: description,
|
||||||
|
CallbackURLs: []string{"https://example.com/callback"},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.UpdateClient(t.Context(), client.ID, input)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var fetched model.OidcClient
|
||||||
|
err = db.First(&fetched, "id = ?", client.ID).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, fetched.Description)
|
||||||
|
assert.Equal(t, description, fetched.Description)
|
||||||
|
|
||||||
|
// Update to clear the description
|
||||||
|
input.Description = ""
|
||||||
|
_, err = s.UpdateClient(t.Context(), client.ID, input)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = db.First(&fetched, "id = ?", client.ID).Error
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Empty(t, fetched.Description)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE oidc_clients DROP COLUMN description;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE oidc_clients ADD COLUMN description TEXT NOT NULL DEFAULT '';
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE oidc_clients DROP COLUMN description;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE oidc_clients ADD COLUMN description TEXT NOT NULL DEFAULT '';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
@@ -455,6 +455,8 @@
|
|||||||
"client_launch_url": "Client Launch URL",
|
"client_launch_url": "Client Launch URL",
|
||||||
"client_launch_url_description": "The URL that will be opened when a user launches the app from the My Apps page.",
|
"client_launch_url_description": "The URL that will be opened when a user launches the app from the My Apps page.",
|
||||||
"client_name_description": "The name of the client that shows in the Pocket ID UI.",
|
"client_name_description": "The name of the client that shows in the Pocket ID UI.",
|
||||||
|
"client_description": "Description",
|
||||||
|
"client_description_description": "An optional description of the client that shows in the Pocket ID UI.",
|
||||||
"revoke_access": "Revoke Access",
|
"revoke_access": "Revoke Access",
|
||||||
"revoke_access_description": "Revoke access to <b>{clientName}</b>. <b>{clientName}</b> will no longer be able to access your account information.",
|
"revoke_access_description": "Revoke access to <b>{clientName}</b>. <b>{clientName}</b> will no longer be able to access your account information.",
|
||||||
"revoke_access_successful": "The access to {clientName} has been successfully revoked.",
|
"revoke_access_successful": "The access to {clientName} has been successfully revoked.",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { UserGroup } from './user-group.type';
|
|||||||
export type OidcClientMetaData = {
|
export type OidcClientMetaData = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
description: string;
|
||||||
hasLogo: boolean;
|
hasLogo: boolean;
|
||||||
hasDarkLogo: boolean;
|
hasDarkLogo: boolean;
|
||||||
requiresReauthentication: boolean;
|
requiresReauthentication: boolean;
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
const client = {
|
const client = {
|
||||||
id: '',
|
id: '',
|
||||||
name: existingClient?.name || '',
|
name: existingClient?.name || '',
|
||||||
|
description: existingClient?.description || '',
|
||||||
callbackURLs: existingClient?.callbackURLs || [],
|
callbackURLs: existingClient?.callbackURLs || [],
|
||||||
logoutCallbackURLs: existingClient?.logoutCallbackURLs || [],
|
logoutCallbackURLs: existingClient?.logoutCallbackURLs || [],
|
||||||
isPublic: existingClient?.isPublic || false,
|
isPublic: existingClient?.isPublic || false,
|
||||||
@@ -73,6 +74,7 @@
|
|||||||
.optional()
|
.optional()
|
||||||
),
|
),
|
||||||
name: z.string().min(2).max(50),
|
name: z.string().min(2).max(50),
|
||||||
|
description: z.string().max(150),
|
||||||
callbackURLs: z.array(callbackUrlSchema).default([]),
|
callbackURLs: z.array(callbackUrlSchema).default([]),
|
||||||
logoutCallbackURLs: z.array(callbackUrlSchema).default([]),
|
logoutCallbackURLs: z.array(callbackUrlSchema).default([]),
|
||||||
isPublic: z.boolean(),
|
isPublic: z.boolean(),
|
||||||
@@ -186,6 +188,12 @@
|
|||||||
description={m.client_name_description()}
|
description={m.client_name_description()}
|
||||||
bind:input={$inputs.name}
|
bind:input={$inputs.name}
|
||||||
/>
|
/>
|
||||||
|
<FormInput
|
||||||
|
label={m.client_description()}
|
||||||
|
class="w-full"
|
||||||
|
description={m.client_description_description()}
|
||||||
|
bind:input={$inputs.description}
|
||||||
|
/>
|
||||||
<FormInput
|
<FormInput
|
||||||
label={m.client_launch_url()}
|
label={m.client_launch_url()}
|
||||||
description={m.client_launch_url_description()}
|
description={m.client_launch_url_description()}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card.Root
|
<Card.Root
|
||||||
class="border-muted group relative h-[140px] p-5 transition-all duration-200 hover:shadow-md sm:max-w-[50vw] md:max-w-[400px]"
|
class="border-muted group relative h-[160px] p-5 transition-all duration-200 hover:shadow-md sm:max-w-[50vw] md:max-w-[400px]"
|
||||||
data-testid="authorized-oidc-client-card"
|
data-testid="authorized-oidc-client-card"
|
||||||
>
|
>
|
||||||
<Card.Content class=" p-0">
|
<Card.Content class=" p-0">
|
||||||
@@ -46,21 +46,28 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex w-full justify-between gap-3">
|
<div class="flex w-full justify-between gap-3">
|
||||||
<div>
|
<div class="h-20">
|
||||||
<div class="mb-1 flex items-start gap-2">
|
<div class="mb-1 flex items-start gap-2">
|
||||||
<h3
|
<h3
|
||||||
class="text-foreground line-clamp-2 leading-tight font-semibold break-words break-all text-ellipsis"
|
class="text-foreground line-clamp-2 leading-tight font-semibold wrap-break-word break-all text-ellipsis"
|
||||||
>
|
>
|
||||||
{client.name}
|
{client.name}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
{#if client.launchURL}
|
{#if client.launchURL}
|
||||||
<p
|
<p
|
||||||
class="text-muted-foreground line-clamp-1 text-xs break-words break-all text-ellipsis"
|
class="text-muted-foreground line-clamp-1 text-xs wrap-break-word break-all text-ellipsis"
|
||||||
>
|
>
|
||||||
{new URL(client.launchURL).hostname}
|
{new URL(client.launchURL).hostname}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if client.description}
|
||||||
|
<p
|
||||||
|
class="text-muted-foreground line-clamp-3 wrap-break-word text-ellipsis text-xs mt-1"
|
||||||
|
>
|
||||||
|
{client.description}
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if $userStore?.isAdmin || client.lastUsedAt}
|
{#if $userStore?.isAdmin || client.lastUsedAt}
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ export const oidcClients = {
|
|||||||
},
|
},
|
||||||
pingvinShare: {
|
pingvinShare: {
|
||||||
name: 'Pingvin Share',
|
name: 'Pingvin Share',
|
||||||
|
description: 'Self-hosted file sharing platform',
|
||||||
callbackUrl: 'http://pingvin-share.localhost/auth/callback',
|
callbackUrl: 'http://pingvin-share.localhost/auth/callback',
|
||||||
secondCallbackUrl: 'http://pingvin-share.localhost/auth/callback2',
|
secondCallbackUrl: 'http://pingvin-share.localhost/auth/callback2',
|
||||||
launchURL: 'https://pingvin-share.local'
|
launchURL: 'https://pingvin-share.local'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"provider": "sqlite",
|
"provider": "sqlite",
|
||||||
"version": 20260707170000,
|
"version": 20260708120000,
|
||||||
"tableOrder": ["users", "user_groups", "oidc_clients", "signup_tokens", "apis", "api_permissions", "oidc_clients_allowed_api_permissions"],
|
"tableOrder": ["users", "user_groups", "oidc_clients", "signup_tokens", "apis", "api_permissions", "oidc_clients_allowed_api_permissions"],
|
||||||
"tables": {
|
"tables": {
|
||||||
"apis": [
|
"apis": [
|
||||||
@@ -92,6 +92,7 @@
|
|||||||
"launch_url": "https://nextcloud.local",
|
"launch_url": "https://nextcloud.local",
|
||||||
"logout_callback_urls": "WyJodHRwOi8vbmV4dGNsb3VkLmxvY2FsaG9zdC9hdXRoL2xvZ291dC9jYWxsYmFjayJd",
|
"logout_callback_urls": "WyJodHRwOi8vbmV4dGNsb3VkLmxvY2FsaG9zdC9hdXRoL2xvZ291dC9jYWxsYmFjayJd",
|
||||||
"name": "Nextcloud",
|
"name": "Nextcloud",
|
||||||
|
"description": "This is an example description for Nextcloud",
|
||||||
"pkce_enabled": false,
|
"pkce_enabled": false,
|
||||||
"pkce_supported": false,
|
"pkce_supported": false,
|
||||||
"requires_pushed_authorization_requests": false,
|
"requires_pushed_authorization_requests": false,
|
||||||
@@ -112,6 +113,7 @@
|
|||||||
"launch_url": null,
|
"launch_url": null,
|
||||||
"logout_callback_urls": "bnVsbA==",
|
"logout_callback_urls": "bnVsbA==",
|
||||||
"name": "Immich",
|
"name": "Immich",
|
||||||
|
"description": "",
|
||||||
"pkce_enabled": false,
|
"pkce_enabled": false,
|
||||||
"pkce_supported": false,
|
"pkce_supported": false,
|
||||||
"requires_pushed_authorization_requests": false,
|
"requires_pushed_authorization_requests": false,
|
||||||
@@ -132,6 +134,7 @@
|
|||||||
"launch_url": null,
|
"launch_url": null,
|
||||||
"logout_callback_urls": "WyJodHRwOi8vdGFpbHNjYWxlLmxvY2FsaG9zdC9hdXRoL2xvZ291dC9jYWxsYmFjayJd",
|
"logout_callback_urls": "WyJodHRwOi8vdGFpbHNjYWxlLmxvY2FsaG9zdC9hdXRoL2xvZ291dC9jYWxsYmFjayJd",
|
||||||
"name": "Tailscale",
|
"name": "Tailscale",
|
||||||
|
"description": "",
|
||||||
"pkce_enabled": false,
|
"pkce_enabled": false,
|
||||||
"pkce_supported": false,
|
"pkce_supported": false,
|
||||||
"requires_pushed_authorization_requests": false,
|
"requires_pushed_authorization_requests": false,
|
||||||
@@ -152,6 +155,7 @@
|
|||||||
"launch_url": null,
|
"launch_url": null,
|
||||||
"logout_callback_urls": "bnVsbA==",
|
"logout_callback_urls": "bnVsbA==",
|
||||||
"name": "Federated",
|
"name": "Federated",
|
||||||
|
"description": "",
|
||||||
"pkce_enabled": false,
|
"pkce_enabled": false,
|
||||||
"pkce_supported": false,
|
"pkce_supported": false,
|
||||||
"requires_pushed_authorization_requests": false,
|
"requires_pushed_authorization_requests": false,
|
||||||
@@ -171,6 +175,7 @@
|
|||||||
"launch_url": null,
|
"launch_url": null,
|
||||||
"logout_callback_urls": "bnVsbA==",
|
"logout_callback_urls": "bnVsbA==",
|
||||||
"name": "SCIM Client",
|
"name": "SCIM Client",
|
||||||
|
"description": "",
|
||||||
"pkce_enabled": false,
|
"pkce_enabled": false,
|
||||||
"pkce_supported": false,
|
"pkce_supported": false,
|
||||||
"requires_pushed_authorization_requests": false,
|
"requires_pushed_authorization_requests": false,
|
||||||
@@ -191,6 +196,7 @@
|
|||||||
"launch_url": null,
|
"launch_url": null,
|
||||||
"logout_callback_urls": "bnVsbA==",
|
"logout_callback_urls": "bnVsbA==",
|
||||||
"name": "PAR Test Client",
|
"name": "PAR Test Client",
|
||||||
|
"description": "",
|
||||||
"pkce_enabled": false,
|
"pkce_enabled": false,
|
||||||
"pkce_supported": false,
|
"pkce_supported": false,
|
||||||
"requires_pushed_authorization_requests": false,
|
"requires_pushed_authorization_requests": false,
|
||||||
@@ -211,6 +217,7 @@
|
|||||||
"launch_url": null,
|
"launch_url": null,
|
||||||
"logout_callback_urls": "bnVsbA==",
|
"logout_callback_urls": "bnVsbA==",
|
||||||
"name": "Skip Consent Client",
|
"name": "Skip Consent Client",
|
||||||
|
"description": "",
|
||||||
"pkce_enabled": false,
|
"pkce_enabled": false,
|
||||||
"pkce_supported": false,
|
"pkce_supported": false,
|
||||||
"requires_pushed_authorization_requests": false,
|
"requires_pushed_authorization_requests": false,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ test.describe('Create OIDC client', () => {
|
|||||||
await page.getByRole('button', { name: 'Add OIDC Client' }).click();
|
await page.getByRole('button', { name: 'Add OIDC Client' }).click();
|
||||||
|
|
||||||
await page.getByLabel('Name').fill(oidcClient.name);
|
await page.getByLabel('Name').fill(oidcClient.name);
|
||||||
|
await page.getByLabel('Description').fill(oidcClient.description);
|
||||||
await page.getByLabel('Client Launch URL').fill(oidcClient.launchURL);
|
await page.getByLabel('Client Launch URL').fill(oidcClient.launchURL);
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Add' }).first().click();
|
await page.getByRole('button', { name: 'Add' }).first().click();
|
||||||
@@ -47,6 +48,7 @@ test.describe('Create OIDC client', () => {
|
|||||||
expect(clientSecret).toMatch(/^\w{32}$/);
|
expect(clientSecret).toMatch(/^\w{32}$/);
|
||||||
|
|
||||||
await expect(page.getByLabel('Name')).toHaveValue(oidcClient.name);
|
await expect(page.getByLabel('Name')).toHaveValue(oidcClient.name);
|
||||||
|
await expect(page.getByLabel('Description')).toHaveValue(oidcClient.description);
|
||||||
await expect(page.getByTestId('callback-url-1')).toHaveValue(oidcClient.callbackUrl);
|
await expect(page.getByTestId('callback-url-1')).toHaveValue(oidcClient.callbackUrl);
|
||||||
await expect(page.getByTestId('callback-url-2')).toHaveValue(oidcClient.secondCallbackUrl);
|
await expect(page.getByTestId('callback-url-2')).toHaveValue(oidcClient.secondCallbackUrl);
|
||||||
await expect(page.getByRole('img', { name: `${oidcClient.name} logo` }).first()).toBeVisible();
|
await expect(page.getByRole('img', { name: `${oidcClient.name} logo` }).first()).toBeVisible();
|
||||||
@@ -69,6 +71,7 @@ test('Edit OIDC client', async ({ page }) => {
|
|||||||
await page.goto(`/settings/admin/oidc-clients/${oidcClient.id}`);
|
await page.goto(`/settings/admin/oidc-clients/${oidcClient.id}`);
|
||||||
|
|
||||||
await page.getByLabel('Name').fill('Nextcloud updated');
|
await page.getByLabel('Name').fill('Nextcloud updated');
|
||||||
|
await page.getByLabel('Description').fill('Updated description');
|
||||||
await page.getByTestId('callback-url-1').first().fill('http://nextcloud-updated/auth/callback');
|
await page.getByTestId('callback-url-1').first().fill('http://nextcloud-updated/auth/callback');
|
||||||
await page.locator('[role="tab"][data-value="light-logo"]').first().click();
|
await page.locator('[role="tab"][data-value="light-logo"]').first().click();
|
||||||
await page.setInputFiles('#oidc-client-logo-light', 'resources/images/cloud-logo.png');
|
await page.setInputFiles('#oidc-client-logo-light', 'resources/images/cloud-logo.png');
|
||||||
|
|||||||
Reference in New Issue
Block a user