package com.constellio.model.entities.records.wrappers;
import static com.constellio.model.entities.schemas.Schemas.TOKENS;
import static com.constellio.model.entities.security.Role.DELETE;
import static com.constellio.model.entities.security.Role.READ;
import static com.constellio.model.entities.security.Role.WRITE;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.where;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.constellio.data.utils.KeySetMap;
import com.constellio.model.entities.enums.GroupAuthorizationsInheritance;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.schemas.Schemas;
import com.constellio.model.entities.security.global.AuthorizationDetails;
import com.constellio.model.services.records.RecordServicesRuntimeException;
import com.constellio.model.services.records.SchemasRecordsServices;
import com.constellio.model.services.security.SecurityTokenManager;
public class UserAuthorizationsUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(UserAuthorizationsUtils.class);
public static boolean containsAnyUserGroupTokens(User user, Record record, String role) {
String prefix;
if (READ.equals(role)) {
prefix = "r_";
} else if (WRITE.equals(role)) {
prefix = "w_";
} else if (DELETE.equals(role)) {
prefix = "d_";
} else {
prefix = role;
}
List<String> tokens = record.getList(TOKENS);
if (tokens.contains(prefix + user.getId())) {
return true;
}
for (String aGroup : user.getUserGroups()) {
if (tokens.contains(prefix + aGroup)) {
return true;
}
}
return false;
}
public static boolean containsAUserToken(User user, Record record) {
SecurityTokenManager securityTokenManager = user.getRolesDetails().getSchemasRecordsServices().getModelLayerFactory()
.getSecurityTokenManager();
for (String token : securityTokenManager.getTokens(user).getAllowTokens()) {
if (record.getList(TOKENS).contains(token)) {
return true;
}
}
return false;
}
public static interface AuthorizationDetailsFilter {
boolean isIncluded(AuthorizationDetails details);
}
public static AuthorizationDetailsFilter anyRole(final String... roles) {
return new AuthorizationDetailsFilter() {
@Override
public boolean isIncluded(AuthorizationDetails details) {
for (String role : roles) {
if (details.getRoles().contains(role)) {
return true;
}
}
return false;
}
};
}
public static AuthorizationDetailsFilter allRoles(final String... roles) {
return new AuthorizationDetailsFilter() {
@Override
public boolean isIncluded(AuthorizationDetails details) {
for (String role : roles) {
if (!details.getRoles().contains(role)) {
return false;
}
}
return true;
}
};
}
public static AuthorizationDetailsFilter ROLE_AUTHS = new AuthorizationDetailsFilter() {
@Override
public boolean isIncluded(AuthorizationDetails details) {
for (String role : details.getRoles()) {
if (!isAccessRole(role)) {
return true;
}
}
return false;
}
};
public static AuthorizationDetailsFilter READ_ACCESS = new AuthorizationDetailsFilter() {
@Override
public boolean isIncluded(AuthorizationDetails details) {
return details.getRoles().contains(READ) || details.getRoles().contains(WRITE) || details.getRoles().contains(DELETE);
}
};
private static boolean isAccessRole(String role) {
return role.equals(READ) || role.equals(WRITE) || role.equals(DELETE);
}
public static AuthorizationDetailsFilter WRITE_ACCESS = new AuthorizationDetailsFilter() {
@Override
public boolean isIncluded(AuthorizationDetails details) {
return details.getRoles().contains(WRITE);
}
};
public static AuthorizationDetailsFilter DELETE_ACCESS = new AuthorizationDetailsFilter() {
@Override
public boolean isIncluded(AuthorizationDetails details) {
return details.getRoles().contains(DELETE);
}
};
public static KeySetMap<String, String> retrieveUserTokens(User user, AuthorizationDetailsFilter filter) {
SchemasRecordsServices schemas = user.getRolesDetails().getSchemasRecordsServices();
GroupAuthorizationsInheritance inheritance = schemas.getModelLayerFactory().getSystemConfigs()
.getGroupAuthorizationsInheritance();
Set<String> authsId;
if (inheritance == GroupAuthorizationsInheritance.FROM_CHILD_TO_PARENT) {
authsId = new HashSet<>();
authsId.addAll(user.getUserAuthorizations());
for (String groupId : user.getUserGroups()) {
Group group = schemas.getGroup(groupId);
authsId.addAll(getAuthsOfGroupAndChildGroups(group, schemas));
}
} else {
authsId = new HashSet<>(user.getAllUserAuthorizations());
}
KeySetMap<String, String> tokens = new KeySetMap<>();
for (String authId : authsId) {
try {
AuthorizationDetails authorizationDetails = user.getAuthorizationDetail(authId);
if (authorizationDetails.isActiveAuthorization() && filter.isIncluded(authorizationDetails)) {
tokens.add(authorizationDetails.getTarget(), authId);
}
} catch (RecordServicesRuntimeException.NoSuchRecordWithId e) {
LOGGER.warn("User " + user.getUsername() + "' has an authorization without details : " + authId);
}
}
return tokens;
}
private static Set<String> getAuthsOfGroupAndChildGroups(Group group, SchemasRecordsServices schemas) {
Set<String> auths = new HashSet<>();
auths.addAll(group.<String>getList(Schemas.AUTHORIZATIONS));
for (Group childGroup : schemas.searchGroups(where(schemas.group.parent()).isEqualTo(group))) {
auths.addAll(getAuthsOfGroupAndChildGroups(childGroup, schemas));
}
return auths;
}
public static Set<String> getRolesOnRecord(User user, Record record) {
Set<String> auths = getMatchingAuthorization(user, record, ROLE_AUTHS);
Set<String> roles = new HashSet<>();
for (String authId : auths) {
AuthorizationDetails authorizationDetails = user.getAuthorizationDetail(authId);
for (String role : authorizationDetails.getRoles()) {
if (!isAccessRole(role)) {
roles.add(role);
}
}
}
return roles;
}
public static boolean hasMatchingAuthorization(User user, Record record, AuthorizationDetailsFilter filter) {
KeySetMap<String, String> tokens = retrieveUserTokens(user, filter);
List<String> attachedAncestors = record.<String>getList(Schemas.ATTACHED_ANCESTORS);
List<String> allRemovedAuths = record.<String>getList(Schemas.ALL_REMOVED_AUTHS);
for (Map.Entry<String, Set<String>> token : tokens.getMapEntries()) {
if (attachedAncestors.contains(token.getKey())) {
for (String auth : token.getValue()) {
if (!allRemovedAuths.contains(auth)) {
return true;
}
}
}
}
return false;
}
public static Set<String> getMatchingAuthorization(User user, Record record, AuthorizationDetailsFilter filter) {
KeySetMap<String, String> tokens = retrieveUserTokens(user, filter);
Set<String> authIds = new HashSet<>();
List<String> attachedAncestors = record.<String>getList(Schemas.ATTACHED_ANCESTORS);
List<String> allRemovedAuths = record.<String>getList(Schemas.ALL_REMOVED_AUTHS);
for (Map.Entry<String, Set<String>> token : tokens.getMapEntries()) {
if (attachedAncestors.contains(token.getKey())) {
for (String auth : token.getValue()) {
if (!allRemovedAuths.contains(auth)) {
authIds.add(auth);
}
}
}
}
return authIds;
}
}