Hi Francesco, My english is also poor, so that explains some misunderstanding.
Basically one PERSON instance like 'titi' (personId="titi") may have many accounts (User instance) like: 'usr-titi', 'adm-titi' ... PERSON titi have their own lifecycle, managed by an external resource like an HR System (see https://github.com/spopoff/persons). So when an event of create / update / delete appears on 'titi', a "business" logic should apply rules that modify accounts. For example: - When 'toto' is created, we creates an account 'usr-toto' with minimal access to some applications - When 'toto' is updated and this operationalUnit attribute equals "SOC", we creates a new account 'adm-toto' with privilege access - When 'toto' quit, is deleted, all the associate accounts are deleted (based on the value 'toto' in the attribute personName) Actually I put this "Business" logic (create /delete) in an extension of DefaultAnyObjectProvisioningManager (see code below). But are there the best implementations ? Generally this "Business" logic takes place in a workflow, I also extend DefaultAnyObjectWorkflowAdapter, but I found a problem with the delete. It's also very deep in Syncope and not user friendly (pure Java code). My view on Syncope is that it's a good tool for synchronizing resources and accounts, and also for authenticating those resources and their accounts. However, its account-centric approach makes it difficult to integrate an identity-oriented logic. At this point in my thinking, I believe that part of the logic needs to be put upstream of Syncope and APIs used to control access management. What did you think ? Best regards, Stéphane POPOFF public class PersonProvisioningManager extends DefaultAnyObjectProvisioningManager { @Autowired UserProvisioningManager userProvisioningManager; @Autowired protected UserDAO userDAO; protected static final Logger LOG = LogManager.getLogger(PersonProvisioningManager.class); public PersonProvisioningManager(AnyObjectWorkflowAdapter awfAdapter, PropagationManager propagationManager, PropagationTaskExecutor taskExecutor, AnyObjectDAO anyObjectDAO) { super(awfAdapter, propagationManager, taskExecutor, anyObjectDAO); } @Transactional(propagation = Propagation.REQUIRES_NEW) @Override public ProvisioningResult<String> create( final AnyObjectCR anyObjectCR, final Set<String> excludedResources, final boolean nullPriorityAsync, final String creator, final String context){ //on teste si c'est un objet PERSON car alors on va peut-être créer un compte d'accès primaire if(!anyObjectCR.getType().equals("PERSON")){ LOG.info("pas un objet PERSON <> "+anyObjectCR.getType()); return super.create(anyObjectCR, excludedResources, nullPriorityAsync, creator, context); } LOG.info("1 Création d'une personne name="+anyObjectCR.getName()); //on fait appel au workflow objet qui reconnait les PERSON WorkflowResult<String> created = awfAdapter.create(anyObjectCR, creator, context); LOG.info("retour du workflow "+created.getResult()); //je sais pas ce qu'il raconte en cas de réussite ou échec ? //on cherche un USER avec un personId == anyObjectCR.getName(); List<User> users = null; boolean erreur = false; try{ users = userDAO.findByDerAttrValue("personName==", anyObjectCR.getName(), false); }catch(Exception ex){ LOG.error("Erreur recherche USER "+ex); erreur = true; } if(!erreur && users != null && !users.isEmpty()){ //on trouve un des comptes LOG.info("2 Déjà des comptes, mais conforme aux besoins métiers ?"); }else if(!erreur){ LOG.info("2 Pas comptes, mais répondre aux besoins métiers ?"); UserCR novo = new UserCR.Builder("/", "usr-"+anyObjectCR.getName()) .plainAttr(new Attr.Builder("personName").value(anyObjectCR.getName()).build()).build(); userProvisioningManager.create(novo, nullPriorityAsync, creator, context); } //Je sais pas encore comment gérer cette partie List<PropagationTaskInfo> taskInfos = propagationManager.getCreateTasks( AnyTypeKind.ANY_OBJECT, created.getResult(), null, created.getPropByRes(), excludedResources); //en fait je retourne zéro pour l'instant LOG.info("3 Taches de propagation nb="+taskInfos.size()); for(PropagationTaskInfo taskInfo : taskInfos){ LOG.info("4 Tache de propagation key="+taskInfo.getKey()); } PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, creator); return new ProvisioningResult<>(created.getResult(), propagationReporter.getStatuses()); } @Transactional(propagation = Propagation.REQUIRES_NEW) @Override public List<PropagationStatus> delete( final String key, final Set<String> excludedResources, final boolean nullPriorityAsync, final String eraser, final String context) { LOG.info("1 Suppression un objet clé="+key); Optional<? extends AnyObject> anyObject = anyObjectDAO.findById(key); boolean objDel = false; if(anyObject.isEmpty() || !anyObject.isPresent()){ LOG.warn("Pas retrouvé l'objet clé="+key); }else{ LOG.info("2 Suppression un objet type="+anyObject.get().getType()+ " avec name="+anyObject.get().getName()); objDel = true; } if(objDel && anyObject.get().getType().toString().equals("JPAAnyType[PERSON]")){ LOG.info("3 Suppression un objet PERSON dans provisioning name="+ anyObject.get().getName()+" key="+key); List<User> users = null; boolean erreur = false; try{ users = userDAO.findByDerAttrValue("personName==", anyObject.get().getName(), false); }catch(Exception ex){ LOG.error("Erreur recherche USER "+ex); erreur = true; } if(!erreur && users != null && !users.isEmpty()){ //on trouve un des comptes LOG.info("4 Trouver des comptes, on flingue"); for(User user : users){ userDAO.delete(user); } } } PropagationByResource<String> propByRes = new PropagationByResource<>(); propByRes.set(ResourceOperation.DELETE, anyObjectDAO.findAllResourceKeys(key)); // Note here that we can only notify about "delete", not any other // task defined in workflow process definition: this because this // information could only be available after awfAdapter.delete(), which // will also effectively remove user from db, thus making virtually // impossible by NotificationManager to fetch required any object information //En gros les informations / objet produits dans le workflow sont inaccessibles car il va supprimer l'objet //donc seuls les "ressources liées" sont prévenues List<PropagationTaskInfo> taskInfos = propagationManager.getDeleteTasks( AnyTypeKind.ANY_OBJECT, key, propByRes, null, excludedResources); PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, eraser); awfAdapter.delete(key, eraser, context); return propagationReporter.getStatuses(); } } Le jeu. 8 janv. 2026 à 08:50, Francesco Chicchiriccò <[email protected]> a écrit : > > Hi, > my French is not as good as it used to be, so I am not very able to follow :-) > > Please try to explain your needs as clear as possible, in English, possibly > in terms of requirements. > > So far, I have understood that: > > 1. you have defined a PERSON AnyType > 2. you have mapped PERSON to one or more External Resources > 3. (maybe?) multiple PERSON instances are in Relationship with a single USER > instance > 4. there are events (REST calls to Syncope API? Console modifications?) that > are triggering changes on PERSON instances ("arrives first", "change > OrganizationalUnit") or possibly the related USER instance; such changes will > propagate, through the mapping(s) provided, to the configured External > Resource(s) > > What I am failing to understand so far: > > 1. why you should be modifying the PERSON or USER AnyType definition when the > events occurs: I would expect changes to PERSON or USER instances (by adding > / removing attributes, memberships or relationships for example) but not the > AnyType itself > 2. whether your are encapsulating somehow the changes (maybe via a custom > REST endpoint) which is meant to affect both a USER and related PERSON > instance(s) > > Maybe you can just provide a couple of examples, using Syncope concepts as > AnyType, Relationships, instances, Resources, etc. > > Regards. > > On 07/01/26 11:30, Stéphane Popoff wrote: > > Happy new year, > > About my use case I made a short video > > [https://sites.google.com/spopoff.net/integrationsyncope/democonnsync?usp=sharing] > > to explain the need. > > > > Best regards, > > Stéphane POPOFF > > > > Le mer. 31 déc. 2025 à 11:27, Stéphane Popoff <[email protected]> a > > écrit : > >> Hi Francesco, > >> I want to manage access (User account) by an identity object, that was > >> supported by an AnyObject PERSON and it's connector. So the life cycle of > >> the object PERSON conducts the need of access of the identity. In fact > >> PERSON is the the real digital identity, not as User in the Syncope's > >> design, and User only supports access. > >> Hope it's more clear. > >> > >> Best regards, > >> Stéphane popoff > >> > >> Le mer. 31 déc. 2025, 07:59, Francesco Chicchiriccò <[email protected]> > >> a écrit : > >>> Hi, > >>> I am not sure to understand your use case - or better, I am not sure to > >>> understand why a change to the USER AnyType should be involved. > >>> > >>> Can you please describe what you are trying to achieve from an abstract > >>> point of view? > >>> > >>> Regards. > >>> > >>> On 30/12/25 19:31, Stéphane Popoff wrote: > >>>> Hello, > >>>> > >>>> I have a use case where a flow of objects (JPAAnyType[PERSON]) may > >>>> produce change on accounts (User). > >>>> Beside the 2 flows I want to introduce a business logic of kind: > >>>> - If a person arrive first, we give it a basic access to RH system and > >>>> a basic access to the tool of this operationalUnit > >>>> - If a person changes this operationalUnit, previous access is closed, > >>>> newest is open (with or without overlay) > >>>> - well real time implementation of an IAM system ;-) > >>>> My question is where can I put this logic ? In the Provisioning > >>>> Manager or/and/xor in the Workflow ? > >>>> > >>>> I did some tests and found that mixing operations across types > >>>> (JPAAnyType[PERSON] and User) in a basic workflow creates problems. > >>>> > >>>> Best regards, happy new eve, > >>>> Stéphane POPOFF > > -- > Francesco Chicchiriccò > > Tirasa - Open Source Excellence > http://www.tirasa.net/ > > Member at The Apache Software Foundation > Syncope, Cocoon, Olingo, CXF, OpenJPA > https://about.me/ilgrosso >
