diff --git a/app/server/appsmith-server/pom.xml b/app/server/appsmith-server/pom.xml
index 96fe6643b4..bf28473990 100644
--- a/app/server/appsmith-server/pom.xml
+++ b/app/server/appsmith-server/pom.xml
@@ -94,6 +94,10 @@
org.springframework.session
spring-session-data-redis
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
org.hibernate.validator
hibernate-validator
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/aspects/ContextAspect.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/aspects/ContextAspect.java
new file mode 100644
index 0000000000..89121d1f63
--- /dev/null
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/aspects/ContextAspect.java
@@ -0,0 +1,42 @@
+package com.appsmith.server.aspects;
+
+import com.appsmith.server.domains.User;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.ReactiveSecurityContextHolder;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Mono;
+
+@Aspect
+@Component
+@Slf4j
+public class ContextAspect {
+
+// @Around("execution(reactor.core.publisher.Mono+ com.appsmith.server.services.CrudService+")
+ @Around("execution(reactor.core.publisher.Mono+ com.appsmith.server.services.CrudService.*(..))")
+ public Mono> addAuthorization(ProceedingJoinPoint joinPoint) {
+ try {
+ log.debug("In the custom aspect");
+ return ReactiveSecurityContextHolder.getContext()
+ .map(ctx -> ctx.getAuthentication())
+ .map(auth -> auth.getPrincipal())
+ .map(principal -> {
+ User user = (User) principal;
+ log.debug("{}", user.getAuthorities());
+ if(user.getAuthorities().contains(new SimpleGrantedAuthority("read:applications"))) {
+ log.debug("Got the permission");
+ }
+ return principal;
+ })
+ .then((Mono>) joinPoint.proceed());
+// return Mono.just(true);
+// return ((Mono>) joinPoint.proceed());
+// .subscriberContext(Context.of(UserRepository.CONTEXT_CLIENT_KEY, getClient()));
+ } catch (Throwable throwable) {
+ return Mono.error(throwable);
+ }
+ }
+}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/authentication/handlers/AuthenticationSuccessHandler.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/authentication/handlers/AuthenticationSuccessHandler.java
index c4ebb50b3b..7d3d096270 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/authentication/handlers/AuthenticationSuccessHandler.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/authentication/handlers/AuthenticationSuccessHandler.java
@@ -5,6 +5,8 @@ import com.appsmith.server.constants.Security;
import com.appsmith.server.domains.LoginSource;
import com.appsmith.server.domains.User;
import com.appsmith.server.domains.UserState;
+import com.appsmith.server.repositories.GroupRepository;
+import com.appsmith.server.services.GroupService;
import com.appsmith.server.services.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -33,6 +35,9 @@ public class AuthenticationSuccessHandler implements ServerAuthenticationSuccess
@Autowired
UserService userService;
+ @Autowired
+ GroupRepository groupRepository;
+
private ServerRedirectStrategy redirectStrategy = new DefaultServerRedirectStrategy();
/**
@@ -48,6 +53,7 @@ public class AuthenticationSuccessHandler implements ServerAuthenticationSuccess
public Mono onAuthenticationSuccess(WebFilterExchange webFilterExchange,
Authentication authentication) {
log.debug("Login succeeded for user: {}", authentication.getPrincipal());
+
if (authentication instanceof OAuth2AuthenticationToken) {
OAuth2AuthenticationToken oauthAuthentication = (OAuth2AuthenticationToken) authentication;
return checkAndCreateUser(oauthAuthentication)
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonConfig.java
index 91b037b5f3..c42a7e2059 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonConfig.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CommonConfig.java
@@ -8,6 +8,7 @@ import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
@@ -21,6 +22,7 @@ import java.util.stream.Collectors;
@Getter
@Setter
@Configuration
+@EnableAspectJAutoProxy
public class CommonConfig {
private String ELASTIC_THREAD_POOL_NAME = "appsmith-elastic-pool";
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CustomPermissionEvaluator.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CustomPermissionEvaluator.java
new file mode 100644
index 0000000000..6ef331f6bb
--- /dev/null
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CustomPermissionEvaluator.java
@@ -0,0 +1,28 @@
+package com.appsmith.server.configurations;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.PermissionEvaluator;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.stereotype.Component;
+
+import java.io.Serializable;
+
+@Slf4j
+@Component
+public class CustomPermissionEvaluator implements PermissionEvaluator {
+
+ @Override
+ public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
+ log.debug("In hasPermission with permission: {}", permission);
+ SimpleGrantedAuthority authority = new SimpleGrantedAuthority((String) permission);
+ return authentication.getAuthorities().contains(authority);
+ }
+
+ @Override
+ public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
+ log.debug("In hasPermission 2");
+ SimpleGrantedAuthority authority = new SimpleGrantedAuthority((String) permission);
+ return authentication.getAuthorities().contains(authority);
+ }
+}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CustomWebExpressionHandler.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CustomWebExpressionHandler.java
new file mode 100644
index 0000000000..a0f6b7f9cb
--- /dev/null
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/CustomWebExpressionHandler.java
@@ -0,0 +1,37 @@
+package com.appsmith.server.configurations;
+
+import org.springframework.security.access.PermissionEvaluator;
+import org.springframework.security.access.expression.SecurityExpressionOperations;
+import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
+import org.springframework.security.web.access.expression.WebSecurityExpressionRoot;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CustomWebExpressionHandler extends DefaultWebSecurityExpressionHandler {
+
+ private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+ private String defaultRolePrefix = "ROLE_";
+
+ @Override
+ protected SecurityExpressionOperations createSecurityExpressionRoot(
+ Authentication authentication, FilterInvocation fi) {
+
+ System.out.println("In the custom security expresssion root");
+ WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);
+ root.setPermissionEvaluator(getPermissionEvaluator());
+ root.setTrustResolver(trustResolver);
+ root.setRoleHierarchy(getRoleHierarchy());
+ root.setDefaultRolePrefix(this.defaultRolePrefix);
+ return root;
+ }
+
+ @Override
+ protected PermissionEvaluator getPermissionEvaluator() {
+ return null;
+ }
+
+}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java
index 59f696046d..783d855c05 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/SecurityConfig.java
@@ -7,9 +7,15 @@ import com.appsmith.server.constants.Url;
import com.appsmith.server.services.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpMethod;
+import org.springframework.security.access.expression.SecurityExpressionHandler;
+import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
+import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
@@ -30,6 +36,7 @@ import java.util.Arrays;
import static com.appsmith.server.constants.Url.USER_URL;
@EnableWebFluxSecurity
+@EnableReactiveMethodSecurity
public class SecurityConfig {
@Autowired
@@ -130,4 +137,12 @@ public class SecurityConfig {
.and().build();
}
+ @Bean
+ public DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler() {
+ DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
+ expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
+
+ return expressionHandler;
+ }
+
}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AclComponent.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AclComponent.java
new file mode 100644
index 0000000000..9620d9982c
--- /dev/null
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AclComponent.java
@@ -0,0 +1,13 @@
+package com.appsmith.server.constants;
+
+import com.appsmith.external.models.BaseDomain;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AclComponent {
+
+ public String getPermission(Object entity) {
+ System.out.println("In the getPermission");
+ return "read:applications";
+ }
+}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AclConstants.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AclConstants.java
index 60c89a3d7d..22fbc34409 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AclConstants.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/constants/AclConstants.java
@@ -17,4 +17,10 @@ public interface AclConstants {
"create:users",
"read:users"
);
+
+ String READ_APPLICATION_PERMISSION = "read:applications";
+ String CREATE_APPLICATION_PERMISSION = "create:applications";
+ String DELETE_APPLICATION_PERMISSION = "delete:applications";
+ String UPDATE_APPLICATION_PERMISSION = "update:applications";
+ String PUBLISH_APPLICATION_PERMISSION = "publish:applications";
}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/User.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/User.java
index 234e38bf5d..c894f50c52 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/User.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/User.java
@@ -59,15 +59,9 @@ public class User extends BaseDomain implements UserDetails {
@Override
public Collection extends GrantedAuthority> getAuthorities() {
-
- if (roles == null || roles.isEmpty()) //No existing roles found.
- return null;
-
- Collection authorities = roles.stream()
- .map(role -> new SimpleGrantedAuthority(role.toString()))
- .collect(Collectors.toList());
-
- return authorities;
+ return this.getPermissions().stream()
+ .map(permission -> new SimpleGrantedAuthority(permission))
+ .collect(Collectors.toSet());
}
@Override
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ApplicationRepository.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ApplicationRepository.java
index 717d807f32..698f9af130 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ApplicationRepository.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/ApplicationRepository.java
@@ -1,7 +1,10 @@
package com.appsmith.server.repositories;
import com.appsmith.server.domains.Application;
+import org.springframework.data.domain.Example;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Repository;
+import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Repository
@@ -10,4 +13,10 @@ public interface ApplicationRepository extends BaseRepository findByIdAndOrganizationId(String id, String orgId);
Mono findByName(String name);
+
+ @Override
+ Flux findAll(Example example);
+
+ @Override
+ Mono findById(String id);
}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/UserRepository.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/UserRepository.java
index b586ff7f2a..34250bd894 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/UserRepository.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/repositories/UserRepository.java
@@ -1,6 +1,7 @@
package com.appsmith.server.repositories;
import com.appsmith.server.domains.User;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Mono;
@@ -8,4 +9,8 @@ import reactor.core.publisher.Mono;
public interface UserRepository extends BaseRepository {
Mono findByEmail(String email);
+// {
+// System.out.println("In the custom findByEmail");
+// return Mono.empty();
+// }
}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ApplicationService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ApplicationService.java
index 082f1e2cd1..e4790cc579 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ApplicationService.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ApplicationService.java
@@ -1,18 +1,31 @@
package com.appsmith.server.services;
import com.appsmith.server.domains.Application;
+import org.springframework.security.access.prepost.PreAuthorize;
import reactor.core.publisher.Mono;
+//@Domain("applications")
public interface ApplicationService extends CrudService {
+
+// @Override
+// @PreAuthorize("hasPermission('someValue', T(com.appsmith.server.constants.AclConstants).READ_APPLICATION_PERMISSION)")
+// Mono getById(String id);
+
+ @PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).READ_APPLICATION_PERMISSION)")
Mono findById(String id);
+ @PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).READ_APPLICATION_PERMISSION)")
Mono findByIdAndOrganizationId(String id, String organizationId);
+ @PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).READ_APPLICATION_PERMISSION)")
Mono findByName(String name);
+ @PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).PUBLISH_APPLICATION_PERMISSION)")
Mono publish(String applicationId);
+ @PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).CREATE_APPLICATION_PERMISSION)")
Mono save(Application application);
+ @PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).DELETE_APPLICATION_PERMISSION)")
Mono archive(Application application);
}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CrudService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CrudService.java
index e9084e217b..d77657591f 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CrudService.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/CrudService.java
@@ -13,6 +13,7 @@ public interface CrudService {
Mono update(ID id, T resource);
+// @PreAuthorize("hasPermission('someValue', @aclComponent.getPermission(#returnObject))")
Mono getById(ID id);
Mono delete(ID id);
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/Domain.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/Domain.java
new file mode 100644
index 0000000000..e1d7f8fd43
--- /dev/null
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/Domain.java
@@ -0,0 +1,4 @@
+package com.appsmith.server.services;
+
+//public @interface Domain {
+//}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java
index 1174000ee7..b54d002954 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java
@@ -11,6 +11,7 @@ import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.helpers.BeanCopyUtils;
import com.appsmith.server.notifications.EmailSender;
+import com.appsmith.server.repositories.GroupRepository;
import com.appsmith.server.repositories.InviteUserRepository;
import com.appsmith.server.repositories.PasswordResetTokenRepository;
import com.appsmith.server.repositories.UserRepository;
@@ -46,7 +47,7 @@ public class UserServiceImpl extends BaseService i
private final PasswordResetTokenRepository passwordResetTokenRepository;
private final PasswordEncoder passwordEncoder;
private final EmailSender emailSender;
- private final GroupService groupService;
+ private final GroupRepository groupRepository;
private final InviteUserRepository inviteUserRepository;
private final UserOrganizationService userOrganizationService;
@@ -68,7 +69,7 @@ public class UserServiceImpl extends BaseService i
PasswordResetTokenRepository passwordResetTokenRepository,
PasswordEncoder passwordEncoder,
EmailSender emailSender,
- GroupService groupService,
+ GroupRepository groupRepository,
InviteUserRepository inviteUserRepository,
UserOrganizationService userOrganizationService) {
super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService);
@@ -79,7 +80,7 @@ public class UserServiceImpl extends BaseService i
this.passwordResetTokenRepository = passwordResetTokenRepository;
this.passwordEncoder = passwordEncoder;
this.emailSender = emailSender;
- this.groupService = groupService;
+ this.groupRepository = groupRepository;
this.inviteUserRepository = inviteUserRepository;
this.userOrganizationService = userOrganizationService;
}
@@ -485,6 +486,15 @@ public class UserServiceImpl extends BaseService i
.switchIfEmpty(Mono.error(new UsernameNotFoundException("Unable to find username: " + username)))
// This object cast is required to ensure that we send the right object type back to Spring framework.
// Doesn't work without this.
- .map(user -> (UserDetails) user);
+ .flatMap(user -> {
+ Set groupSet = user.getGroupIds();
+
+ return groupRepository.findAllById(groupSet)
+ .map(group -> group.getPermissions())
+ // Adding permissions from all the groups that the user is a part of
+ .map(permissions -> user.getPermissions().addAll(permissions))
+ .collectList()
+ .thenReturn((UserDetails) user);
+ });
}
}
diff --git a/app/server/appsmith-server/src/main/resources/application-local.properties b/app/server/appsmith-server/src/main/resources/application-local.properties
index 9ddf6b8227..3cf53d4ad1 100644
--- a/app/server/appsmith-server/src/main/resources/application-local.properties
+++ b/app/server/appsmith-server/src/main/resources/application-local.properties
@@ -1,5 +1,6 @@
# Appsmith Configurations
appsmith.baseUri=http://localhost:8080
+spring.main.allow-bean-definition-overriding=true
#Mongo properties
spring.data.mongodb.database=mobtools