You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2014/09/19 10:53:25 UTC

svn commit: r1626148 [1/3] - in /syncope/branches/1_2_X: ./ common/src/main/java/org/apache/syncope/common/mod/ common/src/main/java/org/apache/syncope/common/services/ common/src/main/java/org/apache/syncope/common/to/ common/src/main/java/org/apache/...

Author: ilgrosso
Date: Fri Sep 19 08:53:24 2014
New Revision: 1626148

URL: http://svn.apache.org/r1626148
Log:
[SYNCOPE-135] core features completed, now let's go to console

Added:
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/SecurityQuestionService.java   (with props)
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/SecurityQuestionTO.java   (with props)
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/SecurityQuestion.java   (with props)
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/SecurityQuestionDAO.java   (with props)
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SecurityQuestionDAOImpl.java   (with props)
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/SecurityQuestionController.java   (with props)
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/SecurityQuestionDataBinder.java   (with props)
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SecurityQuestionServiceImpl.java   (with props)
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/workflow/user/activiti/task/Notify.java   (with props)
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/workflow/user/activiti/task/PasswordReset.java   (with props)
    syncope/branches/1_2_X/core/src/main/resources/mailTemplates/confirmPasswordReset.html.vm   (with props)
    syncope/branches/1_2_X/core/src/main/resources/mailTemplates/confirmPasswordReset.txt.vm   (with props)
    syncope/branches/1_2_X/core/src/main/resources/mailTemplates/requestPasswordReset.html.vm   (with props)
    syncope/branches/1_2_X/core/src/main/resources/mailTemplates/requestPasswordReset.txt.vm   (with props)
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/persistence/dao/SecurityQuestionTest.java   (with props)
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/persistence/relationships/SecurityQuestionTest.java   (with props)
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/rest/SecurityQuestionTestITCase.java   (with props)
Modified:
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/mod/UserMod.java
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/ConnectorService.java
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/UserSelfService.java
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/ConnPoolConfTO.java
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/UserTO.java
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/ClientExceptionType.java
    syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/RESTHeaders.java
    syncope/branches/1_2_X/core/pom.xml
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/UserDAO.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/NotificationDataBinder.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/NotificationServiceImpl.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SchemaServiceImpl.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/UserSelfServiceImpl.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/Encryptor.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/POJOHelper.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/workflow/user/AbstractUserWorkflowAdapter.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/workflow/user/NoOpUserWorkflowAdapter.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/workflow/user/UserWorkflowAdapter.java
    syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/workflow/user/activiti/ActivitiUserWorkflowAdapter.java
    syncope/branches/1_2_X/core/src/main/resources/META-INF/orm.xml
    syncope/branches/1_2_X/core/src/main/resources/META-INF/orm.xml.oracle
    syncope/branches/1_2_X/core/src/main/resources/META-INF/orm.xml.sqlserver
    syncope/branches/1_2_X/core/src/main/resources/content.xml
    syncope/branches/1_2_X/core/src/main/resources/mail.properties
    syncope/branches/1_2_X/core/src/main/resources/userWorkflow.bpmn20.xml
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/connid/PasswordGeneratorTest.java
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/persistence/dao/EntitlementTest.java
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/persistence/dao/NotificationTest.java
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/persistence/dao/UserTest.java
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/rest/AbstractTest.java
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/rest/NotificationTestITCase.java
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/rest/UserSelfTestITCase.java
    syncope/branches/1_2_X/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
    syncope/branches/1_2_X/core/src/test/resources/content.xml
    syncope/branches/1_2_X/core/src/test/resources/mail.properties
    syncope/branches/1_2_X/core/src/test/resources/userWorkflow.bpmn20.xml
    syncope/branches/1_2_X/pom.xml

Modified: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/mod/UserMod.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/mod/UserMod.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/mod/UserMod.java (original)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/mod/UserMod.java Fri Sep 19 08:53:24 2014
@@ -43,6 +43,10 @@ public class UserMod extends AbstractSub
 
     private StatusMod pwdPropRequest;
 
+    private Long securityQuestion;
+
+    private String securityAnswer;
+
     public UserMod() {
         super();
 
@@ -88,6 +92,22 @@ public class UserMod extends AbstractSub
         this.pwdPropRequest = pwdPropRequest;
     }
 
+    public Long getSecurityQuestion() {
+        return securityQuestion;
+    }
+
+    public void setSecurityQuestion(final Long securityQuestion) {
+        this.securityQuestion = securityQuestion;
+    }
+
+    public String getSecurityAnswer() {
+        return securityAnswer;
+    }
+
+    public void setSecurityAnswer(final String securityAnswer) {
+        this.securityAnswer = securityAnswer;
+    }
+
     @JsonIgnore
     @Override
     public boolean isEmpty() {
@@ -96,6 +116,8 @@ public class UserMod extends AbstractSub
                 && username == null
                 && membershipsToAdd.isEmpty()
                 && membershipsToRemove.isEmpty()
-                && pwdPropRequest == null;
+                && pwdPropRequest == null
+                && securityQuestion == null
+                && securityAnswer == null;
     }
 }

Modified: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/ConnectorService.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/ConnectorService.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/ConnectorService.java (original)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/ConnectorService.java Fri Sep 19 08:53:24 2014
@@ -155,12 +155,12 @@ public interface ConnectorService extend
      * Updates the connector instance matching the provided id.
      *
      * @param connInstanceId connector instance id to be updated
-     * @param connInstaceTO connector instance to be stored
+     * @param connInstanceTO connector instance to be stored
      */
     @PUT
     @Path("{connInstanceId}")
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    void update(@NotNull @PathParam("connInstanceId") Long connInstanceId, @NotNull ConnInstanceTO connInstaceTO);
+    void update(@NotNull @PathParam("connInstanceId") Long connInstanceId, @NotNull ConnInstanceTO connInstanceTO);
 
     /**
      * Deletes the connector instance matching the provided id.
@@ -172,14 +172,14 @@ public interface ConnectorService extend
     void delete(@NotNull @PathParam("connInstanceId") Long connInstanceId);
 
     /**
-     * @param connInstaceTO connector instance to be used for connection check
+     * @param connInstanceTO connector instance to be used for connection check
      * @return true if connection could be established
      */
     @POST
     @Path("check")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    boolean check(@NotNull ConnInstanceTO connInstaceTO);
+    boolean check(@NotNull ConnInstanceTO connInstanceTO);
 
     /**
      * Reload all connector bundles and instances.

Added: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/SecurityQuestionService.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/SecurityQuestionService.java?rev=1626148&view=auto
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/SecurityQuestionService.java (added)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/SecurityQuestionService.java Fri Sep 19 08:53:24 2014
@@ -0,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.services;
+
+import java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.jaxrs.model.wadl.Description;
+import org.apache.cxf.jaxrs.model.wadl.Descriptions;
+import org.apache.cxf.jaxrs.model.wadl.DocTarget;
+import org.apache.syncope.common.to.SecurityQuestionTO;
+
+/**
+ * REST operations for configuration.
+ */
+@Path("securityQuestions")
+public interface SecurityQuestionService extends JAXRSService {
+
+    /**
+     * Returns a list of all security questions.
+     *
+     * @return list of all security questions
+     */
+    @GET
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    List<SecurityQuestionTO> list();
+
+    /**
+     * Returns security question with matching id.
+     *
+     * @param securityQuestionId security question id to be read
+     * @return security question with matching id
+     */
+    @GET
+    @Path("{securityQuestionId}")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    SecurityQuestionTO read(@NotNull @PathParam("securityQuestionId") Long securityQuestionId);
+
+    /**
+     * Creates a new security question.
+     *
+     * @param securityQuestionTO security question to be created
+     * @return <tt>Response</tt> object featuring <tt>Location</tt> header of created security question
+     */
+    @Descriptions({
+        @Description(target = DocTarget.RESPONSE,
+                value = "Featuring <tt>Location</tt> header of created security question")
+    })
+    @POST
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    Response create(@NotNull SecurityQuestionTO securityQuestionTO);
+
+    /**
+     * Updates the security question matching the provided id.
+     *
+     * @param securityQuestionId security question id to be updated
+     * @param securityQuestionTO security question to be stored
+     */
+    @PUT
+    @Path("{securityQuestionId}")
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    void update(@NotNull @PathParam("securityQuestionId") Long securityQuestionId,
+            @NotNull SecurityQuestionTO securityQuestionTO);
+
+    /**
+     * Deletes the security question matching the provided id.
+     *
+     * @param securityQuestionId security question id to be deleted
+     */
+    @DELETE
+    @Path("{securityQuestionId}")
+    void delete(@NotNull @PathParam("securityQuestionId") Long securityQuestionId);
+
+    /**
+     * Ask for security question configured for the user matching the given username, if any.
+     *
+     * @param username username for which the security question is requested
+     * @return security question, if configured for the user matching the given username
+     */
+    @GET
+    @Path("byUser/{username}")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    SecurityQuestionTO readByUser(@NotNull @PathParam("username") String username);
+}

Propchange: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/SecurityQuestionService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/SecurityQuestionService.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/SecurityQuestionService.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/UserSelfService.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/UserSelfService.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/UserSelfService.java (original)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/services/UserSelfService.java Fri Sep 19 08:53:24 2014
@@ -46,12 +46,15 @@ public interface UserSelfService extends
     /**
      * Checks whether self-registration is allowed.
      *
-     * @return <tt>Response</tt> contains special Syncope HTTP header indicating if user self registration is allowed
+     * @return <tt>Response</tt> contains special Syncope HTTP header indicating if user self registration and / or
+     * password reset is allowed
      * @see org.apache.syncope.common.types.RESTHeaders#SELFREGISTRATION_ALLOWED
+     * @see org.apache.syncope.common.types.RESTHeaders#PASSWORDRESET_ALLOWED
      */
     @Descriptions({
         @Description(target = DocTarget.RESPONSE,
-                value = "Contains special Syncope HTTP header indicating if user self registration is allowed")
+                value = "Contains special Syncope HTTP header indicating if user self registration "
+                + "and / or password reset is allowed")
     })
     @OPTIONS
     Response getOptions();
@@ -114,4 +117,28 @@ public interface UserSelfService extends
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     Response delete();
 
+    /**
+     * Provides answer for the security question configured for user matching the given username, if any.
+     * If provided anwser matches the one stored for that user, a password reset token is internally generated,
+     * otherwise an error is returned.
+     *
+     * @param username username for which the security answer is provided
+     * @param securityAnswer actual answer text
+     */
+    @POST
+    @Path("requestPasswordReset")
+    void requestPasswordReset(@NotNull @QueryParam("username") String username, String securityAnswer);
+
+    /**
+     * Reset the password value for the user matching the provided token, if available and still valid.
+     * If the token actually matches one of users, and if it is still valid at the time of submission, the matching
+     * user's password value is set as provided. The new password value will need anyway to comply with all relevant
+     * password policies.
+     *
+     * @param token password reset token
+     * @param password new password to be set
+     */
+    @POST
+    @Path("confirmPasswordReset")
+    void confirmPasswordReset(@NotNull @QueryParam("token") String token, String password);
 }

Modified: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/ConnPoolConfTO.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/ConnPoolConfTO.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/ConnPoolConfTO.java (original)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/ConnPoolConfTO.java Fri Sep 19 08:53:24 2014
@@ -26,6 +26,8 @@ import org.apache.syncope.common.Abstrac
 @XmlType
 public class ConnPoolConfTO extends AbstractBaseBean {
 
+    private static final long serialVersionUID = -214360178113476623L;
+
     private Integer maxObjects;
 
     private Integer minIdle;

Added: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/SecurityQuestionTO.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/SecurityQuestionTO.java?rev=1626148&view=auto
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/SecurityQuestionTO.java (added)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/SecurityQuestionTO.java Fri Sep 19 08:53:24 2014
@@ -0,0 +1,51 @@
+/*
+ * 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.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.AbstractBaseBean;
+
+@XmlRootElement(name = "securityQuestion")
+@XmlType
+public class SecurityQuestionTO extends AbstractBaseBean {
+
+    private static final long serialVersionUID = 5969810939993556530L;
+
+    private long id;
+
+    private String content;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(final long id) {
+        this.id = id;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(final String content) {
+        this.content = content;
+    }
+
+}

Propchange: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/SecurityQuestionTO.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/SecurityQuestionTO.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/SecurityQuestionTO.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/UserTO.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/UserTO.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/UserTO.java (original)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/to/UserTO.java Fri Sep 19 08:53:24 2014
@@ -58,6 +58,10 @@ public class UserTO extends AbstractSubj
 
     private Integer failedLogins;
 
+    private Long securityQuestion;
+
+    private String securityAnswer;
+
     public String getPassword() {
         return password;
     }
@@ -150,6 +154,22 @@ public class UserTO extends AbstractSubj
         this.lastLoginDate = lastLoginDate;
     }
 
+    public Long getSecurityQuestion() {
+        return securityQuestion;
+    }
+
+    public void setSecurityQuestion(final Long securityQuestion) {
+        this.securityQuestion = securityQuestion;
+    }
+
+    public String getSecurityAnswer() {
+        return securityAnswer;
+    }
+
+    public void setSecurityAnswer(final String securityAnswer) {
+        this.securityAnswer = securityAnswer;
+    }
+
     @Override
     public String toString() {
         return new ReflectionToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) {

Modified: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/ClientExceptionType.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/ClientExceptionType.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/ClientExceptionType.java (original)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/ClientExceptionType.java Fri Sep 19 08:53:24 2014
@@ -28,6 +28,7 @@ public enum ClientExceptionType {
     DataIntegrityViolation(Response.Status.BAD_REQUEST),
     EntityExists(Response.Status.CONFLICT),
     GenericPersistence(Response.Status.BAD_REQUEST),
+    InvalidSecurityAnswer(Response.Status.BAD_REQUEST),
     InvalidLogger(Response.Status.BAD_REQUEST),
     InvalidConnInstance(Response.Status.BAD_REQUEST),
     InvalidConnIdConf(Response.Status.BAD_REQUEST),

Modified: syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/RESTHeaders.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/RESTHeaders.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/RESTHeaders.java (original)
+++ syncope/branches/1_2_X/common/src/main/java/org/apache/syncope/common/types/RESTHeaders.java Fri Sep 19 08:53:24 2014
@@ -39,6 +39,11 @@ public final class RESTHeaders {
     public static final String SELFREGISTRATION_ALLOWED = "Syncope.SelfRegistration.Allowed";
 
     /**
+     * Option key stating if user request create is allowed or not.
+     */
+    public static final String PASSWORDRESET_ALLOWED = "Syncope.PasswordReset.Allowed";
+
+    /**
      * Option key stating if Activiti workflow adapter is in use for users.
      */
     public static final String ACTIVITI_USER_ENABLED = "Syncope.Activiti.User.Enabled";

Modified: syncope/branches/1_2_X/core/pom.xml
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/pom.xml?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/pom.xml (original)
+++ syncope/branches/1_2_X/core/pom.xml Fri Sep 19 08:53:24 2014
@@ -180,7 +180,11 @@ under the License.
       <groupId>com.fasterxml.jackson.jaxrs</groupId>
       <artifactId>jackson-jaxrs-json-provider</artifactId>
     </dependency>
-
+    <dependency>
+      <groupId>com.fasterxml.jackson.module</groupId>
+      <artifactId>jackson-module-afterburner</artifactId>
+    </dependency>
+      
     <dependency>
       <groupId>org.apache.velocity</groupId>
       <artifactId>velocity</artifactId>

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/notification/NotificationJob.java Fri Sep 19 08:53:24 2014
@@ -89,12 +89,7 @@ public class NotificationJob implements 
     private long maxRetries;
 
     private void init() {
-        try {
-            maxRetries = confDAO.find("notification.maxRetries", "0").getValues().get(0).getLongValue();
-        } catch (NumberFormatException e) {
-            LOG.error("Invalid maximum number of retries, retries disabled", e);
-            maxRetries = 0;
-        }
+        maxRetries = confDAO.find("notification.maxRetries", "0").getValues().get(0).getLongValue();
 
         if (mailSender instanceof JavaMailSenderImpl
                 && StringUtils.isNotBlank(((JavaMailSenderImpl) mailSender).getUsername())) {

Added: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/SecurityQuestion.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/SecurityQuestion.java?rev=1626148&view=auto
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/SecurityQuestion.java (added)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/SecurityQuestion.java Fri Sep 19 08:53:24 2014
@@ -0,0 +1,48 @@
+/*
+ * 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.persistence.beans;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+public class SecurityQuestion extends AbstractBaseBean {
+
+    private static final long serialVersionUID = -7646140284033489392L;
+
+    @Id
+    private Long id;
+
+    @Column(unique = true)
+    private String content;
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(final String content) {
+        this.content = content;
+    }
+
+}

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/SecurityQuestion.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/SecurityQuestion.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/SecurityQuestion.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java Fri Sep 19 08:53:24 2014
@@ -39,6 +39,7 @@ import javax.persistence.JoinColumn;
 import javax.persistence.JoinTable;
 import javax.persistence.Lob;
 import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
@@ -53,6 +54,7 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.beans.AbstractSubject;
 import org.apache.syncope.core.persistence.beans.AbstractVirAttr;
 import org.apache.syncope.core.persistence.beans.ExternalResource;
+import org.apache.syncope.core.persistence.beans.SecurityQuestion;
 import org.apache.syncope.core.persistence.beans.membership.Membership;
 import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
 import org.apache.syncope.core.persistence.validation.entity.SyncopeUserCheck;
@@ -154,7 +156,13 @@ public class SyncopeUser extends Abstrac
             @JoinColumn(name = "resource_name"))
     @Valid
     private Set<ExternalResource> resources;
-    
+
+    @ManyToOne(fetch = FetchType.EAGER, optional = true)
+    private SecurityQuestion securityQuestion;
+
+    @Column(nullable = true)
+    private String securityAnswer;
+
     public SyncopeUser() {
         super();
 
@@ -267,7 +275,7 @@ public class SyncopeUser extends Abstrac
         this.cipherAlgorithm = cipherAlgoritm;
     }
 
-    public void setPassword(final String password, final CipherAlgorithm cipherAlgoritm, final int historySize) {
+    public void setPassword(final String password, final CipherAlgorithm cipherAlgoritm) {
         // clear password
         this.clearPassword = password;
 
@@ -494,8 +502,8 @@ public class SyncopeUser extends Abstrac
                 res = passwordHistory.subList(size >= passwordHistory.size()
                         ? 0
                         : passwordHistory.size() - size, passwordHistory.size()).contains(cipherAlgorithm == null
-                                ? password
-                                : Encryptor.getInstance().encode(password, cipherAlgorithm));
+                                        ? password
+                                        : Encryptor.getInstance().encode(password, cipherAlgorithm));
             } catch (Exception e) {
                 LOG.error("Error evaluating password history", e);
             }
@@ -503,4 +511,21 @@ public class SyncopeUser extends Abstrac
 
         return res;
     }
+
+    public SecurityQuestion getSecurityQuestion() {
+        return securityQuestion;
+    }
+
+    public void setSecurityQuestion(final SecurityQuestion securityQuestion) {
+        this.securityQuestion = securityQuestion;
+    }
+
+    public String getSecurityAnswer() {
+        return securityAnswer;
+    }
+
+    public void setSecurityAnswer(final String securityAnswer) {
+        this.securityAnswer = securityAnswer;
+    }
+
 }

Added: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/SecurityQuestionDAO.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/SecurityQuestionDAO.java?rev=1626148&view=auto
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/SecurityQuestionDAO.java (added)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/SecurityQuestionDAO.java Fri Sep 19 08:53:24 2014
@@ -0,0 +1,35 @@
+/*
+ * 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.persistence.dao;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.beans.SecurityQuestion;
+import org.apache.syncope.core.persistence.validation.entity.InvalidEntityException;
+
+public interface SecurityQuestionDAO extends DAO {
+
+    SecurityQuestion find(Long id);
+
+    List<SecurityQuestion> findAll();
+
+    SecurityQuestion save(SecurityQuestion securityQuestion) throws InvalidEntityException;
+
+    void delete(Long id);
+
+}

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/SecurityQuestionDAO.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/SecurityQuestionDAO.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/SecurityQuestionDAO.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/UserDAO.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/UserDAO.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/UserDAO.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/UserDAO.java Fri Sep 19 08:53:24 2014
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Set;
 
 import org.apache.syncope.core.persistence.beans.ExternalResource;
+import org.apache.syncope.core.persistence.beans.SecurityQuestion;
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.persistence.beans.user.UAttrValue;
 import org.apache.syncope.core.persistence.dao.search.OrderByClause;
@@ -35,6 +36,10 @@ public interface UserDAO extends Subject
 
     SyncopeUser findByWorkflowId(String workflowId);
 
+    SyncopeUser findByToken(String token);
+
+    List<SyncopeUser> findBySecurityQuestion(SecurityQuestion securityQuestion);
+
     List<SyncopeUser> findByDerAttrValue(String schemaName, String value);
 
     List<SyncopeUser> findByAttrValue(String schemaName, UAttrValue attrValue);
@@ -54,4 +59,5 @@ public interface UserDAO extends Subject
     void delete(Long id);
 
     void delete(SyncopeUser user);
+
 }

Added: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SecurityQuestionDAOImpl.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SecurityQuestionDAOImpl.java?rev=1626148&view=auto
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SecurityQuestionDAOImpl.java (added)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SecurityQuestionDAOImpl.java Fri Sep 19 08:53:24 2014
@@ -0,0 +1,70 @@
+/*
+ * 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.persistence.dao.impl;
+
+import java.util.List;
+import javax.persistence.TypedQuery;
+import org.apache.syncope.core.persistence.beans.SecurityQuestion;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
+import org.apache.syncope.core.persistence.dao.SecurityQuestionDAO;
+import org.apache.syncope.core.persistence.dao.UserDAO;
+import org.apache.syncope.core.persistence.validation.entity.InvalidEntityException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class SecurityQuestionDAOImpl extends AbstractDAOImpl implements SecurityQuestionDAO {
+
+    @Autowired
+    private UserDAO userDAO;
+
+    @Override
+    public SecurityQuestion find(final Long id) {
+        return entityManager.find(SecurityQuestion.class, id);
+    }
+
+    @Override
+    public List<SecurityQuestion> findAll() {
+        final TypedQuery<SecurityQuestion> query = entityManager.createQuery(
+                "SELECT e FROM " + SecurityQuestion.class.getSimpleName() + " e ", SecurityQuestion.class);
+        return query.getResultList();
+    }
+
+    @Override
+    public SecurityQuestion save(final SecurityQuestion securityQuestion) throws InvalidEntityException {
+        return entityManager.merge(securityQuestion);
+    }
+
+    @Override
+    public void delete(final Long id) {
+        SecurityQuestion securityQuestion = find(id);
+        if (securityQuestion == null) {
+            return;
+        }
+
+        for (SyncopeUser user : userDAO.findBySecurityQuestion(securityQuestion)) {
+            user.setSecurityQuestion(null);
+            user.setSecurityAnswer(null);
+            userDAO.save(user);
+        }
+
+        entityManager.remove(securityQuestion);
+    }
+
+}

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SecurityQuestionDAOImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SecurityQuestionDAOImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/SecurityQuestionDAOImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/persistence/dao/impl/UserDAOImpl.java Fri Sep 19 08:53:24 2014
@@ -30,6 +30,7 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.beans.AbstractAttributable;
 import org.apache.syncope.core.persistence.beans.AbstractVirAttr;
 import org.apache.syncope.core.persistence.beans.ExternalResource;
+import org.apache.syncope.core.persistence.beans.SecurityQuestion;
 import org.apache.syncope.core.persistence.beans.membership.Membership;
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.persistence.beans.user.UAttrValue;
@@ -78,7 +79,7 @@ public class UserDAOImpl extends Abstrac
     @Override
     public SyncopeUser find(final String username) {
         TypedQuery<SyncopeUser> query = entityManager.createQuery("SELECT e FROM " + SyncopeUser.class.getSimpleName()
-                + " e " + "WHERE e.username = :username", SyncopeUser.class);
+                + " e WHERE e.username = :username", SyncopeUser.class);
         query.setParameter("username", username);
 
         SyncopeUser result = null;
@@ -94,7 +95,7 @@ public class UserDAOImpl extends Abstrac
     @Override
     public SyncopeUser findByWorkflowId(final String workflowId) {
         TypedQuery<SyncopeUser> query = entityManager.createQuery("SELECT e FROM " + SyncopeUser.class.getSimpleName()
-                + " e " + "WHERE e.workflowId = :workflowId", SyncopeUser.class);
+                + " e WHERE e.workflowId = :workflowId", SyncopeUser.class);
         query.setParameter("workflowId", workflowId);
 
         SyncopeUser result = null;
@@ -108,6 +109,31 @@ public class UserDAOImpl extends Abstrac
     }
 
     @Override
+    public SyncopeUser findByToken(final String token) {
+        TypedQuery<SyncopeUser> query = entityManager.createQuery("SELECT e FROM " + SyncopeUser.class.getSimpleName()
+                + " e WHERE e.token = :token", SyncopeUser.class);
+        query.setParameter("token", token);
+
+        SyncopeUser result = null;
+        try {
+            result = query.getSingleResult();
+        } catch (NoResultException e) {
+            LOG.debug("No user found with token {}", token, e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public List<SyncopeUser> findBySecurityQuestion(final SecurityQuestion securityQuestion) {
+        TypedQuery<SyncopeUser> query = entityManager.createQuery("SELECT e FROM " + SyncopeUser.class.getSimpleName()
+                + " e WHERE e.securityQuestion = :securityQuestion", SyncopeUser.class);
+        query.setParameter("securityQuestion", securityQuestion);
+
+        return query.getResultList();
+    }
+
+    @Override
     protected TypedQuery<AbstractAttrValue> findByAttrValueQuery(final String entityName) {
         return entityManager.createQuery("SELECT e FROM " + entityName + " e"
                 + " WHERE e.attribute.schema.name = :schemaName AND (e.stringValue IS NOT NULL"

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/NotificationController.java Fri Sep 19 08:53:24 2014
@@ -66,7 +66,7 @@ public class NotificationController exte
 
     @PreAuthorize("hasRole('NOTIFICATION_CREATE')")
     public NotificationTO create(final NotificationTO notificationTO) {
-        return binder.getNotificationTO(notificationDAO.save(binder.createNotification(notificationTO)));
+        return binder.getNotificationTO(notificationDAO.save(binder.create(notificationTO)));
     }
 
     @PreAuthorize("hasRole('NOTIFICATION_UPDATE')")
@@ -77,7 +77,7 @@ public class NotificationController exte
             throw new NotFoundException(String.valueOf(notificationTO.getId()));
         }
 
-        binder.updateNotification(notification, notificationTO);
+        binder.update(notification, notificationTO);
         notification = notificationDAO.save(notification);
 
         return binder.getNotificationTO(notification);
@@ -87,19 +87,16 @@ public class NotificationController exte
     public NotificationTO delete(final Long notificationId) {
         Notification notification = notificationDAO.find(notificationId);
         if (notification == null) {
-            LOG.error("Could not find notificatin '" + notificationId + "'");
+            LOG.error("Could not find notification '" + notificationId + "'");
 
             throw new NotFoundException(String.valueOf(notificationId));
         }
 
-        NotificationTO notificationToDelete = binder.getNotificationTO(notification);
+        NotificationTO deleted = binder.getNotificationTO(notification);
         notificationDAO.delete(notificationId);
-        return notificationToDelete;
+        return deleted;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected NotificationTO resolveReference(final Method method, final Object... args)
             throws UnresolvedReferenceException {

Added: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/SecurityQuestionController.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/SecurityQuestionController.java?rev=1626148&view=auto
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/SecurityQuestionController.java (added)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/SecurityQuestionController.java Fri Sep 19 08:53:24 2014
@@ -0,0 +1,150 @@
+/*
+ * 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.rest.controller;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.to.SecurityQuestionTO;
+import org.apache.syncope.core.persistence.beans.SecurityQuestion;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
+import org.apache.syncope.core.persistence.dao.NotFoundException;
+import org.apache.syncope.core.persistence.dao.SecurityQuestionDAO;
+import org.apache.syncope.core.persistence.dao.UserDAO;
+import org.apache.syncope.core.rest.data.SecurityQuestionDataBinder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SecurityQuestionController extends AbstractTransactionalController<SecurityQuestionTO> {
+
+    @Autowired
+    private SecurityQuestionDAO securityQuestionDAO;
+
+    @Autowired
+    private UserDAO userDAO;
+
+    @Autowired
+    private SecurityQuestionDataBinder binder;
+
+    @PreAuthorize("hasRole('SECURITY_QUESTION_LIST')")
+    public List<SecurityQuestionTO> list() {
+        List<SecurityQuestionTO> result = new ArrayList<SecurityQuestionTO>();
+        for (SecurityQuestion securityQuestion : securityQuestionDAO.findAll()) {
+            result.add(binder.getSecurityQuestionTO(securityQuestion));
+        }
+
+        return result;
+    }
+
+    @PreAuthorize("hasRole('SECURITY_QUESTION_READ')")
+    public SecurityQuestionTO read(final Long securityQuestionId) {
+        SecurityQuestion securityQuestion = securityQuestionDAO.find(securityQuestionId);
+        if (securityQuestion == null) {
+            LOG.error("Could not find security question '" + securityQuestionId + "'");
+
+            throw new NotFoundException(String.valueOf(securityQuestionId));
+        }
+
+        return binder.getSecurityQuestionTO(securityQuestion);
+    }
+
+    @PreAuthorize("hasRole('SECURITY_QUESTION_CREATE')")
+    public SecurityQuestionTO create(final SecurityQuestionTO securityQuestionTO) {
+        return binder.getSecurityQuestionTO(securityQuestionDAO.save(binder.create(securityQuestionTO)));
+    }
+
+    @PreAuthorize("hasRole('SECURITY_QUESTION_UPDATE')")
+    public SecurityQuestionTO update(final SecurityQuestionTO securityQuestionTO) {
+        SecurityQuestion securityQuestion = securityQuestionDAO.find(securityQuestionTO.getId());
+        if (securityQuestion == null) {
+            LOG.error("Could not find security question '" + securityQuestionTO.getId() + "'");
+
+            throw new NotFoundException(String.valueOf(securityQuestionTO.getId()));
+        }
+
+        binder.update(securityQuestion, securityQuestionTO);
+        securityQuestion = securityQuestionDAO.save(securityQuestion);
+
+        return binder.getSecurityQuestionTO(securityQuestion);
+    }
+
+    @PreAuthorize("hasRole('SECURITY_QUESTION_DELETE')")
+    public SecurityQuestionTO delete(final Long securityQuestionId) {
+        SecurityQuestion securityQuestion = securityQuestionDAO.find(securityQuestionId);
+        if (securityQuestion == null) {
+            LOG.error("Could not find security question '" + securityQuestionId + "'");
+
+            throw new NotFoundException(String.valueOf(securityQuestionId));
+        }
+
+        SecurityQuestionTO deleted = binder.getSecurityQuestionTO(securityQuestion);
+        securityQuestionDAO.delete(securityQuestionId);
+        return deleted;
+    }
+
+    @PreAuthorize("isAnonymous() or hasRole(T(org.apache.syncope.common.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
+    public SecurityQuestionTO read(final String username) {
+        if (username == null) {
+            throw new NotFoundException("Null username");
+        }
+        SyncopeUser user = userDAO.find(username);
+        if (user == null) {
+            throw new NotFoundException("User " + username);
+        }
+
+        if (user.getSecurityQuestion() == null) {
+            LOG.error("Could not find security question for user '" + username + "'");
+
+            throw new NotFoundException("Security question for user " + username);
+        }
+
+        return binder.getSecurityQuestionTO(user.getSecurityQuestion());
+    }
+
+    @Override
+    protected SecurityQuestionTO resolveReference(final Method method, final Object... args)
+            throws UnresolvedReferenceException {
+
+        Long id = null;
+
+        if (ArrayUtils.isNotEmpty(args)) {
+            for (int i = 0; id == null && i < args.length; i++) {
+                if (args[i] instanceof Long) {
+                    id = (Long) args[i];
+                } else if (args[i] instanceof SecurityQuestionTO) {
+                    id = ((SecurityQuestionTO) args[i]).getId();
+                }
+            }
+        }
+
+        if (id != null) {
+            try {
+                return binder.getSecurityQuestionTO(securityQuestionDAO.find(id));
+            } catch (Throwable ignore) {
+                LOG.debug("Unresolved reference", ignore);
+                throw new UnresolvedReferenceException(ignore);
+            }
+        }
+
+        throw new UnresolvedReferenceException();
+    }
+}

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/SecurityQuestionController.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/SecurityQuestionController.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/SecurityQuestionController.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java Fri Sep 19 08:53:24 2014
@@ -46,6 +46,7 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.persistence.dao.SubjectSearchDAO;
 import org.apache.syncope.core.persistence.dao.ConfDAO;
+import org.apache.syncope.core.persistence.dao.NotFoundException;
 import org.apache.syncope.core.persistence.dao.RoleDAO;
 import org.apache.syncope.core.persistence.dao.UserDAO;
 import org.apache.syncope.core.persistence.dao.search.OrderByClause;
@@ -107,6 +108,11 @@ public class UserController extends Abst
         return confDAO.find("selfRegistration.allowed", "false").getValues().get(0).getBooleanValue();
     }
 
+    @Transactional(readOnly = true)
+    public boolean isPasswordResetAllowed() {
+        return confDAO.find("passwordReset.allowed", "false").getValues().get(0).getBooleanValue();
+    }
+
     @PreAuthorize("hasRole('USER_READ')")
     public String getUsername(final Long userId) {
         return binder.getUserTO(userId).getUsername();
@@ -359,6 +365,46 @@ public class UserController extends Abst
         return savedTO;
     }
 
+    @PreAuthorize("isAnonymous() or hasRole(T(org.apache.syncope.common.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
+    @Transactional
+    public void requestPasswordReset(final String username, final String securityAnswer) {
+        if (username == null) {
+            throw new NotFoundException("Null username");
+        }
+
+        SyncopeUser user = userDAO.find(username);
+        if (user == null) {
+            throw new NotFoundException("User " + username);
+        }
+
+        if (securityAnswer == null || !securityAnswer.equals(user.getSecurityAnswer())) {
+            throw SyncopeClientException.build(ClientExceptionType.InvalidSecurityAnswer);
+        }
+
+        uwfAdapter.requestPasswordReset(user.getId());
+    }
+
+    @PreAuthorize("isAnonymous() or hasRole(T(org.apache.syncope.common.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
+    @Transactional
+    public void confirmPasswordReset(final String token, final String password) {
+        SyncopeUser user = userDAO.findByToken(token);
+        if (user == null) {
+            throw new NotFoundException("User with token " + token);
+        }
+
+        uwfAdapter.confirmPasswordReset(user.getId(), token, password);
+
+        List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(user, null, 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);
+        }
+    }
+
     @PreAuthorize("isAuthenticated() "
             + "and not(hasRole(T(org.apache.syncope.common.SyncopeConstants).ANONYMOUS_ENTITLEMENT))")
     public UserTO deleteSelf() {
@@ -564,14 +610,11 @@ public class UserController extends Abst
         return original;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     protected UserTO resolveReference(final Method method, final Object... args) throws UnresolvedReferenceException {
         Object id = null;
 
-        if (ArrayUtils.isNotEmpty(args)) {
+        if (!"confirmPasswordReset".equals(method.getName()) && ArrayUtils.isNotEmpty(args)) {
             for (int i = 0; id == null && i < args.length; i++) {
                 if (args[i] instanceof Long) {
                     id = (Long) args[i];

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java Fri Sep 19 08:53:24 2014
@@ -73,7 +73,6 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.beans.user.UVirSchema;
 import org.apache.syncope.core.persistence.dao.AttrDAO;
 import org.apache.syncope.core.persistence.dao.AttrValueDAO;
-import org.apache.syncope.core.persistence.dao.ConfDAO;
 import org.apache.syncope.core.persistence.dao.DerAttrDAO;
 import org.apache.syncope.core.persistence.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.dao.MembershipDAO;
@@ -101,9 +100,6 @@ public abstract class AbstractAttributab
     protected static final Logger LOG = LoggerFactory.getLogger(AbstractAttributableDataBinder.class);
 
     @Autowired
-    protected ConfDAO confDAO;
-
-    @Autowired
     protected RoleDAO roleDAO;
 
     @Autowired
@@ -215,8 +211,8 @@ public abstract class AbstractAttributab
         List<String> valuesProvided = schema.isMultivalue()
                 ? values
                 : (values.isEmpty()
-                ? Collections.<String>emptyList()
-                : Collections.singletonList(values.iterator().next()));
+                        ? Collections.<String>emptyList()
+                        : Collections.singletonList(values.iterator().next()));
 
         for (String value : valuesProvided) {
             if (value == null || value.isEmpty()) {

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/NotificationDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/NotificationDataBinder.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/NotificationDataBinder.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/NotificationDataBinder.java Fri Sep 19 08:53:24 2014
@@ -41,13 +41,13 @@ public class NotificationDataBinder {
         return result;
     }
 
-    public Notification createNotification(final NotificationTO notificationTO) {
+    public Notification create(final NotificationTO notificationTO) {
         Notification result = new Notification();
-        updateNotification(result, notificationTO);
+        update(result, notificationTO);
         return result;
     }
 
-    public void updateNotification(final Notification notification, final NotificationTO notificationTO) {
+    public void update(final Notification notification, final NotificationTO notificationTO) {
         BeanUtils.copyProperties(notificationTO, notification, IGNORE_PROPERTIES);
 
         notification.setUserAbout(notificationTO.getUserAbout());

Added: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/SecurityQuestionDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/SecurityQuestionDataBinder.java?rev=1626148&view=auto
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/SecurityQuestionDataBinder.java (added)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/SecurityQuestionDataBinder.java Fri Sep 19 08:53:24 2014
@@ -0,0 +1,46 @@
+/*
+ * 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.rest.data;
+
+import org.apache.syncope.common.to.SecurityQuestionTO;
+import org.apache.syncope.common.util.BeanUtils;
+import org.apache.syncope.core.persistence.beans.SecurityQuestion;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SecurityQuestionDataBinder {
+
+    public SecurityQuestionTO getSecurityQuestionTO(final SecurityQuestion securityQuestion) {
+        SecurityQuestionTO securityQuestionTO = new SecurityQuestionTO();
+
+        BeanUtils.copyProperties(securityQuestion, securityQuestionTO);
+
+        return securityQuestionTO;
+    }
+
+    public SecurityQuestion create(final SecurityQuestionTO securityQuestionTO) {
+        SecurityQuestion result = new SecurityQuestion();
+        update(result, securityQuestionTO);
+        return result;
+    }
+
+    public void update(final SecurityQuestion securityQuestion, final SecurityQuestionTO securityQuestionTO) {
+        BeanUtils.copyProperties(securityQuestionTO, securityQuestion, "id");
+    }
+}

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/SecurityQuestionDataBinder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/SecurityQuestionDataBinder.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/SecurityQuestionDataBinder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java Fri Sep 19 08:53:24 2014
@@ -30,9 +30,7 @@ import org.apache.syncope.common.mod.Use
 import org.apache.syncope.common.to.MembershipTO;
 import org.apache.syncope.common.to.UserTO;
 import org.apache.syncope.common.types.AttributableType;
-import org.apache.syncope.common.types.CipherAlgorithm;
 import org.apache.syncope.common.types.IntMappingType;
-import org.apache.syncope.common.types.PasswordPolicySpec;
 import org.apache.syncope.common.types.ResourceOperation;
 import org.apache.syncope.common.types.ClientExceptionType;
 import org.apache.syncope.common.util.BeanUtils;
@@ -45,7 +43,7 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.beans.AbstractMappingItem;
 import org.apache.syncope.core.persistence.beans.AbstractVirAttr;
 import org.apache.syncope.core.persistence.beans.ExternalResource;
-import org.apache.syncope.core.persistence.beans.PasswordPolicy;
+import org.apache.syncope.core.persistence.beans.SecurityQuestion;
 import org.apache.syncope.core.persistence.beans.membership.MAttr;
 import org.apache.syncope.core.persistence.beans.membership.MDerAttr;
 import org.apache.syncope.core.persistence.beans.membership.MVirAttr;
@@ -53,6 +51,7 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.persistence.dao.NotFoundException;
+import org.apache.syncope.core.persistence.dao.SecurityQuestionDAO;
 import org.apache.syncope.core.propagation.PropagationByResource;
 import org.apache.syncope.core.rest.controller.UnauthorizedRoleException;
 import org.apache.syncope.core.util.AttributableUtil;
@@ -68,12 +67,15 @@ import org.springframework.transaction.a
 public class UserDataBinder extends AbstractAttributableDataBinder {
 
     private static final String[] IGNORE_USER_PROPERTIES = {
-        "memberships", "attrs", "derAttrs", "virAttrs", "resources"
+        "memberships", "attrs", "derAttrs", "virAttrs", "resources", "securityQuestion"
     };
 
     @Autowired
     private ConnObjectUtil connObjectUtil;
 
+    @Autowired
+    private SecurityQuestionDAO securityQuestionDAO;
+
     @Resource(name = "adminUser")
     private String adminUser;
 
@@ -82,6 +84,21 @@ public class UserDataBinder extends Abst
 
     private final Encryptor encryptor = Encryptor.getInstance();
 
+    private void securityChecks(final SyncopeUser user) {
+        // Allows anonymous (during self-registration) and self (during self-update) to read own SyncopeUser,
+        // otherwise goes thorugh security checks to see if needed role entitlements are owned
+        if (!EntitlementUtil.getAuthenticatedUsername().equals(anonymousUser)
+                && !EntitlementUtil.getAuthenticatedUsername().equals(user.getUsername())) {
+
+            Set<Long> roleIds = user.getRoleIds();
+            Set<Long> adminRoleIds = EntitlementUtil.getRoleIds(EntitlementUtil.getOwnedEntitlementNames());
+            roleIds.removeAll(adminRoleIds);
+            if (!roleIds.isEmpty()) {
+                throw new UnauthorizedRoleException(roleIds);
+            }
+        }
+    }
+
     @Transactional(readOnly = true)
     public SyncopeUser getUserFromId(final Long userId) {
         if (userId == null) {
@@ -93,19 +110,24 @@ public class UserDataBinder extends Abst
             throw new NotFoundException("User " + userId);
         }
 
-        // Allows anonymous (during self-registration) and self (during self-update) to read own SyncopeUser,
-        // otherwise goes thorugh security checks to see if needed role entitlements are owned
-        if (!EntitlementUtil.getAuthenticatedUsername().equals(anonymousUser)
-                && !EntitlementUtil.getAuthenticatedUsername().equals(user.getUsername())) {
+        securityChecks(user);
 
-            Set<Long> roleIds = user.getRoleIds();
-            Set<Long> adminRoleIds = EntitlementUtil.getRoleIds(EntitlementUtil.getOwnedEntitlementNames());
-            roleIds.removeAll(adminRoleIds);
-            if (!roleIds.isEmpty()) {
-                throw new UnauthorizedRoleException(roleIds);
-            }
+        return user;
+    }
+
+    @Transactional(readOnly = true)
+    public SyncopeUser getUserFromUsername(final String username) {
+        if (username == null) {
+            throw new NotFoundException("Null username");
+        }
+
+        SyncopeUser user = userDAO.find(username);
+        if (user == null) {
+            throw new NotFoundException("User " + username);
         }
 
+        securityChecks(user);
+
         return user;
     }
 
@@ -159,55 +181,11 @@ public class UserDataBinder extends Abst
         return encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword());
     }
 
-    @Transactional(readOnly = true)
-    public SyncopeUser getUserFromUsername(final String username) {
-        if (username == null) {
-            throw new NotFoundException("Null username");
-        }
-
-        SyncopeUser user = userDAO.find(username);
-        if (user == null) {
-            throw new NotFoundException("User " + username);
-        }
-
-        Set<Long> roleIds = user.getRoleIds();
-        Set<Long> adminRoleIds = EntitlementUtil.getRoleIds(EntitlementUtil.getOwnedEntitlementNames());
-        roleIds.removeAll(adminRoleIds);
-
-        if (!roleIds.isEmpty()) {
-            throw new UnauthorizedRoleException(roleIds);
-        }
-
-        return user;
-    }
-
-    /**
-     * Get predefined password cipher algorithm from SyncopeConf.
-     *
-     * @return cipher algorithm.
-     */
-    private CipherAlgorithm getPredefinedCipherAlgoritm() {
-        final String algorithm = confDAO.find(
-                "password.cipher.algorithm", CipherAlgorithm.AES.name()).getValues().get(0).getStringValue();
-
-        try {
-            return CipherAlgorithm.valueOf(algorithm);
-        } catch (IllegalArgumentException e) {
-            throw new NotFoundException("Cipher algorithm " + algorithm);
-        }
-    }
-
     private void setPassword(final SyncopeUser user, final String password,
             final SyncopeClientCompositeException scce) {
 
-        int passwordHistorySize = 0;
-        PasswordPolicy policy = policyDAO.getGlobalPasswordPolicy();
-        if (policy != null && policy.getSpecification(PasswordPolicySpec.class) != null) {
-            passwordHistorySize = policy.getSpecification(PasswordPolicySpec.class).getHistoryLength();
-        }
-
         try {
-            user.setPassword(password, getPredefinedCipherAlgoritm(), passwordHistorySize);
+            user.setPassword(password, Encryptor.getPredefinedCipherAlgoritm());
         } catch (NotFoundException e) {
             final SyncopeClientException invalidCiperAlgorithm =
                     SyncopeClientException.build(ClientExceptionType.NotFound);
@@ -261,6 +239,15 @@ public class UserDataBinder extends Abst
 
         // set username
         user.setUsername(userTO.getUsername());
+
+        // security question / answer
+        if (userTO.getSecurityQuestion() != null) {
+            SecurityQuestion securityQuestion = securityQuestionDAO.find(userTO.getSecurityQuestion());
+            if (securityQuestion != null) {
+                user.setSecurityQuestion(securityQuestion);
+            }
+        }
+        user.setSecurityAnswer(userTO.getSecurityAnswer());
     }
 
     /**
@@ -304,6 +291,21 @@ public class UserDataBinder extends Abst
             }
         }
 
+        // security question / answer:
+        // userMod.getSecurityQuestion() is null => remove user security question and answer
+        // userMod.getSecurityQuestion() == 0 => don't change anything
+        // userMod.getSecurityQuestion() > 0 => update user security question and answer
+        if (userMod.getSecurityQuestion() == null) {
+            user.setSecurityQuestion(null);
+            user.setSecurityAnswer(null);
+        } else if (userMod.getSecurityQuestion() > 0) {
+            SecurityQuestion securityQuestion = securityQuestionDAO.find(userMod.getSecurityQuestion());
+            if (securityQuestion != null) {
+                user.setSecurityQuestion(securityQuestion);
+                user.setSecurityAnswer(userMod.getSecurityAnswer());
+            }
+        }
+
         // attributes, derived attributes, virtual attributes and resources
         propByRes.merge(fill(user, userMod, AttributableUtil.getInstance(AttributableType.USER), scce));
 
@@ -413,8 +415,11 @@ public class UserDataBinder extends Abst
 
         BeanUtils.copyProperties(user, userTO, IGNORE_USER_PROPERTIES);
 
-        connObjectUtil.retrieveVirAttrValues(user, AttributableUtil.getInstance(AttributableType.USER));
+        if (user.getSecurityQuestion() != null) {
+            userTO.setSecurityQuestion(user.getSecurityQuestion().getId());
+        }
 
+        connObjectUtil.retrieveVirAttrValues(user, AttributableUtil.getInstance(AttributableType.USER));
         fillTO(userTO, user.getAttrs(), user.getDerAttrs(), user.getVirAttrs(), user.getResources());
 
         MembershipTO membershipTO;
@@ -495,8 +500,8 @@ public class UserDataBinder extends Abst
                 ? fillVirtual(
                         membership,
                         membership.getVirAttrs() == null
-                        ? Collections.<String>emptySet()
-                        : getAttributeNames(membership.getVirAttrs()),
+                                ? Collections.<String>emptySet()
+                                : getAttributeNames(membership.getVirAttrs()),
                         vAttrsToBeUpdated,
                         AttributableUtil.getInstance(AttributableType.MEMBERSHIP))
                 : fillVirtual(

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/NotificationServiceImpl.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/NotificationServiceImpl.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/NotificationServiceImpl.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/NotificationServiceImpl.java Fri Sep 19 08:53:24 2014
@@ -38,10 +38,10 @@ public class NotificationServiceImpl ext
 
     @Override
     public Response create(final NotificationTO notificationTO) {
-        NotificationTO createdNotificationTO = controller.create(notificationTO);
-        URI location = uriInfo.getAbsolutePathBuilder().path(String.valueOf(createdNotificationTO.getId())).build();
+        NotificationTO created = controller.create(notificationTO);
+        URI location = uriInfo.getAbsolutePathBuilder().path(String.valueOf(created.getId())).build();
         return Response.created(location).
-                header(RESTHeaders.RESOURCE_ID, createdNotificationTO.getId()).
+                header(RESTHeaders.RESOURCE_ID, created.getId()).
                 build();
     }
 

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SchemaServiceImpl.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SchemaServiceImpl.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SchemaServiceImpl.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SchemaServiceImpl.java Fri Sep 19 08:53:24 2014
@@ -42,11 +42,11 @@ public class SchemaServiceImpl extends A
     public <T extends AbstractSchemaTO> Response create(final AttributableType attrType, final SchemaType schemaType,
             final T schemaTO) {
 
-        T response = controller.create(attrType, schemaType, schemaTO);
+        T created = controller.create(attrType, schemaType, schemaTO);
 
-        URI location = uriInfo.getAbsolutePathBuilder().path(response.getName()).build();
+        URI location = uriInfo.getAbsolutePathBuilder().path(created.getName()).build();
         return Response.created(location).
-                header(RESTHeaders.RESOURCE_ID, response.getName()).
+                header(RESTHeaders.RESOURCE_ID, created.getName()).
                 build();
     }
 

Added: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SecurityQuestionServiceImpl.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SecurityQuestionServiceImpl.java?rev=1626148&view=auto
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SecurityQuestionServiceImpl.java (added)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SecurityQuestionServiceImpl.java Fri Sep 19 08:53:24 2014
@@ -0,0 +1,73 @@
+/*
+ * 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.services;
+
+import java.net.URI;
+import java.util.List;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.services.SecurityQuestionService;
+import org.apache.syncope.common.to.SecurityQuestionTO;
+import org.apache.syncope.common.types.RESTHeaders;
+import org.apache.syncope.core.rest.controller.SecurityQuestionController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class SecurityQuestionServiceImpl extends AbstractServiceImpl implements SecurityQuestionService {
+
+    @Autowired
+    private SecurityQuestionController controller;
+
+    @Override
+    public List<SecurityQuestionTO> list() {
+        return controller.list();
+    }
+
+    @Override
+    public SecurityQuestionTO read(final Long securityQuestionId) {
+        return controller.read(securityQuestionId);
+    }
+
+    @Override
+    public Response create(final SecurityQuestionTO securityQuestionTO) {
+        SecurityQuestionTO created = controller.create(securityQuestionTO);
+
+        URI location = uriInfo.getAbsolutePathBuilder().path(String.valueOf(created.getId())).build();
+        return Response.created(location).
+                header(RESTHeaders.RESOURCE_ID, String.valueOf(created.getId())).
+                build();
+    }
+
+    @Override
+    public void update(final Long securityQuestionId, final SecurityQuestionTO securityQuestionTO) {
+        securityQuestionTO.setId(securityQuestionId);
+        controller.update(securityQuestionTO);
+    }
+
+    @Override
+    public void delete(final Long securityQuestionId) {
+        controller.delete(securityQuestionId);
+    }
+
+    @Override
+    public SecurityQuestionTO readByUser(final String username) {
+        return controller.read(username);
+    }
+
+}

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SecurityQuestionServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SecurityQuestionServiceImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/SecurityQuestionServiceImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/UserSelfServiceImpl.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/UserSelfServiceImpl.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/UserSelfServiceImpl.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/services/UserSelfServiceImpl.java Fri Sep 19 08:53:24 2014
@@ -40,6 +40,7 @@ public class UserSelfServiceImpl extends
     public Response getOptions() {
         return Response.ok().header(HttpHeaders.ALLOW, OPTIONS_ALLOW).
                 header(RESTHeaders.SELFREGISTRATION_ALLOWED, controller.isSelfRegistrationAllowed()).
+                header(RESTHeaders.PASSWORDRESET_ALLOWED, controller.isSelfRegistrationAllowed()).
                 build();
     }
 
@@ -47,7 +48,7 @@ public class UserSelfServiceImpl extends
     public Response create(final UserTO userTO, final boolean storePassword) {
         if (!controller.isSelfRegistrationAllowed()) {
             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unauthorized);
-            sce.getElements().add("SelfRegistration forbidden by configuration");
+            sce.getElements().add("Self registration forbidden by configuration");
             throw sce;
         }
 
@@ -73,4 +74,26 @@ public class UserSelfServiceImpl extends
         return modificationResponse(deleted);
     }
 
+    @Override
+    public void requestPasswordReset(final String username, final String securityAnswer) {
+        if (!controller.isPasswordResetAllowed()) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unauthorized);
+            sce.getElements().add("Password reset forbidden by configuration");
+            throw sce;
+        }
+
+        controller.requestPasswordReset(username, securityAnswer);
+    }
+
+    @Override
+    public void confirmPasswordReset(final String token, final String password) {
+        if (!controller.isPasswordResetAllowed()) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unauthorized);
+            sce.getElements().add("Password reset forbidden by configuration");
+            throw sce;
+        }
+
+        controller.confirmPasswordReset(token, password);
+    }
+
 }

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/Encryptor.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/Encryptor.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/Encryptor.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/Encryptor.java Fri Sep 19 08:53:24 2014
@@ -35,6 +35,8 @@ import org.apache.commons.lang3.ArrayUti
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.SyncopeConstants;
 import org.apache.syncope.common.types.CipherAlgorithm;
+import org.apache.syncope.core.persistence.dao.ConfDAO;
+import org.apache.syncope.core.persistence.dao.NotFoundException;
 import org.jasypt.commons.CommonUtils;
 import org.jasypt.digest.StandardStringDigester;
 import org.slf4j.Logger;
@@ -132,6 +134,22 @@ public final class Encryptor {
         }
     }
 
+    /**
+     * Get predefined password cipher algorithm from SyncopeConf.
+     *
+     * @return cipher algorithm.
+     */
+    public static CipherAlgorithm getPredefinedCipherAlgoritm() {
+        ConfDAO confDAO = ApplicationContextProvider.getApplicationContext().getBean(ConfDAO.class);
+        final String algorithm = confDAO.find(
+                "password.cipher.algorithm", CipherAlgorithm.AES.name()).getValues().get(0).getStringValue();
+        try {
+            return CipherAlgorithm.valueOf(algorithm);
+        } catch (IllegalArgumentException e) {
+            throw new NotFoundException("Cipher algorithm " + algorithm);
+        }
+    }
+
     public static Encryptor getInstance() {
         return getInstance(secretKey);
     }

Modified: syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/POJOHelper.java
URL: http://svn.apache.org/viewvc/syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/POJOHelper.java?rev=1626148&r1=1626147&r2=1626148&view=diff
==============================================================================
--- syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/POJOHelper.java (original)
+++ syncope/branches/1_2_X/core/src/main/java/org/apache/syncope/core/util/POJOHelper.java Fri Sep 19 08:53:24 2014
@@ -18,9 +18,11 @@
  */
 package org.apache.syncope.core.util;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.core.Version;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
 import org.identityconnectors.common.security.GuardedString;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.SyncToken;
@@ -46,6 +48,7 @@ public final class POJOHelper {
 
         MAPPER = new ObjectMapper();
         MAPPER.registerModule(pojoModule);
+        MAPPER.registerModule(new AfterburnerModule());
     }
 
     public static String serialize(final Object object) {