[SYNCOPE-671] 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/4cd6f5dc
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/4cd6f5dc
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/4cd6f5dc

Branch: refs/heads/master
Commit: 4cd6f5dc673497b83c56873f007f61e405f40f2a
Parents: 22a9e12 4c90ea8
Author: Francesco Chicchiriccò <[email protected]>
Authored: Sun May 24 19:07:20 2015 +0200
Committer: Francesco Chicchiriccò <[email protected]>
Committed: Sun May 24 19:07:20 2015 +0200

----------------------------------------------------------------------
 .../java/DefaultUserProvisioningManager.java         |  9 ++++++++-
 .../processor/UserConfirmPwdResetProcessor.java      | 13 ++++++++++++-
 .../syncope/fit/core/reference/UserSelfITCase.java   | 15 +++++++++++++++
 3 files changed, 35 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/4cd6f5dc/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 c1eff8c,0000000..2f959b5
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,362 -1,0 +1,369 @@@
 +/*
 + * 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.MembershipMod;
 +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.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.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.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 boolean storePassword,
 +            final boolean disablePwdPolicyCheck, final Boolean enabled, final 
Set<String> excludedResources) {
 +
 +        WorkflowResult<Pair<Long, Boolean>> created;
 +        try {
 +            created = uwfAdapter.create(userTO, disablePwdPolicyCheck, 
enabled, storePassword);
 +        } catch (PropagationException e) {
 +            throw e;
 +        }
 +
 +        List<PropagationTask> tasks = propagationManager.getUserCreateTasks(
 +                created.getResult().getKey(),
 +                created.getResult().getValue(),
 +                created.getPropByRes(),
 +                userTO.getPassword(),
 +                userTO.getVirAttrs(),
 +                userTO.getMemberships(),
 +                excludedResources);
 +        PropagationReporter propagationReporter =
 +                
ApplicationContextProvider.getApplicationContext().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) {
 +        return update(userMod, false);
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> update(final UserMod userMod, 
final boolean removeMemberships) {
 +        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 ...
 +            final PropagationByResource propByResVirAttr = 
virtAttrHandler.fillVirtual(
 +                    updated.getResult().getKey().getKey(),
 +                    userMod.getVirAttrsToRemove(),
 +                    userMod.getVirAttrsToUpdate());
 +            // SYNCOPE-501: update only virtual attributes (if any of them 
changed), password propagation is
 +            // not required, take care also of membership virtual attributes
 +            boolean addOrUpdateMemberships = false;
 +            for (MembershipMod membershipMod : userMod.getMembershipsToAdd()) 
{
 +                if (!virtAttrHandler.fillMembershipVirtual(
 +                        updated.getResult().getKey().getKey(),
 +                        membershipMod.getGroup(),
 +                        null,
 +                        membershipMod.getVirAttrsToRemove(),
 +                        membershipMod.getVirAttrsToUpdate(),
 +                        false).isEmpty()) {
 +                    addOrUpdateMemberships = true;
 +                }
 +            }
 +            tasks.addAll(!propByResVirAttr.isEmpty() || 
addOrUpdateMemberships || removeMemberships
 +                    ? propagationManager.getUserUpdateTasks(updated, false, 
null)
 +                    : Collections.<PropagationTask>emptyList());
 +        }
 +        PropagationReporter propagationReporter = 
ApplicationContextProvider.getApplicationContext().
 +                getBean(PropagationReporter.class);
 +        if (!tasks.isEmpty()) {
 +            try {
 +                taskExecutor.execute(tasks, propagationReporter);
 +            } catch (PropagationException e) {
 +                LOG.error("Error propagation primary resource", e);
 +                propagationReporter.onPrimaryResourceFailure(tasks);
 +            }
 +        }
 +
 +        Pair<Long, List<PropagationStatus>> result = new ImmutablePair<>(
 +                updated.getResult().getKey().getKey(), 
propagationReporter.getStatuses());
 +        return result;
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> delete(final Long userKey) {
 +        return delete(userKey, Collections.<String>emptySet());
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> delete(final Long subjectId, 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(subjectId, excludedResources);
 +
 +        PropagationReporter propagationReporter =
 +                
ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propagationReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propagationReporter.onPrimaryResourceFailure(tasks);
 +        }
 +
 +        try {
 +            uwfAdapter.delete(subjectId);
 +        } 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 subjectMod) {
 +        return uwfAdapter.update(subjectMod).getResult().getKey().getKey();
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> activate(final User user, 
final StatusMod statusMod) {
 +        WorkflowResult<Long> updated = statusMod.isOnSyncope()
 +                ? uwfAdapter.activate(user.getKey(), statusMod.getToken())
 +                : new WorkflowResult<>(user.getKey(), null, 
statusMod.getType().name().toLowerCase());
 +
 +        return new ImmutablePair<>(updated.getResult(), propagateStatus(user, 
statusMod));
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> reactivate(final User user, 
final StatusMod statusMod) {
 +        WorkflowResult<Long> updated = statusMod.isOnSyncope()
 +                ? uwfAdapter.reactivate(user.getKey())
 +                : new WorkflowResult<>(user.getKey(), null, 
statusMod.getType().name().toLowerCase());
 +
 +        return new ImmutablePair<>(updated.getResult(), propagateStatus(user, 
statusMod));
 +    }
 +
 +    @Override
 +    public Pair<Long, List<PropagationStatus>> suspend(final User user, final 
StatusMod statusMod) {
 +        WorkflowResult<Long> updated = statusMod.isOnSyncope()
 +                ? uwfAdapter.suspend(user.getKey())
 +                : new WorkflowResult<>(user.getKey(), null, 
statusMod.getType().name().toLowerCase());
 +
 +        return new ImmutablePair<>(updated.getResult(), propagateStatus(user, 
statusMod));
 +    }
 +
 +    protected List<PropagationStatus> propagateStatus(final User user, final 
StatusMod statusMod) {
 +        Collection<String> noPropResourceNames =
 +                CollectionUtils.removeAll(userDAO.findAllResourceNames(user), 
statusMod.getResourceNames());
 +
 +        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
 +                user, statusMod.getType() != StatusMod.ModType.SUSPEND, 
noPropResourceNames);
 +        PropagationReporter propReporter =
 +                
ApplicationContextProvider.getApplicationContext().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 innerSuspend(final User user, final boolean propagate) {
 +        final WorkflowResult<Long> updated = uwfAdapter.suspend(user);
 +
 +        // propagate suspension if and only if it is required by policy
 +        if (propagate) {
 +            UserMod userMod = new UserMod();
 +            userMod.setKey(updated.getResult());
 +
 +            final List<PropagationTask> tasks = 
propagationManager.getUserUpdateTasks(
 +                    new WorkflowResult<Pair<UserMod, Boolean>>(
 +                            new ImmutablePair<>(userMod, Boolean.FALSE),
 +                            updated.getPropByRes(), 
updated.getPerformedTasks()));
 +
 +            taskExecutor.execute(tasks);
 +        }
 +    }
 +
 +    @Override
 +    public List<PropagationStatus> deprovision(final Long userKey, final 
Collection<String> resources) {
 +        final User user = userDAO.authFetch(userKey);
 +
 +        List<PropagationTask> tasks = propagationManager.getUserDeleteTasks(
 +                userKey,
 +                new HashSet<>(resources),
 +                CollectionUtils.removeAll(userDAO.findAllResourceNames(user), 
resources));
 +        PropagationReporter propagationReporter =
 +                
ApplicationContextProvider.getApplicationContext().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 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.getApplicationContext().
 +                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 void requestPasswordReset(final Long id) {
 +        uwfAdapter.requestPasswordReset(id);
 +    }
 +
 +    @Override
 +    public void confirmPasswordReset(final User user, final String token, 
final String password) {
 +        uwfAdapter.confirmPasswordReset(user.getKey(), token, password);
 +
-         List<PropagationTask> tasks = 
propagationManager.getUserUpdateTasks(user, null, null);
++        UserMod userMod = new UserMod();
++        userMod.setKey(user.getKey());
++        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.getApplicationContext().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propReporter.onPrimaryResourceFailure(tasks);
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4cd6f5dc/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
----------------------------------------------------------------------
diff --cc 
ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
index 903f882,0000000..f0c6851
mode 100644,000000..100644
--- 
a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
+++ 
b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
@@@ -1,61 -1,0 +1,72 @@@
 +/*
 + * 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.camel.processor;
 +
 +import java.util.List;
 +import org.apache.camel.Exchange;
 +import org.apache.camel.Processor;
++import org.apache.commons.lang3.tuple.ImmutablePair;
++import org.apache.commons.lang3.tuple.Pair;
++import org.apache.syncope.common.lib.mod.UserMod;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +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.WorkflowResult;
 +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.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.stereotype.Component;
 +
 +@Component
 +public class UserConfirmPwdResetProcessor implements Processor {
 +
 +    private static final Logger LOG = 
LoggerFactory.getLogger(UserConfirmPwdResetProcessor.class);
 +
 +    @Autowired
 +    protected PropagationManager propagationManager;
 +
 +    @Autowired
 +    protected PropagationTaskExecutor taskExecutor;
 +
 +    @Override
 +    public void process(final Exchange exchange) {
 +        User user = exchange.getProperty("user", User.class);
 +
-         List<PropagationTask> tasks = 
propagationManager.getUserUpdateTasks(user, null, null);
++        UserMod userMod = new UserMod();
++        userMod.setKey(user.getKey());
++        userMod.setPassword(exchange.getProperty("password", String.class));
++
++        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
++                new WorkflowResult<Pair<UserMod, Boolean>>(
++                        new ImmutablePair<UserMod, Boolean>(userMod, null), 
null, "confirmPasswordReset"),
++                true, null);
 +        PropagationReporter propReporter =
 +                
ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
 +        try {
 +            taskExecutor.execute(tasks, propReporter);
 +        } catch (PropagationException e) {
 +            LOG.error("Error propagation primary resource", e);
 +            propReporter.onPrimaryResourceFailure(tasks);
 +        }
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4cd6f5dc/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserSelfITCase.java
----------------------------------------------------------------------
diff --cc 
fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserSelfITCase.java
index f01a15c,0000000..14e2f9f
mode 100644,000000..100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserSelfITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserSelfITCase.java
@@@ -1,349 -1,0 +1,364 @@@
 +/*
 + * 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.fit.core.reference;
 +
 +import static org.junit.Assert.assertEquals;
 +import static org.junit.Assert.assertFalse;
++import static org.junit.Assert.assertNotEquals;
 +import static org.junit.Assert.assertNotNull;
 +import static org.junit.Assert.assertNull;
 +import static org.junit.Assert.assertTrue;
 +import static org.junit.Assert.fail;
 +
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.security.AccessControlException;
 +import java.util.Map;
 +import java.util.Set;
 +import javax.ws.rs.core.Response;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.cxf.helpers.IOUtils;
 +import org.apache.syncope.client.lib.SyncopeClient;
 +import org.apache.syncope.common.lib.SyncopeClientException;
 +import org.apache.syncope.common.lib.mod.AttrMod;
 +import org.apache.syncope.common.lib.mod.MembershipMod;
 +import org.apache.syncope.common.lib.mod.StatusMod;
 +import org.apache.syncope.common.lib.mod.UserMod;
 +import org.apache.syncope.common.lib.to.MembershipTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.to.WorkflowFormPropertyTO;
 +import org.apache.syncope.common.lib.to.WorkflowFormTO;
 +import org.apache.syncope.common.lib.types.ClientExceptionType;
 +import org.apache.syncope.common.lib.types.SubjectType;
 +import org.apache.syncope.common.rest.api.Preference;
 +import org.apache.syncope.common.rest.api.RESTHeaders;
 +import org.apache.syncope.common.rest.api.service.UserSelfService;
 +import org.apache.syncope.common.rest.api.service.UserService;
 +import org.junit.Assume;
 +import org.junit.FixMethodOrder;
 +import org.junit.Test;
 +import org.junit.runners.MethodSorters;
++import org.springframework.jdbc.core.JdbcTemplate;
 +
 +@FixMethodOrder(MethodSorters.JVM)
 +public class UserSelfITCase extends AbstractITCase {
 +
 +    @Test
 +    public void selfRegistrationAllowed() {
 +        assertTrue(syncopeService.info().isSelfRegAllowed());
 +    }
 +
 +    @Test
 +    public void create() {
 +        
Assume.assumeTrue(ActivitiDetector.isActivitiEnabledForUsers(syncopeService));
 +
 +        // 1. self-registration as admin: failure
 +        try {
 +            
userSelfService.create(UserITCase.getUniqueSampleTO("[email protected]"),
 true);
 +            fail();
 +        } catch (AccessControlException e) {
 +            assertNotNull(e);
 +        }
 +
 +        // 2. self-registration as anonymous: works
 +        SyncopeClient anonClient = clientFactory.createAnonymous();
 +        UserTO self = anonClient.getService(UserSelfService.class).
 +                
create(UserITCase.getUniqueSampleTO("[email protected]"), true).
 +                readEntity(UserTO.class);
 +        assertNotNull(self);
 +        assertEquals("createApproval", self.getStatus());
 +    }
 +
 +    @Test
 +    public void createAndApprove() {
 +        
Assume.assumeTrue(ActivitiDetector.isActivitiEnabledForUsers(syncopeService));
 +
 +        // self-create user with membership: goes 'createApproval' with 
resources and membership but no propagation
 +        UserTO userTO = 
UserITCase.getUniqueSampleTO("[email protected]");
 +        MembershipTO membership = new MembershipTO();
 +        membership.setGroupKey(3L);
 +        userTO.getMemberships().add(membership);
 +        userTO.getResources().add(RESOURCE_NAME_TESTDB);
 +
 +        SyncopeClient anonClient = clientFactory.createAnonymous();
 +        userTO = anonClient.getService(UserSelfService.class).
 +                create(userTO, true).
 +                readEntity(UserTO.class);
 +        assertNotNull(userTO);
 +        assertEquals("createApproval", userTO.getStatus());
 +        assertFalse(userTO.getMemberships().isEmpty());
 +        assertFalse(userTO.getResources().isEmpty());
 +
 +        try {
 +            resourceService.getConnectorObject(RESOURCE_NAME_TESTDB, 
SubjectType.USER, userTO.getKey());
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +        }
 +
 +        // now approve and verify that propagation has happened
 +        WorkflowFormTO form = 
userWorkflowService.getFormForUser(userTO.getKey());
 +        form = userWorkflowService.claimForm(form.getTaskId());
 +        Map<String, WorkflowFormPropertyTO> props = form.getPropertyMap();
 +        props.get("approve").setValue(Boolean.TRUE.toString());
 +        form.getProperties().clear();
 +        form.getProperties().addAll(props.values());
 +        userTO = userWorkflowService.submitForm(form);
 +        assertNotNull(userTO);
 +        assertEquals("active", userTO.getStatus());
 +        
assertNotNull(resourceService.getConnectorObject(RESOURCE_NAME_TESTDB, 
SubjectType.USER, userTO.getKey()));
 +    }
 +
 +    @Test
 +    public void read() {
 +        UserService userService2 = clientFactory.create("rossini", 
ADMIN_PWD).getService(UserService.class);
 +
 +        try {
 +            userService2.read(1L);
 +            fail();
 +        } catch (AccessControlException e) {
 +            assertNotNull(e);
 +        }
 +
 +        Pair<Map<String, Set<String>>, UserTO> self = 
clientFactory.create("rossini", ADMIN_PWD).self();
 +        assertEquals("rossini", self.getValue().getUsername());
 +    }
 +
 +    @Test
 +    public void updateWithoutApproval() {
 +        // 1. create user as admin
 +        UserTO created = 
createUser(UserITCase.getUniqueSampleTO("[email protected]"));
 +        assertNotNull(created);
 +        assertFalse(created.getUsername().endsWith("XX"));
 +
 +        // 2. self-update (username) - works
 +        UserMod userMod = new UserMod();
 +        userMod.setUsername(created.getUsername() + "XX");
 +
 +        SyncopeClient authClient = 
clientFactory.create(created.getUsername(), "password123");
 +        UserTO updated = 
authClient.getService(UserSelfService.class).update(created.getKey(), userMod).
 +                readEntity(UserTO.class);
 +        assertNotNull(updated);
 +        
assertEquals(ActivitiDetector.isActivitiEnabledForUsers(syncopeService)
 +                ? "active" : "created", updated.getStatus());
 +        assertTrue(updated.getUsername().endsWith("XX"));
 +    }
 +
 +    @Test
 +    public void updateWithApproval() {
 +        
Assume.assumeTrue(ActivitiDetector.isActivitiEnabledForUsers(syncopeService));
 +
 +        // 1. create user as admin
 +        UserTO created = 
createUser(UserITCase.getUniqueSampleTO("[email protected]"));
 +        assertNotNull(created);
 +        assertFalse(created.getUsername().endsWith("XX"));
 +
 +        // 2. self-update (username + memberships + resource) - works but 
needs approval
 +        MembershipMod membershipMod = new MembershipMod();
 +        membershipMod.setGroup(7L);
 +        AttrMod testAttrMod = new AttrMod();
 +        testAttrMod.setSchema("testAttribute");
 +        testAttrMod.getValuesToBeAdded().add("a value");
 +        membershipMod.getPlainAttrsToUpdate().add(testAttrMod);
 +
 +        UserMod userMod = new UserMod();
 +        userMod.setUsername(created.getUsername() + "XX");
 +        userMod.getMembershipsToAdd().add(membershipMod);
 +        userMod.getResourcesToAdd().add(RESOURCE_NAME_TESTDB);
 +        userMod.setPassword("newPassword123");
 +        StatusMod statusMod = new StatusMod();
 +        statusMod.setOnSyncope(false);
 +        statusMod.getResourceNames().add(RESOURCE_NAME_TESTDB);
 +        userMod.setPwdPropRequest(statusMod);
 +
 +        SyncopeClient authClient = 
clientFactory.create(created.getUsername(), "password123");
 +        UserTO updated = 
authClient.getService(UserSelfService.class).update(created.getKey(), userMod).
 +                readEntity(UserTO.class);
 +        assertNotNull(updated);
 +        assertEquals("updateApproval", updated.getStatus());
 +        assertFalse(updated.getUsername().endsWith("XX"));
 +        assertTrue(updated.getMemberships().isEmpty());
 +
 +        // no propagation happened
 +        assertTrue(updated.getResources().isEmpty());
 +        try {
 +            resourceService.getConnectorObject(RESOURCE_NAME_TESTDB, 
SubjectType.USER, updated.getKey());
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +        }
 +
 +        // 3. approve self-update as admin
 +        WorkflowFormTO form = 
userWorkflowService.getFormForUser(updated.getKey());
 +        form = userWorkflowService.claimForm(form.getTaskId());
 +        Map<String, WorkflowFormPropertyTO> props = form.getPropertyMap();
 +        props.get("approve").setValue(Boolean.TRUE.toString());
 +        form.getProperties().clear();
 +        form.getProperties().addAll(props.values());
 +        updated = userWorkflowService.submitForm(form);
 +        assertNotNull(updated);
 +        assertEquals("active", updated.getStatus());
 +        assertTrue(updated.getUsername().endsWith("XX"));
 +        assertEquals(1, updated.getMemberships().size());
 +
 +        // check that propagation also happened
 +        assertTrue(updated.getResources().contains(RESOURCE_NAME_TESTDB));
 +        
assertNotNull(resourceService.getConnectorObject(RESOURCE_NAME_TESTDB, 
SubjectType.USER, updated.getKey()));
 +    }
 +
 +    @Test
 +    public void delete() {
 +        UserTO created = 
createUser(UserITCase.getUniqueSampleTO("[email protected]"));
 +        assertNotNull(created);
 +
 +        SyncopeClient authClient = 
clientFactory.create(created.getUsername(), "password123");
 +        UserTO deleted = 
authClient.getService(UserSelfService.class).delete().readEntity(UserTO.class);
 +        assertNotNull(deleted);
 +        
assertEquals(ActivitiDetector.isActivitiEnabledForUsers(syncopeService)
 +                ? "deleteApproval" : null, deleted.getStatus());
 +    }
 +
 +    @Test
 +    public void issueSYNCOPE373() {
 +        UserTO userTO = adminClient.self().getValue();
 +        assertEquals(ADMIN_UNAME, userTO.getUsername());
 +    }
 +
 +    @Test
 +    public void noContent() throws IOException {
 +        
Assume.assumeTrue(ActivitiDetector.isActivitiEnabledForUsers(syncopeService));
 +
 +        SyncopeClient anonClient = clientFactory.createAnonymous();
 +        UserSelfService noContentService = 
anonClient.prefer(UserSelfService.class, Preference.RETURN_NO_CONTENT);
 +
 +        UserTO user = 
UserITCase.getUniqueSampleTO("[email protected]");
 +
 +        Response response = noContentService.create(user, true);
 +        assertEquals(Response.Status.CREATED.getStatusCode(), 
response.getStatus());
 +        assertEquals(Preference.RETURN_NO_CONTENT.toString(), 
response.getHeaderString(RESTHeaders.PREFERENCE_APPLIED));
 +        assertEquals(StringUtils.EMPTY, IOUtils.toString((InputStream) 
response.getEntity()));
 +    }
 +
 +    @Test
 +    public void passwordReset() {
 +        // 0. ensure that password request DOES require security question
 +        configurationService.set("passwordReset.securityQuestion",
 +                attrTO("passwordReset.securityQuestion", "true"));
 +
 +        // 1. create an user with security question and answer
 +        UserTO user = 
UserITCase.getUniqueSampleTO("[email protected]");
 +        user.setSecurityQuestion(1L);
 +        user.setSecurityAnswer("Rossi");
++        user.getResources().add(RESOURCE_NAME_TESTDB);
 +        createUser(user);
 +
++        // verify propagation (including password) on external db
++        JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
++        String pwdOnResource = jdbcTemplate.queryForObject("SELECT password 
FROM test WHERE id=?", String.class,
++                user.getUsername());
++        assertTrue(StringUtils.isNotBlank(pwdOnResource));
++
 +        // 2. verify that new user is able to authenticate
 +        SyncopeClient authClient = clientFactory.create(user.getUsername(), 
"password123");
 +        UserTO read = authClient.self().getValue();
 +        assertNotNull(read);
 +
 +        // 3. request password reset (as anonymous) providing the expected 
security answer
 +        SyncopeClient anonClient = clientFactory.createAnonymous();
 +        try {
 +            
anonClient.getService(UserSelfService.class).requestPasswordReset(user.getUsername(),
 "WRONG");
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.InvalidSecurityAnswer, 
e.getType());
 +        }
 +        
anonClient.getService(UserSelfService.class).requestPasswordReset(user.getUsername(),
 "Rossi");
 +
 +        // 4. get token (normally sent via e-mail, now reading as admin)
 +        String token = userService.read(read.getKey()).getToken();
 +        assertNotNull(token);
 +
 +        // 5. confirm password reset
 +        try {
 +            
anonClient.getService(UserSelfService.class).confirmPasswordReset("WRONG 
TOKEN", "newPassword");
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +            assertTrue(e.getMessage().contains("WRONG TOKEN"));
 +        }
 +        
anonClient.getService(UserSelfService.class).confirmPasswordReset(token, 
"newPassword123");
 +
 +        // 6. verify that password was reset and token removed
 +        authClient = clientFactory.create(user.getUsername(), 
"newPassword123");
 +        read = authClient.self().getValue();
 +        assertNotNull(read);
 +        assertNull(read.getToken());
++
++        // 7. verify that password was changed on external resource
++        String newPwdOnResource = jdbcTemplate.queryForObject("SELECT 
password FROM test WHERE id=?", String.class,
++                user.getUsername());
++        assertTrue(StringUtils.isNotBlank(newPwdOnResource));
++        assertNotEquals(pwdOnResource, newPwdOnResource);
 +    }
 +
 +    @Test
 +    public void passwordResetWithoutSecurityQuestion() {
 +        // 0. disable security question for password reset
 +        configurationService.set("passwordReset.securityQuestion",
 +                attrTO("passwordReset.securityQuestion", "false"));
 +
 +        // 1. create an user with security question and answer
 +        UserTO user = 
UserITCase.getUniqueSampleTO("[email protected]");
 +        createUser(user);
 +
 +        // 2. verify that new user is able to authenticate
 +        SyncopeClient authClient = clientFactory.create(user.getUsername(), 
"password123");
 +        UserTO read = authClient.self().getValue();
 +        assertNotNull(read);
 +
 +        // 3. request password reset (as anonymous) with no security answer
 +        SyncopeClient anonClient = clientFactory.createAnonymous();
 +        
anonClient.getService(UserSelfService.class).requestPasswordReset(user.getUsername(),
 null);
 +
 +        // 4. get token (normally sent via e-mail, now reading as admin)
 +        String token = userService.read(read.getKey()).getToken();
 +        assertNotNull(token);
 +
 +        // 5. confirm password reset
 +        try {
 +            
anonClient.getService(UserSelfService.class).confirmPasswordReset("WRONG 
TOKEN", "newPassword");
 +            fail();
 +        } catch (SyncopeClientException e) {
 +            assertEquals(ClientExceptionType.NotFound, e.getType());
 +            assertTrue(e.getMessage().contains("WRONG TOKEN"));
 +        }
 +        
anonClient.getService(UserSelfService.class).confirmPasswordReset(token, 
"newPassword123");
 +
 +        // 6. verify that password was reset and token removed
 +        authClient = clientFactory.create(user.getUsername(), 
"newPassword123");
 +        read = authClient.self().getValue();
 +        assertNotNull(read);
 +        assertNull(read.getToken());
 +
 +        // 7. re-enable security question for password reset
 +        configurationService.set("passwordReset.securityQuestion",
 +                attrTO("passwordReset.securityQuestion", "true"));
 +    }
 +
 +}

Reply via email to