mirror of
https://github.com/pocket-id/pocket-id.git
synced 2025-12-23 17:25:22 +03:00
Compare commits
1 Commits
main
...
feat/user-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f61c784988 |
@@ -18,6 +18,7 @@ type OidcClientDto struct {
|
|||||||
IsPublic bool `json:"isPublic"`
|
IsPublic bool `json:"isPublic"`
|
||||||
PkceEnabled bool `json:"pkceEnabled"`
|
PkceEnabled bool `json:"pkceEnabled"`
|
||||||
Credentials OidcClientCredentialsDto `json:"credentials"`
|
Credentials OidcClientCredentialsDto `json:"credentials"`
|
||||||
|
IsGroupRestricted bool `json:"isGroupRestricted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OidcClientWithAllowedUserGroupsDto struct {
|
type OidcClientWithAllowedUserGroupsDto struct {
|
||||||
@@ -43,6 +44,7 @@ type OidcClientUpdateDto struct {
|
|||||||
HasDarkLogo bool `json:"hasDarkLogo"`
|
HasDarkLogo bool `json:"hasDarkLogo"`
|
||||||
LogoURL *string `json:"logoUrl"`
|
LogoURL *string `json:"logoUrl"`
|
||||||
DarkLogoURL *string `json:"darkLogoUrl"`
|
DarkLogoURL *string `json:"darkLogoUrl"`
|
||||||
|
IsGroupRestricted bool `json:"isGroupRestricted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OidcClientCreateDto struct {
|
type OidcClientCreateDto struct {
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ type OidcClient struct {
|
|||||||
RequiresReauthentication bool `sortable:"true" filterable:"true"`
|
RequiresReauthentication bool `sortable:"true" filterable:"true"`
|
||||||
Credentials OidcClientCredentials
|
Credentials OidcClientCredentials
|
||||||
LaunchURL *string
|
LaunchURL *string
|
||||||
|
IsGroupRestricted bool
|
||||||
|
|
||||||
AllowedUserGroups []UserGroup `gorm:"many2many:oidc_clients_allowed_user_groups;"`
|
AllowedUserGroups []UserGroup `gorm:"many2many:oidc_clients_allowed_user_groups;"`
|
||||||
CreatedByID *string
|
CreatedByID *string
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ func (s *OidcService) hasAuthorizedClientInternal(ctx context.Context, clientID,
|
|||||||
|
|
||||||
// IsUserGroupAllowedToAuthorize checks if the user group of the user is allowed to authorize the client
|
// IsUserGroupAllowedToAuthorize checks if the user group of the user is allowed to authorize the client
|
||||||
func (s *OidcService) IsUserGroupAllowedToAuthorize(user model.User, client model.OidcClient) bool {
|
func (s *OidcService) IsUserGroupAllowedToAuthorize(user model.User, client model.OidcClient) bool {
|
||||||
if len(client.AllowedUserGroups) == 0 {
|
if !client.IsGroupRestricted {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -816,6 +816,7 @@ func updateOIDCClientModelFromDto(client *model.OidcClient, input *dto.OidcClien
|
|||||||
client.PkceEnabled = input.IsPublic || input.PkceEnabled
|
client.PkceEnabled = input.IsPublic || input.PkceEnabled
|
||||||
client.RequiresReauthentication = input.RequiresReauthentication
|
client.RequiresReauthentication = input.RequiresReauthentication
|
||||||
client.LaunchURL = input.LaunchURL
|
client.LaunchURL = input.LaunchURL
|
||||||
|
client.IsGroupRestricted = input.IsGroupRestricted
|
||||||
|
|
||||||
// Credentials
|
// Credentials
|
||||||
client.Credentials.FederatedIdentities = make([]model.OidcClientFederatedIdentity, len(input.Credentials.FederatedIdentities))
|
client.Credentials.FederatedIdentities = make([]model.OidcClientFederatedIdentity, len(input.Credentials.FederatedIdentities))
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE oidc_clients DROP COLUMN is_group_restricted;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
PRAGMA foreign_keys= OFF;
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE oidc_clients
|
||||||
|
ADD COLUMN is_group_restricted BOOLEAN NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
|
UPDATE oidc_clients
|
||||||
|
SET is_group_restricted = (SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END
|
||||||
|
FROM oidc_client_user_groups
|
||||||
|
WHERE oidc_client_user_groups.oidc_client_id = oidc_clients.id);
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
PRAGMA foreign_keys= ON;
|
||||||
@@ -301,13 +301,16 @@
|
|||||||
"are_you_sure_you_want_to_create_a_new_client_secret": "Are you sure you want to create a new client secret? The old one will be invalidated.",
|
"are_you_sure_you_want_to_create_a_new_client_secret": "Are you sure you want to create a new client secret? The old one will be invalidated.",
|
||||||
"generate": "Generate",
|
"generate": "Generate",
|
||||||
"new_client_secret_created_successfully": "New client secret created successfully",
|
"new_client_secret_created_successfully": "New client secret created successfully",
|
||||||
"allowed_user_groups_updated_successfully": "Allowed user groups updated successfully",
|
|
||||||
"oidc_client_name": "OIDC Client {name}",
|
"oidc_client_name": "OIDC Client {name}",
|
||||||
"client_id": "Client ID",
|
"client_id": "Client ID",
|
||||||
"client_secret": "Client secret",
|
"client_secret": "Client secret",
|
||||||
"show_more_details": "Show more details",
|
"show_more_details": "Show more details",
|
||||||
"allowed_user_groups": "Allowed User Groups",
|
"allowed_user_groups": "Allowed User Groups",
|
||||||
"add_user_groups_to_this_client_to_restrict_access_to_users_in_these_groups": "Add user groups to this client to restrict access to users in these groups. If no user groups are selected, all users will have access to this client.",
|
"allowed_user_groups_description": "Select user groups to restrict signing in to this client to only users in these groups.",
|
||||||
|
"allowed_user_groups_status_unrestricted_description": "No user group restrictions are applied. Any user can sign in to this client.",
|
||||||
|
"unrestrict": "Unrestrict",
|
||||||
|
"restrict": "Restrict",
|
||||||
|
"user_groups_restriction_updated_successfully": "User groups restriction updated successfully",
|
||||||
"favicon": "Favicon",
|
"favicon": "Favicon",
|
||||||
"light_mode_logo": "Light Mode Logo",
|
"light_mode_logo": "Light Mode Logo",
|
||||||
"dark_mode_logo": "Dark Mode Logo",
|
"dark_mode_logo": "Dark Mode Logo",
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
defaultExpanded = false,
|
defaultExpanded = false,
|
||||||
|
forcedExpanded,
|
||||||
|
button,
|
||||||
icon,
|
icon,
|
||||||
children
|
children
|
||||||
}: {
|
}: {
|
||||||
@@ -19,7 +21,9 @@
|
|||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
defaultExpanded?: boolean;
|
defaultExpanded?: boolean;
|
||||||
|
forcedExpanded?: boolean;
|
||||||
icon?: typeof IconType;
|
icon?: typeof IconType;
|
||||||
|
button?: Snippet;
|
||||||
children: Snippet;
|
children: Snippet;
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
@@ -47,6 +51,12 @@
|
|||||||
}
|
}
|
||||||
loadExpandedState();
|
loadExpandedState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (forcedExpanded !== undefined) {
|
||||||
|
expanded = forcedExpanded;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card.Root>
|
<Card.Root>
|
||||||
@@ -63,11 +73,18 @@
|
|||||||
<Card.Description>{description}</Card.Description>
|
<Card.Description>{description}</Card.Description>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{#if button}
|
||||||
|
{@render button()}
|
||||||
|
{:else}
|
||||||
<Button class="ml-10 h-8 p-3" variant="ghost" aria-label={m.expand_card()}>
|
<Button class="ml-10 h-8 p-3" variant="ghost" aria-label={m.expand_card()}>
|
||||||
<LucideChevronDown
|
<LucideChevronDown
|
||||||
class={cn('size-5 transition-transform duration-200', expanded && 'rotate-180 transform')}
|
class={cn(
|
||||||
|
'size-5 transition-transform duration-200',
|
||||||
|
expanded && 'rotate-180 transform'
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
{#if expanded}
|
{#if expanded}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export type OidcClient = OidcClientMetaData & {
|
|||||||
requiresReauthentication: boolean;
|
requiresReauthentication: boolean;
|
||||||
credentials?: OidcClientCredentials;
|
credentials?: OidcClientCredentials;
|
||||||
launchURL?: string;
|
launchURL?: string;
|
||||||
|
isGroupRestricted: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type OidcClientWithAllowedUserGroups = OidcClient & {
|
export type OidcClientWithAllowedUserGroups = OidcClient & {
|
||||||
|
|||||||
@@ -80,6 +80,16 @@
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function toggleGroupRestriction() {
|
||||||
|
client.isGroupRestricted = !client.isGroupRestricted;
|
||||||
|
await oidcService
|
||||||
|
.updateClient(client.id, client)
|
||||||
|
.then(() => {
|
||||||
|
toast.success(m.user_groups_restriction_updated_successfully());
|
||||||
|
})
|
||||||
|
.catch(axiosErrorToast);
|
||||||
|
}
|
||||||
|
|
||||||
async function createClientSecret() {
|
async function createClientSecret() {
|
||||||
openConfirmDialog({
|
openConfirmDialog({
|
||||||
title: m.create_new_client_secret(),
|
title: m.create_new_client_secret(),
|
||||||
@@ -104,7 +114,7 @@
|
|||||||
await oidcService
|
await oidcService
|
||||||
.updateAllowedUserGroups(client.id, allowedGroups)
|
.updateAllowedUserGroups(client.id, allowedGroups)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success(m.allowed_user_groups_updated_successfully());
|
toast.success(m.user_groups_restriction_updated_successfully());
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
axiosErrorToast(e);
|
axiosErrorToast(e);
|
||||||
@@ -120,6 +130,14 @@
|
|||||||
<title>{m.oidc_client_name({ name: client.name })}</title>
|
<title>{m.oidc_client_name({ name: client.name })}</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
{#snippet UnrestrictButton()}
|
||||||
|
<Button
|
||||||
|
onclick={toggleGroupRestriction}
|
||||||
|
variant={client.isGroupRestricted ? 'secondary' : 'default'}
|
||||||
|
>{client.isGroupRestricted ? m.unrestrict() : m.restrict()}</Button
|
||||||
|
>
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="text-muted-foreground flex text-sm" onclick={backNavigation.go}
|
<button type="button" class="text-muted-foreground flex text-sm" onclick={backNavigation.go}
|
||||||
><LucideChevronLeft class="size-5" /> {m.back()}</button
|
><LucideChevronLeft class="size-5" /> {m.back()}</button
|
||||||
@@ -193,12 +211,23 @@
|
|||||||
<CollapsibleCard
|
<CollapsibleCard
|
||||||
id="allowed-user-groups"
|
id="allowed-user-groups"
|
||||||
title={m.allowed_user_groups()}
|
title={m.allowed_user_groups()}
|
||||||
description={m.add_user_groups_to_this_client_to_restrict_access_to_users_in_these_groups()}
|
button={!client.isGroupRestricted ? UnrestrictButton : undefined}
|
||||||
|
forcedExpanded={client.isGroupRestricted ? undefined : false}
|
||||||
|
description={client.isGroupRestricted
|
||||||
|
? m.allowed_user_groups_description()
|
||||||
|
: m.allowed_user_groups_status_unrestricted_description()}
|
||||||
>
|
>
|
||||||
<UserGroupSelection bind:selectedGroupIds={client.allowedUserGroupIds} />
|
{#if client.isGroupRestricted}
|
||||||
<div class="mt-5 flex justify-end">
|
<UserGroupSelection
|
||||||
|
bind:selectedGroupIds={client.allowedUserGroupIds}
|
||||||
|
selectionDisabled={!client.isGroupRestricted}
|
||||||
|
/>
|
||||||
|
<div class="mt-5 flex justify-end gap-3">
|
||||||
|
<Button onclick={toggleGroupRestriction} variant="secondary">{m.unrestrict()}</Button>
|
||||||
|
|
||||||
<Button onclick={() => updateUserGroupClients(client.allowedUserGroupIds)}>{m.save()}</Button>
|
<Button onclick={() => updateUserGroupClients(client.allowedUserGroupIds)}>{m.save()}</Button>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
</CollapsibleCard>
|
</CollapsibleCard>
|
||||||
<Card.Root>
|
<Card.Root>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
|
|||||||
@@ -102,7 +102,8 @@
|
|||||||
logo: $inputs.logoUrl?.value ? undefined : logo,
|
logo: $inputs.logoUrl?.value ? undefined : logo,
|
||||||
logoUrl: $inputs.logoUrl?.value,
|
logoUrl: $inputs.logoUrl?.value,
|
||||||
darkLogo: $inputs.darkLogoUrl?.value ? undefined : darkLogo,
|
darkLogo: $inputs.darkLogoUrl?.value ? undefined : darkLogo,
|
||||||
darkLogoUrl: $inputs.darkLogoUrl?.value
|
darkLogoUrl: $inputs.darkLogoUrl?.value,
|
||||||
|
isGroupRestricted: existingClient?.isGroupRestricted ?? true
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasLogo = logo != null || !!$inputs.logoUrl?.value;
|
const hasLogo = logo != null || !!$inputs.logoUrl?.value;
|
||||||
|
|||||||
Reference in New Issue
Block a user