WIP Commit to save the dev state

This commit is contained in:
Arpit Mohan 2020-02-13 12:47:40 +05:30
parent 81d39042a6
commit 9f3197792a
17 changed files with 203 additions and 13 deletions

View File

@ -94,6 +94,10 @@
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>

View File

@ -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);
}
}
}

View File

@ -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<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange,
Authentication authentication) {
log.debug("Login succeeded for user: {}", authentication.getPrincipal());
if (authentication instanceof OAuth2AuthenticationToken) {
OAuth2AuthenticationToken oauthAuthentication = (OAuth2AuthenticationToken) authentication;
return checkAndCreateUser(oauthAuthentication)

View File

@ -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";

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,13 @@
package com.appsmith.server.constants;
import com.appsmith.external.models.BaseDomain;
import org.springframework.stereotype.Component;
@Component
public class AclComponent<T extends BaseDomain> {
public String getPermission(Object entity) {
System.out.println("In the getPermission");
return "read:applications";
}
}

View File

@ -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";
}

View File

@ -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<SimpleGrantedAuthority> 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

View File

@ -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<Application, Strin
Mono<Application> findByIdAndOrganizationId(String id, String orgId);
Mono<Application> findByName(String name);
@Override
Flux<Application> findAll(Example example);
@Override
Mono<Application> findById(String id);
}

View File

@ -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<User, String> {
Mono<User> findByEmail(String email);
// {
// System.out.println("In the custom findByEmail");
// return Mono.empty();
// }
}

View File

@ -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<Application, String> {
// @Override
// @PreAuthorize("hasPermission('someValue', T(com.appsmith.server.constants.AclConstants).READ_APPLICATION_PERMISSION)")
// Mono<Application> getById(String id);
@PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).READ_APPLICATION_PERMISSION)")
Mono<Application> findById(String id);
@PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).READ_APPLICATION_PERMISSION)")
Mono<Application> findByIdAndOrganizationId(String id, String organizationId);
@PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).READ_APPLICATION_PERMISSION)")
Mono<Application> findByName(String name);
@PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).PUBLISH_APPLICATION_PERMISSION)")
Mono<Boolean> publish(String applicationId);
@PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).CREATE_APPLICATION_PERMISSION)")
Mono<Application> save(Application application);
@PreAuthorize("hasPermission(#user, T(com.appsmith.server.constants.AclConstants).DELETE_APPLICATION_PERMISSION)")
Mono<Application> archive(Application application);
}

View File

@ -13,6 +13,7 @@ public interface CrudService<T extends BaseDomain, ID> {
Mono<T> update(ID id, T resource);
// @PreAuthorize("hasPermission('someValue', @aclComponent.getPermission(#returnObject))")
Mono<T> getById(ID id);
Mono<T> delete(ID id);

View File

@ -0,0 +1,4 @@
package com.appsmith.server.services;
//public @interface Domain {
//}

View File

@ -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<UserRepository, User, String> 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<UserRepository, User, String> 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<UserRepository, User, String> 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<UserRepository, User, String> 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<String> 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);
});
}
}

View File

@ -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