Skip to content

Commit

Permalink
[SYNCOPE-1764] Managing connectors' Spring beans (un)registration in …
Browse files Browse the repository at this point in the history
…case HA is set up (#512)
  • Loading branch information
ilgrosso committed Sep 6, 2023
1 parent 83be6fe commit b9d1d40
Show file tree
Hide file tree
Showing 19 changed files with 262 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ protected Iterator<String> getChoices(final String input) {
"bundleName",
"bundleName",
new PropertyModel<>(connInstanceTO, "bundleName"), false);
bundleName.setEnabled(connInstanceTO.getKey() == null);
bundleName.setEnabled(connInstanceTO.getKey() == null || connInstanceTO.isErrored());
bundleName.setChoices(bundles.stream().map(ConnIdBundle::getBundleName).
distinct().sorted().collect(Collectors.toList()));
bundleName.getField().setOutputMarkupId(true);
Expand All @@ -100,14 +100,14 @@ protected Iterator<String> getChoices(final String input) {
"connectorName",
"connectorName",
new PropertyModel<>(connInstanceTO, "connectorName"), false);
connectorName.setEnabled(connInstanceTO.getBundleName() == null);
connectorName.setEnabled(connInstanceTO.getBundleName() == null || connInstanceTO.isErrored());
Optional.ofNullable(connInstanceTO.getConnectorName()).ifPresent(v -> connectorName.setChoices(List.of(v)));
connectorName.getField().setOutputMarkupId(true);
add(connectorName.addRequiredLabel().setOutputMarkupId(true));

AjaxDropDownChoicePanel<String> version = new AjaxDropDownChoicePanel<>(
"version", "version", new PropertyModel<>(connInstanceTO, "version"), false);
version.setEnabled(connInstanceTO.getConnectorName() == null);
version.setEnabled(connInstanceTO.getConnectorName() == null || connInstanceTO.isErrored());
Optional.ofNullable(connInstanceTO.getVersion()).ifPresent(v -> version.setChoices(List.of(v)));
version.getField().setOutputMarkupId(true);
add(version.addRequiredLabel().setOutputMarkupId(true));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ public ConnectorLogic(
}

protected void securityChecks(final Set<String> effectiveRealms, final String realm, final String key) {
boolean authorized = effectiveRealms.stream().anyMatch(realm::startsWith);
if (!authorized) {
if (!effectiveRealms.stream().anyMatch(realm::startsWith)) {
throw new DelegatedAdministrationException(realm, ConnInstance.class.getSimpleName(), key);
}
}
Expand Down Expand Up @@ -132,10 +131,8 @@ public ConnInstanceTO update(final ConnInstanceTO connInstanceTO) {

@PreAuthorize("hasRole('" + IdMEntitlement.CONNECTOR_DELETE + "')")
public ConnInstanceTO delete(final String key) {
ConnInstance connInstance = connInstanceDAO.authFind(key);
if (connInstance == null) {
throw new NotFoundException("Connector '" + key + '\'');
}
ConnInstance connInstance = Optional.ofNullable(connInstanceDAO.authFind(key)).
orElseThrow(() -> new NotFoundException("Connector '" + key + '\''));

Set<String> effectiveRealms = RealmUtils.getEffective(
AuthContextUtils.getAuthorizations().get(IdMEntitlement.CONNECTOR_DELETE),
Expand All @@ -151,7 +148,6 @@ public ConnInstanceTO delete(final String key) {

ConnInstanceTO deleted = binder.getConnInstanceTO(connInstance);
connInstanceDAO.delete(key);
connectorManager.unregisterConnector(key);
return deleted;
}

Expand Down Expand Up @@ -210,7 +206,6 @@ public List<ConnIdBundle> getBundles(final String lang) {
}

@PreAuthorize("hasRole('" + IdMEntitlement.CONNECTOR_READ + "')")

public List<ConnIdObjectClass> buildObjectClassInfo(
final ConnInstanceTO connInstanceTO, final boolean includeSpecial) {

Expand Down Expand Up @@ -261,12 +256,10 @@ public void check(final ConnInstanceTO connInstanceTO) {
public ConnInstanceTO readByResource(final String resourceName, final String lang) {
CurrentLocale.set(StringUtils.isBlank(lang) ? Locale.ENGLISH : new Locale(lang));

ExternalResource resource = resourceDAO.find(resourceName);
if (resource == null) {
throw new NotFoundException("Resource '" + resourceName + '\'');
}
ConnInstanceTO connInstance = binder.
getConnInstanceTO(connectorManager.getConnector(resource).getConnInstance());
ExternalResource resource = Optional.ofNullable(resourceDAO.find(resourceName)).
orElseThrow(() -> new NotFoundException("Resource '" + resourceName + '\''));
ConnInstanceTO connInstance = binder.getConnInstanceTO(
connectorManager.getConnector(resource).getConnInstance());
connInstance.setKey(resource.getConnector().getKey());
return connInstance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,8 @@ public ResourceTO create(final ResourceTO resourceTO) {

@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_UPDATE + "')")
public ResourceTO update(final ResourceTO resourceTO) {
ExternalResource resource = resourceDAO.authFind(resourceTO.getKey());
if (resource == null) {
throw new NotFoundException("Resource '" + resourceTO.getKey() + '\'');
}
ExternalResource resource = Optional.ofNullable(resourceDAO.authFind(resourceTO.getKey())).
orElseThrow(() -> new NotFoundException("Resource '" + resourceTO.getKey() + '\''));

Set<String> effectiveRealms = RealmUtils.getEffective(
AuthContextUtils.getAuthorizations().get(IdMEntitlement.RESOURCE_UPDATE),
Expand Down Expand Up @@ -202,10 +200,8 @@ public void setLatestSyncToken(final String key, final String anyTypeKey) {
resource.getOrgUnit().setSyncToken(ConnObjectUtils.toString(
connector.getLatestSyncToken(new ObjectClass(resource.getOrgUnit().getObjectClass()))));
} else {
AnyType anyType = anyTypeDAO.find(anyTypeKey);
if (anyType == null) {
throw new NotFoundException("AnyType '" + anyTypeKey + '\'');
}
AnyType anyType = Optional.ofNullable(anyTypeDAO.find(anyTypeKey)).
orElseThrow(() -> new NotFoundException("AnyType '" + anyTypeKey + '\''));
Provision provision = resource.getProvisionByAnyType(anyType.getKey()).
orElseThrow(() -> new NotFoundException(
"Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + '\''));
Expand All @@ -224,21 +220,17 @@ public void setLatestSyncToken(final String key, final String anyTypeKey) {

@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_UPDATE + "')")
public void removeSyncToken(final String key, final String anyTypeKey) {
ExternalResource resource = resourceDAO.authFind(key);
if (resource == null) {
throw new NotFoundException("Resource '" + key + '\'');
}
ExternalResource resource = Optional.ofNullable(resourceDAO.authFind(key)).
orElseThrow(() -> new NotFoundException("Resource '" + key + '\''));
if (SyncopeConstants.REALM_ANYTYPE.equals(anyTypeKey)) {
if (resource.getOrgUnit() == null) {
throw new NotFoundException("Realm provision not enabled for Resource '" + key + '\'');
}

resource.getOrgUnit().setSyncToken(null);
} else {
AnyType anyType = anyTypeDAO.find(anyTypeKey);
if (anyType == null) {
throw new NotFoundException("AnyType '" + anyTypeKey + '\'');
}
AnyType anyType = Optional.ofNullable(anyTypeDAO.find(anyTypeKey)).
orElseThrow(() -> new NotFoundException("AnyType '" + anyTypeKey + '\''));
Provision provision = resource.getProvisionByAnyType(anyType.getKey()).
orElseThrow(() -> new NotFoundException(
"Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + '\''));
Expand All @@ -256,30 +248,26 @@ public void removeSyncToken(final String key, final String anyTypeKey) {

@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_DELETE + "')")
public ResourceTO delete(final String key) {
ExternalResource resource = resourceDAO.authFind(key);
if (resource == null) {
throw new NotFoundException("Resource '" + key + '\'');
}
ExternalResource resource = Optional.ofNullable(resourceDAO.authFind(key)).
orElseThrow(() -> new NotFoundException("Resource '" + key + '\''));

Set<String> effectiveRealms = RealmUtils.getEffective(
AuthContextUtils.getAuthorizations().get(IdMEntitlement.RESOURCE_DELETE),
resource.getConnector().getAdminRealm().getFullPath());
securityChecks(effectiveRealms, resource.getConnector().getAdminRealm().getFullPath(), resource.getKey());

ResourceTO resourceToDelete = binder.getResourceTO(resource);
connectorManager.unregisterConnector(resource);

ResourceTO deleted = binder.getResourceTO(resource);
resourceDAO.delete(key);

return resourceToDelete;
return deleted;
}

@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_READ + "')")
@Transactional(readOnly = true)
public ResourceTO read(final String key) {
ExternalResource resource = resourceDAO.authFind(key);
if (resource == null) {
throw new NotFoundException("Resource '" + key + '\'');
}
ExternalResource resource = Optional.ofNullable(resourceDAO.authFind(key)).
orElseThrow(() -> new NotFoundException("Resource '" + key + '\''));

return binder.getResourceTO(resource);
}
Expand All @@ -293,15 +281,11 @@ public List<ResourceTO> list() {
protected Triple<AnyType, ExternalResource, Provision> getProvision(
final String anyTypeKey, final String resourceKey) {

AnyType anyType = anyTypeDAO.find(anyTypeKey);
if (anyType == null) {
throw new NotFoundException("AnyType '" + anyTypeKey + "'");
}
AnyType anyType = Optional.ofNullable(anyTypeDAO.find(anyTypeKey)).
orElseThrow(() -> new NotFoundException("AnyType '" + anyTypeKey + '\''));

ExternalResource resource = resourceDAO.find(resourceKey);
if (resource == null) {
throw new NotFoundException("Resource '" + resourceKey + "'");
}
ExternalResource resource = Optional.ofNullable(resourceDAO.authFind(resourceKey)).
orElseThrow(() -> new NotFoundException("Resource '" + resourceKey + '\''));
Provision provision = resource.getProvisionByAnyType(anyType.getKey()).
orElseThrow(() -> new NotFoundException(
"Provision for " + anyType + " on Resource '" + resourceKey + "'"));
Expand All @@ -322,10 +306,9 @@ public String getConnObjectKeyValue(
Triple<AnyType, ExternalResource, Provision> triple = getProvision(anyTypeKey, key);

// 1. find any
Any<?> any = anyUtilsFactory.getInstance(triple.getLeft().getKind()).dao().authFind(anyKey);
if (any == null) {
throw new NotFoundException(triple.getLeft() + " " + anyKey);
}
Any<?> any = Optional.ofNullable(anyUtilsFactory.getInstance(triple.getLeft().getKind()).
dao().authFind(anyKey)).
orElseThrow(() -> new NotFoundException(triple.getLeft() + " " + anyKey));

// 2.get ConnObjectKey value
return mappingManager.getConnObjectKeyValue(any, triple.getMiddle(), triple.getRight()).
Expand All @@ -343,10 +326,9 @@ public ConnObject readConnObjectByAnyKey(
Triple<AnyType, ExternalResource, Provision> triple = getProvision(anyTypeKey, key);

// 1. find any
Any<?> any = anyUtilsFactory.getInstance(triple.getLeft().getKind()).dao().authFind(anyKey);
if (any == null) {
throw new NotFoundException(triple.getLeft() + " " + anyKey);
}
Any<?> any = Optional.ofNullable(anyUtilsFactory.getInstance(triple.getLeft().getKind()).
dao().authFind(anyKey)).
orElseThrow(() -> new NotFoundException(triple.getLeft() + " " + anyKey));

// 2. find on resource
List<ConnectorObject> connObjs = outboundMatcher.match(
Expand Down Expand Up @@ -473,10 +455,8 @@ public void handleResult(final SearchResult sr) {
@PreAuthorize("hasRole('" + IdMEntitlement.CONNECTOR_READ + "')")
@Transactional(readOnly = true)
public void check(final ResourceTO resourceTO) {
ConnInstance connInstance = connInstanceDAO.find(resourceTO.getConnector());
if (connInstance == null) {
throw new NotFoundException("Connector '" + resourceTO.getConnector() + '\'');
}
ConnInstance connInstance = Optional.ofNullable(connInstanceDAO.find(resourceTO.getConnector())).
orElseThrow(() -> new NotFoundException("Connector '" + resourceTO.getConnector() + '\''));

connectorManager.createConnector(
connectorManager.buildConnInstanceOverride(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public interface ExternalResourceDAO extends DAO<ExternalResource> {

boolean anyItemHaving(Implementation transformer);

List<ExternalResource> findByConnInstance(String connInstance);

List<ExternalResource> findByProvisionSorter(Implementation provisionSorter);

List<ExternalResource> findByPropagationActions(Implementation propagationActions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import javax.sql.DataSource;
import org.apache.syncope.common.keymaster.client.api.model.Domain;
import org.apache.syncope.core.persistence.api.DomainRegistry;
import org.apache.syncope.core.persistence.jpa.openjpa.ConnectorManagerRemoteCommitListener;
import org.apache.syncope.core.persistence.jpa.spring.DomainEntityManagerFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -124,12 +125,16 @@ public void register(final Domain domain) {
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setDatabasePlatform(domain.getDatabasePlatform());

ConnectorManagerRemoteCommitListener connectorManagerRemoteCommitListener =
new ConnectorManagerRemoteCommitListener(domain.getKey());

BeanDefinitionBuilder emf = BeanDefinitionBuilder.rootBeanDefinition(DomainEntityManagerFactoryBean.class).
addPropertyValue("mappingResources", domain.getOrm()).
addPropertyValue("persistenceUnitName", domain.getKey()).
addPropertyReference("dataSource", domain.getKey() + "DataSource").
addPropertyValue("jpaVendorAdapter", vendorAdapter).
addPropertyReference("commonEntityManagerFactoryConf", "commonEMFConf");
addPropertyReference("commonEntityManagerFactoryConf", "commonEMFConf").
addPropertyValue("connectorManagerRemoteCommitListener", connectorManagerRemoteCommitListener);
if (ctx.getEnvironment().containsProperty("openjpaMetaDataFactory")) {
emf.addPropertyValue("jpaPropertyMap", Map.of(
"openjpa.MetaDataFactory",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.Objects;
import javax.sql.DataSource;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.core.persistence.jpa.openjpa.ConnectorManagerRemoteCommitListener;
import org.apache.syncope.core.persistence.jpa.spring.CommonEntityManagerFactoryConf;
import org.apache.syncope.core.persistence.jpa.spring.DomainEntityManagerFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
Expand Down Expand Up @@ -106,6 +107,8 @@ public DomainEntityManagerFactoryBean masterEntityManagerFactory(
masterEntityManagerFactory.setDataSource(Objects.requireNonNull((DataSource) masterDataSource.getObject()));
masterEntityManagerFactory.setJpaVendorAdapter(vendorAdapter);
masterEntityManagerFactory.setCommonEntityManagerFactoryConf(commonEMFConf);
masterEntityManagerFactory.setConnectorManagerRemoteCommitListener(
new ConnectorManagerRemoteCommitListener(SyncopeConstants.MASTER_DOMAIN));

if (props.getMetaDataFactory() != null) {
masterEntityManagerFactory.setJpaPropertyMap(Map.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public int count() {
return ((Number) query.getSingleResult()).intValue();
}

@Transactional(readOnly = true)
@Override
public ExternalResource find(final String name) {
return entityManager().find(JPAExternalResource.class, name);
Expand Down Expand Up @@ -135,6 +136,17 @@ public boolean anyItemHaving(final Implementation transformer) {
count() > 0;
}

@Transactional(readOnly = true)
@Override
public List<ExternalResource> findByConnInstance(final String connInstance) {
TypedQuery<ExternalResource> query = entityManager().createQuery(
"SELECT e FROM " + JPAExternalResource.class.getSimpleName() + " e "
+ "WHERE e.connector.id=:connInstance", ExternalResource.class);
query.setParameter("connInstance", connInstance);

return query.getResultList();
}

@Override
public List<ExternalResource> findByPropagationActions(final Implementation propagationActions) {
TypedQuery<ExternalResource> query = entityManager().createQuery(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,14 +206,13 @@ public void setDisplayName(final String displayName) {

@Override
public List<? extends ExternalResource> getResources() {
return this.resources;
return resources;
}

@Override
public boolean add(final ExternalResource resource) {
checkType(resource, JPAExternalResource.class);
return this.resources.contains((JPAExternalResource) resource)
|| this.resources.add((JPAExternalResource) resource);
return resources.contains((JPAExternalResource) resource) || resources.add((JPAExternalResource) resource);
}

@Override
Expand Down
Loading

0 comments on commit b9d1d40

Please sign in to comment.