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);
 +        }
 +    }
 +}