You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by md...@apache.org on 2015/08/27 13:12:56 UTC
[29/33] syncope git commit: [SYNCOPE-686] Merge from 1_2_X
[SYNCOPE-686] Merge from 1_2_X
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/054ea9ca
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/054ea9ca
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/054ea9ca
Branch: refs/heads/SYNCOPE-156
Commit: 054ea9ca212911475b6d8b0bd16011c9f831c980
Parents: 3559e69 a1737d3
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Wed Aug 26 16:53:57 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Wed Aug 26 16:53:57 2015 +0200
----------------------------------------------------------------------
.../console/commons/status/StatusUtils.java | 2 +-
.../client/console/rest/GroupRestClient.java | 15 +--
.../client/console/rest/UserRestClient.java | 15 +--
.../syncope/common/lib/mod/StatusMod.java | 2 +-
.../apache/syncope/core/logic/UserLogic.java | 2 +-
.../java/DefaultUserProvisioningManager.java | 4 +-
.../java/data/UserDataBinderImpl.java | 40 ++++++
.../propagation/PropagationManagerImpl.java | 2 +-
.../activiti/ActivitiUserWorkflowAdapter.java | 4 +-
.../camel/processor/UserProvisionProcessor.java | 2 +-
.../UserStatusPropagationProcessor.java | 2 +-
.../fit/core/reference/SyncTaskITCase.java | 2 +-
.../syncope/fit/core/reference/UserITCase.java | 127 +++++++++++++------
.../fit/core/reference/UserSelfITCase.java | 2 +-
.../fit/core/reference/VirAttrITCase.java | 4 +-
15 files changed, 154 insertions(+), 71 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/054ea9ca/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
index 1a6f04f,0000000..4165c7d
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
@@@ -1,281 -1,0 +1,281 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.commons.status;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.client.console.commons.ConnIdSpecialAttributeName;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.ImagePanel;
+import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.wicket.Component;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.request.resource.ContextRelativeResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class StatusUtils implements Serializable {
+
+ private static final long serialVersionUID = 7238009174387184309L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(StatusUtils.class);
+
+ private static final String IMG_PREFIX = "/img/statuses/";
+
+ private final AbstractAnyRestClient restClient;
+
+ public StatusUtils(final AbstractAnyRestClient restClient) {
+ this.restClient = restClient;
+ }
+
+ public List<ConnObjectWrapper> getConnectorObjects(final AnyTO any) {
+ final List<ConnObjectWrapper> objects = new ArrayList<>();
+ objects.addAll(getConnectorObjects(any, any.getResources()));
+ return objects;
+ }
+
+ public List<ConnObjectWrapper> getConnectorObjects(
+ final Collection<AnyTO> anys, final Collection<String> resources) {
+
+ final List<ConnObjectWrapper> objects = new ArrayList<>();
+
+ for (AnyTO any : anys) {
+ objects.addAll(getConnectorObjects(any, resources));
+ }
+
+ return objects;
+ }
+
+ private List<ConnObjectWrapper> getConnectorObjects(
+ final AnyTO any, final Collection<String> resources) {
+
+ final List<ConnObjectWrapper> objects = new ArrayList<>();
+
+ for (String resourceName : resources) {
+ ConnObjectTO objectTO = null;
+ try {
+ objectTO = restClient.readConnObject(resourceName, any.getKey());
+ } catch (Exception e) {
+ LOG.warn("ConnObject '{}' not found on resource '{}'", any.getKey(), resourceName);
+ }
+
+ objects.add(new ConnObjectWrapper(any, resourceName, objectTO));
+ }
+
+ return objects;
+ }
+
+ public StatusBean getStatusBean(
+ final AnyTO anyTO,
+ final String resourceName,
+ final ConnObjectTO objectTO,
+ final boolean isGroup) {
+
+ final StatusBean statusBean = new StatusBean(anyTO, resourceName);
+
+ if (objectTO != null) {
+ final Boolean enabled = isEnabled(objectTO);
+
+ final Status status = enabled == null
+ ? (isGroup ? Status.ACTIVE : Status.UNDEFINED)
+ : enabled
+ ? Status.ACTIVE
+ : Status.SUSPENDED;
+
+ String connObjectLink = getConnObjectLink(objectTO);
+
+ statusBean.setStatus(status);
+ statusBean.setConnObjectLink(connObjectLink);
+ }
+
+ return statusBean;
+ }
+
+ private Boolean isEnabled(final ConnObjectTO objectTO) {
+ final Map<String, AttrTO> attributeTOs = objectTO.getPlainAttrMap();
+
+ final AttrTO status = attributeTOs.get(ConnIdSpecialAttributeName.ENABLE);
+
+ return status != null && status.getValues() != null && !status.getValues().isEmpty()
+ ? Boolean.parseBoolean(status.getValues().get(0))
+ : null;
+ }
+
+ private String getConnObjectLink(final ConnObjectTO objectTO) {
+ final Map<String, AttrTO> attributeTOs = objectTO == null
+ ? Collections.<String, AttrTO>emptyMap()
+ : objectTO.getPlainAttrMap();
+
+ final AttrTO name = attributeTOs.get(ConnIdSpecialAttributeName.NAME);
+
+ return name != null && name.getValues() != null && !name.getValues().isEmpty()
+ ? name.getValues().get(0)
+ : null;
+ }
+
+ public static StatusMod buildStatusMod(final Collection<StatusBean> statuses) {
+ return buildStatusMod(statuses, null);
+ }
+
+ public static StatusMod buildStatusMod(final Collection<StatusBean> statuses, final Boolean enable) {
+ StatusMod statusMod = new StatusMod();
+ statusMod.setOnSyncope(false);
+
+ for (StatusBean status : statuses) {
+ if (enable == null
+ || (enable && !status.getStatus().isActive()) || (!enable && status.getStatus().isActive())) {
+
+ if ("syncope".equalsIgnoreCase(status.getResourceName())) {
+ statusMod.setOnSyncope(true);
+ } else {
- statusMod.getResourceNames().add(status.getResourceName());
++ statusMod.getResources().add(status.getResourceName());
+ }
+
+ }
+ }
+
+ return statusMod;
+ }
+
+ public ConnObjectTO getConnObjectTO(
+ final Long anyKey, final String resourceName, final List<ConnObjectWrapper> objects) {
+
+ for (ConnObjectWrapper object : objects) {
+ if (anyKey.equals(object.getAny().getKey())
+ && resourceName.equalsIgnoreCase(object.getResourceName())) {
+
+ return object.getConnObjectTO();
+ }
+ }
+
+ return null;
+ }
+
+ public Image getStatusImage(final String componentId, final Status status) {
+ final String alt, title, statusName;
+
+ switch (status) {
+
+ case NOT_YET_SUBMITTED:
+ statusName = Status.UNDEFINED.toString();
+ alt = "undefined icon";
+ title = "Not yet submitted";
+ break;
+
+ case ACTIVE:
+ statusName = Status.ACTIVE.toString();
+ alt = "active icon";
+ title = "Enabled";
+ break;
+
+ case UNDEFINED:
+ statusName = Status.UNDEFINED.toString();
+ alt = "undefined icon";
+ title = "Undefined status";
+ break;
+
+ case OBJECT_NOT_FOUND:
+ statusName = Status.OBJECT_NOT_FOUND.toString();
+ alt = "notfound icon";
+ title = "Not found";
+ break;
+
+ default:
+ statusName = Status.SUSPENDED.toString();
+ alt = "inactive icon";
+ title = "Disabled";
+ }
+
+ final Image img = new Image(componentId,
+ new ContextRelativeResource(IMG_PREFIX + statusName + Constants.PNG_EXT));
+ img.add(new Behavior() {
+
+ private static final long serialVersionUID = 1469628524240283489L;
+
+ @Override
+ public void onComponentTag(final Component component, final ComponentTag tag) {
+ tag.put("alt", alt);
+ tag.put("title", title);
+ }
+ });
+
+ return img;
+ }
+
+ public ImagePanel getStatusImagePanel(final String componentId, final Status status) {
+ final String alt, title, statusName;
+
+ switch (status) {
+
+ case NOT_YET_SUBMITTED:
+ statusName = Status.UNDEFINED.toString();
+ alt = "undefined icon";
+ title = "Not yet submitted";
+ break;
+
+ case ACTIVE:
+ statusName = Status.ACTIVE.toString();
+ alt = "active icon";
+ title = "Enabled";
+ break;
+
+ case UNDEFINED:
+ statusName = Status.UNDEFINED.toString();
+ alt = "undefined icon";
+ title = "Undefined status";
+ break;
+
+ case OBJECT_NOT_FOUND:
+ statusName = Status.OBJECT_NOT_FOUND.toString();
+ alt = "notfound icon";
+ title = "Not found";
+ break;
+
+ default:
+ statusName = Status.SUSPENDED.toString();
+ alt = "inactive icon";
+ title = "Disabled";
+ }
+
+ final ImagePanel imagePanel = new ImagePanel(componentId,
+ new ContextRelativeResource(IMG_PREFIX + statusName + Constants.PNG_EXT));
+ imagePanel.add(new Behavior() {
+
+ private static final long serialVersionUID = 1469628524240283489L;
+
+ @Override
+ public void onComponentTag(final Component component, final ComponentTag tag) {
+ tag.put("alt", alt);
+ tag.put("title", title);
+ }
+ });
+
+ return imagePanel;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/054ea9ca/client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
index 4644fc0,0000000..ae2c923
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/GroupRestClient.java
@@@ -1,204 -1,0 +1,201 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.rest;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.mod.GroupMod;
+import org.apache.syncope.common.lib.mod.ResourceAssociationMod;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ResourceAssociationAction;
+import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
+import org.apache.syncope.common.lib.wrap.ResourceKey;
+import org.apache.syncope.common.rest.api.CollectionWrapper;
+import org.apache.syncope.common.rest.api.service.ResourceService;
+import org.apache.syncope.common.rest.api.service.GroupService;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.springframework.stereotype.Component;
+
+/**
+ * Console client for invoking Rest Group's services.
+ */
+@Component
+public class GroupRestClient extends AbstractAnyRestClient {
+
+ private static final long serialVersionUID = -8549081557283519638L;
+
+ @Override
+ public int count(final String realm) {
+ return getService(GroupService.class).
+ list(SyncopeClient.getAnyListQueryBuilder().realm(realm).page(1).size(1).build()).
+ getTotalCount();
+ }
+
+ @Override
+ public List<GroupTO> list(final String realm, final int page, final int size, final SortParam<String> sort) {
+ return getService(GroupService.class).
+ list(SyncopeClient.getAnyListQueryBuilder().realm(realm).page(page).size(size).
+ orderBy(toOrderBy(sort)).details(false).build()).
+ getResult();
+ }
+
+ @Override
+ public int searchCount(final String realm, final String fiql) {
+ return getService(GroupService.class).
+ search(SyncopeClient.getAnySearchQueryBuilder().realm(realm).fiql(fiql).page(1).size(1).build()).
+ getTotalCount();
+ }
+
+ @Override
+ public List<GroupTO> search(
+ final String realm, final String fiql, final int page, final int size, final SortParam<String> sort) {
+
+ return getService(GroupService.class).
+ search(SyncopeClient.getAnySearchQueryBuilder().realm(realm).fiql(fiql).page(page).size(size).
+ orderBy(toOrderBy(sort)).details(false).build()).
+ getResult();
+ }
+
+ @Override
+ public ConnObjectTO readConnObject(final String resourceName, final Long id) {
+ return getService(ResourceService.class).readConnObject(resourceName, AnyTypeKind.GROUP.name(), id);
+ }
+
+ public GroupTO create(final GroupTO groupTO) {
+ Response response = getService(GroupService.class).create(groupTO);
+ return response.readEntity(GroupTO.class);
+ }
+
+ public GroupTO read(final Long key) {
+ return getService(GroupService.class).read(key);
+ }
+
+ public GroupTO update(final String etag, final GroupMod groupMod) {
+ GroupTO result;
+ synchronized (this) {
+ GroupService service = getService(etag, GroupService.class);
+ result = service.update(groupMod).readEntity(GroupTO.class);
+ resetClient(GroupService.class);
+ }
+ return result;
+ }
+
+ @Override
+ public GroupTO delete(final String etag, final Long key) {
+ GroupTO result;
+ synchronized (this) {
+ GroupService service = getService(etag, GroupService.class);
+ result = service.delete(key).readEntity(GroupTO.class);
+ resetClient(GroupService.class);
+ }
+ return result;
+ }
+
+ @Override
+ public BulkActionResult bulkAction(final BulkAction action) {
+ return getService(GroupService.class).bulk(action);
+ }
+
+ public void unlink(final String etag, final long groupKey, final List<StatusBean> statuses) {
+ synchronized (this) {
+ GroupService service = getService(etag, GroupService.class);
+ service.deassociate(groupKey, ResourceDeassociationActionType.UNLINK,
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
- ResourceKey.class));
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class));
+ resetClient(GroupService.class);
+ }
+ }
+
+ public void link(final String etag, final long groupKey, final List<StatusBean> statuses) {
+ synchronized (this) {
+ GroupService service = getService(etag, GroupService.class);
+
+ ResourceAssociationMod associationMod = new ResourceAssociationMod();
+ associationMod.getTargetResources().addAll(
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(), ResourceKey.class));
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class));
+ service.associate(groupKey, ResourceAssociationAction.LINK, associationMod);
+
+ resetClient(GroupService.class);
+ }
+ }
+
+ public BulkActionResult deprovision(final String etag, final long groupKey, final List<StatusBean> statuses) {
+ BulkActionResult result;
+ synchronized (this) {
+ GroupService service = getService(etag, GroupService.class);
+ result = service.deassociate(groupKey, ResourceDeassociationActionType.DEPROVISION,
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
- ResourceKey.class)).
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class)).
+ readEntity(BulkActionResult.class);
+ resetClient(GroupService.class);
+ }
+ return result;
+ }
+
+ public BulkActionResult provision(final String etag, final long groupKey, final List<StatusBean> statuses) {
+ BulkActionResult result;
+ synchronized (this) {
+ GroupService service = getService(etag, GroupService.class);
+
+ ResourceAssociationMod associationMod = new ResourceAssociationMod();
+ associationMod.getTargetResources().addAll(
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(), ResourceKey.class));
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class));
+
+ result = service.associate(groupKey, ResourceAssociationAction.PROVISION, associationMod).
+ readEntity(BulkActionResult.class);
+ resetClient(GroupService.class);
+ }
+ return result;
+ }
+
+ public BulkActionResult unassign(final String etag, final long groupKey, final List<StatusBean> statuses) {
+ BulkActionResult result;
+ synchronized (this) {
+ GroupService service = getService(etag, GroupService.class);
+ result = service.deassociate(groupKey, ResourceDeassociationActionType.UNASSIGN,
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
- ResourceKey.class)).
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class)).
+ readEntity(BulkActionResult.class);
+ resetClient(GroupService.class);
+ }
+ return result;
+ }
+
+ public BulkActionResult assign(final String etag, final long groupKey, final List<StatusBean> statuses) {
+ BulkActionResult result;
+ synchronized (this) {
+ GroupService service = getService(etag, GroupService.class);
+
+ ResourceAssociationMod associationMod = new ResourceAssociationMod();
+ associationMod.getTargetResources().addAll(
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(), ResourceKey.class));
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class));
+
+ result = service.associate(groupKey, ResourceAssociationAction.ASSIGN, associationMod).
+ readEntity(BulkActionResult.class);
+
+ resetClient(GroupService.class);
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/054ea9ca/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
----------------------------------------------------------------------
diff --cc client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
index d161658,0000000..36f1124
mode 100644,000000..100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
@@@ -1,240 -1,0 +1,237 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.rest;
+
+import java.util.List;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.ResourceAssociationMod;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ResourceAssociationAction;
+import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
+import org.apache.syncope.common.lib.wrap.ResourceKey;
+import org.apache.syncope.common.rest.api.CollectionWrapper;
+import org.apache.syncope.common.rest.api.service.ResourceService;
+import org.apache.syncope.common.rest.api.service.UserService;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.springframework.stereotype.Component;
+
+/**
+ * Console client for invoking rest users services.
+ */
+@Component
+public class UserRestClient extends AbstractAnyRestClient {
+
+ private static final long serialVersionUID = -1575748964398293968L;
+
+ @Override
+ public int count(final String realm) {
+ return getService(UserService.class).
+ list(SyncopeClient.getAnyListQueryBuilder().realm(realm).page(1).size(1).build()).
+ getTotalCount();
+ }
+
+ @Override
+ public List<UserTO> list(final String realm, final int page, final int size, final SortParam<String> sort) {
+ return getService(UserService.class).
+ list(SyncopeClient.getAnyListQueryBuilder().realm(realm).page(page).size(size).
+ orderBy(toOrderBy(sort)).details(false).build()).
+ getResult();
+ }
+
+ public UserTO create(final UserTO userTO, final boolean storePassword) {
+ Response response = getService(UserService.class).create(userTO, storePassword);
+ return response.readEntity(UserTO.class);
+ }
+
+ public UserTO update(final String etag, final UserMod userMod) {
+ UserTO result;
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+ result = service.update(userMod).readEntity(UserTO.class);
+ resetClient(UserService.class);
+ }
+ return result;
+ }
+
+ @Override
+ public UserTO delete(final String etag, final Long id) {
+ UserTO result;
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+ result = service.delete(id).readEntity(UserTO.class);
+ resetClient(UserService.class);
+ }
+ return result;
+ }
+
+ public UserTO read(final Long id) {
+ UserTO userTO = null;
+ try {
+ userTO = getService(UserService.class).read(id);
+ } catch (SyncopeClientException e) {
+ LOG.error("While reading a user", e);
+ }
+ return userTO;
+ }
+
+ @Override
+ public int searchCount(final String realm, final String fiql) {
+ return getService(UserService.class).
+ search(SyncopeClient.getAnySearchQueryBuilder().realm(realm).fiql(fiql).page(1).size(1).build()).
+ getTotalCount();
+ }
+
+ @Override
+ public List<UserTO> search(
+ final String realm, final String fiql, final int page, final int size, final SortParam<String> sort) {
+
+ return getService(UserService.class).
+ search(SyncopeClient.getAnySearchQueryBuilder().realm(realm).fiql(fiql).page(page).size(size).
+ orderBy(toOrderBy(sort)).details(false).build()).
+ getResult();
+ }
+
+ @Override
+ public ConnObjectTO readConnObject(final String resourceName, final Long id) {
+ return getService(ResourceService.class).readConnObject(resourceName, AnyTypeKind.USER.name(), id);
+ }
+
+ public void suspend(final String etag, final long userKey, final List<StatusBean> statuses) {
+ StatusMod statusMod = StatusUtils.buildStatusMod(statuses, false);
+ statusMod.setKey(userKey);
+ statusMod.setType(StatusMod.ModType.SUSPEND);
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+ service.status(statusMod);
+ resetClient(UserService.class);
+ }
+ }
+
+ public void reactivate(final String etag, final long userKey, final List<StatusBean> statuses) {
+ StatusMod statusMod = StatusUtils.buildStatusMod(statuses, true);
+ statusMod.setKey(userKey);
+ statusMod.setType(StatusMod.ModType.REACTIVATE);
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+ service.status(statusMod);
+ resetClient(UserService.class);
+ }
+ }
+
+ @Override
+ public BulkActionResult bulkAction(final BulkAction action) {
+ return getService(UserService.class).bulk(action);
+ }
+
+ public void unlink(final String etag, final long userKey, final List<StatusBean> statuses) {
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+ service.deassociate(userKey, ResourceDeassociationActionType.UNLINK,
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
- ResourceKey.class));
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class));
+ resetClient(UserService.class);
+ }
+ }
+
+ public void link(final String etag, final long userKey, final List<StatusBean> statuses) {
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+
+ ResourceAssociationMod associationMod = new ResourceAssociationMod();
+ associationMod.getTargetResources().addAll(
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(), ResourceKey.class));
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class));
+ service.associate(userKey, ResourceAssociationAction.LINK, associationMod);
+
+ resetClient(UserService.class);
+ }
+ }
+
+ public BulkActionResult deprovision(final String etag, final long userKey, final List<StatusBean> statuses) {
+ BulkActionResult result;
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+ result = service.deassociate(userKey, ResourceDeassociationActionType.DEPROVISION,
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
- ResourceKey.class)).
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class)).
+ readEntity(BulkActionResult.class);
+ resetClient(UserService.class);
+ }
+ return result;
+ }
+
+ public BulkActionResult provision(final String etag, final long userKey,
+ final List<StatusBean> statuses, final boolean changepwd, final String password) {
+
+ BulkActionResult result;
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+
+ ResourceAssociationMod associationMod = new ResourceAssociationMod();
+ associationMod.getTargetResources().addAll(
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(), ResourceKey.class));
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class));
+ associationMod.setChangePwd(changepwd);
+ associationMod.setPassword(password);
+
+ result = service.associate(userKey, ResourceAssociationAction.PROVISION, associationMod).
+ readEntity(BulkActionResult.class);
+ resetClient(UserService.class);
+ }
+ return result;
+ }
+
+ public BulkActionResult unassign(final String etag, final long userKey, final List<StatusBean> statuses) {
+ BulkActionResult result;
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+ result = service.deassociate(userKey, ResourceDeassociationActionType.UNASSIGN,
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
- ResourceKey.class)).
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class)).
+ readEntity(BulkActionResult.class);
+ resetClient(UserService.class);
+ }
+ return result;
+ }
+
+ public BulkActionResult assign(final String etag, final long userKey,
+ final List<StatusBean> statuses, final boolean changepwd, final String password) {
+
+ BulkActionResult result;
+ synchronized (this) {
+ UserService service = getService(etag, UserService.class);
+
+ ResourceAssociationMod associationMod = new ResourceAssociationMod();
+ associationMod.getTargetResources().addAll(
- CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(), ResourceKey.class));
++ CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResources(), ResourceKey.class));
+ associationMod.setChangePwd(changepwd);
+ associationMod.setPassword(password);
+
+ result = service.associate(userKey, ResourceAssociationAction.ASSIGN, associationMod).
+ readEntity(BulkActionResult.class);
+ resetClient(UserService.class);
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/054ea9ca/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
index e3fc901,0000000..7f087b7
mode 100644,000000..100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
@@@ -1,110 -1,0 +1,110 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.mod;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.ws.rs.PathParam;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "statusMod")
+@XmlType
+public class StatusMod extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 3230910033784302656L;
+
+ @XmlEnum
+ @XmlType(name = "statusModType")
+ public enum ModType {
+
+ ACTIVATE,
+ SUSPEND,
+ REACTIVATE;
+
+ }
+
+ /**
+ * Key of user to for which status update is requested.
+ */
+ private long key;
+
+ private ModType type;
+
+ /**
+ * Update token (if required).
+ */
+ private String token;
+
+ /**
+ * Whether update should be performed on internal storage.
+ */
+ private boolean onSyncope = true;
+
+ /**
+ * External resources for which update is needed to be propagated.
+ */
+ private final List<String> resourceNames = new ArrayList<>();
+
+ public long getKey() {
+ return key;
+ }
+
+ @PathParam("key")
+ public void setKey(final long key) {
+ this.key = key;
+ }
+
+ public ModType getType() {
+ return type;
+ }
+
+ public void setType(final ModType type) {
+ this.type = type;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(final String token) {
+ this.token = token;
+ }
+
+ public boolean isOnSyncope() {
+ return onSyncope;
+ }
+
+ public void setOnSyncope(final boolean onSyncope) {
+ this.onSyncope = onSyncope;
+ }
+
+ @XmlElementWrapper(name = "resources")
+ @XmlElement(name = "resource")
+ @JsonProperty("resources")
- public List<String> getResourceNames() {
++ public List<String> getResources() {
+ return resourceNames;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/054ea9ca/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
----------------------------------------------------------------------
diff --cc core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
index ff87d6b,0000000..c8a986d
mode 100644,000000..100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
@@@ -1,525 -1,0 +1,525 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.logic;
+
+import java.lang.reflect.Method;
+import java.security.AccessControlException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+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.apache.syncope.core.persistence.api.dao.search.SearchCond;
+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.provisioning.api.UserProvisioningManager;
+import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.misc.security.AuthContextUtils;
+import org.apache.syncope.core.misc.serialization.POJOHelper;
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.provisioning.api.AnyTransformer;
+import org.apache.syncope.core.provisioning.api.VirAttrHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Note that this controller does not extend {@link AbstractTransactionalLogic}, hence does not provide any
+ * Spring's Transactional logic at class level.
+ */
+@Component
+public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
+
+ @Autowired
+ protected UserDAO userDAO;
+
+ @Autowired
+ protected GroupDAO groupDAO;
+
+ @Autowired
+ protected AnySearchDAO searchDAO;
+
+ @Autowired
+ protected UserDataBinder binder;
+
+ @Autowired
+ protected VirAttrHandler virtAttrHandler;
+
+ @Autowired
+ protected PropagationManager propagationManager;
+
+ @Autowired
+ protected PropagationTaskExecutor taskExecutor;
+
+ @Autowired
+ protected AnyTransformer anyTransformer;
+
+ @Autowired
+ protected UserProvisioningManager provisioningManager;
+
+ @Autowired
+ protected SyncopeLogic syncopeLogic;
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_READ + "')")
+ @Transactional(readOnly = true)
+ public String getUsername(final Long key) {
+ return binder.getUserTO(key).getUsername();
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_READ + "')")
+ @Transactional(readOnly = true)
+ public Long getKey(final String username) {
+ return binder.getUserTO(username).getKey();
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_LIST + "')")
+ @Transactional(readOnly = true)
+ @Override
+ public int count(final List<String> realms) {
+ return userDAO.count(
+ getEffectiveRealms(AuthContextUtils.getAuthorizations().get(Entitlement.USER_LIST), realms));
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_LIST + "')")
+ @Transactional(readOnly = true)
+ @Override
+ public List<UserTO> list(
+ final int page, final int size, final List<OrderByClause> orderBy,
+ final List<String> realms, final boolean details) {
+
+ return CollectionUtils.collect(userDAO.findAll(
+ getEffectiveRealms(AuthContextUtils.getAuthorizations().get(Entitlement.USER_LIST), realms),
+ page, size, orderBy),
+ new Transformer<User, UserTO>() {
+
+ @Override
+ public UserTO transform(final User input) {
+ return binder.getUserTO(input, details);
+ }
+ }, new ArrayList<UserTO>());
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ @Transactional(readOnly = true)
+ public Pair<String, UserTO> readSelf() {
+ return ImmutablePair.of(
+ POJOHelper.serialize(AuthContextUtils.getAuthorizations()),
+ binder.getAuthenticatedUserTO());
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_READ + "')")
+ @Transactional(readOnly = true)
+ @Override
+ public UserTO read(final Long key) {
+ return binder.getUserTO(key);
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_SEARCH + "')")
+ @Transactional(readOnly = true)
+ @Override
+ public int searchCount(final SearchCond searchCondition, final List<String> realms) {
+ return searchDAO.count(
+ getEffectiveRealms(AuthContextUtils.getAuthorizations().get(Entitlement.USER_SEARCH), realms),
+ searchCondition, AnyTypeKind.USER);
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_SEARCH + "')")
+ @Transactional(readOnly = true)
+ @Override
+ public List<UserTO> search(final SearchCond searchCondition, final int page, final int size,
+ final List<OrderByClause> orderBy, final List<String> realms, final boolean details) {
+
+ List<User> matchingUsers = searchDAO.search(
+ getEffectiveRealms(AuthContextUtils.getAuthorizations().get(Entitlement.USER_SEARCH), realms),
+ searchCondition, page, size, orderBy, AnyTypeKind.USER);
+ return CollectionUtils.collect(matchingUsers, new Transformer<User, UserTO>() {
+
+ @Override
+ public UserTO transform(final User input) {
+ return binder.getUserTO(input, details);
+ }
+ }, new ArrayList<UserTO>());
+ }
+
+ @PreAuthorize("isAnonymous() or hasRole('" + Entitlement.ANONYMOUS + "')")
+ public UserTO selfCreate(final UserTO userTO, final boolean storePassword) {
+ return doCreate(userTO, storePassword);
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_CREATE + "')")
+ @Override
+ public UserTO create(final UserTO userTO) {
+ return create(userTO, true);
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_CREATE + "')")
+ public UserTO create(final UserTO userTO, final boolean storePassword) {
+ if (userTO.getRealm() == null) {
+ throw SyncopeClientException.build(ClientExceptionType.InvalidRealm);
+ }
+ // security checks
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_CREATE),
+ Collections.singleton(userTO.getRealm()));
+ securityChecks(effectiveRealms, userTO.getRealm(), null);
+
+ return doCreate(userTO, storePassword);
+ }
+
+ protected UserTO doCreate(final UserTO userTO, final boolean storePassword) {
+ // Any transformation (if configured)
+ UserTO actual = anyTransformer.transform(userTO);
+ LOG.debug("Transformed: {}", actual);
+
+ Map.Entry<Long, List<PropagationStatus>> created = provisioningManager.create(actual, storePassword);
+
+ UserTO savedTO = binder.getUserTO(created.getKey());
+ savedTO.getPropagationStatusTOs().addAll(created.getValue());
+ return savedTO;
+ }
+
+ @PreAuthorize("isAuthenticated() and not(hasRole('" + Entitlement.ANONYMOUS + "'))")
+ public UserTO selfUpdate(final UserMod userMod) {
+ UserTO userTO = binder.getAuthenticatedUserTO();
+
+ if (userTO.getKey() != userMod.getKey()) {
+ throw new AccessControlException("Not allowed for user with key " + userMod.getKey());
+ }
+
+ return doUpdate(userMod);
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
+ @Override
+ public UserTO update(final UserMod userMod) {
+ // Any transformation (if configured)
+ UserMod actual = anyTransformer.transform(userMod);
+ LOG.debug("Transformed: {}", actual);
+
+ // security checks
+ UserTO toUpdate = binder.getUserTO(userMod.getKey());
+ Set<String> requestedRealms = new HashSet<>();
+ requestedRealms.add(toUpdate.getRealm());
+ if (StringUtils.isNotBlank(actual.getRealm())) {
+ requestedRealms.add(actual.getRealm());
+ }
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+ requestedRealms);
+ securityChecks(effectiveRealms, toUpdate.getRealm(), toUpdate.getKey());
+ if (StringUtils.isNotBlank(actual.getRealm())) {
+ securityChecks(effectiveRealms, actual.getRealm(), toUpdate.getKey());
+ }
+
+ return doUpdate(actual);
+ }
+
+ protected UserTO doUpdate(final UserMod userMod) {
+ Map.Entry<Long, List<PropagationStatus>> updated = provisioningManager.update(userMod);
+
+ UserTO updatedTO = binder.getUserTO(updated.getKey());
+ updatedTO.getPropagationStatusTOs().addAll(updated.getValue());
+ return updatedTO;
+ }
+
+ protected Map.Entry<Long, List<PropagationStatus>> setStatusOnWfAdapter(final StatusMod statusMod) {
+ Map.Entry<Long, List<PropagationStatus>> updated;
+
+ switch (statusMod.getType()) {
+ case SUSPEND:
+ updated = provisioningManager.suspend(statusMod);
+ break;
+
+ case REACTIVATE:
+ updated = provisioningManager.reactivate(statusMod);
+ break;
+
+ case ACTIVATE:
+ default:
+ updated = provisioningManager.activate(statusMod);
+ break;
+
+ }
+
+ return updated;
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
+ public UserTO status(final StatusMod statusMod) {
+ // security checks
+ UserTO toUpdate = binder.getUserTO(statusMod.getKey());
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+ Collections.singleton(toUpdate.getRealm()));
+ securityChecks(effectiveRealms, toUpdate.getRealm(), toUpdate.getKey());
+
+ Map.Entry<Long, List<PropagationStatus>> updated = setStatusOnWfAdapter(statusMod);
+ UserTO savedTO = binder.getUserTO(updated.getKey());
+ savedTO.getPropagationStatusTOs().addAll(updated.getValue());
+ return savedTO;
+ }
+
+ @PreAuthorize("isAnonymous() or hasRole('" + Entitlement.ANONYMOUS + "')")
+ @Transactional
+ public void requestPasswordReset(final String username, final String securityAnswer) {
+ if (username == null) {
+ throw new NotFoundException("Null username");
+ }
+
+ User user = userDAO.find(username);
+ if (user == null) {
+ throw new NotFoundException("User " + username);
+ }
+
+ if (syncopeLogic.isPwdResetRequiringSecurityQuestions()
+ && (securityAnswer == null || !securityAnswer.equals(user.getSecurityAnswer()))) {
+
+ throw SyncopeClientException.build(ClientExceptionType.InvalidSecurityAnswer);
+ }
+
+ provisioningManager.requestPasswordReset(user.getKey());
+ }
+
+ @PreAuthorize("isAnonymous() or hasRole('" + Entitlement.ANONYMOUS + "')")
+ @Transactional
+ public void confirmPasswordReset(final String token, final String password) {
+ User user = userDAO.findByToken(token);
+ if (user == null) {
+ throw new NotFoundException("User with token " + token);
+ }
+ provisioningManager.confirmPasswordReset(user.getKey(), token, password);
+ }
+
+ @PreAuthorize("isAuthenticated() and not(hasRole('" + Entitlement.ANONYMOUS + "'))")
+ public UserTO selfDelete() {
+ UserTO userTO = binder.getAuthenticatedUserTO();
+
+ return doDelete(userTO.getKey());
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_DELETE + "')")
+ @Override
+ public UserTO delete(final Long key) {
+ // security checks
+ UserTO toDelete = binder.getUserTO(key);
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_DELETE),
+ Collections.singleton(toDelete.getRealm()));
+ securityChecks(effectiveRealms, toDelete.getRealm(), toDelete.getKey());
+
+ return doDelete(key);
+ }
+
+ protected UserTO doDelete(final Long key) {
+ List<Group> ownedGroups = groupDAO.findOwnedByUser(key);
+ if (!ownedGroups.isEmpty()) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.GroupOwnership);
+ sce.getElements().addAll(CollectionUtils.collect(ownedGroups, new Transformer<Group, String>() {
+
+ @Override
+ public String transform(final Group group) {
+ return group.getKey() + " " + group.getName();
+ }
+ }, new ArrayList<String>()));
+ throw sce;
+ }
+
+ List<PropagationStatus> statuses = provisioningManager.delete(key);
+
+ UserTO deletedTO;
+ if (userDAO.find(key) == null) {
+ deletedTO = new UserTO();
+ deletedTO.setKey(key);
+ } else {
+ deletedTO = binder.getUserTO(key);
+ }
+ deletedTO.getPropagationStatusTOs().addAll(statuses);
+
+ return deletedTO;
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
+ @Override
+ public UserTO unlink(final Long key, final Collection<String> resources) {
+ // security checks
+ UserTO user = binder.getUserTO(key);
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+ Collections.singleton(user.getRealm()));
+ securityChecks(effectiveRealms, user.getRealm(), user.getKey());
+
+ UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToRemove().addAll(resources);
+
+ return binder.getUserTO(provisioningManager.unlink(userMod));
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
+ @Override
+ public UserTO link(final Long key, final Collection<String> resources) {
+ // security checks
+ UserTO user = binder.getUserTO(key);
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+ Collections.singleton(user.getRealm()));
+ securityChecks(effectiveRealms, user.getRealm(), user.getKey());
+
+ UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToAdd().addAll(resources);
+
+ return binder.getUserTO(provisioningManager.link(userMod));
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
+ @Override
+ public UserTO unassign(final Long key, final Collection<String> resources) {
+ // security checks
+ UserTO user = binder.getUserTO(key);
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+ Collections.singleton(user.getRealm()));
+ securityChecks(effectiveRealms, user.getRealm(), user.getKey());
+
+ UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToRemove().addAll(resources);
+ return update(userMod);
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
+ @Override
+ public UserTO assign(
+ final Long key,
+ final Collection<String> resources,
+ final boolean changepwd,
+ final String password) {
+
+ // security checks
+ UserTO user = binder.getUserTO(key);
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+ Collections.singleton(user.getRealm()));
+ securityChecks(effectiveRealms, user.getRealm(), user.getKey());
+
+ UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToAdd().addAll(resources);
+
+ if (changepwd) {
+ StatusMod statusMod = new StatusMod();
+ statusMod.setOnSyncope(false);
- statusMod.getResourceNames().addAll(resources);
++ statusMod.getResources().addAll(resources);
+ userMod.setPwdPropRequest(statusMod);
+ userMod.setPassword(password);
+ }
+
+ return update(userMod);
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
+ @Override
+ public UserTO deprovision(final Long key, final Collection<String> resources) {
+ // security checks
+ UserTO user = binder.getUserTO(key);
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+ Collections.singleton(user.getRealm()));
+ securityChecks(effectiveRealms, user.getRealm(), user.getKey());
+
+ List<PropagationStatus> statuses = provisioningManager.deprovision(key, resources);
+
+ UserTO updatedTO = binder.getUserTO(key);
+ updatedTO.getPropagationStatusTOs().addAll(statuses);
+ return updatedTO;
+ }
+
+ @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
+ @Override
+ public UserTO provision(
+ final Long key,
+ final Collection<String> resources,
+ final boolean changePwd,
+ final String password) {
+
+ // security checks
+ UserTO user = binder.getUserTO(key);
+ Set<String> effectiveRealms = getEffectiveRealms(
+ AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+ Collections.singleton(user.getRealm()));
+ securityChecks(effectiveRealms, user.getRealm(), user.getKey());
+
+ user.getPropagationStatusTOs().addAll(provisioningManager.provision(key, changePwd, password, resources));
+ return user;
+ }
+
+ @Override
+ protected UserTO resolveReference(final Method method, final Object... args) throws UnresolvedReferenceException {
+ Object key = null;
+
+ if (!"confirmPasswordReset".equals(method.getName()) && ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; key == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ key = (Long) args[i];
+ } else if (args[i] instanceof String) {
+ key = (String) args[i];
+ } else if (args[i] instanceof UserTO) {
+ key = ((UserTO) args[i]).getKey();
+ } else if (args[i] instanceof UserMod) {
+ key = ((UserMod) args[i]).getKey();
+ }
+ }
+ }
+
+ if ((key != null) && !key.equals(0L)) {
+ try {
+ return key instanceof Long ? binder.getUserTO((Long) key) : binder.getUserTO((String) key);
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/054ea9ca/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
----------------------------------------------------------------------
diff --cc core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
index 38264de,0000000..5fd3ec1
mode 100644,000000..100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
@@@ -1,388 -1,0 +1,388 @@@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
+import org.apache.syncope.core.provisioning.api.WorkflowResult;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.provisioning.api.VirAttrHandler;
+import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultUserProvisioningManager implements UserProvisioningManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UserProvisioningManager.class);
+
+ @Autowired
+ protected UserWorkflowAdapter uwfAdapter;
+
+ @Autowired
+ protected PropagationManager propagationManager;
+
+ @Autowired
+ protected PropagationTaskExecutor taskExecutor;
+
+ @Autowired
+ protected VirAttrHandler virtAttrHandler;
+
+ @Autowired
+ protected UserDAO userDAO;
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> create(final UserTO userTO) {
+ return create(userTO, true, false, null, Collections.<String>emptySet());
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword) {
+ return create(userTO, storePassword, false, null, Collections.<String>emptySet());
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> create(final UserTO userTO, final Set<String> excludedResources) {
+ return create(userTO, false, false, null, excludedResources);
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword,
+ final boolean disablePwdPolicyCheck, final Boolean enabled, final Set<String> excludedResources) {
+
+ WorkflowResult<Pair<Long, Boolean>> created =
+ uwfAdapter.create(userTO, disablePwdPolicyCheck, enabled, storePassword);
+
+ List<PropagationTask> tasks = propagationManager.getUserCreateTasks(
+ created.getResult().getKey(),
+ created.getResult().getValue(),
+ created.getPropByRes(),
+ userTO.getPassword(),
+ userTO.getVirAttrs(),
+ excludedResources);
+ PropagationReporter propagationReporter =
+ ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+ try {
+ taskExecutor.execute(tasks, propagationReporter);
+ } catch (PropagationException e) {
+ LOG.error("Error propagation primary resource", e);
+ propagationReporter.onPrimaryResourceFailure(tasks);
+ }
+
+ return new ImmutablePair<>(created.getResult().getKey(), propagationReporter.getStatuses());
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> update(final UserMod userMod) {
+ WorkflowResult<Pair<UserMod, Boolean>> updated = uwfAdapter.update(userMod);
+
+ List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(updated);
+ if (tasks.isEmpty()) {
+ // SYNCOPE-459: take care of user virtual attributes ...
+ PropagationByResource propByResVirAttr = virtAttrHandler.fillVirtual(
+ updated.getResult().getKey().getKey(),
+ AnyTypeKind.USER,
+ userMod.getVirAttrsToRemove(),
+ userMod.getVirAttrsToUpdate());
+ tasks.addAll(!propByResVirAttr.isEmpty()
+ ? propagationManager.getUserUpdateTasks(updated, false, null)
+ : Collections.<PropagationTask>emptyList());
+ }
+ PropagationReporter propagationReporter = ApplicationContextProvider.getBeanFactory().
+ getBean(PropagationReporter.class);
+ if (!tasks.isEmpty()) {
+ try {
+ taskExecutor.execute(tasks, propagationReporter);
+ } catch (PropagationException e) {
+ LOG.error("Error propagation primary resource", e);
+ propagationReporter.onPrimaryResourceFailure(tasks);
+ }
+ }
+
+ return new ImmutablePair<>(updated.getResult().getKey().getKey(), propagationReporter.getStatuses());
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> update(final UserMod userMod, final Set<String> excludedResources) {
+ return update(userMod, userMod.getKey(), new ProvisioningResult(), null, excludedResources);
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> update(final UserMod userMod, final Long key,
+ final ProvisioningResult result, final Boolean enabled, final Set<String> excludedResources) {
+
+ WorkflowResult<Pair<UserMod, Boolean>> updated;
+ try {
+ updated = uwfAdapter.update(userMod);
+ } catch (Exception e) {
+ LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", key, e);
+
+ result.setStatus(ProvisioningResult.Status.FAILURE);
+ result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
+
+ updated = new WorkflowResult<Pair<UserMod, Boolean>>(
+ new ImmutablePair<>(userMod, false), new PropagationByResource(),
+ new HashSet<String>());
+ }
+
+ if (enabled != null) {
+ User user = userDAO.find(key);
+
+ WorkflowResult<Long> enableUpdate = null;
+ if (user.isSuspended() == null) {
+ enableUpdate = uwfAdapter.activate(key, null);
+ } else if (enabled && user.isSuspended()) {
+ enableUpdate = uwfAdapter.reactivate(key);
+ } else if (!enabled && !user.isSuspended()) {
+ enableUpdate = uwfAdapter.suspend(key);
+ }
+
+ if (enableUpdate != null) {
+ if (enableUpdate.getPropByRes() != null) {
+ updated.getPropByRes().merge(enableUpdate.getPropByRes());
+ updated.getPropByRes().purge();
+ }
+ updated.getPerformedTasks().addAll(enableUpdate.getPerformedTasks());
+ }
+ }
+
+ List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
+ updated, updated.getResult().getKey().getPassword() != null, excludedResources);
+ PropagationReporter propagationReporter = ApplicationContextProvider.getBeanFactory().
+ getBean(PropagationReporter.class);
+ try {
+ taskExecutor.execute(tasks, propagationReporter);
+ } catch (PropagationException e) {
+ LOG.error("Error propagation primary resource", e);
+ propagationReporter.onPrimaryResourceFailure(tasks);
+ }
+
+ return new ImmutablePair<>(updated.getResult().getKey().getKey(), propagationReporter.getStatuses());
+ }
+
+ @Override
+ public List<PropagationStatus> delete(final Long key) {
+ return delete(key, Collections.<String>emptySet());
+ }
+
+ @Override
+ public List<PropagationStatus> delete(final Long key, final Set<String> excludedResources) {
+ // 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 uwfAdapter.delete(), which
+ // will also effectively remove user from db, thus making virtually
+ // impossible by NotificationManager to fetch required user information
+ List<PropagationTask> tasks = propagationManager.getUserDeleteTasks(key, excludedResources);
+
+ PropagationReporter propagationReporter =
+ ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+ try {
+ taskExecutor.execute(tasks, propagationReporter);
+ } catch (PropagationException e) {
+ LOG.error("Error propagation primary resource", e);
+ propagationReporter.onPrimaryResourceFailure(tasks);
+ }
+
+ try {
+ uwfAdapter.delete(key);
+ } catch (PropagationException e) {
+ throw e;
+ }
+
+ return propagationReporter.getStatuses();
+ }
+
+ @Override
+ public Long unlink(final UserMod userMod) {
+ WorkflowResult<Pair<UserMod, Boolean>> updated = uwfAdapter.update(userMod);
+ return updated.getResult().getKey().getKey();
+ }
+
+ @Override
+ public Long link(final UserMod userMod) {
+ return uwfAdapter.update(userMod).getResult().getKey().getKey();
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> activate(final StatusMod statusMod) {
+ WorkflowResult<Long> updated = statusMod.isOnSyncope()
+ ? uwfAdapter.activate(statusMod.getKey(), statusMod.getToken())
+ : new WorkflowResult<>(statusMod.getKey(), null, statusMod.getType().name().toLowerCase());
+
+ return new ImmutablePair<>(updated.getResult(), propagateStatus(statusMod));
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> reactivate(final StatusMod statusMod) {
+ WorkflowResult<Long> updated = statusMod.isOnSyncope()
+ ? uwfAdapter.reactivate(statusMod.getKey())
+ : new WorkflowResult<>(statusMod.getKey(), null, statusMod.getType().name().toLowerCase());
+
+ return new ImmutablePair<>(updated.getResult(), propagateStatus(statusMod));
+ }
+
+ @Override
+ public Pair<Long, List<PropagationStatus>> suspend(final StatusMod statusMod) {
+ WorkflowResult<Long> updated = statusMod.isOnSyncope()
+ ? uwfAdapter.suspend(statusMod.getKey())
+ : new WorkflowResult<>(statusMod.getKey(), null, statusMod.getType().name().toLowerCase());
+
+ return new ImmutablePair<>(updated.getResult(), propagateStatus(statusMod));
+ }
+
+ protected List<PropagationStatus> propagateStatus(final StatusMod statusMod) {
+ Collection<String> noPropResourceNames = CollectionUtils.removeAll(
- userDAO.findAllResourceNames(userDAO.find(statusMod.getKey())), statusMod.getResourceNames());
++ userDAO.findAllResourceNames(userDAO.find(statusMod.getKey())), statusMod.getResources());
+
+ List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
+ statusMod.getKey(), statusMod.getType() != StatusMod.ModType.SUSPEND, noPropResourceNames);
+ PropagationReporter propReporter =
+ ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+ try {
+ taskExecutor.execute(tasks, propReporter);
+ } catch (PropagationException e) {
+ LOG.error("Error propagation primary resource", e);
+ propReporter.onPrimaryResourceFailure(tasks);
+ }
+
+ return propReporter.getStatuses();
+
+ }
+
+ @Override
+ public void internalSuspend(final Long key) {
+ Pair<WorkflowResult<Long>, Boolean> updated = uwfAdapter.internalSuspend(key);
+
+ // propagate suspension if and only if it is required by policy
+ if (updated != null && updated.getValue()) {
+ UserMod userMod = new UserMod();
+ userMod.setKey(updated.getKey().getResult());
+
+ List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
+ new WorkflowResult<Pair<UserMod, Boolean>>(
+ new ImmutablePair<>(userMod, Boolean.FALSE),
+ updated.getKey().getPropByRes(), updated.getKey().getPerformedTasks()));
+ taskExecutor.execute(tasks);
+ }
+ }
+
+ @Override
+ public List<PropagationStatus> provision(
+ final Long key, final boolean changePwd, final String password, final Collection<String> resources) {
+
+ UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToAdd().addAll(resources);
+
+ if (changePwd) {
+ StatusMod statusMod = new StatusMod();
+ statusMod.setOnSyncope(false);
- statusMod.getResourceNames().addAll(resources);
++ statusMod.getResources().addAll(resources);
+ userMod.setPwdPropRequest(statusMod);
+ userMod.setPassword(password);
+ }
+
+ PropagationByResource propByRes = new PropagationByResource();
+ propByRes.addAll(ResourceOperation.UPDATE, resources);
+
+ WorkflowResult<Pair<UserMod, Boolean>> wfResult = new WorkflowResult<Pair<UserMod, Boolean>>(
+ ImmutablePair.of(userMod, (Boolean) null), propByRes, "update");
+
+ List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(wfResult, changePwd, null);
+ PropagationReporter propagationReporter =
+ ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+ try {
+ taskExecutor.execute(tasks, propagationReporter);
+ } catch (PropagationException e) {
+ LOG.error("Error propagation primary resource", e);
+ propagationReporter.onPrimaryResourceFailure(tasks);
+ }
+
+ return propagationReporter.getStatuses();
+ }
+
+ @Override
+ public List<PropagationStatus> deprovision(final Long key, final Collection<String> resources) {
+ User user = userDAO.authFind(key);
+
+ List<PropagationTask> tasks = propagationManager.getUserDeleteTasks(
+ key,
+ new HashSet<>(resources),
+ CollectionUtils.removeAll(userDAO.findAllResourceNames(user), resources));
+ PropagationReporter propagationReporter =
+ ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+ try {
+ taskExecutor.execute(tasks, propagationReporter);
+ } catch (PropagationException e) {
+ LOG.error("Error propagation primary resource", e);
+ propagationReporter.onPrimaryResourceFailure(tasks);
+ }
+
+ return propagationReporter.getStatuses();
+ }
+
+ @Override
+ public void requestPasswordReset(final Long key) {
+ uwfAdapter.requestPasswordReset(key);
+ }
+
+ @Override
+ public void confirmPasswordReset(final Long key, final String token, final String password) {
+ uwfAdapter.confirmPasswordReset(key, token, password);
+
+ UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.setPassword(password);
+
+ List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
+ new WorkflowResult<Pair<UserMod, Boolean>>(
+ new ImmutablePair<UserMod, Boolean>(userMod, null), null, "confirmPasswordReset"),
+ true, null);
+ PropagationReporter propReporter =
+ ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+ try {
+ taskExecutor.execute(tasks, propReporter);
+ } catch (PropagationException e) {
+ LOG.error("Error propagation primary resource", e);
+ propReporter.onPrimaryResourceFailure(tasks);
+ }
+ }
+}