Implemented custom serialization for UserImpl again. This should fix

deserialization of object cycles (UserImpl -> HashSet -> RoleImpl ->
UserImpl) where uninitialized objects are inserted into a HashSet.
This commit is contained in:
Steffen Schaefer committed 2018-12-18 08:34:41 +01:00
1 parent 70b036826c
commit aa16714fd5
3 files changed
+67 -38

No files matched your search

@@ -1,21 +1,35 @@
package com.sap.sse.security.shared.dto;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.sap.sse.common.Util;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.SecurityUserImpl;
public class StrippedUserDTO extends SecurityUserImpl<RoleDefinitionDTO, RoleDTO, StrippedUserGroupDTO> {
private static final long serialVersionUID = 1L;
private Set<RoleDTO> roles;
@Deprecated
private StrippedUserDTO() {
super(null);
}
public StrippedUserDTO(String name, Iterable<RoleDTO> roles, Iterable<WildcardPermission> permissions) {
super(name, roles, permissions);
super(name, permissions);
roles = new HashSet<>();
Util.addAll(roles, this.getRolesInternal());
}
public StrippedUserDTO(String name) {
super(name);
this(name, Collections.<RoleDTO>emptySet(), Collections.<WildcardPermission>emptySet());
}
@Override
protected Set<RoleDTO> getRolesInternal() {
return roles;
}
}
@@ -5,7 +5,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.sap.sse.common.Util;
import com.sap.sse.security.shared.AbstractRole;
import com.sap.sse.security.shared.RoleDefinition;
import com.sap.sse.security.shared.SecurityUser;
@@ -18,51 +17,24 @@ public abstract class SecurityUserImpl<RD extends RoleDefinition, R extends Abst
private String name;
/**
* Roles can refer back to this user object, e.g., for the user qualification, or during the tenant
* qualification if this user belongs to the tenant for which the role is qualified. Therefore, this
* set has to be transient, and the {@link #roleListForSerialization} field takes over the serialization
* which is resolved by {@link #readResolve}.
*
* @see #writeObject
* @see #readResolve
*/
private Set<R> roles;
// private List<R> roleListForSerialization;
private Set<WildcardPermission> permissions;
/**
* Creates a user with empty permission set and empty role set
*/
public SecurityUserImpl(String name) {
this(name, new HashSet<R>(), new HashSet<WildcardPermission>());
this(name, new HashSet<WildcardPermission>());
}
public SecurityUserImpl(String name, Iterable<R> roles, Iterable<WildcardPermission> permissions) {
public SecurityUserImpl(String name, Iterable<WildcardPermission> permissions) {
this.name = name;
this.roles = new HashSet<>();
Util.addAll(roles, this.roles);
this.permissions = new HashSet<>();
for (WildcardPermission permission : permissions) {
this.permissions.add(permission);
}
}
// @GwtIncompatible
// private void writeObject(ObjectOutputStream oos) throws IOException {
// roleListForSerialization = new ArrayList<>(roles);
// oos.defaultWriteObject();
// roleListForSerialization = null;
// }
//
// @GwtIncompatible
// protected Object readResolve() {
// roles = new HashSet<>(roleListForSerialization);
// roleListForSerialization = null;
// return this;
// }
protected abstract Set<R> getRolesInternal();
@Override
public String getName() {
@@ -76,12 +48,12 @@ public abstract class SecurityUserImpl<RD extends RoleDefinition, R extends Abst
@Override
public Iterable<R> getRoles() {
return roles;
return getRolesInternal();
}
@Override
public boolean hasRole(R role) {
return roles.contains(role);
return getRolesInternal().contains(role);
}
@Override
@@ -90,11 +62,11 @@ public abstract class SecurityUserImpl<RD extends RoleDefinition, R extends Abst
}
public void addRole(R role) {
roles.add(role);
getRolesInternal().add(role);
}
public void removeRole(R role) {
roles.remove(role);
getRolesInternal().remove(role);
}
public void addPermission(WildcardPermission permission) {
@@ -1,15 +1,21 @@
package com.sap.sse.security;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import org.apache.shiro.crypto.hash.Sha256Hash;
@@ -69,6 +75,19 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup>
private final Map<AccountType, Account> accounts;
private transient UserGroupProvider userGroupProvider;
/**
* Roles can refer back to this user object, e.g., for the user qualification, or during the tenant
* qualification if this user belongs to the tenant for which the role is qualified. Therefore, this
* set has to be transient, and the {@link #roleListForSerialization} field takes over the serialization
* which is resolved by {@link #readResolve}.
*
* @see #writeObject
* @see #readResolve
*/
private transient Set<Role> roles;
private List<Role> roleListForSerialization;
public UserImpl(String name, String email, Map<String, UserGroup> defaultTenantForServer,
UserGroupProvider userGroupProvider, Account... accounts) {
@@ -99,6 +118,30 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup>
for (Account a : accounts) {
this.accounts.put(a.getAccountType(), a);
}
roles = new HashSet<>();
}
@Override
protected Set<Role> getRolesInternal() {
return roles;
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(new ArrayList<>(roles));
}
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
roleListForSerialization = (List<Role>) ois.readObject();
}
protected Object readResolve() {
roles = new HashSet<>(roleListForSerialization);
roleListForSerialization = null;
return this;
}
/**