Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
12d7b8c
WIP: intermediate changes
ludomikula Aug 7, 2023
d3cf4ba
WIP: new plugin system first iteration
ludomikula Aug 12, 2023
a119225
fix: check plugin endpoint method for proper return class
ludomikula Aug 28, 2023
f42b4f5
new: make default max query timeout configurable
ludomikula Aug 20, 2023
005611d
WIP: new plugin system first iteration
ludomikula Aug 12, 2023
f3358b5
fix: check plugin endpoint method for proper return class
ludomikula Aug 28, 2023
1b820ca
Add support for SUPER_ADMIN role
aq-ikhwa-tech Sep 7, 2023
ec518d8
Publish server log event for ee plugin to consume
aq-ikhwa-tech Sep 28, 2023
8b30ced
new: reworked Plugin classloader system
ludomikula Oct 10, 2023
0b54e90
WIP: intermediate changes
ludomikula Aug 7, 2023
47d1dad
WIP: new plugin system first iteration
ludomikula Aug 12, 2023
0451776
fix: check plugin endpoint method for proper return class
ludomikula Aug 28, 2023
042f511
new: make default max query timeout configurable
ludomikula Aug 20, 2023
0cfad7d
WIP: new plugin system first iteration
ludomikula Aug 12, 2023
d8ed9c1
fix: check plugin endpoint method for proper return class
ludomikula Aug 28, 2023
dda057d
Publish server log event for ee plugin to consume
aq-ikhwa-tech Sep 28, 2023
8d0c483
new: reworked Plugin classloader system
ludomikula Oct 10, 2023
e5afe8f
Add handling for audit logs feature
aq-ikhwa-tech Nov 4, 2023
a8cc6d9
Add handling for geolocation data for audit logs
aq-ikhwa-tech Nov 6, 2023
39e3e1f
new: extend new plugin system
ludomikula Nov 6, 2023
4bd4373
WIP: intermediate changes
ludomikula Aug 7, 2023
6e57773
WIP: new plugin system first iteration
ludomikula Aug 12, 2023
1dff91e
fix: check plugin endpoint method for proper return class
ludomikula Aug 28, 2023
04498f9
new: make default max query timeout configurable
ludomikula Aug 20, 2023
77ea427
WIP: new plugin system first iteration
ludomikula Aug 12, 2023
c60b4da
fix: check plugin endpoint method for proper return class
ludomikula Aug 28, 2023
46179cb
Publish server log event for ee plugin to consume
aq-ikhwa-tech Sep 28, 2023
f81924f
new: reworked Plugin classloader system
ludomikula Oct 10, 2023
e582b1e
WIP: intermediate changes
ludomikula Aug 7, 2023
d394e76
WIP: new plugin system first iteration
ludomikula Aug 12, 2023
4429800
fix: check plugin endpoint method for proper return class
ludomikula Aug 28, 2023
3194009
new: make default max query timeout configurable
ludomikula Aug 20, 2023
25dad14
WIP: new plugin system first iteration
ludomikula Aug 12, 2023
67d6a74
fix: check plugin endpoint method for proper return class
ludomikula Aug 28, 2023
d1224a1
Publish server log event for ee plugin to consume
aq-ikhwa-tech Sep 28, 2023
4ae0e0a
new: reworked Plugin classloader system
ludomikula Oct 10, 2023
4930575
Add handling for audit logs feature
aq-ikhwa-tech Nov 4, 2023
63d5dde
Add handling for geolocation data for audit logs
aq-ikhwa-tech Nov 6, 2023
7a3b3e5
new: extend new plugin system
ludomikula Nov 6, 2023
ea9d6fc
Add handling for api delays in case of rate limit
aq-ikhwa-tech Nov 8, 2023
083110c
fix: reload router functions when a plugin adds endpoints
ludomikula Nov 9, 2023
c5f6d5d
wip: plugin endpoint authentication
ludomikula Nov 13, 2023
19b0c4d
new: propagate plugin specific environment variables to plugins
ludomikula Nov 19, 2023
f145904
new: add environment variable for controlling plugin location
ludomikula Nov 19, 2023
cdc42c6
new: implemented plugin endpoints security
ludomikula Feb 2, 2024
acc402f
Merge remote-tracking branch 'origin/new_plugin_system' into merge-wi…
ludomikula Feb 3, 2024
d0b2b09
new: merge with latest LC
ludomikula Feb 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add support for SUPER_ADMIN role
  • Loading branch information
aq-ikhwa-tech authored and ludomikula committed Nov 24, 2023
commit 1b820ca51a82e9fe98c63e2ed55458aeb21b7ddd
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public boolean isAdmin() {
return role == MemberRole.ADMIN;
}

public boolean isSuperAdmin() {
return role == MemberRole.SUPER_ADMIN;
}


@JsonIgnore
public boolean isInvalid() {
return this == NOT_EXIST || StringUtils.isBlank(groupId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
public enum MemberRole {

MEMBER("member"),
ADMIN("admin");
ADMIN("admin"),
SUPER_ADMIN("super_admin");

private static final Map<String, MemberRole> VALUE_MAP;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ public MemberRole getRole() {
return role;
}

public boolean isSuperAdmin() {
return role == MemberRole.SUPER_ADMIN;
}

public boolean isAdmin() {
return role == MemberRole.ADMIN;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public interface OrganizationService {
@PossibleEmptyMono
Mono<Organization> getOrganizationInEnterpriseMode();

Mono<Organization> create(Organization organization, String creatorUserId);
Mono<Organization> create(Organization organization, String creatorUserId, boolean isSuperAdmin);

Mono<Organization> createDefault(User user);
Mono<Organization> createDefault(User user, boolean isSuperAdmin);

Mono<Organization> getById(String id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public OrganizationServiceImpl(ConfigCenter configCenter) {
}

@Override
public Mono<Organization> createDefault(User user) {
public Mono<Organization> createDefault(User user, boolean isSuperAdmin) {
return Mono.deferContextual(contextView -> {
Locale locale = getLocale(contextView);
String userOrgSuffix = getMessage(locale, "USER_ORG_SUFFIX");
Expand All @@ -96,7 +96,7 @@ public Mono<Organization> createDefault(User user) {
organization.setIsAutoGeneratedOrganization(true);
// saas mode
if (commonConfig.getWorkspace().getMode() == WorkspaceMode.SAAS) {
return create(organization, user.getId());
return create(organization, user.getId(), isSuperAdmin);
}
// enterprise mode
return joinOrganizationInEnterpriseMode(user.getId())
Expand All @@ -107,7 +107,7 @@ public Mono<Organization> createDefault(User user) {
OrganizationDomain organizationDomain = new OrganizationDomain();
organizationDomain.setConfigs(List.of(DEFAULT_AUTH_CONFIG));
organization.setOrganizationDomain(organizationDomain);
return create(organization, user.getId());
return create(organization, user.getId(), isSuperAdmin);
});
});
}
Expand Down Expand Up @@ -145,7 +145,7 @@ private Mono<Organization> getByEnterpriseOrgId() {
}

@Override
public Mono<Organization> create(Organization organization, String creatorId) {
public Mono<Organization> create(Organization organization, String creatorId, boolean isSuperAdmin) {

return Mono.defer(() -> {
if (organization == null || StringUtils.isNotBlank(organization.getId())) {
Expand All @@ -155,19 +155,19 @@ public Mono<Organization> create(Organization organization, String creatorId) {
return Mono.just(organization);
})
.flatMap(repository::save)
.flatMap(newOrg -> onOrgCreated(creatorId, newOrg))
.flatMap(newOrg -> onOrgCreated(creatorId, newOrg, isSuperAdmin))
.log();
}

private Mono<Organization> onOrgCreated(String userId, Organization newOrg) {
private Mono<Organization> onOrgCreated(String userId, Organization newOrg, boolean isSuperAdmin) {
return groupService.createAllUserGroup(newOrg.getId())
.then(groupService.createDevGroup(newOrg.getId()))
.then(setOrgAdmin(userId, newOrg))
.then(setOrgAdmin(userId, newOrg, isSuperAdmin))
.thenReturn(newOrg);
}

private Mono<Boolean> setOrgAdmin(String userId, Organization newOrg) {
return orgMemberService.addMember(newOrg.getId(), userId, MemberRole.ADMIN);
private Mono<Boolean> setOrgAdmin(String userId, Organization newOrg, boolean isSuperAdmin) {
return orgMemberService.addMember(newOrg.getId(), userId, isSuperAdmin ? MemberRole.SUPER_ADMIN : MemberRole.ADMIN);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public Mono<Map<String, List<ResourcePermission>>> getAllMatchingPermissions(Str
return getOrgId(resourceIds.iterator().next())
.flatMap(orgId -> orgMemberService.getOrgMember(orgId, userId))
.flatMap(orgMember -> {
if (orgMember.isAdmin()) {
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
return Mono.just(buildAdminPermissions(resourceType, resourceIds, userId));
}
return getAllMatchingPermissions0(userId, orgMember.getOrgId(), resourceType, resourceIds, resourceAction);
Expand Down Expand Up @@ -97,7 +97,7 @@ public Mono<UserPermissionOnResourceStatus> checkUserPermissionStatusOnResource(
Mono<UserPermissionOnResourceStatus> orgUserPermissionMono = getOrgId(resourceId)
.flatMap(orgId -> orgMemberService.getOrgMember(orgId, userId))
.flatMap(orgMember -> {
if (orgMember.isAdmin()) {
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
return Mono.just(UserPermissionOnResourceStatus.success(buildAdminPermission(resourceType, resourceId, userId)));
}
return getAllMatchingPermissions0(userId, orgMember.getOrgId(), resourceType, Collections.singleton(resourceId), resourceAction)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ protected Mono<List<Map<String, String>>> buildUserDetailGroups(String userId, O
Locale locale) {
String orgId = orgMember.getOrgId();
Flux<Group> groups;
if (orgMember.isAdmin()) {
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
groups = groupService.getByOrgId(orgId).sort();
} else {
if (withoutDynamicGroups) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class CommonConfig {
private JsExecutor jsExecutor = new JsExecutor();
private Set<String> disallowedHosts = new HashSet<>();
private List<String> pluginDirs = new ArrayList<>();
private SuperAdmin superAdmin = new SuperAdmin();

public boolean isSelfHost() {
return !isCloud();
Expand Down Expand Up @@ -152,4 +153,10 @@ public static class JsExecutor {
public static class Query {
private long readStructureTimeout = 15000;
}

@Data
public static class SuperAdmin {
private String userName;
private String password;
}
}
6 changes: 6 additions & 0 deletions server/api-service/lowcoder-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@
<version>4.4.0</version>
</dependency>

<dependency>
<groupId>org.passay</groupId>
<artifactId>passay</artifactId>
<version>1.6.3</version>
</dependency>

<dependency>
<groupId>it.ozimov</groupId>
<artifactId>embedded-redis</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public Mono<Void> loginOrRegister(AuthUser authUser, ServerWebExchange exchange,
// after register
.delayUntil(user -> {
if (user.getIsNewUser()) {
return onUserRegister(user);
return onUserRegister(user, false);
}
return Mono.empty();
})
Expand All @@ -160,7 +160,7 @@ public Mono<Void> loginOrRegister(AuthUser authUser, ServerWebExchange exchange,
.then(businessEventPublisher.publishUserLoginEvent(authUser.getSource()));
}

private Mono<User> updateOrCreateUser(AuthUser authUser) {
public Mono<User> updateOrCreateUser(AuthUser authUser) {
return findByAuthUser(authUser)
.flatMap(findByAuthUser -> {
if (findByAuthUser.userExist()) {
Expand Down Expand Up @@ -224,8 +224,8 @@ protected Connection getAuthConnection(AuthUser authUser, User user) {
.get();
}

protected Mono<Void> onUserRegister(User user) {
return organizationService.createDefault(user).then();
public Mono<Void> onUserRegister(User user, boolean isSuperAdmin) {
return organizationService.createDefault(user, isSuperAdmin).then();
}

protected Mono<Void> onUserLogin(String orgId, User user, String source) {
Expand Down Expand Up @@ -330,7 +330,7 @@ private Mono<Void> removeTokensByAuthId(String authId) {
private Mono<Void> checkIfAdmin() {
return sessionUserService.getVisitorOrgMemberCache()
.flatMap(orgMember -> {
if (orgMember.isAdmin()) {
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
return Mono.empty();
}
return deferredError(BizError.NOT_AUTHORIZED, "NOT_AUTHORIZED");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public Flux<?> getElements(@Nullable String folderId, @Nullable ApplicationType
if (folderInfoView == null) {
return;
}
folderInfoView.setManageable(orgMember.isAdmin() || orgMember.getUserId().equals(folderInfoView.getCreateBy()));
folderInfoView.setManageable(orgMember.isAdmin() || orgMember.isSuperAdmin() || orgMember.getUserId().equals(folderInfoView.getCreateBy()));

List<FolderInfoView> folderInfoViews = folderNode.getFolderChildren().stream().filter(FolderInfoView::isVisible).toList();
folderInfoView.setSubFolders(folderInfoViews);
Expand Down Expand Up @@ -335,7 +335,7 @@ private Mono<Tree<ApplicationInfoView, FolderInfoView>> buildApplicationInfoView
private Mono<OrgMember> checkManagePermission(String folderId) {
return sessionUserService.getVisitorOrgMemberCache()
.flatMap(orgMember -> {
if (orgMember.isAdmin()) {
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
return Mono.just(orgMember);
}
return isCreator(folderId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ public Mono<GroupMemberAggregateView> getGroupMembers(String groupId, int page,
Mono<MemberRole> visitorRoleMono = groupAndOrgMemberInfo.flatMap(tuple -> {
GroupMember groupMember = tuple.getT1();
OrgMember orgMember = tuple.getT2();
if (groupMember.isSuperAdmin() || orgMember.isSuperAdmin()) {
return Mono.just(MemberRole.SUPER_ADMIN);
}
if (groupMember.isAdmin() || orgMember.isAdmin()) {
return Mono.just(MemberRole.ADMIN);
}
Expand Down Expand Up @@ -109,7 +112,7 @@ private boolean hasReadPermission(Tuple2<GroupMember, OrgMember> tuple) {
private boolean hasManagePermission(Tuple2<GroupMember, OrgMember> tuple) {
GroupMember groupMember = tuple.getT1();
OrgMember orgMember = tuple.getT2();
return groupMember.isAdmin() || orgMember.isAdmin();
return groupMember.isAdmin() || orgMember.isAdmin() || groupMember.isSuperAdmin() || orgMember.isSuperAdmin();
}

private Mono<Tuple2<GroupMember, OrgMember>> getGroupAndOrgMemberInfo(String groupId) {
Expand Down Expand Up @@ -175,10 +178,16 @@ public Mono<List<GroupView>> getGroups() {
return sessionUserService.getVisitorOrgMemberCache()
.flatMap(orgMember -> {
String orgId = orgMember.getOrgId();
if (orgMember.isAdmin()) {
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
MemberRole memberRole;
if(orgMember.isAdmin()) {
memberRole = MemberRole.ADMIN;
} else {
memberRole = MemberRole.SUPER_ADMIN;
}
return groupService.getByOrgId(orgId)
.sort()
.flatMapSequential(group -> GroupView.from(group, MemberRole.ADMIN.getValue()))
.flatMapSequential(group -> GroupView.from(group, memberRole.getValue()))
.collectList();
}
return groupMemberService.getUserGroupMembersInOrg(orgId, orgMember.getUserId())
Expand Down Expand Up @@ -211,7 +220,7 @@ public Mono<Boolean> deleteGroup(String groupId) {

public Mono<Group> create(CreateGroupRequest createGroupRequest) {
return sessionUserService.getVisitorOrgMemberCache()
.filter(OrgMember::isAdmin)
.filter(orgMember -> orgMember.isAdmin() || orgMember.isSuperAdmin())
.switchIfEmpty(deferredError(BizError.NOT_AUTHORIZED, NOT_AUTHORIZED))
.delayUntil(orgMember -> bizThresholdChecker.checkMaxGroupCount(orgMember))
.flatMap(orgMember -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ public Mono<OrgView> create(Organization organization) {
return sessionUserService.getVisitorId()
.delayUntil(userId -> bizThresholdChecker.checkMaxOrgCount(userId))
.delayUntil(__ -> checkIfSaasMode())
.flatMap(userId -> organizationService.create(organization, userId))
.flatMap(userId -> organizationService.create(organization, userId, false))
.map(OrgView::new);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public Mono<Void> checkCurrentOrgDev() {
public Mono<Boolean> isCurrentOrgDev() {
return sessionUserService.getVisitorOrgMemberCache()
.flatMap(orgMember -> {
if (orgMember.isAdmin()) {
if (orgMember.isAdmin() || orgMember.isSuperAdmin()) {
return Mono.just(true);
}
return inDevGroup(orgMember.getOrgId(), orgMember.getUserId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public Mono<UserDetail> getUserDetailById(String userId) {
private Mono<Void> checkAdminPermissionAndUserBelongsToCurrentOrg(String userId) {
return sessionUserService.getVisitorOrgMemberCache()
.flatMap(orgMember -> {
if (!orgMember.isAdmin()) {
if (!orgMember.isAdmin() && !orgMember.isSuperAdmin()) {
return ofError(UNSUPPORTED_OPERATION, "BAD_REQUEST");
}
return orgMemberService.getOrgMember(orgMember.getOrgId(), userId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.lowcoder.api.util;

import org.passay.CharacterData;
import org.passay.CharacterRule;
import org.passay.EnglishCharacterData;
import org.passay.PasswordGenerator;

public class RandomPasswordGeneratorConfig {

public String generatePassayPassword() {
PasswordGenerator gen = new PasswordGenerator();
CharacterData lowerCaseChars = EnglishCharacterData.LowerCase;
CharacterRule lowerCaseRule = new CharacterRule(lowerCaseChars);
lowerCaseRule.setNumberOfCharacters(3);

CharacterData upperCaseChars = EnglishCharacterData.UpperCase;
CharacterRule upperCaseRule = new CharacterRule(upperCaseChars);
upperCaseRule.setNumberOfCharacters(3);

CharacterData digitChars = EnglishCharacterData.Digit;
CharacterRule digitRule = new CharacterRule(digitChars);
digitRule.setNumberOfCharacters(3);


String password = gen.generatePassword(10, lowerCaseRule, upperCaseRule, digitRule);
return password;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.lowcoder.infra.config.model.ServerConfig;
import org.lowcoder.infra.eventlog.EventLog;
import org.lowcoder.infra.serverlog.ServerLog;
import org.lowcoder.runner.migrations.job.AddSuperAdminUser;
import org.lowcoder.runner.migrations.job.CompleteAuthType;
import org.lowcoder.runner.migrations.job.MigrateAuthConfigJob;
import org.springframework.data.domain.Sort;
Expand Down Expand Up @@ -175,6 +176,11 @@ public void completeAuthType(CompleteAuthType completeAuthType) {
completeAuthType.complete();
}

@ChangeSet(order = "019", id = "add-super-admin-user", author = "")
public void addSuperAdminUser(AddSuperAdminUser addSuperAdminUser) {
addSuperAdminUser.addSuperAdmin();
}

public static Index makeIndex(String... fields) {
if (fields.length == 1) {
return new Index(fields[0], Sort.Direction.ASC).named(fields[0]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.lowcoder.runner.migrations.job;

public interface AddSuperAdminUser {

void addSuperAdmin();
}
Loading