You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by gi...@apache.org on 2016/01/12 16:35:10 UTC
syncope git commit: [SYNCOPE-720] Password reset functionality
implemented
Repository: syncope
Updated Branches:
refs/heads/master 03d7de338 -> 4ed984ef6
[SYNCOPE-720] Password reset functionality implemented
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/4ed984ef
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/4ed984ef
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/4ed984ef
Branch: refs/heads/master
Commit: 4ed984ef6c7def62159e94b939ab3bfc6c83fe1d
Parents: 03d7de3
Author: giacomolm <gi...@hotmail.it>
Authored: Tue Jan 12 16:34:20 2016 +0100
Committer: giacomolm <gi...@hotmail.it>
Committed: Tue Jan 12 16:34:33 2016 +0100
----------------------------------------------------------------------
.../enduser/SyncopeEnduserApplication.java | 23 ++++-
.../resources/SecurityQuestionResource.java | 35 +++++--
.../resources/UserSelfPasswordReset.java | 93 ++++++++++++++++++
.../META-INF/resources/app/css/app.css | 20 ++++
.../resources/META-INF/resources/app/index.html | 6 +-
.../resources/META-INF/resources/app/js/app.js | 99 +++++++++++++++-----
.../app/js/controllers/LoginController.js | 3 +-
.../app/js/controllers/UserController.js | 60 +++++++++++-
.../resources/app/js/directives/captcha.js | 2 +
.../app/js/services/securityQuestionService.js | 12 ++-
.../app/js/services/userSelfService.js | 24 +++--
.../META-INF/resources/app/views/captcha.html | 2 +-
.../resources/app/views/passwordreset.html | 75 +++++++++++++++
13 files changed, 403 insertions(+), 51 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
index d1ab35c..9fe4cf7 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserApplication.java
@@ -36,6 +36,7 @@ import org.apache.syncope.client.enduser.resources.SchemaResource;
import org.apache.syncope.client.enduser.resources.SecurityQuestionResource;
import org.apache.syncope.client.enduser.resources.SyncopeResourceResource;
import org.apache.syncope.client.enduser.resources.UserSelfCreateResource;
+import org.apache.syncope.client.enduser.resources.UserSelfPasswordReset;
import org.apache.syncope.client.enduser.resources.UserSelfReadResource;
import org.apache.syncope.client.enduser.resources.UserSelfUpdateResource;
import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
@@ -173,6 +174,16 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali
}
});
+ mountResource("/api/self/requestPasswordReset", new ResourceReference("userSelfPasswordReset") {
+
+ private static final long serialVersionUID = -128426276529456602L;
+
+ @Override
+ public IResource getResource() {
+ return new UserSelfPasswordReset();
+ }
+ });
+
mountResource("/api/schemas", new ResourceReference("schemas") {
private static final long serialVersionUID = -128426276529456602L;
@@ -192,7 +203,7 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali
return new SyncopeResourceResource();
}
});
-
+
mountResource("/api/securityQuestions", new ResourceReference("securityQuestions") {
private static final long serialVersionUID = -128426276529456602L;
@@ -203,6 +214,16 @@ public class SyncopeEnduserApplication extends WebApplication implements Seriali
}
});
+ mountResource("/api/securityQuestions/byUser/${username}", new ResourceReference("securityQuestions") {
+
+ private static final long serialVersionUID = -128426276529456602L;
+
+ @Override
+ public IResource getResource() {
+ return new SecurityQuestionResource();
+ }
+ });
+
mountResource("/api/info", new ResourceReference("info") {
private static final long serialVersionUID = -128426276529456602L;
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java
index 3f6c0ea..7e79b1b 100644
--- a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/SecurityQuestionResource.java
@@ -26,8 +26,10 @@ import org.apache.syncope.client.enduser.SyncopeEnduserSession;
import org.apache.syncope.common.lib.to.SecurityQuestionTO;
import org.apache.syncope.common.rest.api.service.SecurityQuestionService;
import org.apache.syncope.core.misc.serialization.POJOHelper;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.AbstractResource;
import org.apache.wicket.request.resource.IResource;
+import org.apache.wicket.util.string.StringValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,15 +62,30 @@ public class SecurityQuestionResource extends AbstractBaseResource {
return response;
}
- final List<SecurityQuestionTO> securityQuestionTOs = securityQuestionService.list();
-
- response.setWriteCallback(new AbstractResource.WriteCallback() {
-
- @Override
- public void writeData(final IResource.Attributes attributes) throws IOException {
- attributes.getResponse().write(POJOHelper.serialize(securityQuestionTOs));
- }
- });
+ PageParameters parameters = attributes.getParameters();
+ StringValue username = parameters.get("username");
+ //if the username is defined then retrieve its security questions, otherwise retrieve all security questions
+ if (!username.isEmpty()) {
+ final SecurityQuestionTO securityQuestionTO = securityQuestionService.readByUser(username.toString());
+
+ response.setWriteCallback(new AbstractResource.WriteCallback() {
+
+ @Override
+ public void writeData(final IResource.Attributes attributes) throws IOException {
+ attributes.getResponse().write(POJOHelper.serialize(securityQuestionTO));
+ }
+ });
+ } else {
+ final List<SecurityQuestionTO> securityQuestionTOs = securityQuestionService.list();
+
+ response.setWriteCallback(new AbstractResource.WriteCallback() {
+
+ @Override
+ public void writeData(final IResource.Attributes attributes) throws IOException {
+ attributes.getResponse().write(POJOHelper.serialize(securityQuestionTOs));
+ }
+ });
+ }
response.setStatusCode(Response.Status.OK.getStatusCode());
} catch (Exception e) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfPasswordReset.java
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfPasswordReset.java b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfPasswordReset.java
new file mode 100644
index 0000000..5198ba7
--- /dev/null
+++ b/client/enduser/src/main/java/org/apache/syncope/client/enduser/resources/UserSelfPasswordReset.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.enduser.resources;
+
+import java.io.IOException;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.enduser.SyncopeEnduserSession;
+import org.apache.syncope.common.rest.api.service.UserSelfService;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.request.resource.IResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UserSelfPasswordReset extends AbstractBaseResource {
+
+ private static final long serialVersionUID = -2721621682300247583L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(UserSelfPasswordReset.class);
+
+ private final UserSelfService userSelfService;
+
+ public UserSelfPasswordReset() {
+ userSelfService = SyncopeEnduserSession.get().getService(UserSelfService.class);
+ }
+
+ @Override
+ protected ResourceResponse newResourceResponse(final IResource.Attributes attributes) {
+
+ AbstractResource.ResourceResponse response = new AbstractResource.ResourceResponse();
+
+ try {
+ HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest();
+ if (!xsrfCheck(request)) {
+ LOG.error("XSRF TOKEN does not match");
+ response.setError(Response.Status.BAD_REQUEST.getStatusCode(), "XSRF TOKEN does not match");
+ return response;
+ }
+ Map<String, String[]> parameters = request.getParameterMap();
+ if (parameters.get("username") == null || parameters.get("username").length == 0) {
+ throw new Exception("A valid username should be provided");
+ }
+ if (SyncopeEnduserSession.get().getSyncopeTO().isPwdResetRequiringSecurityQuestions()) {
+ if (parameters.get("securityanswer") == null || parameters.get("securityanswer").length == 0) {
+ throw new Exception("A correct security answer should be provided");
+ }
+ userSelfService.requestPasswordReset(parameters.get("username")[0],
+ parameters.get("securityanswer")[0]);
+ } else {
+ userSelfService.requestPasswordReset(parameters.get("username")[0], null);
+ }
+ final String responseMessage = new StringBuilder().append("Password reset request sent for user ").append(
+ parameters.get("username")[0]).toString();
+
+ response.setWriteCallback(new WriteCallback() {
+
+ @Override
+ public void writeData(final Attributes attributes) throws IOException {
+ attributes.getResponse().write(responseMessage);
+ }
+ });
+
+ response.setStatusCode(Response.Status.OK.getStatusCode());
+
+ } catch (final Exception e) {
+ LOG.error("Error while updating user", e);
+ response.setError(Response.Status.BAD_REQUEST.getStatusCode(), new StringBuilder()
+ .append("ErrorMessage{{ ")
+ .append(e.getMessage())
+ .append(" }}")
+ .toString());
+ }
+ return response;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/css/app.css
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/css/app.css b/client/enduser/src/main/resources/META-INF/resources/app/css/app.css
index a4ae15d..2f18d47 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/css/app.css
+++ b/client/enduser/src/main/resources/META-INF/resources/app/css/app.css
@@ -33,4 +33,24 @@ under the License.
.k-notification{
width : 320px;
+}
+
+.suggestions{
+ font-size: 10px;
+ display: inline-block;
+ margin-bottom: 5px;
+}
+
+#resetpassword{
+ background: -moz-linear-gradient(top, #a9db80 0%, #96c56f 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a9db80), color-stop(100%,#96c56f)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* Opera 11.10+ */
+ background: -ms-linear-gradient(top, #a9db80 0%,#96c56f 100%); /* IE10+ */
+ color: black;
+ margin-left: 5px;
+ //width: 15%;
+}
+#resetpassword:hover {
+ background: #658D5D;
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/index.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/index.html b/client/enduser/src/main/resources/META-INF/resources/app/index.html
index eb9b50a..f83defa 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/index.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/index.html
@@ -40,11 +40,11 @@ under the License.
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->
+ <span id="notifications" kendo-notification="notifications"></span>
+
<!--<div ng-view ng-cloak ng-controller="ApplicationController"></div>-->
<div ui-view ng-cloak ng-controller="ApplicationController" ng-init="initApplication()">
- </div>
-
- <span id="notification" kendo-notification="notification"></span>
+ </div>
<!-- <footer id="footer" class="hidden-print">
<ul class="nav pull-right">
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
index 4d791dc..113fc86 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
@@ -173,6 +173,10 @@ app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
return AuthenticationHelper.authenticated();
}
}
+ })
+ .state('passwordreset', {
+ url: '/passwordreset',
+ templateUrl: 'views/passwordreset.html'
});
// catch all other routes
@@ -187,14 +191,18 @@ app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
$httpProvider.interceptors.push(function ($q, $rootScope, $location) {
var numLoadings = 0;
return {
-// 'request': function (config) {
-// numLoadings++;
-// // Show loader
-// if (config.url.indexOf("skipLoader=true") == -1) {
-// $rootScope.$broadcast("loader_show");
-// }
-// return config || $q.when(config);
-// },
+ 'request': function (config, a, b) {
+ //if the url is an html, we're changing page
+ if (config.url.indexOf('.html', config.url.length - 5) == -1) {
+ $rootScope.$broadcast("xhrStarted");
+ }
+ /*numLoadings++;
+ // Show loader
+ if (config.url.indexOf("skipLoader=true") == -1) {
+ $rootScope.$broadcast("loader_show");
+ }*/
+ return config || $q.when(config);
+ },
// 'response': function (response) {
// if ((--numLoadings) === 0) {
// // Hide loader
@@ -274,12 +282,14 @@ app.controller('ApplicationController', ['$scope', '$rootScope', 'InfoService',
$rootScope.selfRegAllowed = false;
$rootScope.pwdResetAllowed = false;
$rootScope.version = "";
+ $rootScope.pwdResetRequiringSecurityQuestions = false;
//info settings are initialized every time an user open the login page
InfoService.getInfo().then(
function (response) {
$rootScope.pwdResetAllowed = response.pwdResetAllowed;
$rootScope.selfRegAllowed = response.selfRegAllowed;
$rootScope.version = response.version;
+ $rootScope.pwdResetRequiringSecurityQuestions = response.pwdResetRequiringSecurityQuestions;
},
function (response) {
console.log("Something went wrong while accessing info resource", response);
@@ -295,30 +305,71 @@ app.controller('ApplicationController', ['$scope', '$rootScope', 'InfoService',
return $rootScope.version;
};
- //Intercepting location change event
- $rootScope.$on("$locationChangeStart", function (event, next, current) {
- //When a location changes, old notifications should be removed
+ //Notification management
+ $scope.notification = $('#notifications').kendoNotification().data("kendoNotification");
+ $scope.notification.setOptions({stacking: "down"});
+ $scope.notification.options.position["top"] = 20;
+ $scope.showSuccess = function (message, component) {
+ if (!$scope.notificationExists(message)) {
+ component.options.autoHideAfter = 3000;
+ component.show(message, "success");
+ }
+ }
+ $scope.showError = function (message, component) {
+ if (!$scope.notificationExists(message)) {
+ component.options.autoHideAfter = 0;
+ component.show(message, "error");
+ }
+ }
+ $scope.notificationExists = function (message) {
+ var result = false;
if ($scope.notification != null) {
- var pendingNotifications = $scope.notification.getNotifications();
- setTimeout(function () {
+ var pendingNotifications = $scope.notification.getNotifications();
+ pendingNotifications.each(function (idx, element) {
+ var popup = $(element).data("kendoPopup");
+ if (!popup.hide && popup.wrapper.html().indexOf(message) > -1) {
+ result = true;
+ return false; //breaking the each and storing the real result
+ }
+ });
+ }
+ return result;
+ }
+ $scope.hideNotifications = function (timer) {
+ if ($scope.notification != null) {
+ var pendingNotifications = $scope.notification.getNotifications();
+ if (timer && timer > 0) {
+ setTimeout(function () {
+ pendingNotifications.each(function (idx, element) {
+ var popup = $(element).data("kendoPopup");
+ if (popup) {
+ popup.hide = true;
+ popup.close();
+ }
+ });
+ }, timer);
+ }
+ else {
pendingNotifications.each(function (idx, element) {
var popup = $(element).data("kendoPopup");
if (popup) {
- popup.close();
+ popup.hide = true;
+ //we should destroy the message immediately
+ popup.destroy();
}
});
- }, 3000);
+ }
}
- });
-
- $scope.showSuccess = function (message, component) {
- component.options.autoHideAfter = 3000;
- component.show(message, "success");
- }
- $scope.showError = function (message, component) {
- component.options.autoHideAfter = 0;
- component.show(message, "error");
}
+ //Intercepting location change event
+ $rootScope.$on("$locationChangeStart", function (event, next, current) {
+ //When a location changes, old notifications should be removed
+ $scope.hideNotifications(3000)
+ });
+ //Intercepting xhr start event
+ $scope.$on('xhrStarted', function (event, next, current) {
+ $scope.hideNotifications(0);
+ });
}
}]);
app.factory('AuthenticationHelper', ['$q', '$rootScope',
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
index 40794a3..c1c563c 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
@@ -66,8 +66,7 @@ angular.module("login").controller("LoginController", ['$scope', '$rootScope', '
};
$scope.passwordReset = function () {
- // TODO
- console.log("NOT YET IMPLEMENTED")
+ $location.path("/passwordreset");
};
$scope.errorAPI = function () {
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
index 89eccae..7521553 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
@@ -226,7 +226,7 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
if ($scope.createMode) {
UserSelfService.create(user).then(function (response) {
- console.log("Created user: ", response);
+ console.log("Created user: ", response);
$scope.showSuccess("User " + $scope.user.username + " successfully created", $scope.notification);
$location.path('/self');
}, function (response) {
@@ -273,5 +273,63 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
$scope.showError("Error: " + (errorMessage || response), $scope.notification);
return;
});
+ },
+ $scope.retrieveSecurityQuestion = function (user) {
+ if ($rootScope.pwdResetRequiringSecurityQuestions){
+ if(user && user.username && user.username.length) {
+ return SecurityQuestionService.
+ getSecurityQuestionByUser(user.username).then(function (data) {
+ $scope.userSecurityQuestion = data.content;
+ }, function (response) {
+ var errorMessage;
+ // parse error response
+ if (response !== undefined) {
+ errorMessage = response.split("ErrorMessage{{")[1];
+ errorMessage = errorMessage.split("}}")[0];
+ $scope.userSecurityQuestion = "";
+ }
+ $scope.showError("Error retrieving user security question: " + errorMessage, $scope.notification);
+ });
+ }
+ else{
+ $scope.userSecurityQuestion = "";
+ }
+ }
+ },
+ $scope.resetPassword = function (user) {
+ if (user && user.username) {
+ $scope.retrieveSecurityQuestion(user);
+ CaptchaService.validate($scope.captchaInput).then(function (response) {
+ if (!(response === 'true')) {
+ $scope.showError("Captcha inserted is not valid, please digit the correct captcha", $scope.notification);
+ return;
+ }
+ UserSelfService.passwordReset(user).then(function (data) {
+ $scope.showSuccess(data, $scope.notification);
+ $location.path('/self');
+ }, function (response) {
+ var errorMessage;
+ // parse error response
+ if (response !== undefined) {
+ errorMessage = response.split("ErrorMessage{{")[1];
+ errorMessage = errorMessage.split("}}")[0];
+ $scope.showError("An error occured during password reset: " + errorMessage, $scope.notification);
+ //we need to refresh captcha after a valid request
+ $scope.$broadcast("refreshCaptcha");
+ }
+ });
+ }, function (response) {
+ var errorMessage;
+ // parse error response
+ if (response !== undefined) {
+ errorMessage = response.split("ErrorMessage{{")[1];
+ errorMessage = errorMessage.split("}}")[0];
+ }
+ $scope.showError("Error: " + (errorMessage || response), $scope.notification);
+ return;
+ });
+ } else {
+ $scope.showError("You should use a valid and non-empty username", $scope.notification);
+ }
};
}]);
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js
index c00a4f2..00720fa 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js
@@ -37,6 +37,8 @@ angular.module('self')
// initialize captcha
$scope.refreshCaptcha();
+
+ $scope.$on("refreshCaptcha", function(){$scope.refreshCaptcha()});
}
};
});
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
index ff91f18..417468c 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/securityQuestionService.js
@@ -28,11 +28,17 @@ angular.module('self')
securityQuestionService.getAvailableSecurityQuestions = function () {
return $http.get("/syncope-enduser/api/securityQuestions")
.then(function (response) {
- console.log("security questions response: ", response);
return response.data;
}, function (response) {
- console.log("Something went wrong during security questions retrieval, exit with status: ",
- response);
+ return $q.reject(response.data || response.statusText);
+ });
+ };
+
+ securityQuestionService.getSecurityQuestionByUser = function (username) {
+ return $http.get("/syncope-enduser/api/securityQuestions/byUser/"+username)
+ .then(function (response) {
+ return response.data;
+ }, function (response) {
return $q.reject(response.data || response.statusText);
});
};
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
index 2f713a7..fc60c10 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/userSelfService.js
@@ -18,13 +18,11 @@
*/
'use strict';
-
angular.module('login')
.factory('UserSelfService', ['$resource', '$q', '$http',
function ($resource, $q, $http) {
var userSelfService = {};
-
userSelfService.read = function () {
return $http
.get('/syncope-enduser/api/self/read')
@@ -36,7 +34,6 @@ angular.module('login')
return $q.reject(response.data || response.statusText);
});
};
-
userSelfService.create = function (user) {
return $http
.post('/syncope-enduser/api/self/create', user)
@@ -48,7 +45,6 @@ angular.module('login')
return $q.reject(response.data || response.statusText);
});
};
-
userSelfService.update = function (user) {
return $http
.post('/syncope-enduser/api/self/update', user)
@@ -59,10 +55,24 @@ angular.module('login')
return $q.reject(response.data || response.statusText);
});
};
-
- userSelfService.passwordReset = function () {
+ userSelfService.passwordReset = function (user) {
+ return $http
+ .post('/syncope-enduser/api/self/requestPasswordReset', user,
+ {
+ headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'},
+ transformRequest: function (obj) {
+ var str = [];
+ for (var p in obj)
+ str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
+ return str.join("&");
+ }
+ })
+ .then(function (response) {
+ return response.data || response.statusText;
+ }, function (response) {
+ return $q.reject(response.data || response.statusText);
+ });
};
-
return userSelfService;
}]);
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html b/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html
index 06582dc..c40e8dc 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/captcha.html
@@ -2,7 +2,7 @@
<nav class="navbar">
<div class="container-fluid">
<div class="navbar-header">
- <img alt="captcha" ng-src="{{captchaUrl}}'"/>
+ <img id="captchaImg" alt="captcha" ng-src="{{captchaUrl}}'"/>
<div style="margin-top: 5%">
<button id="refresh" type="button" class="btn btn-default btn-xs glyphicon glyphicon-refresh"
ng-click="refreshCaptcha()" title="Refresh Captcha"></button>
http://git-wip-us.apache.org/repos/asf/syncope/blob/4ed984ef/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html b/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html
new file mode 100644
index 0000000..f4fdc57
--- /dev/null
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+<div ng-cloak class="container">
+ <div ng-controller="UserController" style="box-sizing: border-box; ">
+
+ <div id="form-container" class="col-md-6 col-md-offset-3" style="box-sizing: border-box; background-color: #F7F7F7;">
+
+ <div>
+ <div class="page-header" style="text-align: left; font-weight: 700;">
+ <span>Password reset</span>
+ </div>
+ <div class="breadcrumb-header text-center">
+
+ <div class="row">
+ <div id="status-buttons" class="btn-group btn-breadcrumb">
+ <a href="#/self" class="btn btn-default"><i class="glyphicon glyphicon-home"></i></a>
+ <!--add class breadcrumb-disabled-link to buttons to prevent click-->
+ <a ui-sref-active="active" class="btn btn-default">User Details</a>
+ </div>
+ </div>
+ </div>
+ <form class="signup-form" name="passwordResetForm" ng-submit="resetPassword(user)" novalidate>
+
+ <div id="form-views" ui-view>
+ <div id="attribute" class="form-group">
+ <label for="user.username">User</label>
+ <input name="username" type="text" class="form-control" ng-model="user.username" required
+ placeholder="Username" ng-blur="retrieveSecurityQuestion(user)">
+ <p ng-show="(userForm.username.$error.required && !userForm.username.$pristine)"
+ class="text-validation-error">Username is required</p>
+ </div>
+ <div id="attribute" class="form-group" ng-show="$root.pwdResetRequiringSecurityQuestions">
+ <label for="user.securityquestion">Security Question</label>
+ <div class="suggestions">(Not Loading? <a href ng-click="retrieveSecurityQuestion(user)">Reload</a>)</div>
+ <input name="securityquestion" type="text" class="form-control" ng-model="userSecurityQuestion"
+ disabled="disabled">
+ </div>
+ <div id="attribute" class="form-group" ng-show="$root.pwdResetRequiringSecurityQuestions">
+ <label for="user.securityanswer">Security Answer</label>
+ <input name="securityanswer" type="text" class="form-control" ng-model="user.securityanswer"
+ placeholder="Security Answer" >
+ </div>
+ <div id="attribute" class="form-group row">
+ <!--captcha-->
+ <div class="form-group row">
+ <captcha input="captchaInput"></captcha>
+ </div>
+ <button id="resetpassword" type="submit" class="btn btn-default pull-right">Submit</button>
+ <div class="pull-left">
+ <a id="cancel" href="#/self" class="btn btn-danger">Cancel</a>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+</div>