added URL parameters to EditProfile to allow for passing a password reset secret, default user name and default e-mail address

This commit is contained in:
Axel Uhl committed 2014-11-05 16:17:11 +01:00
1 parent 405464197b
commit 1ef688dc13
20 files changed
+239 -103

No files matched your search

@@ -8,6 +8,9 @@ import com.sap.sse.gwt.client.AbstractEntryPointLinkFactory;
public class EntryPointLinkFactory extends AbstractEntryPointLinkFactory {
private static final String PARAM_LOCALE = "locale";
private static final String PARAM_GWT_CODESVR = "gwt.codesvr";
public static String createRegistrationLink(Map<String, String> parameters) {
return createEntryPointLink("/security/ui/Register.html", parameters);
}
@@ -23,12 +26,38 @@ public class EntryPointLinkFactory extends AbstractEntryPointLinkFactory {
public static String createUserManagementLink(Map<String, String> parameters) {
return createEntryPointLink("/security/ui/UserManagement.html", parameters);
}
private static void addGwtUrlParameters(final Map<String, String> parameters) {
final String debugParam = Window.Location.getParameter(PARAM_GWT_CODESVR);
if (debugParam != null) {
parameters.put(PARAM_GWT_CODESVR, debugParam);
}
final String localeParam = Window.Location.getParameter(PARAM_LOCALE);
if (localeParam != null) {
parameters.put(PARAM_LOCALE, localeParam);
}
}
/**
* Produces an absolute base URL for the validation
*
* @param parameters must be a writable map because debug and locale parameters may be added to the map
*/
public static String createEmailValidationLink(Map<String, String> parameters) {
UrlBuilder builder = Window.Location.createUrlBuilder().setPath("/security/ui/EmailValidation.html");
addGwtUrlParameters(parameters);
for (Map.Entry<String, String> param : parameters.entrySet()) {
builder.setParameter(param.getKey(), param.getValue());
}
return builder.buildString();
}
/**
* @param parameters must be a writable map because debug and locale parameters may be added to the map
*/
public static String createPasswordResetLink(Map<String, String> parameters) {
UrlBuilder builder = Window.Location.createUrlBuilder().setPath("/security/ui/EditProfile.html");
addGwtUrlParameters(parameters);
for (Map.Entry<String, String> param : parameters.entrySet()) {
builder.setParameter(param.getKey(), param.getValue());
}
@@ -1,6 +1,6 @@
package com.sap.sse.security.ui.client.component;
import java.util.Collections;
import java.util.HashMap;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -26,8 +26,7 @@ public class CreateUserDialog extends AbstractUserDialog {
userManagementService
.createSimpleUser(usernameEmailPassword.getUsername(),
usernameEmailPassword.getEmail(), usernameEmailPassword.getPassword(),
EntryPointLinkFactory.createEmailValidationLink(Collections
.<String, String> emptyMap()), new AsyncCallback<UserDTO>() {
EntryPointLinkFactory.createEmailValidationLink(new HashMap<String, String>()), new AsyncCallback<UserDTO>() {
@Override
public void onSuccess(UserDTO result) {
for (UserCreatedEventHandler handler : handlers) {
@@ -1,6 +1,6 @@
package com.sap.sse.security.ui.client.component;
import java.util.Collections;
import java.util.HashMap;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -31,7 +31,7 @@ public class EditEmailDialogWithDefaultCallback extends EditEmailDialog {
@Override
public void ok(final UserData userData) {
userManagementService.updateSimpleUserEmail(userData.getUsername(), userData.getEmail(),
EntryPointLinkFactory.createEmailValidationLink(Collections.<String, String>emptyMap()),
EntryPointLinkFactory.createEmailValidationLink(new HashMap<String, String>()),
new MarkedAsyncCallback<Void>(
new AsyncCallback<Void>() {
@Override
@@ -11,7 +11,7 @@ public class ForgotPasswordDialog extends AbstractUserDialog {
public ForgotPasswordDialog(StringMessages stringMessages, UserManagementServiceAsync userManagementService, UserDTO user,
com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback<UserData> callback) {
super(stringMessages, stringMessages.forgotPassword(), stringMessages.enterUsernameOrEmail(),
userManagementService, user, callback);
userManagementService, user, /* validator */ null, callback);
}
@Override
@@ -157,7 +157,8 @@ public class UserDetailsView extends FlowPanel {
new ChangePasswordDialog(stringMessages, userManagementService, UserDetailsView.this.user, new DataEntryDialog.DialogCallback<UserData>() {
@Override
public void ok(UserData userData) {
userManagementService.updateSimpleUserPassword(UserDetailsView.this.user.getName(), /* admin doesn't need to provide old password */ null, userData.getPassword(), new MarkedAsyncCallback<Void>(
userManagementService.updateSimpleUserPassword(UserDetailsView.this.user.getName(), /* admin doesn't need to provide old password */ null,
/* resetPasswordSecret */ null, userData.getPassword(), new MarkedAsyncCallback<Void>(
new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
@@ -186,30 +187,6 @@ public class UserDetailsView extends FlowPanel {
}).show();
}
});
// only offer password reset if the user's e-mail address has successfully been validated
if (UserDetailsView.this.user.isEmailValidated()) {
final Button resetPasswordButton = new Button(stringMessages.forgotPassword());
accountPanelContent.add(resetPasswordButton);
resetPasswordButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
userManagementService.resetPassword(UserDetailsView.this.user.getName(),
new MarkedAsyncCallback<Void>(new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
Window.alert(stringMessages.errorResettingPassword(
UserDetailsView.this.user.getName(), caught.getMessage()));
}
@Override
public void onSuccess(Void result) {
Window.alert(stringMessages
.successfullyResetPassword(UserDetailsView.this.user.getName()));
}
}));
}
});
}
} else if (a instanceof SocialUserDTO) {
SocialUserDTO sua = (SocialUserDTO) a;
FlexTable table = new FlexTable();
@@ -61,7 +61,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages {
String forgotPassword();
String errorDuringPasswordReset(String message);
String cannotResetPasswordWithoutValidatedEmail(String username);
String newPasswordSent(String username);
String passwordResetLinkSent(String username);
String errorValidatingEmail(String username, String message);
String emailValidatedSuccessfully(String username);
String errorResettingPassword(String username, String message);
@@ -54,7 +54,7 @@ successfullyUpdatedEmail=Successfully updated e-mail address for user {0}.\nVali
forgotPassword=Forgot password
errorDuringPasswordReset=Error during password reset: {0}
cannotResetPasswordWithoutValidatedEmail=Cannot reset password because user {0} does not have a validated e-mail address
newPasswordSent=A new password has been sent to {0}''s validated e-mail address
passwordResetLinkSent=A link for resetting the password has been sent to {0}''s validated e-mail address
errorValidatingEmail=Error validating e-mail address of user {0}: {1}
emailValidatedSuccessfully=e-mail address of user {0} validated successfully
errorResettingPassword=Error resetting password for user {0}: {1}
@@ -66,4 +66,4 @@ signInWith=Sign in with...
generalWelcome=Welcome!
newUser=New here?
pleaseSignIn=Please sign in.
enterUsernameOrEmail=Enter user name or e-mail address
enterUsernameOrEmail=Enter user name or e-mail address
@@ -54,7 +54,7 @@ successfullyUpdatedEmail=e-Mail-Adresse f�r Benutzer {0} erfolgreich aktualisi
forgotPassword=Passwort vergessen
errorDuringPasswordReset=Fehler beim Zurücksetzen des Passworts: {0}
cannotResetPasswordWithoutValidatedEmail=Passwort für Benutzer {0} kann nicht zurückgesetzt werden, da keine validierte e-Mail-Adresse vorliegt
newPasswordSent=Ein neues Passwort ist an die validierte e-Mail-Adresse des Benutzers {0} gesendet worden
passwordResetLinkSent=Ein Link zum Setzen eines neuen Passwortes ist an die validierte e-Mail-Adresse des Benutzers {0} gesendet worden
errorValidatingEmail=Fehler beim Validieren der e-Mail-Adresse für Benutzer {0}: {1}
emailValidatedSuccessfully=e-Mail-Adresse für Benutzer {0} erfolgreich validiert
errorResettingPassword=Fehler beim Zurücksetzen des Passworts für Benutzer {0}: {1}
@@ -46,6 +46,9 @@ public class EditProfileEntryPoint implements EntryPoint {
RemoteServiceMappingConstants.userManagementServiceRemotePath);
final UserService userService = new UserService(userManagementService);
final NewAccountValidator validator = new NewAccountValidator(stringMessages);
final String usernameFromURL = Window.Location.getParameter("u");
final String emailFromURL = Window.Location.getParameter("e");
final String passwordResetSecret = Window.Location.getParameter("s");
RootLayoutPanel rootPanel = RootLayoutPanel.get();
DockLayoutPanel dockPanel = new DockLayoutPanel(Unit.PX);
rootPanel.add(dockPanel);
@@ -58,7 +61,9 @@ public class EditProfileEntryPoint implements EntryPoint {
nameText.setEnabled(false);
fp.add(nameText);
nameText.setEnabled(false);
fp.add(nameText);
if (usernameFromURL != null) {
nameText.setText(usernameFromURL);
}
HorizontalPanel rolesPanel = new HorizontalPanel();
rolesPanel.add(new Label(stringMessages.roles()));
final Label rolesLabel = new Label();
@@ -69,14 +74,22 @@ public class EditProfileEntryPoint implements EntryPoint {
HorizontalPanel emailTextBoxAndButtonPanel = new HorizontalPanel();
final TextBox emailText = new TextBox();
emailText.setEnabled(false);
if (emailFromURL != null) {
emailText.setText(emailFromURL);
}
emailTextBoxAndButtonPanel.add(emailText);
final Button updateEmailButton = new Button(stringMessages.editEmail());
emailTextBoxAndButtonPanel.add(updateEmailButton);
fp.add(emailTextBoxAndButtonPanel);
Label currentPasswordLabel = new Label(stringMessages.currentPassword());
fp.add(currentPasswordLabel);
final TextBox currentPasswordText = new PasswordTextBox();
fp.add(currentPasswordText);
final TextBox currentPasswordText;
if (passwordResetSecret == null) {
Label currentPasswordLabel = new Label(stringMessages.currentPassword());
fp.add(currentPasswordLabel);
currentPasswordText = new PasswordTextBox();
fp.add(currentPasswordText);
} else {
currentPasswordText = null;
}
updateEmailButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
@@ -135,7 +148,9 @@ public class EditProfileEntryPoint implements EntryPoint {
formPanel.addSubmitHandler(new SubmitHandler() {
@Override
public void onSubmit(SubmitEvent event) {
userManagementService.updateSimpleUserPassword(nameText.getText(), currentPasswordText.getText(), pwText.getText(), new AsyncCallback<Void>() {
userManagementService.updateSimpleUserPassword(nameText.getText(),
currentPasswordText==null?null:currentPasswordText.getText(),
passwordResetSecret, pwText.getText(), new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
GWT.log(caught.getMessage());
@@ -1,6 +1,7 @@
package com.sap.sse.security.ui.login;
import java.util.Collections;
import java.util.HashMap;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -16,9 +17,12 @@ import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.ui.client.EntryPointLinkFactory;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.client.component.AbstractUserDialog.UserData;
import com.sap.sse.security.ui.client.component.ForgotPasswordDialog;
import com.sap.sse.security.ui.client.i18n.StringMessages;
import com.sap.sse.security.ui.client.shared.oauthlogin.OAuthLogin;
import com.sap.sse.security.ui.shared.SuccessInfo;
@@ -84,24 +88,44 @@ public class LoginView extends Composite {
@UiHandler("forgotPasswordAnchor")
void forgotPasswordClicked(ClickEvent e) {
userManagementService.resetPassword(userNameTextBox.getText(), new MarkedAsyncCallback<Void>(new AsyncCallback<Void>() {
new ForgotPasswordDialog(StringMessages.INSTANCE, userManagementService, userService.getCurrentUser(), new DialogCallback<UserData>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof UserManagementException) {
if (UserManagementException.CANNOT_RESET_PASSWORD_WITHOUT_VALIDATED_EMAIL.equals(caught.getMessage())) {
Window.alert(StringMessages.INSTANCE.cannotResetPasswordWithoutValidatedEmail(userNameTextBox.getText()));
} else {
Window.alert(StringMessages.INSTANCE.errorDuringPasswordReset(caught.getMessage()));
public void ok(final UserData userData) {
userManagementService.resetPassword(userData.getUsername(), userData.getEmail(),
EntryPointLinkFactory.createPasswordResetLink(new HashMap<String, String>()),
new MarkedAsyncCallback<Void>(new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable caught) {
if (caught instanceof UserManagementException) {
if (UserManagementException.CANNOT_RESET_PASSWORD_WITHOUT_VALIDATED_EMAIL.equals(caught.getMessage())) {
Window.alert(StringMessages.INSTANCE.cannotResetPasswordWithoutValidatedEmail(userNameTextBox.getText()));
} else {
Window.alert(StringMessages.INSTANCE.errorDuringPasswordReset(caught.getMessage()));
}
} else {
Window.alert(StringMessages.INSTANCE.errorDuringPasswordReset(caught.getMessage()));
}
}
} else {
Window.alert(StringMessages.INSTANCE.errorDuringPasswordReset(caught.getMessage()));
}
@Override
public void onSuccess(Void result) {
final StringBuilder nameOrEmail = new StringBuilder();
if (userData.getUsername() != null && !userData.getUsername().isEmpty()) {
nameOrEmail.append(userData.getUsername());
}
if (userData.getEmail() != null && !userData.getEmail().isEmpty()) {
if (nameOrEmail.length() > 0) {
nameOrEmail.append(" / ");
}
nameOrEmail.append(userData.getEmail());
}
Window.alert(StringMessages.INSTANCE.passwordResetLinkSent(nameOrEmail.toString()));
}
}));
}
@Override
public void onSuccess(Void result) {
Window.alert(StringMessages.INSTANCE.newPasswordSent(userNameTextBox.getText()));
}
}));
@Override public void cancel() {}
}).show();
}
}
@@ -1,6 +1,6 @@
package com.sap.sse.security.ui.loginpanel;
import java.util.Collections;
import java.util.HashMap;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
@@ -74,7 +74,7 @@ public class LoginPanel extends HorizontalPanel implements UserStatusEventHandle
@Override
public void ok(final UserData userData) {
userManagementService.createSimpleUser(userData.getUsername(), userData.getEmail(), userData.getPassword(),
EntryPointLinkFactory.createEmailValidationLink(Collections.<String, String> emptyMap()),
EntryPointLinkFactory.createEmailValidationLink(new HashMap<String, String>()),
new MarkedAsyncCallback<UserDTO>(new AsyncCallback<UserDTO>() {
@Override
public void onFailure(Throwable caught) {
@@ -1,6 +1,6 @@
package com.sap.sse.security.ui.registration;
import java.util.Collections;
import java.util.HashMap;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
@@ -86,7 +86,7 @@ public class RegisterEntryPoint implements EntryPoint {
@Override
public void onSubmit(SubmitEvent event) {
userManagementService.createSimpleUser(nameText.getText(), emailText.getText(), pwText.getText(),
EntryPointLinkFactory.createEmailValidationLink(Collections.<String, String>emptyMap()),
EntryPointLinkFactory.createEmailValidationLink(new HashMap<String, String>()),
new AsyncCallback<UserDTO>() {
@Override
public void onFailure(Throwable caught) {
@@ -141,11 +141,12 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
@Override
public void updateSimpleUserPassword(final String username, String oldPassword, String newPassword) throws UserManagementException {
public void updateSimpleUserPassword(final String username, String oldPassword, String passwordResetSecret, String newPassword) throws UserManagementException {
final Subject subject = SecurityUtils.getSubject();
if (!subject.hasRole(DefaultRoles.ADMIN.getRolename())) {
// validate old password before proceeding
if (!getSecurityService().checkPassword(username, oldPassword)) {
// validate old password or password reset secret before proceeding
if ((oldPassword == null || !getSecurityService().checkPassword(username, oldPassword)) &&
(passwordResetSecret == null || !getSecurityService().checkPasswordResetSecret(username, passwordResetSecret))) {
throw new UserManagementException(UserManagementException.INVALID_CREDENTIALS);
}
}
@@ -176,8 +177,11 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
}
@Override
public void resetPassword(String username) throws UserManagementException {
getSecurityService().resetPassword(username);
public void resetPassword(String username, String email, String baseURL) throws UserManagementException, MailException {
if (username == null || username.isEmpty()) {
username = getSecurityService().getUserByEmail(email).getName();
}
getSecurityService().resetPassword(username, baseURL);
}
@Override
@@ -21,11 +21,15 @@ public interface UserManagementService extends RemoteService {
UserDTO createSimpleUser(String name, String email, String password, String validationBaseURL) throws UserManagementException, MailException;
void updateSimpleUserPassword(String name, String oldPassword, String newPassword) throws UserManagementException, MailException;
/**
* Either <code>oldPassword</code> or <code>passwordResetSecret</code> need to be provided, or the current user needs to have
* the {@link DefaultRoles#ADMIN} role to be able to set the new password.
*/
void updateSimpleUserPassword(String name, String oldPassword, String passwordResetSecret, String newPassword) throws UserManagementException;
void updateSimpleUserEmail(String username, String newEmail, String validationBaseURL) throws UserManagementException, MailException;
void resetPassword(String username) throws UserManagementException;
void resetPassword(String username, String eMailAddress, String baseURL) throws UserManagementException, MailException;
boolean validateEmail(String username, String validationSecret) throws UserManagementException;
@@ -17,9 +17,9 @@ public interface UserManagementServiceAsync {
void createSimpleUser(String name, String email, String password, String validationBaseURL, AsyncCallback<UserDTO> callback);
void updateSimpleUserPassword(String name, String oldPassword, String newPassword, AsyncCallback<Void> callback);
void updateSimpleUserPassword(String name, String oldPassword, String passwordResetSecret, String newPassword, AsyncCallback<Void> callback);
void resetPassword(String username, AsyncCallback<Void> callback);
void resetPassword(String username, String eMailAddress, String baseURL, AsyncCallback<Void> callback);
void validateEmail(String username, String validationSecret, AsyncCallback<Boolean> markedAsyncCallback);
@@ -2,6 +2,7 @@ package com.sap.sse.security.userstore.mongodb;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -20,6 +21,8 @@ public class UserStoreImpl implements UserStore {
private String name = "MongoDB user store";
private final ConcurrentHashMap<String, User> users;
private final ConcurrentHashMap<String, Set<User>> usersByEmail;
private final ConcurrentHashMap<User, String> emailForUser;
private final ConcurrentHashMap<String, Object> settings;
private final ConcurrentHashMap<String, Class<?>> settingTypes;
private final ConcurrentHashMap<String, Map<String, String>> preferences;
@@ -28,6 +31,8 @@ public class UserStoreImpl implements UserStore {
public UserStoreImpl() {
users = new ConcurrentHashMap<>();
usersByEmail = new ConcurrentHashMap<>();
emailForUser = new ConcurrentHashMap<>();
settings = new ConcurrentHashMap<>();
settingTypes = new ConcurrentHashMap<String, Class<?>>();
preferences = new ConcurrentHashMap<>();
@@ -50,9 +55,32 @@ public class UserStoreImpl implements UserStore {
}
for (User u : domainObjectFactory.loadAllUsers()) {
users.put(u.getName(), u);
addToUsersByEmail(u);
}
}
private void addToUsersByEmail(User u) {
if (u.getEmail() != null && !u.getEmail().isEmpty()) {
Set<User> set = usersByEmail.get(u.getEmail());
if (set == null) {
set = new HashSet<>();
usersByEmail.put(u.getEmail(), set);
}
set.add(u);
emailForUser.put(u, u.getEmail());
}
}
private void removeFromUsersByEmail(User u) {
if (u != null) {
Set<User> set = usersByEmail.get(emailForUser.get(u)); // this also works if the user's e-mail has changed meanwhile
if (set != null) {
set.remove(u);
}
emailForUser.remove(u);
}
}
private boolean initSocialSettingsIfEmpty() {
boolean changed = false;
for (SocialSettingsKeys ssk : SocialSettingsKeys.values()) {
@@ -79,12 +107,15 @@ public class UserStoreImpl implements UserStore {
logger.info("Creating user: " + user);
mongoObjectFactory.storeUser(user);
users.put(name, user);
addToUsersByEmail(user);
return user;
}
@Override
public void updateUser(User user) {
logger.info("Updating user "+user+" in DB");
removeFromUsersByEmail(user);
addToUsersByEmail(user);
mongoObjectFactory.storeUser(user);
}
@@ -101,6 +132,22 @@ public class UserStoreImpl implements UserStore {
return users.get(name);
}
@Override
public User getUserByEmail(String email) {
final User result;
if (email == null) {
result = null;
} else {
Set<User> set = usersByEmail.get(email);
if (set.isEmpty()) {
result = null;
} else {
result = set.iterator().next();
}
}
return result;
}
@Override
public Set<String> getRolesFromUser(String username) throws UserManagementException {
if (users.get(username) == null) {
@@ -135,7 +182,7 @@ public class UserStoreImpl implements UserStore {
}
logger.info("Deleting user: " + users.get(name).toString());
mongoObjectFactory.deleteUser(users.get(name));
users.remove(name);
removeFromUsersByEmail(users.remove(name));
}
@Override
@@ -26,7 +26,8 @@ Require-Bundle: javax.servlet;bundle-version="2.5.0",
org.apache.shiro.ehcache;bundle-version="1.2.3",
org.apache.shiro.web;bundle-version="1.2.2",
org.apache.servicemix.bundles.ehcache;bundle-version="2.6.9",
org.apache.servicemix.bundles.scribe;bundle-version="1.3.3"
org.apache.servicemix.bundles.scribe;bundle-version="1.3.3",
com.sap.sse.common
Web-ContextPath: /security
Export-Package: com.sap.sse.security,
com.sap.sse.security.shared
@@ -23,6 +23,8 @@ public interface SecurityService {
User getUserByName(String username);
User getUserByEmail(String email);
User getCurrentUser();
/**
@@ -100,11 +102,13 @@ public interface SecurityService {
*/
boolean checkPassword(String username, String password) throws UserManagementException;
boolean checkPasswordResetSecret(String username, String passwordResetSecret) throws UserManagementException;
/**
* Generates a new random password for the user identified by <code>username</code> and sends it
* to the user's e-mail address.
*/
void resetPassword(String username) throws UserManagementException;
void resetPassword(String username, String baseURL) throws UserManagementException, MailException;
boolean validateEmail(String username, String validationSecret) throws UserManagementException;
@@ -127,4 +131,5 @@ public interface SecurityService {
* @return <code>null</code> if no preference for the user identified by <code>username</code> is found
*/
String getPreference(String username, String key);
}
@@ -8,7 +8,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
@@ -64,6 +63,7 @@ import org.scribe.model.Token;
import org.scribe.oauth.OAuthService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.sap.sse.common.Util;
import com.sap.sse.security.shared.Account.AccountType;
import com.sap.sse.security.shared.DefaultRoles;
import com.sap.sse.security.shared.MailException;
@@ -161,7 +161,7 @@ public class SecurityServiceImpl extends RemoteServiceServlet implements Securit
}
@Override
public void resetPassword(final String username) throws UserManagementException {
public void resetPassword(final String username, String baseURL) throws UserManagementException, MailException {
final User user = store.getUserByName(username);
if (user == null) {
throw new UserManagementException(UserManagementException.USER_DOES_NOT_EXIST);
@@ -169,21 +169,31 @@ public class SecurityServiceImpl extends RemoteServiceServlet implements Securit
if (!user.isEmailValidated()) {
throw new UserManagementException(UserManagementException.CANNOT_RESET_PASSWORD_WITHOUT_VALIDATED_EMAIL);
}
byte[] randomBytes = new byte[16];
new Random().nextBytes(randomBytes);
final String newPassword = new Sha256Hash(randomBytes).toBase64();
updateSimpleUserPassword(user, newPassword);
new Thread("sending new password to user "+username+" by e-mail") {
@Override public void run() {
try {
sendMail(username, "Password Reset", "Your new password for your username "+username+
" is \n "+newPassword+"\nPlease change after next sign-in.");
} catch (MailException e) {
// TODO Auto-generated catch block
e.printStackTrace();
final String passwordResetSecret = user.startPasswordReset();
Map<String, String> urlParameters = new HashMap<>();
try {
urlParameters.put("u", URLEncoder.encode(user.getName(), "UTF-8"));
urlParameters.put("e", URLEncoder.encode(user.getEmail(), "UTF-8"));
urlParameters.put("s", URLEncoder.encode(passwordResetSecret, "UTF-8"));
final StringBuilder url = buildURL(baseURL, urlParameters);
new Thread("sending password reset e-mail to user " + username) {
@Override
public void run() {
try {
sendMail(user.getName(), "Password Reset",
"Please click on the link below to reset your password for user " + user.getName()
+ ".\n " + url.toString());
} catch (MailException e) {
logger.log(Level.SEVERE, "Error sending mail for password reset of user " + user.getName()
+ " to address " + user.getEmail(), e);
}
}
}
}.start();
}.start();
} catch (UnsupportedEncodingException e) {
logger.log(Level.SEVERE,
"Internal error: encoding UTF-8 not found. Couldn't send e-mail to user " + user.getName()
+ " at e-mail address " + user.getEmail(), e);
}
}
@Override
@@ -227,6 +237,11 @@ public class SecurityServiceImpl extends RemoteServiceServlet implements Securit
return store.getUserByName(name);
}
@Override
public User getUserByEmail(String email) {
return store.getUserByEmail(email);
}
@Override
public User createSimpleUser(final String username, final String email, String password,
final String validationBaseURL) throws UserManagementException, MailException {
@@ -291,9 +306,18 @@ public class SecurityServiceImpl extends RemoteServiceServlet implements Securit
}
final UsernamePasswordAccount account = (UsernamePasswordAccount) user.getAccount(AccountType.USERNAME_PASSWORD);
String hashedOldPassword = hashPassword(password, account.getSalt());
return hashedOldPassword.equals(account.getSaltedPassword());
return Util.equalsWithNull(hashedOldPassword, account.getSaltedPassword());
}
@Override
public boolean checkPasswordResetSecret(String username, String passwordResetSecret) throws UserManagementException {
final User user = store.getUserByName(username);
if (user == null) {
throw new UserManagementException(UserManagementException.USER_DOES_NOT_EXIST);
}
return Util.equalsWithNull(user.getPasswordResetSecret(), passwordResetSecret);
}
@Override
public void updateSimpleUserEmail(final String username, final String newEmail, final String validationBaseURL) throws UserManagementException {
final User user = store.getUserByName(username);
@@ -331,7 +355,7 @@ public class SecurityServiceImpl extends RemoteServiceServlet implements Securit
* {@link User#startEmailValidation() Triggers} e-mail validation for the <code>user</code> object and sends out a
* URL to the user's e-mail that has the validation secret ready for validation by clicking.
*
* @param baserURL
* @param baseURL
* the URL under which the user can reach the e-mail validation service; this URL is required to assemble a
* validation URL that is sent by e-mail to the user, to make the user return the validation secret
* to the right server again.
@@ -342,19 +366,7 @@ public class SecurityServiceImpl extends RemoteServiceServlet implements Securit
Map<String, String> urlParameters = new HashMap<>();
urlParameters.put("u", URLEncoder.encode(user.getName(), "UTF-8"));
urlParameters.put("v", URLEncoder.encode(secret, "UTF-8"));
StringBuilder url = new StringBuilder(baseURL);
boolean first = !baseURL.contains("?");
for (Map.Entry<String, String> e : urlParameters.entrySet()) {
if (first) {
url.append('?');
first = false;
} else {
url.append('&');
}
url.append(e.getKey());
url.append('=');
url.append(e.getValue());
}
StringBuilder url = buildURL(baseURL, urlParameters);
sendMail(user.getName(), "e-Mail Validation",
"Please click on the link below to validate your e-mail address for user "+user.getName()+".\n "+url.toString());
} catch (UnsupportedEncodingException e) {
@@ -364,6 +376,23 @@ public class SecurityServiceImpl extends RemoteServiceServlet implements Securit
}
}
public StringBuilder buildURL(String baseURL, Map<String, String> urlParameters) {
StringBuilder url = new StringBuilder(baseURL);
boolean first = !baseURL.contains("?");
for (Map.Entry<String, String> e : urlParameters.entrySet()) {
if (first) {
url.append('?');
first = false;
} else {
url.append('&');
}
url.append(e.getKey());
url.append('=');
url.append(e.getValue());
}
return url;
}
protected String hashPassword(String password, Object salt) {
return new Sha256Hash(password, salt, 1024).toBase64();
}
@@ -16,6 +16,8 @@ public interface UserStore {
User getUserByName(String name);
User getUserByEmail(String email);
User createUser(String name, String email, Account... accounts) throws UserManagementException;
void updateUser(User user);