You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2025/08/19 20:59:35 UTC
(streampipes) branch add-alternate-ids-to-groups-roles created (now 7808d7e19f)
This is an automated email from the ASF dual-hosted git repository.
riemer pushed a change to branch add-alternate-ids-to-groups-roles
in repository https://gitbox.apache.org/repos/asf/streampipes.git
at 7808d7e19f feat: Support alternate ids for groups and roles
This branch includes the following new commits:
new 7808d7e19f feat: Support alternate ids for groups and roles
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(streampipes) 01/01: feat: Support alternate ids for groups and roles
Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch add-alternate-ids-to-groups-roles
in repository https://gitbox.apache.org/repos/asf/streampipes.git
commit 7808d7e19faaf5c7b3ff977efe429909d55551fc
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Tue Aug 19 22:59:15 2025 +0200
feat: Support alternate ids for groups and roles
---
.../environment/model/OAuthConfiguration.java | 12 +++-
.../parser/OAuthConfigurationParser.java | 19 +++++-
.../streampipes/model/client/user/Group.java | 9 +++
.../apache/streampipes/model/client/user/Role.java | 11 ++++
.../tasks/ApplyDefaultRolesAndPrivilegesTask.java | 16 +++--
.../service/core/oauth2/UserService.java | 71 +++++++++++++++++++---
.../src/lib/model/gen/streampipes-model-client.ts | 10 ++-
ui/src/app/configuration/configuration.module.ts | 2 +
.../alternate-id-configuration.component.html | 48 +++++++++++++++
.../alternate-id-configuration.component.ts} | 39 ++++++------
.../edit-group-dialog.component.html | 7 +++
.../edit-role-dialog.component.html | 20 ++++--
.../edit-role-dialog.component.scss | 1 -
.../edit-role-dialog/edit-role-dialog.component.ts | 19 ++++--
.../role-configuration.component.html | 1 -
15 files changed, 237 insertions(+), 48 deletions(-)
diff --git a/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/model/OAuthConfiguration.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/model/OAuthConfiguration.java
index 607bf468b5..65ce2ea3a7 100644
--- a/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/model/OAuthConfiguration.java
+++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/model/OAuthConfiguration.java
@@ -18,6 +18,8 @@
package org.apache.streampipes.commons.environment.model;
+import java.util.Set;
+
public class OAuthConfiguration {
private String authorizationUri;
@@ -35,7 +37,7 @@ public class OAuthConfiguration {
private String emailAttributeName;
private String userIdAttributeName;
private String roleAttributeName;
-
+ private Set<String> defaultRoles;
public String getRegistrationId() {
return registrationId;
@@ -156,4 +158,12 @@ public class OAuthConfiguration {
public void setRegistrationName(String registrationName) {
this.registrationName = registrationName;
}
+
+ public Set<String> getDefaultRoles() {
+ return defaultRoles;
+ }
+
+ public void setDefaultRoles(Set<String> defaultRoles) {
+ this.defaultRoles = defaultRoles;
+ }
}
diff --git a/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/parser/OAuthConfigurationParser.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/parser/OAuthConfigurationParser.java
index 3650a06104..98d4004ca6 100644
--- a/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/parser/OAuthConfigurationParser.java
+++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/environment/parser/OAuthConfigurationParser.java
@@ -28,6 +28,8 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
/**
* The {@code OAuthConfigurationParser} class is responsible for parsing OAuth provider configurations
@@ -52,8 +54,16 @@ public class OAuthConfigurationParser {
private static final Logger LOG = LoggerFactory.getLogger(OAuthConfigurationParser.class);
-
private static final String OAUTH_PREFIX = "SP_OAUTH_PROVIDER";
+ private static final Set<String> defaultRoles = Set.of(
+ "ROLE_PIPELINE_USER",
+ "ROLE_PIPELINE_ADMIN",
+ "ROLE_CONNECT_ADMIN",
+ "ROLE_DASHBOARD_USER",
+ "ROLE_DASHBOARD_ADMIN",
+ "ROLE_DATA_EXPLORER_USER",
+ "ROLE_DATA_EXPLORER_ADMIN"
+ );
public List<OAuthConfiguration> parse(Map<String, String> env) {
Map<String, OAuthConfiguration> oAuthConfigurationsMap = new HashMap<>();
@@ -97,6 +107,12 @@ public class OAuthConfigurationParser {
case "USER_ID_ATTRIBUTE_NAME" -> oAuthConfiguration.setUserIdAttributeName(value);
case "ROLE_ATTRIBUTE_NAME" -> oAuthConfiguration.setRoleAttributeName(value);
case "NAME" -> oAuthConfiguration.setRegistrationName(value);
+ case "DEFAULT_ROLES" -> {
+ var defaultRoles = Arrays.stream(value.split(","))
+ .map(String::trim)
+ .collect(Collectors.toSet());
+ oAuthConfiguration.setDefaultRoles(defaultRoles);
+ }
default -> LOG.warn(
"Unknown setting {} for oauth configuration in environment variable {}",
settingName,
@@ -133,6 +149,7 @@ public class OAuthConfigurationParser {
) {
var oAuthConfiguration = oAuthConfigurationsMap.computeIfAbsent(registrationId, k -> new OAuthConfiguration());
oAuthConfiguration.setRegistrationId(registrationId);
+ oAuthConfiguration.setDefaultRoles(defaultRoles);
return oAuthConfiguration;
}
}
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java
index 4ce6d272c9..906555ccaf 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Group.java
@@ -37,6 +37,7 @@ public class Group implements Storable {
@JsonIgnore
private String type = "group";
+ private Set<String> alternateIds = new HashSet<>();
private String groupName;
private Set<String> roles;
@@ -94,4 +95,12 @@ public class Group implements Storable {
public void setType(String type) {
this.type = type;
}
+
+ public Set<String> getAlternateIds() {
+ return alternateIds;
+ }
+
+ public void setAlternateIds(Set<String> alternateIds) {
+ this.alternateIds = alternateIds;
+ }
}
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
index 84542b9a30..7fce8f516f 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/Role.java
@@ -24,6 +24,7 @@ import org.apache.streampipes.model.shared.api.Storable;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.gson.annotations.SerializedName;
+import java.util.ArrayList;
import java.util.List;
@TsModel
@@ -35,6 +36,7 @@ public class Role implements Storable {
private String label;
private boolean defaultRole;
private List<String> privilegeIds;
+ private List<String> alternateIds;
// document type should be persisted to CouchDB with Gson serialization, but not via Jackson to the UI
@JsonIgnore
@@ -49,6 +51,7 @@ public class Role implements Storable {
role.label = label;
role.defaultRole = true;
role.privilegeIds = privilegeIds;
+ role.alternateIds = new ArrayList<>();
return role;
}
@@ -103,4 +106,12 @@ public class Role implements Storable {
public void setPrivilegeIds(List<String> privilegeIds) {
this.privilegeIds = privilegeIds;
}
+
+ public List<String> getAlternateIds() {
+ return alternateIds;
+ }
+
+ public void setAlternateIds(List<String> alternateIds) {
+ this.alternateIds = alternateIds;
+ }
}
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/ApplyDefaultRolesAndPrivilegesTask.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/ApplyDefaultRolesAndPrivilegesTask.java
index da26dc9031..f3d346aa6c 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/ApplyDefaultRolesAndPrivilegesTask.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/setup/tasks/ApplyDefaultRolesAndPrivilegesTask.java
@@ -54,13 +54,17 @@ public class ApplyDefaultRolesAndPrivilegesTask implements InstallationTask {
private <T extends Storable> void updateDocs(CRUDStorage<T> storage,
List<T> defaultDocs) {
- defaultDocs.forEach(role -> {
- var doc = storage.getElementById(role.getElementId());
- if (doc != null) {
- role.setRev(doc.getRev());
- storage.updateElement(role);
+ defaultDocs.forEach(doc -> {
+ var existingDoc = storage.getElementById(doc.getElementId());
+ if (existingDoc != null) {
+ doc.setRev(existingDoc.getRev());
+ // Preserve alternateIds for Role objects
+ if (doc instanceof Role && existingDoc instanceof Role) {
+ ((Role) doc).setAlternateIds(((Role) existingDoc).getAlternateIds());
+ }
+ storage.updateElement(doc);
} else {
- storage.persist(role);
+ storage.persist(doc);
}
});
}
diff --git a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/oauth2/UserService.java b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/oauth2/UserService.java
index 956a99778d..5f766659c8 100755
--- a/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/oauth2/UserService.java
+++ b/streampipes-service-core/src/main/java/org/apache/streampipes/service/core/oauth2/UserService.java
@@ -21,13 +21,17 @@ package org.apache.streampipes.service.core.oauth2;
import org.apache.streampipes.commons.environment.Environment;
import org.apache.streampipes.commons.environment.Environments;
import org.apache.streampipes.commons.environment.model.OAuthConfiguration;
-import org.apache.streampipes.model.client.user.DefaultRole;
+import org.apache.streampipes.model.client.user.Group;
+import org.apache.streampipes.model.client.user.Role;
import org.apache.streampipes.model.client.user.UserAccount;
import org.apache.streampipes.resource.management.UserResourceManager;
import org.apache.streampipes.rest.security.OAuth2AuthenticationProcessingException;
+import org.apache.streampipes.storage.api.CRUDStorage;
import org.apache.streampipes.storage.api.IUserStorage;
import org.apache.streampipes.storage.management.StorageDispatcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
@@ -37,15 +41,24 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
public class UserService {
+ private static final Logger LOG = LoggerFactory.getLogger(UserService.class);
+
private final IUserStorage userStorage;
+ private final CRUDStorage<Role> roleStorage;
+ private final CRUDStorage<Group> groupStorage;
private final Environment env;
+ private List<Role> allRoles;
+ private List<Group> allGroups;
public UserService() {
this.userStorage = StorageDispatcher.INSTANCE.getNoSqlStore().getUserStorageAPI();
+ this.roleStorage = StorageDispatcher.INSTANCE.getNoSqlStore().getRoleStorage();
+ this.groupStorage = StorageDispatcher.INSTANCE.getNoSqlStore().getUserGroupStorage();
+ this.allGroups = this.groupStorage.findAll();
+ this.allRoles = this.roleStorage.findAll();
this.env = Environments.getEnvironment();
}
@@ -78,11 +91,11 @@ public class UserService {
String.format("Already signed up with another provider %s", user.getProvider())
);
}
- applyRoles(user, oAuthConfig, attributes);
+ applyRoles(user, oAuthConfig, attributes, false);
userStorage.updateUser(user);
} else {
user = toUserAccount(registrationId, principalId, email, fullName);
- applyRoles(user, oAuthConfig, attributes);
+ applyRoles(user, oAuthConfig, attributes, true);
new UserResourceManager().registerOauthUser(user);
}
@@ -97,7 +110,8 @@ public class UserService {
private void applyRoles(UserAccount user,
OAuthConfiguration oAuthConfig,
- Map<String, Object> attributes) {
+ Map<String, Object> attributes,
+ boolean newUser) {
if (oAuthConfig.getRoleAttributeName() != null) {
Object rolesObject = attributes.get(oAuthConfig.getRoleAttributeName());
@@ -105,20 +119,57 @@ public class UserService {
Set<String> roles = extractRoleOrGroup("ROLE", rolesList);
Set<String> groups = convertGroup(extractRoleOrGroup("GROUP", rolesList));
+ allRoles.forEach(role -> {
+ if (Objects.nonNull(role.getAlternateIds())) {
+ role.getAlternateIds().forEach(a -> {
+ if (rolesList.contains(a)) {
+ roles.add(role.getElementId());
+ }
+ });
+ }
+ });
+
+ allGroups.forEach(group -> {
+ if (Objects.nonNull(group.getAlternateIds())) {
+ group.getAlternateIds().forEach(a -> {
+ if (rolesList.contains(a)) {
+ groups.add(group.getElementId());
+ }
+ });
+ }
+ });
+
user.setRoles(roles);
user.setGroups(groups);
user.setExternallyManagedRoles(true);
} else {
- applyDefaultRole(user);
+ LOG.warn(
+ "Invalid role attribute: {} of type {}",
+ oAuthConfig.getRoleAttributeName(),
+ Objects.nonNull(rolesObject) ? rolesObject.getClass().getName() : "null"
+ );
+ applyDefaultRole(user, oAuthConfig.getDefaultRoles(), newUser);
}
} else {
- applyDefaultRole(user);
+ LOG.warn("Applying default roles as no role attribute is configured");
+ applyDefaultRole(user, oAuthConfig.getDefaultRoles(), newUser);
}
}
- private void applyDefaultRole(UserAccount user) {
- user.setRoles(Stream.of(DefaultRole.ROLE_ADMIN.toString()).collect(Collectors.toSet()));
- user.setExternallyManagedRoles(false);
+ private void applyDefaultRole(UserAccount user,
+ Set<String> defaultRoles,
+ boolean newUser) {
+ if (newUser) {
+ user.setRoles(
+ defaultRoles
+ .stream()
+ .filter(r -> allRoles
+ .stream()
+ .anyMatch(role -> role.getElementId().equals(r)))
+ .collect(Collectors.toSet())
+ );
+ user.setExternallyManagedRoles(false);
+ }
}
private UserAccount toUserAccount(String registrationId,
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
index f6d00886bf..09c378e914 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
@@ -20,11 +20,12 @@
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
-// Generated using typescript-generator version 3.2.1263 on 2025-08-05 18:37:35.
+// Generated using typescript-generator version 3.2.1263 on 2025-08-19 20:00:50.
import { Storable } from './streampipes-model';
export class Group implements Storable {
+ alternateIds: string[];
elementId: string;
groupId: string;
groupName: string;
@@ -36,6 +37,9 @@ export class Group implements Storable {
return data;
}
const instance = target || new Group();
+ instance.alternateIds = __getCopyArrayFn(__identity<string>())(
+ data.alternateIds,
+ );
instance.elementId = data.elementId;
instance.groupId = data.groupId;
instance.groupName = data.groupName;
@@ -189,6 +193,7 @@ export class RawUserApiToken {
}
export class Role implements Storable {
+ alternateIds: string[];
defaultRole: boolean;
elementId: string;
label: string;
@@ -200,6 +205,9 @@ export class Role implements Storable {
return data;
}
const instance = target || new Role();
+ instance.alternateIds = __getCopyArrayFn(__identity<string>())(
+ data.alternateIds,
+ );
instance.defaultRole = data.defaultRole;
instance.elementId = data.elementId;
instance.label = data.label;
diff --git a/ui/src/app/configuration/configuration.module.ts b/ui/src/app/configuration/configuration.module.ts
index 25fe8959aa..14ad6a1fac 100644
--- a/ui/src/app/configuration/configuration.module.ts
+++ b/ui/src/app/configuration/configuration.module.ts
@@ -102,6 +102,7 @@ import { GenericStorageItemsComponent } from './export/export-dialog/generic-sto
import { TranslateModule } from '@ngx-translate/core';
import { CertificateConfigurationComponent } from './extensions-service-management/certificate-configuration/certificate-configuration.component';
import { CertificateDetailsDialogComponent } from './dialog/certificate-details/certificate-details-dialog.component';
+import { AlternateIdConfigurationComponent } from './security-configuration/alternate-id-configuration/alternate-id-configuration.component';
@NgModule({
imports: [
@@ -259,6 +260,7 @@ import { CertificateDetailsDialogComponent } from './dialog/certificate-details/
PipelineElementTypeFilter,
CertificateConfigurationComponent,
CertificateDetailsDialogComponent,
+ AlternateIdConfigurationComponent,
],
providers: [
OrderByPipe,
diff --git a/ui/src/app/configuration/security-configuration/alternate-id-configuration/alternate-id-configuration.component.html b/ui/src/app/configuration/security-configuration/alternate-id-configuration/alternate-id-configuration.component.html
new file mode 100644
index 0000000000..f02c21b7bb
--- /dev/null
+++ b/ui/src/app/configuration/security-configuration/alternate-id-configuration/alternate-id-configuration.component.html
@@ -0,0 +1,48 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<div fxLayout="column">
+ @for (id of alternateIds; track $index) {
+ <div fxLayout="row" fxLayoutAlign="start center" class="p-5 border">
+ <span fxFlex>{{ id }}</span>
+ <button
+ mat-icon-button
+ color="accent"
+ (click)="removeAlternateId(id)"
+ >
+ <mat-icon>delete</mat-icon>
+ </button>
+ </div>
+ }
+ <div fxLayout="row" fxLayoutAlign="start center" class="alternate-id-row">
+ <mat-form-field color="accent" fxFlex subscriptSizing="dynamic">
+ <mat-label>New Alternate ID</mat-label>
+ <input
+ matInput
+ [(ngModel)]="newAlternateId"
+ (keyup.enter)="addAlternateId()"
+ placeholder="Enter new alternate ID"
+ />
+ </mat-form-field>
+ <div fxLayoutAlign="start center">
+ <button mat-button class="mat-basic" (click)="addAlternateId()">
+ <mat-icon>add</mat-icon><span>Add</span>
+ </button>
+ </div>
+ </div>
+</div>
diff --git a/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.scss b/ui/src/app/configuration/security-configuration/alternate-id-configuration/alternate-id-configuration.component.ts
similarity index 56%
copy from ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.scss
copy to ui/src/app/configuration/security-configuration/alternate-id-configuration/alternate-id-configuration.component.ts
index 72634367f4..23838e01b2 100644
--- a/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.scss
+++ b/ui/src/app/configuration/security-configuration/alternate-id-configuration/alternate-id-configuration.component.ts
@@ -1,4 +1,4 @@
-/*!
+/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
@@ -16,24 +16,27 @@
*
*/
-.lists-container {
- display: flex;
- justify-content: space-between;
-}
+import { Component, Input, OnInit } from '@angular/core';
-.list-section {
- width: 45%;
- font-size: 10pt;
- border: 1px solid var(--color-bg-2);
-}
+@Component({
+ selector: 'sp-alternate-id-configuration',
+ templateUrl: './alternate-id-configuration.component.html',
+ standalone: false,
+})
+export class AlternateIdConfigurationComponent {
+ @Input()
+ alternateIds: string[] = [];
-.button-section {
- display: flex;
- flex-direction: column;
- justify-content: center;
-}
+ newAlternateId: string = '';
+
+ addAlternateId(): void {
+ if (!this.alternateIds) {
+ this.alternateIds = [];
+ }
+ this.alternateIds.push(this.newAlternateId);
+ }
-.privilege-header {
- padding: 10px;
- font-weight: bold;
+ removeAlternateId(id: string): void {
+ this.alternateIds.splice(this.alternateIds.indexOf(id), 1);
+ }
}
diff --git a/ui/src/app/configuration/security-configuration/edit-group-dialog/edit-group-dialog.component.html b/ui/src/app/configuration/security-configuration/edit-group-dialog/edit-group-dialog.component.html
index 53eac39a15..1769401974 100644
--- a/ui/src/app/configuration/security-configuration/edit-group-dialog/edit-group-dialog.component.html
+++ b/ui/src/app/configuration/security-configuration/edit-group-dialog/edit-group-dialog.component.html
@@ -44,6 +44,13 @@
{{ role.label }}
</mat-checkbox>
</div>
+ <div fxLayout="column" class="general-options-panel">
+ <span class="general-options-header">Alternate IDs</span>
+ <sp-alternate-id-configuration
+ [alternateIds]="clonedGroup.alternateIds"
+ >
+ </sp-alternate-id-configuration>
+ </div>
</form>
</div>
</div>
diff --git a/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.html b/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.html
index b404b3ff57..be0ed9da1a 100644
--- a/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.html
+++ b/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.html
@@ -52,7 +52,7 @@
fxLayoutGap="10px"
class="lists-container"
>
- <div class="list-section">
+ <div class="list-section" fxFlex="50">
<div class="privilege-header">
Available Privileges
</div>
@@ -62,7 +62,10 @@
mat-icon-button
color="accent"
(click)="assignPrivilege(privilege)"
- [disabled]="isAssigned(privilege)"
+ [disabled]="
+ isAssigned(privilege) ||
+ clonedRole.defaultRole
+ "
>
<mat-icon>add</mat-icon>
</button>
@@ -70,7 +73,7 @@
</div>
</div>
</div>
- <div class="list-section">
+ <div class="list-section" fxFlex="50">
<div class="privilege-header">
Selected Privileges
</div>
@@ -79,6 +82,7 @@
<button
mat-icon-button
color="accent"
+ [disabled]="clonedRole.defaultRole"
(click)="removePrivilege(privilege)"
>
<mat-icon>remove</mat-icon>
@@ -89,6 +93,14 @@
</div>
</div>
</div>
+
+ <div fxLayout="column" class="general-options-panel">
+ <span class="general-options-header">Alternate IDs</span>
+ <sp-alternate-id-configuration
+ [alternateIds]="clonedRole.alternateIds"
+ >
+ </sp-alternate-id-configuration>
+ </div>
</form>
</div>
</div>
@@ -102,7 +114,7 @@
(click)="save()"
style="margin-right: 10px"
[disabled]="
- !parentForm.valid || selectedPrivileges.length === 0
+ parentForm.invalid || selectedPrivileges.length === 0
"
data-cy="sp-edit-role-save"
>
diff --git a/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.scss b/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.scss
index 72634367f4..ebb3e55286 100644
--- a/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.scss
+++ b/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.scss
@@ -22,7 +22,6 @@
}
.list-section {
- width: 45%;
font-size: 10pt;
border: 1px solid var(--color-bg-2);
}
diff --git a/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.ts b/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.ts
index 0032d0a3cb..415649811a 100644
--- a/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.ts
+++ b/ui/src/app/configuration/security-configuration/edit-role-dialog/edit-role-dialog.component.ts
@@ -74,14 +74,23 @@ export class EditRoleDialogComponent implements OnInit {
this.parentForm = this.fb.group({});
this.parentForm.addControl(
'label',
- new FormControl(this.clonedRole.label, Validators.required),
+ new FormControl(
+ {
+ value: this.clonedRole.label,
+ disabled: this.clonedRole.defaultRole,
+ },
+ Validators.required,
+ ),
);
this.parentForm.addControl(
'elementId',
- new FormControl(this.clonedRole.elementId, [
- Validators.required,
- Validators.pattern(/^ROLE_[A-Z_]+$/),
- ]),
+ new FormControl(
+ {
+ value: this.clonedRole.elementId,
+ disabled: this.clonedRole.defaultRole,
+ },
+ [Validators.required, Validators.pattern(/^ROLE_[A-Z_]+$/)],
+ ),
);
}
diff --git a/ui/src/app/configuration/security-configuration/role-configuration/role-configuration.component.html b/ui/src/app/configuration/security-configuration/role-configuration/role-configuration.component.html
index b5feadd27e..79c00bdd35 100644
--- a/ui/src/app/configuration/security-configuration/role-configuration/role-configuration.component.html
+++ b/ui/src/app/configuration/security-configuration/role-configuration/role-configuration.component.html
@@ -77,7 +77,6 @@
matTooltip="Edit user"
matTooltipPosition="above"
data-cy="role-edit-btn"
- [disabled]="role.defaultRole"
(click)="editRole(role)"
>
<i class="material-icons">edit</i>