Is it possible to secure update of certain entity properties using spring security.? for example if I have a user entity , I want ROLE_USER to be able to modify/update all the p
I haven't found any solution strictly provided by Spring Security Yet. However I have achieved what I wanted as follows by using custom annotation @SecureUpdate() on entity variables:-
Following is my paging and sorting repository:-
@Transactional("jpaTXManager")
public interface ScreenRepo extends PagingAndSortingRepository<Screen, Integer>{
@Override
@PreAuthorize("@patchSecurityService.canUpdate(#screen)")
Screen save(@Param("screen")Screen screen);
}
PatchSecurityService.java
@Service("patchSecurityService")
public class PatchSecurityService {
public boolean canUpdate(Object obj){
List<GrantedAuthority> authorities =
(List<GrantedAuthority>) SecurityContextHolder
.getContext()
.getAuthentication()
.getAuthorities();
if (obj instanceof OEntity){
OEntity oEntity = (OEntity) obj;
return oEntity.canUpdate(authorities);
}else{
return true;
}
}
}
OEntity.java
@MappedSuperclass
public class OEntity<T> {
@Transient
T originalObj;
@Transient
public T getOriginalObj(){
return this.originalObj;
}
@PostLoad
public void onLoad(){
ObjectMapper mapper = new ObjectMapper();
try {
String serialized = mapper.writeValueAsString(this);
this.originalObj = (T) mapper.readValue(serialized, this.getClass());
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean canUpdate(List<GrantedAuthority> authorities){
for (Field field : this.getClass().getDeclaredFields()){
SecureUpdate secureUpdate = field.getAnnotation(SecureUpdate.class);
if (secureUpdate != null){
try{
field.setAccessible(true);
Object persistedField = field.get(this);
Object originalField = field.get(originalObj);
String[] allowedRoles = secureUpdate.value();
if (!persistedField.equals(originalField)){
boolean canUpdate = false;
for (String role : allowedRoles){
for (GrantedAuthority authority : authorities){
if (authority.getAuthority().equalsIgnoreCase(role)){
return true;
}
}
}
return false;
}
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
return true;
}
}
@SecureUpdate
@Documented
@Target(FIELD)
@Retention(RUNTIME)
public @interface SecureUpdate {
String[] value();
}
and finally entity class (Screen.class)
@Entity
@Table(name="screen",schema="public")
@JsonIgnoreProperties(ignoreUnknown=true)
public class Screen extends OEntity<Screen>{
Integer screenId;
String screenName;
@SecureUpdate({"ROLE_CLIENT"})
String address;
ScreenType screenType;
@SecureUpdate({"ROLE_ADMIN"})
ScreenSize screenSize;
BigDecimal latitude;
BigDecimal longitude;
Boolean active;
AppUser appUser;
.......Constructor, Getters and Setters...
}