Skip to content

Commit

Permalink
[SYNCOPE-1769] Any Objects: unique constraint now on (name, type) (#488)
Browse files Browse the repository at this point in the history
  • Loading branch information
ilgrosso committed Jul 6, 2023
1 parent 39dc5ab commit 872e4b7
Show file tree
Hide file tree
Showing 32 changed files with 275 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,16 @@ public AnyObjectCompleteCondition notInGroups(final String group, final String..
notInGroups(group, moreGroups);
}

public AnyObjectCompleteCondition inRelationships(final String anyType, final String... moreAnyTypes) {
public AnyObjectCompleteCondition inRelationships(final String anyObject, final String... moreAnyObjects) {
return newBuilderInstance().
is(SpecialAttr.RELATIONSHIPS.toString()).
inRelationships(anyType, moreAnyTypes);
inRelationships(anyObject, moreAnyObjects);
}

public AnyObjectCompleteCondition notInRelationships(final String anyType, final String... moreAnyTypes) {
public AnyObjectCompleteCondition notInRelationships(final String anyObject, final String... moreAnyObjects) {
return newBuilderInstance().
is(SpecialAttr.RELATIONSHIPS.toString()).
notInRelationships(anyType, moreAnyTypes);
notInRelationships(anyObject, moreAnyObjects);
}

public AnyObjectCompleteCondition inRelationshipTypes(final String type, final String... moreTypes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ public UserCompleteCondition notInGroups(final String group, final String... mor
notInGroups(group, moreGroups);
}

public UserCompleteCondition inRelationships(final String anyType, final String... moreAnyTypes) {
public UserCompleteCondition inRelationships(final String anyObject, final String... moreAnyObjects) {
return newBuilderInstance().
is(SpecialAttr.RELATIONSHIPS.toString()).
inRelationships(anyType, moreAnyTypes);
inRelationships(anyObject, moreAnyObjects);
}

public UserCompleteCondition notInRelationships(final String anyType, final String... moreAnyTypes) {
public UserCompleteCondition notInRelationships(final String anyObject, final String... moreAnyObjects) {
return newBuilderInstance().
is(SpecialAttr.RELATIONSHIPS.toString()).
notInRelationships(anyType, moreAnyTypes);
notInRelationships(anyObject, moreAnyObjects);
}

public UserCompleteCondition inRelationshipTypes(final String type, final String... moreTypes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
Expand All @@ -57,15 +59,26 @@ public interface AnyObjectService extends AnyService<AnyObjectTO> {

@ApiResponses(
@ApiResponse(responseCode = "200", description =
"Any object matching the provided key; if value looks like a UUID then it is interpreted as key,"
+ " otherwise as a name.", headers =
"Any object matching the provided key.", headers =
@Header(name = HttpHeaders.ETAG, schema =
@Schema(type = "string"),
description = "Opaque identifier for the latest modification made to the entity returned"
+ " by this endpoint")))
@Override
AnyObjectTO read(String key);

@ApiResponses(
@ApiResponse(responseCode = "200", description =
"Any object matching the provided type and name.", headers =
@Header(name = HttpHeaders.ETAG, schema =
@Schema(type = "string"),
description = "Opaque identifier for the latest modification made to the entity returned"
+ " by this endpoint")))
@GET
@Path("byName/{type}/{name}")
@Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
AnyObjectTO read(@NotNull @PathParam("type") String type, @NotNull @PathParam("name") String name);

@Override
PagedResult<AnyObjectTO> search(AnyQuery anyQuery);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,16 @@
import org.apache.syncope.common.rest.api.beans.CSVPullSpec;
import org.apache.syncope.common.rest.api.beans.CSVPushSpec;
import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
Expand Down Expand Up @@ -223,10 +226,17 @@ protected ConnObject getOnSyncope(
}

protected Any<?> getAny(final Provision provision, final AnyTypeKind anyTypeKind, final String anyKey) {
AnyDAO<Any<?>> dao = anyUtilsFactory.getInstance(anyTypeKind).dao();
Any<?> any = SyncopeConstants.UUID_PATTERN.matcher(anyKey).matches()
? dao.authFind(anyKey)
: dao.authFind(dao.findKey(anyKey));
AnyDAO<?> dao = anyUtilsFactory.getInstance(anyTypeKind).dao();

String actualKey = anyKey;
if (!SyncopeConstants.UUID_PATTERN.matcher(anyKey).matches()) {
actualKey = dao instanceof UserDAO
? ((UserDAO) dao).findKey(anyKey)
: dao instanceof GroupDAO
? ((GroupDAO) dao).findKey(anyKey)
: ((AnyObjectDAO) dao).findKey(provision.getAnyType(), anyKey);
}
Any<?> any = dao.authFind(actualKey);
if (any == null) {
throw new NotFoundException(provision.getAnyType() + " '" + anyKey + "'");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ public AnyObjectTO read(final String key) {
return binder.getAnyObjectTO(key);
}

@Transactional(readOnly = true)
public AnyObjectTO read(final String type, final String name) {
return Optional.ofNullable(anyObjectDAO.findKey(type, name)).
map(binder::getAnyObjectTO).
orElseThrow(() -> new NotFoundException("AnyObject " + type + " " + name));
}

@Transactional(readOnly = true)
@Override
public Pair<Integer, List<AnyObjectTO>> search(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public Attr read(final String key, final SchemaType schemaType, final String sch

@Override
public TO read(final String key) {
return getAnyLogic().read(getActualKey(getAnyDAO(), key));
return getAnyLogic().read(findActualKey(getAnyDAO(), key));
}

@Override
Expand Down Expand Up @@ -157,7 +157,7 @@ protected OffsetDateTime findLastChange(final String key) {
}

protected Response doUpdate(final UR updateReq) {
updateReq.setKey(getActualKey(getAnyDAO(), updateReq.getKey()));
updateReq.setKey(findActualKey(getAnyDAO(), updateReq.getKey()));
OffsetDateTime etag = findLastChange(updateReq.getKey());
checkETag(String.valueOf(etag.toInstant().toEpochMilli()));

Expand Down Expand Up @@ -192,23 +192,22 @@ protected void addUpdateOrReplaceAttr(

@Override
public Response update(final String key, final SchemaType schemaType, final Attr attrTO) {
String actualKey = getActualKey(getAnyDAO(), key);
String actualKey = findActualKey(getAnyDAO(), key);
addUpdateOrReplaceAttr(actualKey, schemaType, attrTO, PatchOperation.ADD_REPLACE);
return modificationResponse(read(actualKey, schemaType, attrTO.getSchema()));
}

@Override
public void delete(final String key, final SchemaType schemaType, final String schema) {
addUpdateOrReplaceAttr(
getActualKey(getAnyDAO(), key),
addUpdateOrReplaceAttr(findActualKey(getAnyDAO(), key),
schemaType,
new Attr.Builder(schema).build(),
PatchOperation.DELETE);
}

@Override
public Response delete(final String key) {
String actualKey = getActualKey(getAnyDAO(), key);
String actualKey = findActualKey(getAnyDAO(), key);

OffsetDateTime etag = findLastChange(actualKey);
checkETag(String.valueOf(etag.toInstant().toEpochMilli()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
import org.apache.syncope.common.rest.api.RESTHeaders;
import org.apache.syncope.common.rest.api.service.JAXRSService;
import org.apache.syncope.core.persistence.api.dao.AnyDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -59,7 +61,7 @@ public abstract class AbstractService implements JAXRSService {
@Context
protected SearchContext searchContext;

protected String getActualKey(final AnyDAO<?> dao, final String pretendingKey) {
protected String findActualKey(final AnyDAO<?> dao, final String pretendingKey) {
String actualKey = pretendingKey;
if (uriInfo.getPathParameters(true).containsKey("key")) {
String keyInPath = uriInfo.getPathParameters(true).get("key").get(0);
Expand All @@ -77,7 +79,11 @@ protected String getActualKey(final AnyDAO<?> dao, final String pretendingKey) {
throw sce;
}
if (!SyncopeConstants.UUID_PATTERN.matcher(actualKey).matches()) {
actualKey = dao.findKey(actualKey);
actualKey = dao instanceof UserDAO
? ((UserDAO) dao).findKey(actualKey)
: dao instanceof GroupDAO
? ((GroupDAO) dao).findKey(actualKey)
: null;
}
return actualKey;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@ protected AbstractAnyLogic<AnyObjectTO, AnyObjectCR, AnyObjectUR> getAnyLogic()
return logic;
}

@Override
public AnyObjectTO read(final String key) {
return logic.read(key);
}

@Override
public AnyObjectTO read(final String type, final String name) {
return logic.read(type, name);
}

@Override
protected AnyObjectUR newUpdateReq(final String key) {
return new AnyObjectUR.Builder(key).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ public interface AnyDAO<A extends Any<?>> extends DAO<A> {

int DEFAULT_PAGE_SIZE = 500;

String findKey(String name);

List<A> findByKeys(List<String> keys);

OffsetDateTime findLastChange(String key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@

public interface AnyObjectDAO extends AnyDAO<AnyObject> {

String findKey(String type, String name);

AnyObject findByName(String type, String name);

List<AnyObject> findByName(String name);

/**
* Checks if the calling user is authorized to access the Any Object matching the provided key, under the given
* realm.
Expand All @@ -54,8 +60,6 @@ public interface AnyObjectDAO extends AnyDAO<AnyObject> {

Map<String, Integer> countByRealm(AnyType anyType);

AnyObject findByName(String name);

AMembership findMembership(String key);

List<Group> findDynGroups(String key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@

public interface GroupDAO extends AnyDAO<Group> {

String findKey(String name);

Group findByName(String name);

/**
* Checks if the calling user is authorized to access the Group matching the provided key, under the given
* realm.
Expand All @@ -45,8 +49,6 @@ public interface GroupDAO extends AnyDAO<Group> {

Map<String, Integer> countByRealm();

Group findByName(String name);

List<String> findKeysByNamePattern(String pattern);

List<Group> findOwnedByUser(String userKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@

public interface UserDAO extends AnyDAO<User> {

String findKey(String username);

Optional<String> findUsername(String key);

/**
* Checks if the calling user is authorized to access the User matching the provided key, under the given
* realm.
Expand All @@ -46,8 +50,6 @@ public interface UserDAO extends AnyDAO<User> {
*/
void securityChecks(Set<String> authRealms, String key, String realm, Collection<String> groups);

Optional<String> findUsername(String key);

Map<String, Integer> countByRealm();

Map<String, Integer> countByStatus();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ protected String getQuery(
final List<Object> parameters,
final SearchSupport svs) {

String memberKey = check(cond);
Set<String> members = check(cond);

StringBuilder query = new StringBuilder().append('(');

Expand All @@ -477,7 +477,9 @@ protected String getQuery(

query.append("SELECT DISTINCT group_id AS any_id FROM ").
append(new SearchSupport(AnyTypeKind.USER).membership().name).append(" WHERE ").
append("any_id=?").append(setParameter(parameters, memberKey)).
append(members.stream().
map(key -> "any_id=?" + setParameter(parameters, key)).
collect(Collectors.joining(" OR "))).
append(") ");

if (not) {
Expand All @@ -488,7 +490,9 @@ protected String getQuery(

query.append("SELECT DISTINCT group_id AS any_id FROM ").
append(new SearchSupport(AnyTypeKind.ANY_OBJECT).membership().name).append(" WHERE ").
append("any_id=?").append(setParameter(parameters, memberKey)).
append(members.stream().
map(key -> "any_id=?" + setParameter(parameters, key)).
collect(Collectors.joining(" OR "))).
append(')');

query.append(')');
Expand Down Expand Up @@ -531,7 +535,7 @@ protected String getQuery(
final List<Object> parameters,
final SearchSupport svs) {

String rightAnyObjectKey = check(cond);
Set<String> rightAnyObjectKeys = check(cond);

StringBuilder query = new StringBuilder().append('(');

Expand All @@ -543,7 +547,9 @@ protected String getQuery(

query.append("SELECT DISTINCT any_id FROM ").
append(svs.relationship().name).append(" WHERE ").
append("right_any_id=?").append(setParameter(parameters, rightAnyObjectKey)).
append(rightAnyObjectKeys.stream().
map(key -> "right_any_id=?" + setParameter(parameters, key)).
collect(Collectors.joining(" OR "))).
append(')');

query.append(')');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import jakarta.persistence.EntityListeners;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import jakarta.persistence.UniqueConstraint;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
Expand All @@ -36,7 +37,8 @@
import org.apache.syncope.core.persistence.jpa.validation.entity.JPAJSONAttributableCheck;

@Entity
@Table(name = JPAAnyObject.TABLE)
@Table(name = JPAAnyObject.TABLE, uniqueConstraints =
@UniqueConstraint(columnNames = { "name", "type_id" }))
@EntityListeners({ JPAJSONAnyObjectListener.class })
@JPAJSONAttributableCheck
public class JPAJSONAnyObject extends JPAAnyObject implements JSONAttributable<AnyObject>, AnyObject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -102,22 +101,6 @@ protected AnyUtils anyUtils() {
return anyUtils;
}

protected String findKey(final String name, final String table) {
Query query = entityManager().createNativeQuery(
"SELECT id FROM " + table + " WHERE " + (JPAUser.TABLE.equals(table) ? "username" : "name") + "=?");
query.setParameter(1, name);

String key = null;

for (Object resultKey : query.getResultList()) {
key = resultKey instanceof Object[]
? (String) ((Object[]) resultKey)[0]
: ((String) resultKey);
}

return key;
}

@SuppressWarnings("unchecked")
protected List<String> findAllKeys(final String table, final int page, final int itemsPerPage) {
Query query = entityManager().createNativeQuery(
Expand Down
Loading

0 comments on commit 872e4b7

Please sign in to comment.