CCM NG:
- User registration and password recover now work - Improvements for ChallengeManager - Groups and roles assigned to a user are now shown in in the user details view - Groups assigned to a user can be edited git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3981 8810af33-2d31-482b-a856-94f89814c4dfpull/2/head
parent
49357d190a
commit
81fd867e31
|
|
@ -20,12 +20,12 @@ package com.arsdigita.ui.admin.usersgroupsroles;
|
|||
|
||||
import com.arsdigita.bebop.ActionLink;
|
||||
import com.arsdigita.bebop.BoxPanel;
|
||||
import com.arsdigita.bebop.ColumnPanel;
|
||||
import com.arsdigita.bebop.Component;
|
||||
import com.arsdigita.bebop.ControlLink;
|
||||
import com.arsdigita.bebop.Form;
|
||||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.FormSection;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
|
|
@ -49,16 +49,30 @@ import com.arsdigita.bebop.table.TableCellRenderer;
|
|||
import com.arsdigita.bebop.table.TableColumn;
|
||||
import com.arsdigita.bebop.table.TableColumnModel;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.util.UncheckedWrapperException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.core.EmailAddress;
|
||||
import org.libreccm.security.ChallengeManager;
|
||||
import org.libreccm.security.Group;
|
||||
import org.libreccm.security.GroupManager;
|
||||
import org.libreccm.security.GroupRepository;
|
||||
import org.libreccm.security.User;
|
||||
import org.libreccm.security.UserManager;
|
||||
import org.libreccm.security.UserRepository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TooManyListenersException;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminUiConstants.*;
|
||||
|
|
@ -86,6 +100,7 @@ public class UserAdmin extends BoxPanel {
|
|||
// private final UserDetails userDetails;
|
||||
private final BoxPanel userDetails;
|
||||
private final Form emailForm;
|
||||
private final Form editGroupMembershipsForm;
|
||||
private final Form newUserForm;
|
||||
|
||||
public UserAdmin() {
|
||||
|
|
@ -132,17 +147,6 @@ public class UserAdmin extends BoxPanel {
|
|||
|
||||
add(usersTablePanel);
|
||||
|
||||
// final Text text = new Text();
|
||||
// text.setPrintListener((final PrintEvent e) -> {
|
||||
// final Text target = (Text) e.getTarget();
|
||||
// final PageState state = e.getPageState();
|
||||
// if (selectedUserId.isSelected(state)) {
|
||||
// target.setText(selectedUserId.getSelectedKey(state));
|
||||
// }
|
||||
// });
|
||||
// add(text);
|
||||
// userDetails = new UserDetails(this, selectedUserId);
|
||||
// add(new UserDetails(this, selectedUserId));
|
||||
userDetails = new BoxPanel();
|
||||
userDetails.setIdAttr("userDetails");
|
||||
|
||||
|
|
@ -533,6 +537,71 @@ public class UserAdmin extends BoxPanel {
|
|||
|
||||
userDetails.add(emailTable);
|
||||
|
||||
final Table groupsRolesTable = new Table();
|
||||
groupsRolesTable.setModelBuilder(new UserGroupsRolesTableModelBuilder(
|
||||
selectedUserId));
|
||||
final TableColumnModel groupsRolesColModel = groupsRolesTable
|
||||
.getColumnModel();
|
||||
groupsRolesColModel.add(new TableColumn(
|
||||
UserGroupsRolesTableModel.COL_LABEL));
|
||||
groupsRolesColModel
|
||||
.add(new TableColumn(UserGroupsRolesTableModel.COL_VALUE));
|
||||
groupsRolesColModel.add(
|
||||
new TableColumn(UserGroupsRolesTableModel.COL_ACTION));
|
||||
groupsRolesColModel.get(UserGroupsRolesTableModel.COL_ACTION)
|
||||
.setCellRenderer(new TableCellRenderer() {
|
||||
|
||||
@Override
|
||||
public Component getComponent(final Table table,
|
||||
final PageState state,
|
||||
final Object value,
|
||||
final boolean isSelected,
|
||||
final Object key,
|
||||
final int row,
|
||||
final int column) {
|
||||
switch (row) {
|
||||
case UserGroupsRolesTableModel.ROW_GROUPS: {
|
||||
return new ControlLink((Component) value);
|
||||
}
|
||||
case UserGroupsRolesTableModel.ROW_ROLES: {
|
||||
return new ControlLink((Component) value);
|
||||
}
|
||||
case UserGroupsRolesTableModel.ROW_ALL_ROLES:
|
||||
return new Text("");
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
groupsRolesTable.addTableActionListener(new TableActionListener() {
|
||||
|
||||
@Override
|
||||
public void cellSelected(final TableActionEvent event) {
|
||||
final int selectedRow = Integer.parseInt((String) event
|
||||
.getRowKey());
|
||||
final PageState state = event.getPageState();
|
||||
|
||||
switch (selectedRow) {
|
||||
case UserGroupsRolesTableModel.ROW_GROUPS:
|
||||
showEditGroupMembershipsForm(state);
|
||||
break;
|
||||
case UserGroupsRolesTableModel.ROW_ROLES:
|
||||
//ToDo
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void headSelected(final TableActionEvent event) {
|
||||
//Nothing
|
||||
}
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
userDetails.add(groupsRolesTable);
|
||||
|
||||
final ActionLink addEmailLink = new ActionLink(new GlobalizedMessage(
|
||||
"ui.admin.user.email_addresses.add", ADMIN_BUNDLE));
|
||||
addEmailLink.addActionListener(e -> {
|
||||
|
|
@ -541,9 +610,6 @@ public class UserAdmin extends BoxPanel {
|
|||
userDetails.add(addEmailLink);
|
||||
|
||||
emailForm = new Form("email_form");
|
||||
// emailForm.add(new Label(new GlobalizedMessage(
|
||||
// "ui.admin.user.email_form.address",
|
||||
// ADMIN_BUNDLE)));
|
||||
final TextField emailFormAddress = new TextField("email_form_address");
|
||||
emailFormAddress.setLabel(new GlobalizedMessage(
|
||||
"ui.admin.user.email_form.address", ADMIN_BUNDLE));
|
||||
|
|
@ -668,11 +734,15 @@ public class UserAdmin extends BoxPanel {
|
|||
|
||||
add(userDetails);
|
||||
|
||||
editGroupMembershipsForm = buildEditGroupMembershipsForm();
|
||||
add(editGroupMembershipsForm);
|
||||
|
||||
newUserForm = buildNewUserForm();
|
||||
add(newUserForm);
|
||||
}
|
||||
|
||||
private void setBasicProperties() {
|
||||
setIdAttr("userAdmin");
|
||||
setIdAttr("userAdmin");
|
||||
}
|
||||
|
||||
private Form buildNewUserForm() {
|
||||
|
|
@ -722,11 +792,24 @@ public class UserAdmin extends BoxPanel {
|
|||
.addValidationListener(new StringLengthValidationListener(256));
|
||||
form.add(emailField);
|
||||
|
||||
final FormSection setPasswordSection = new FormSection(new BoxPanel(
|
||||
BoxPanel.VERTICAL));
|
||||
setPasswordSection.setLabel(new GlobalizedMessage(
|
||||
"ui.admin.new_user_form.password_options.set_password.label",
|
||||
ADMIN_BUNDLE));
|
||||
final String passwordOptions = "passwordOptions";
|
||||
final String optionSetPassword = "setPassword";
|
||||
final String optionSendPassword = "sendPassword";
|
||||
final RadioGroup passwordOptionsGroup = new RadioGroup(passwordOptions);
|
||||
final Option sendPasswordOption = new Option(
|
||||
optionSendPassword,
|
||||
new Label(new GlobalizedMessage(
|
||||
"ui.admin.new_user_form.password_options.send_password.label",
|
||||
ADMIN_BUNDLE)));
|
||||
passwordOptionsGroup.addOption(sendPasswordOption);
|
||||
final Option setPasswordOption = new Option(
|
||||
optionSetPassword,
|
||||
new Label(new GlobalizedMessage(
|
||||
"ui.admin.new_user_form.password_options.set_password",
|
||||
ADMIN_BUNDLE)));
|
||||
passwordOptionsGroup.addOption(setPasswordOption);
|
||||
form.add(passwordOptionsGroup);
|
||||
|
||||
final String password = "password";
|
||||
final String passwordConfirmation = "passwordConfirmation";
|
||||
final Password passwordField = new Password(password);
|
||||
|
|
@ -738,7 +821,7 @@ public class UserAdmin extends BoxPanel {
|
|||
passwordField.addValidationListener(new NotEmptyValidationListener());
|
||||
passwordField.addValidationListener(new StringLengthValidationListener(
|
||||
256));
|
||||
setPasswordSection.add(passwordField);
|
||||
form.add(passwordField);
|
||||
final Password passwordConfirmationField = new Password(
|
||||
passwordConfirmation);
|
||||
passwordConfirmationField.setLabel(new GlobalizedMessage(
|
||||
|
|
@ -750,27 +833,7 @@ public class UserAdmin extends BoxPanel {
|
|||
new NotEmptyValidationListener());
|
||||
passwordConfirmationField.addValidationListener(
|
||||
new StringLengthValidationListener(256));
|
||||
setPasswordSection.add(passwordConfirmationField);
|
||||
|
||||
final String passwordOptions = "passwordOptions";
|
||||
final String optionSetPassword = "setPassword";
|
||||
final String optionSendPassword = "sendPassword";
|
||||
final RadioGroup passwordOptionsGroup = new RadioGroup(passwordOptions);
|
||||
// final Option setPasswordOption = new Option(
|
||||
// optionSetPassword,
|
||||
// new Label(new GlobalizedMessage(
|
||||
// "ui.admin.new_user_form.password_options.set_password",
|
||||
// ADMIN_BUNDLE)));
|
||||
final Option setPasswordOption = new Option(
|
||||
optionSetPassword, setPasswordSection);
|
||||
passwordOptionsGroup.addOption(setPasswordOption);
|
||||
final Option sendPasswordOption = new Option(
|
||||
optionSendPassword,
|
||||
new Label(new GlobalizedMessage(
|
||||
"ui.admin.new_user_form.password_options.send_password.label",
|
||||
ADMIN_BUNDLE)));
|
||||
passwordOptionsGroup.addOption(sendPasswordOption);
|
||||
form.add(passwordOptionsGroup);
|
||||
form.add(passwordConfirmationField);
|
||||
|
||||
final SaveCancelSection saveCancelSection = new SaveCancelSection();
|
||||
form.add(saveCancelSection);
|
||||
|
|
@ -871,6 +934,156 @@ public class UserAdmin extends BoxPanel {
|
|||
return form;
|
||||
}
|
||||
|
||||
private Form buildEditGroupMembershipsForm() {
|
||||
final Form form = new Form("edit-usergroupmemberships-form");
|
||||
|
||||
final BoxPanel links = new BoxPanel(BoxPanel.VERTICAL);
|
||||
final Label header = new Label(e -> {
|
||||
final PageState state = e.getPageState();
|
||||
final Label target = (Label) e.getTarget();
|
||||
|
||||
final String userIdStr = selectedUserId.getSelectedKey(state);
|
||||
final UserRepository userRepository = CdiUtil.createCdiUtil()
|
||||
.findBean(UserRepository.class);
|
||||
final User user = userRepository.findById(Long.parseLong(userIdStr));
|
||||
|
||||
target.setLabel(new GlobalizedMessage(
|
||||
"ui.admin.user.edit_group_memberships", ADMIN_BUNDLE,
|
||||
new String[]{user.getName()}));
|
||||
});
|
||||
links.add(header);
|
||||
|
||||
final ActionLink backLink = new ActionLink(new GlobalizedMessage(
|
||||
"ui.admin.user.edit_group_memberships.back_to_user_details",
|
||||
ADMIN_BUNDLE));
|
||||
backLink.addActionListener(e -> {
|
||||
closeEditGroupMembershipsForm(e.getPageState());
|
||||
});
|
||||
links.add(backLink);
|
||||
|
||||
form.add(links);
|
||||
|
||||
final String groupsSelector = "groupsselector";
|
||||
final CheckboxGroup groups = new CheckboxGroup(groupsSelector);
|
||||
try {
|
||||
groups.addPrintListener(e -> {
|
||||
// final PageState state = e.getPageState();
|
||||
final CheckboxGroup target = (CheckboxGroup) e.getTarget();
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
// final UserRepository userRepository = cdiUtil.findBean(
|
||||
// UserRepository.class);
|
||||
final GroupRepository groupRepository = cdiUtil.findBean(
|
||||
GroupRepository.class);
|
||||
|
||||
target.clearOptions();
|
||||
|
||||
final SortedSet<Group> allGroups = new TreeSet<>(
|
||||
(g1, g2) -> {
|
||||
return g1.getName().compareTo(g2.getName());
|
||||
});
|
||||
allGroups.addAll(groupRepository.findAll());
|
||||
// final List<Group> assignedGroups = new ArrayList<>();
|
||||
// final User user = userRepository.findById(Long.parseLong(
|
||||
// selectedUserId.getSelectedKey(state)));
|
||||
// user.getGroupMemberships().forEach(m -> {
|
||||
// assignedGroups.add(m.getGroup());
|
||||
// });
|
||||
|
||||
allGroups.forEach(g -> {
|
||||
final Option option = new Option(
|
||||
Long.toString(g.getPartyId()), new Text(g.getName()));
|
||||
target.addOption(option);
|
||||
// if (assignedGroups.contains(g)) {
|
||||
// target.setOptionSelected(option);
|
||||
// }
|
||||
});
|
||||
});
|
||||
} catch (TooManyListenersException ex) {
|
||||
throw new UncheckedWrapperException(ex);
|
||||
}
|
||||
form.add(groups);
|
||||
|
||||
final SaveCancelSection saveCancelSection = new SaveCancelSection();
|
||||
form.add(saveCancelSection);
|
||||
|
||||
form.addInitListener(e -> {
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final UserRepository userRepository = cdiUtil.findBean(
|
||||
UserRepository.class);
|
||||
|
||||
final PageState state = e.getPageState();
|
||||
|
||||
final User user = userRepository.findById(Long.parseLong(
|
||||
selectedUserId.getSelectedKey(state)));
|
||||
final List<Group> assignedGroups = new ArrayList<>();
|
||||
user.getGroupMemberships().forEach(m -> {
|
||||
assignedGroups.add(m.getGroup());
|
||||
});
|
||||
|
||||
final String[] selectedGroups = new String[assignedGroups.size()];
|
||||
IntStream.range(0, assignedGroups.size()).forEach(i -> {
|
||||
selectedGroups[i] = Long.toString(assignedGroups.get(i)
|
||||
.getPartyId());
|
||||
});
|
||||
|
||||
groups.setValue(state, selectedGroups);
|
||||
});
|
||||
|
||||
form.addProcessListener(e -> {
|
||||
final PageState state = e.getPageState();
|
||||
if (saveCancelSection.getSaveButton().isSelected(state)) {
|
||||
final FormData data = e.getFormData();
|
||||
|
||||
final CdiUtil cdiUtil = CdiUtil.createCdiUtil();
|
||||
final UserRepository userRepository = cdiUtil.findBean(
|
||||
UserRepository.class);
|
||||
final GroupRepository groupRepository = cdiUtil.findBean(
|
||||
GroupRepository.class);
|
||||
final GroupManager groupManager = cdiUtil.findBean(
|
||||
GroupManager.class);
|
||||
|
||||
final String[] selectedGroupIds = (String[]) data.get(
|
||||
groupsSelector);
|
||||
|
||||
final User user = userRepository.findById(Long.parseLong(
|
||||
selectedUserId.getSelectedKey(state)));
|
||||
final List<Group> selectedGroups = new ArrayList<>();
|
||||
if (selectedGroupIds != null) {
|
||||
for (String selectedGroupId : selectedGroupIds) {
|
||||
final Group group = groupRepository.findById(Long
|
||||
.parseLong(
|
||||
selectedGroupId));
|
||||
selectedGroups.add(group);
|
||||
}
|
||||
}
|
||||
final List<Group> assignedGroups = new ArrayList<>();
|
||||
user.getGroupMemberships().forEach(m -> {
|
||||
assignedGroups.add(m.getGroup());
|
||||
});
|
||||
|
||||
//First check for newly added groups
|
||||
selectedGroups.forEach(g -> {
|
||||
if (!assignedGroups.contains(g)) {
|
||||
groupManager.addMemberToGroup(user, g);
|
||||
}
|
||||
});
|
||||
|
||||
//Than check for removed groups
|
||||
assignedGroups.forEach(g -> {
|
||||
if (!selectedGroups.contains(g)) {
|
||||
final Group group = groupRepository.findById(
|
||||
g.getPartyId());
|
||||
groupManager.removeMemberFromGroup(user, group);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
closeEditGroupMembershipsForm(state);
|
||||
});
|
||||
|
||||
return form;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(final Page page) {
|
||||
super.register(page);
|
||||
|
|
@ -883,6 +1096,7 @@ public class UserAdmin extends BoxPanel {
|
|||
page.setVisibleDefault(userEditForm, false);
|
||||
page.setVisibleDefault(passwordSetForm, false);
|
||||
page.setVisibleDefault(emailForm, false);
|
||||
page.setVisibleDefault(editGroupMembershipsForm, false);
|
||||
page.setVisibleDefault(newUserForm, false);
|
||||
}
|
||||
|
||||
|
|
@ -892,6 +1106,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
@ -902,6 +1117,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
@ -911,6 +1127,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, true);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
@ -920,6 +1137,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
@ -929,6 +1147,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, true);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
@ -938,6 +1157,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
@ -947,6 +1167,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, true);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
@ -957,6 +1178,28 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
protected void showEditGroupMembershipsForm(final PageState state) {
|
||||
usersTablePanel.setVisible(state, false);
|
||||
userDetails.setVisible(state, false);
|
||||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, true);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
protected void closeEditGroupMembershipsForm(final PageState state) {
|
||||
selectedEmailAddress.clearSelection(state);
|
||||
usersTablePanel.setVisible(state, false);
|
||||
userDetails.setVisible(state, true);
|
||||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
@ -967,6 +1210,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, true);
|
||||
}
|
||||
|
||||
|
|
@ -977,6 +1221,7 @@ public class UserAdmin extends BoxPanel {
|
|||
userEditForm.setVisible(state, false);
|
||||
passwordSetForm.setVisible(state, false);
|
||||
emailForm.setVisible(state, false);
|
||||
editGroupMembershipsForm.setVisible(state, false);
|
||||
newUserForm.setVisible(state, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright (C) 2016 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package com.arsdigita.ui.admin.usersgroupsroles;
|
||||
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.table.TableModel;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
import org.libreccm.security.User;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminUiConstants.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class UserGroupsRolesTableModel implements TableModel {
|
||||
|
||||
protected static final int COL_LABEL = 0;
|
||||
protected static final int COL_VALUE = 1;
|
||||
protected static final int COL_ACTION = 2;
|
||||
|
||||
protected static final int ROW_GROUPS = 0;
|
||||
protected static final int ROW_ROLES = 1;
|
||||
protected static final int ROW_ALL_ROLES = 2;
|
||||
|
||||
private int row = -1;
|
||||
|
||||
private final User user;
|
||||
|
||||
public UserGroupsRolesTableModel(final User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean nextRow() {
|
||||
row++;
|
||||
return row < 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getElementAt(final int columnIndex) {
|
||||
switch (row) {
|
||||
case ROW_GROUPS:
|
||||
return buildGroupRow(columnIndex);
|
||||
case ROW_ROLES:
|
||||
return buildRolesRow(columnIndex);
|
||||
case ROW_ALL_ROLES:
|
||||
return buildAllRolesRow(columnIndex);
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getKeyAt(final int columnIndex) {
|
||||
return row;
|
||||
}
|
||||
|
||||
private Object buildGroupRow(final int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COL_LABEL:
|
||||
return new Label(new GlobalizedMessage("ui.admin.user.groups",
|
||||
ADMIN_BUNDLE));
|
||||
case COL_VALUE:
|
||||
final List<String> groupNames = new ArrayList<>();
|
||||
user.getGroupMemberships().forEach(m -> {
|
||||
groupNames.add(m.getGroup().getName());
|
||||
});
|
||||
|
||||
groupNames.sort((name1, name2) -> {
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
|
||||
return String.join(
|
||||
", ", groupNames.toArray(new String[groupNames.size()]));
|
||||
|
||||
case COL_ACTION:
|
||||
return new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.groups.edit", ADMIN_BUNDLE));
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private Object buildRolesRow(final int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COL_LABEL:
|
||||
return new Label(new GlobalizedMessage("ui.admin.user.roles",
|
||||
ADMIN_BUNDLE));
|
||||
case COL_VALUE:
|
||||
final List<String> roleNames = new ArrayList<>();
|
||||
user.getRoleMemberships().forEach(m -> {
|
||||
roleNames.add(m.getRole().getName());
|
||||
});
|
||||
|
||||
roleNames.sort((name1, name2) -> {
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
|
||||
return String.join(
|
||||
", ", roleNames.toArray(new String[roleNames.size()]));
|
||||
|
||||
case COL_ACTION:
|
||||
return new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.roles.edit", ADMIN_BUNDLE));
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
private Object buildAllRolesRow(final int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COL_LABEL:
|
||||
return new Label(new GlobalizedMessage(
|
||||
"ui.admin.user.all_roles", ADMIN_BUNDLE));
|
||||
case COL_VALUE:
|
||||
final Set<String> roleNames = new HashSet<>();
|
||||
user.getRoleMemberships().forEach(m -> {
|
||||
roleNames.add(m.getRole().getName());
|
||||
});
|
||||
|
||||
user.getGroupMemberships().forEach(m -> {
|
||||
m.getGroup().getRoleMemberships().forEach(r -> {
|
||||
roleNames.add(r.getRole().getName());
|
||||
});
|
||||
});
|
||||
|
||||
final List<String> allRoleNames = new ArrayList<>(roleNames);
|
||||
allRoleNames.sort((name1, name2) -> {
|
||||
return name1.compareTo(name2);
|
||||
});
|
||||
|
||||
return String.join(", ", allRoleNames.toArray(
|
||||
new String[allRoleNames.size()]));
|
||||
|
||||
case COL_ACTION:
|
||||
return "";
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (C) 2016 LibreCCM Foundation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
package com.arsdigita.ui.admin.usersgroupsroles;
|
||||
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.ParameterSingleSelectionModel;
|
||||
import com.arsdigita.bebop.Table;
|
||||
import com.arsdigita.bebop.table.TableModel;
|
||||
import com.arsdigita.bebop.table.TableModelBuilder;
|
||||
import com.arsdigita.util.LockableImpl;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.User;
|
||||
import org.libreccm.security.UserRepository;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
public class UserGroupsRolesTableModelBuilder extends LockableImpl
|
||||
implements TableModelBuilder{
|
||||
|
||||
private final ParameterSingleSelectionModel<String> selectedUserId;
|
||||
|
||||
public UserGroupsRolesTableModelBuilder(
|
||||
final ParameterSingleSelectionModel<String> selectedUserId) {
|
||||
this.selectedUserId = selectedUserId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableModel makeModel(final Table table, final PageState state) {
|
||||
final String userIdStr = selectedUserId.getSelectedKey(state);
|
||||
final User selectedUser ;
|
||||
if (userIdStr == null || userIdStr.isEmpty()) {
|
||||
selectedUser = null;
|
||||
} else {
|
||||
final UserRepository userRepository = CdiUtil.createCdiUtil()
|
||||
.findBean(UserRepository.class);
|
||||
final long userId = Long.parseLong(userIdStr);
|
||||
selectedUser = userRepository.findById(userId);
|
||||
}
|
||||
|
||||
return new UserGroupsRolesTableModel(selectedUser);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -20,8 +20,10 @@ package com.arsdigita.ui.admin.usersgroupsroles;
|
|||
|
||||
import com.arsdigita.bebop.PropertySheetModel;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.libreccm.security.User;
|
||||
|
||||
import static com.arsdigita.ui.admin.AdminUiConstants.*;
|
||||
|
|
@ -38,7 +40,7 @@ public class UserPropertySheetModel implements PropertySheetModel {
|
|||
GIVEN_NAME,
|
||||
PASSWORD_SET,
|
||||
BANNED,
|
||||
PASSWORD_RESET_REQUIRED,
|
||||
PASSWORD_RESET_REQUIRED
|
||||
}
|
||||
|
||||
private final User selectedUser;
|
||||
|
|
@ -102,5 +104,4 @@ public class UserPropertySheetModel implements PropertySheetModel {
|
|||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ public class UsersTable extends Table {
|
|||
final UserRepository userRepository = CdiUtil.createCdiUtil()
|
||||
.findBean(UserRepository.class);
|
||||
if (filterTerm == null || filterTerm.isEmpty()) {
|
||||
users = userRepository.findAll();
|
||||
users = userRepository.findAllOrderdByUsername();
|
||||
LOGGER.debug("Found {} users in database.", users.size());
|
||||
} else {
|
||||
users = userRepository.filtered(filterTerm);
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ public interface LoginConstants {
|
|||
// updating existing databases (table applications)!
|
||||
public static final String LOGIN_PAGE_URL = "/register/";
|
||||
|
||||
public static final String LOGIN_PATH = "/register";
|
||||
|
||||
public static final String LOGIN_SERVLET_PATH = "/login/*";
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,16 +108,25 @@ public class LoginServlet extends BebopApplicationServlet {
|
|||
/**
|
||||
* PathInfo into the Login application to access the <em>password reset</em>
|
||||
* page which allows the user to replace a forgotten password with a new one
|
||||
* (using a previously requested one time auth token). Ends with "/" because
|
||||
* it is a servlet/directory
|
||||
* (using a previously requested one time authentication token). Ends with
|
||||
* "/" because it is a servlet/directory
|
||||
*/
|
||||
public static final String RESET_USER_PASSWORD_PATH_INFO = "/reset-password";
|
||||
public static final String RESET_USER_PASSWORD_PATH_INFO = "/reset-password/";
|
||||
|
||||
/**
|
||||
* PathInfo into the Login application to access the <em>verify email</em>
|
||||
* page. Ends with "/" because it is a servlet/directory
|
||||
* page (not implemted yet!). Ends with "/" because it is a
|
||||
* servlet/directory
|
||||
*/
|
||||
public static final String VERIFY_EMAIL = "/verify-email/";
|
||||
public static final String VERIFY_EMAIL_PATH_INFO = "/verify-email/";
|
||||
|
||||
/**
|
||||
* PathInfo into the Login application to access the <em>confirm email</em>
|
||||
* page which allows the user to confirm his/her email address by submitting
|
||||
* a previously requested one time authentication token (not implemented!).
|
||||
* Ends with "/" because it is a servlet/directory
|
||||
*/
|
||||
public static final String CONFIRM_EMAIL_PATH_INFO = "/verify-email/";
|
||||
|
||||
/**
|
||||
* PathInfo into the Login application to access the (optional) <em>explain
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
|||
import com.arsdigita.bebop.parameters.StringLengthValidationListener;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.security.ChallengeManager;
|
||||
import org.libreccm.security.User;
|
||||
|
|
@ -48,6 +50,9 @@ import static com.arsdigita.ui.login.LoginServlet.*;
|
|||
*/
|
||||
public class RecoverPasswordForm extends Form {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
RecoverPasswordForm.class);
|
||||
|
||||
private static final String EMAIL = "email";
|
||||
|
||||
private BoxPanel formPanel;
|
||||
|
|
@ -93,6 +98,7 @@ public class RecoverPasswordForm extends Form {
|
|||
LOGIN_BUNDLE)),
|
||||
LOGIN_PAGE_URL + RESET_USER_PASSWORD_PATH_INFO);
|
||||
finishedMessagePanel.add(link);
|
||||
add(finishedMessagePanel);
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
|
|
@ -155,9 +161,14 @@ public class RecoverPasswordForm extends Form {
|
|||
}
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
LOGGER.warn(
|
||||
"Password recover requested for not existing user {}.",
|
||||
data.get(EMAIL));
|
||||
}
|
||||
|
||||
formPanel.setVisible(state, false);
|
||||
finishedMessagePanel.setVisible(state, true);
|
||||
data.clear();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.arsdigita.bebop.Form;
|
|||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Link;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SaveCancelSection;
|
||||
|
|
@ -31,6 +32,7 @@ import com.arsdigita.bebop.form.TextField;
|
|||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringLengthValidationListener;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.web.URL;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.configuration.ConfigurationManager;
|
||||
|
|
@ -45,6 +47,8 @@ import org.libreccm.security.UserRepository;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static com.arsdigita.ui.login.LoginConstants.*;
|
||||
|
||||
/**
|
||||
|
|
@ -136,12 +140,32 @@ public class ResetPasswordForm extends Form {
|
|||
successPanel = new BoxPanel(BoxPanel.VERTICAL);
|
||||
successPanel.add(new Label(new GlobalizedMessage(
|
||||
"login.form.reset_password.scucess", LOGIN_BUNDLE)));
|
||||
successPanel.add(new Link(new Label(new GlobalizedMessage(
|
||||
"login.form.reset_password.scucess.login",
|
||||
LOGIN_BUNDLE)),
|
||||
URL.there(LOGIN_PAGE_URL, null).getURL()));
|
||||
|
||||
add(successPanel);
|
||||
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
addInitListener(e -> {
|
||||
final PageState state = e.getPageState();
|
||||
final HttpServletRequest request = state.getRequest();
|
||||
|
||||
final String paramEmail = request.getParameter("email");
|
||||
final String paramToken = request.getParameter("token");
|
||||
|
||||
if (paramEmail != null) {
|
||||
email.setValue(state, paramEmail);
|
||||
}
|
||||
|
||||
if (paramToken != null) {
|
||||
authToken.setValue(state, paramToken);
|
||||
}
|
||||
});
|
||||
|
||||
addValidationListener(e -> {
|
||||
final PageState state = e.getPageState();
|
||||
|
||||
|
|
@ -177,7 +201,7 @@ public class ResetPasswordForm extends Form {
|
|||
|
||||
final List<OneTimeAuthToken> tokens = oneTimeAuthManager
|
||||
.retrieveForUser(
|
||||
user, OneTimeAuthTokenPurpose.ACCOUNT_ACTIVATION);
|
||||
user, OneTimeAuthTokenPurpose.RECOVER_PASSWORD);
|
||||
|
||||
boolean result = false;
|
||||
for (OneTimeAuthToken token : tokens) {
|
||||
|
|
@ -234,13 +258,12 @@ public class ResetPasswordForm extends Form {
|
|||
throw new FormProcessException(
|
||||
"Failed to finish password recovery.",
|
||||
new GlobalizedMessage(
|
||||
"login.form.account_activation.error.failed"),
|
||||
"login.form.password_reset.error.failed"),
|
||||
ex);
|
||||
}
|
||||
|
||||
formPanel.setVisible(state, false);
|
||||
successPanel.setVisible(state, true);
|
||||
data.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.arsdigita.bebop.Form;
|
|||
import com.arsdigita.bebop.FormData;
|
||||
import com.arsdigita.bebop.FormProcessException;
|
||||
import com.arsdigita.bebop.Label;
|
||||
import com.arsdigita.bebop.Link;
|
||||
import com.arsdigita.bebop.Page;
|
||||
import com.arsdigita.bebop.PageState;
|
||||
import com.arsdigita.bebop.SaveCancelSection;
|
||||
|
|
@ -30,6 +31,7 @@ import com.arsdigita.bebop.form.TextField;
|
|||
import com.arsdigita.bebop.parameters.NotEmptyValidationListener;
|
||||
import com.arsdigita.bebop.parameters.StringLengthValidationListener;
|
||||
import com.arsdigita.globalization.GlobalizedMessage;
|
||||
import com.arsdigita.web.URL;
|
||||
|
||||
import org.libreccm.cdi.utils.CdiUtil;
|
||||
import org.libreccm.configuration.ConfigurationManager;
|
||||
|
|
@ -44,6 +46,8 @@ import org.libreccm.security.UserRepository;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static com.arsdigita.ui.login.LoginConstants.*;
|
||||
|
||||
/**
|
||||
|
|
@ -102,11 +106,30 @@ public class UserAccountActivationForm extends Form {
|
|||
successPanel = new BoxPanel(BoxPanel.VERTICAL);
|
||||
successPanel.add(new Label(new GlobalizedMessage(
|
||||
"login.form.account_activation.success", LOGIN_BUNDLE)));
|
||||
|
||||
successPanel.add(new Link(new Label(
|
||||
new GlobalizedMessage("login.form.account_activation.success.login",
|
||||
LOGIN_BUNDLE)),
|
||||
URL.there(LOGIN_PAGE_URL, null).getURL()));
|
||||
add(successPanel);
|
||||
}
|
||||
|
||||
private void addListeners() {
|
||||
addInitListener(e -> {
|
||||
final PageState state = e.getPageState();
|
||||
final HttpServletRequest request = state.getRequest();
|
||||
|
||||
final String paramEmail = request.getParameter("email");
|
||||
final String paramToken = request.getParameter("token");
|
||||
|
||||
if (paramEmail != null) {
|
||||
email.setValue(state, paramEmail);
|
||||
}
|
||||
|
||||
if (paramToken != null) {
|
||||
authToken.setValue(state, paramToken);
|
||||
}
|
||||
});
|
||||
|
||||
addValidationListener(e -> {
|
||||
final PageState state = e.getPageState();
|
||||
|
||||
|
|
@ -193,7 +216,6 @@ public class UserAccountActivationForm extends Form {
|
|||
|
||||
formPanel.setVisible(state, false);
|
||||
successPanel.setVisible(state, true);
|
||||
data.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import javax.persistence.EntityManager;
|
|||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Order;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
|
|
@ -208,8 +209,7 @@ public abstract class AbstractEntityRepository<K, E> {
|
|||
public List<E> findAll(final String entityGraphName) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final EntityGraph<E> entityGraph = (EntityGraph<E>) entityManager
|
||||
.getEntityGraph(
|
||||
entityGraphName);
|
||||
.getEntityGraph(entityGraphName);
|
||||
|
||||
return findAll(entityGraph);
|
||||
}
|
||||
|
|
@ -237,8 +237,8 @@ public abstract class AbstractEntityRepository<K, E> {
|
|||
if (hasDefaultEntityGraph()) {
|
||||
return executeCriteriaQuery(criteriaQuery, getDefaultEntityGraph());
|
||||
} else {
|
||||
final TypedQuery<E> query = entityManager.createQuery(criteriaQuery);
|
||||
return query.getResultList();
|
||||
final TypedQuery<E> query = entityManager.createQuery(criteriaQuery);
|
||||
return query.getResultList();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -286,9 +286,9 @@ public abstract class AbstractEntityRepository<K, E> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Overwrite this method to initialise new entities with default values.
|
||||
* One example is assigning a (random) UUID to new entity which implements
|
||||
* the {@link Identifiable} interface.
|
||||
* Overwrite this method to initialise new entities with default values. One
|
||||
* example is assigning a (random) UUID to new entity which implements the
|
||||
* {@link Identifiable} interface.
|
||||
*
|
||||
* @param entity The entity to init.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -54,10 +54,11 @@ import javax.servlet.http.HttpSession;
|
|||
* </li>
|
||||
* </ol>
|
||||
*
|
||||
* A historic note: This CDI bean replaces the old {@code GlobalizationHelper} class which used
|
||||
* static methods and relied on the old {@code DispatcherHelper} for getting the
|
||||
* current request. In a CDI environment we can simply inject the current request
|
||||
* and don't need to bother with static methods etc.
|
||||
* A historic note: This CDI bean replaces the old {@code GlobalizationHelper}
|
||||
* class which used static methods and relied on the old
|
||||
* {@code DispatcherHelper} for getting the current request. In a CDI
|
||||
* environment we can simply inject the current request and don't need to bother
|
||||
* with static methods etc.
|
||||
*
|
||||
* @author <a href="mailto:jens.pelzetter@googlemail.com">Jens Pelzetter</a>
|
||||
*/
|
||||
|
|
@ -73,13 +74,12 @@ public class GlobalizationHelper {
|
|||
private ConfigurationManager confManager;
|
||||
|
||||
// private final KernelConfig kernelConfig;
|
||||
|
||||
// public GlobalizationHelper() {
|
||||
// kernelConfig = confManager.findConfiguration(KernelConfig.class);
|
||||
// }
|
||||
|
||||
public Locale getNegotiatedLocale() {
|
||||
final KernelConfig kernelConfig = confManager.findConfiguration(KernelConfig.class);
|
||||
final KernelConfig kernelConfig = confManager.findConfiguration(
|
||||
KernelConfig.class);
|
||||
|
||||
Locale preferred = new Locale(kernelConfig.getDefaultLanguage());
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ public class GlobalizationHelper {
|
|||
while (acceptedLocales.hasMoreElements()) {
|
||||
final Locale current = acceptedLocales.nextElement();
|
||||
if (kernelConfig.hasLanguage(current.getLanguage())) {
|
||||
preferred = current;
|
||||
preferred = new Locale(current.getLanguage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,13 @@ package org.libreccm.security;
|
|||
|
||||
import com.arsdigita.kernel.KernelConfig;
|
||||
import com.arsdigita.mail.Mail;
|
||||
import com.arsdigita.ui.login.LoginConstants;
|
||||
import com.arsdigita.web.ParameterMap;
|
||||
import com.arsdigita.web.URL;
|
||||
|
||||
import org.apache.commons.lang.text.StrSubstitutor;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.libreccm.configuration.ConfigurationManager;
|
||||
import org.libreccm.configuration.LocalizedStringSetting;
|
||||
import org.libreccm.l10n.GlobalizationHelper;
|
||||
|
|
@ -37,6 +42,9 @@ import javax.enterprise.context.RequestScoped;
|
|||
import javax.inject.Inject;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static com.arsdigita.ui.login.LoginServlet.*;
|
||||
|
||||
/**
|
||||
* A service class for managing several so called challenges. These challenges
|
||||
|
|
@ -73,6 +81,9 @@ import javax.servlet.ServletContext;
|
|||
@RequestScoped
|
||||
public class ChallengeManager {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(
|
||||
ChallengeManager.class);
|
||||
|
||||
@Inject
|
||||
private GlobalizationHelper globalizationHelper;
|
||||
|
||||
|
|
@ -89,7 +100,7 @@ public class ChallengeManager {
|
|||
private UserManager userManager;
|
||||
|
||||
@Inject
|
||||
private ServletContext servletContext;
|
||||
private HttpServletRequest request;
|
||||
|
||||
public String createEmailVerification(final User user) {
|
||||
if (user == null) {
|
||||
|
|
@ -137,7 +148,7 @@ public class ChallengeManager {
|
|||
|
||||
public void sendAccountActivation(final User user)
|
||||
throws MessagingException {
|
||||
final String text = createEmailVerification(user);
|
||||
final String text = createAccountActivation(user);
|
||||
sendMessage(
|
||||
user,
|
||||
retrieveEmailSubject(OneTimeAuthTokenPurpose.ACCOUNT_ACTIVATION),
|
||||
|
|
@ -172,7 +183,7 @@ public class ChallengeManager {
|
|||
|
||||
public void sendPasswordRecover(final User user)
|
||||
throws MessagingException {
|
||||
final String text = createEmailVerification(user);
|
||||
final String text = createPasswordRecover(user);
|
||||
sendMessage(
|
||||
user,
|
||||
retrieveEmailSubject(OneTimeAuthTokenPurpose.RECOVER_PASSWORD),
|
||||
|
|
@ -211,13 +222,13 @@ public class ChallengeManager {
|
|||
final String path;
|
||||
switch (purpose) {
|
||||
case ACCOUNT_ACTIVATION:
|
||||
path = "activate-account";
|
||||
path = ACTIVATE_ACCOUNT_PATH_INFO;
|
||||
break;
|
||||
case EMAIL_VERIFICATION:
|
||||
path = "verify-email";
|
||||
path = VERIFY_EMAIL_PATH_INFO;
|
||||
break;
|
||||
case RECOVER_PASSWORD:
|
||||
path = "recover-password";
|
||||
path = RESET_USER_PASSWORD_PATH_INFO;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format(
|
||||
|
|
@ -225,17 +236,28 @@ public class ChallengeManager {
|
|||
purpose.toString()));
|
||||
}
|
||||
values.put("link",
|
||||
String.format("%s/%s/register/%s",
|
||||
servletContext.getVirtualServerName(),
|
||||
servletContext.getContextPath(),
|
||||
path));
|
||||
URL.there(request,
|
||||
LoginConstants.LOGIN_PATH + path, null)
|
||||
.getURL());
|
||||
|
||||
final ParameterMap params = new ParameterMap();
|
||||
params.setParameter("email", user.getPrimaryEmailAddress().getAddress());
|
||||
params.setParameter("token", token.getToken());
|
||||
values.put("full_link",
|
||||
URL.there(request,
|
||||
LoginConstants.LOGIN_PATH + path, params)
|
||||
.getURL());
|
||||
|
||||
values.put("token", token.getToken());
|
||||
|
||||
final StrSubstitutor substitutor = new StrSubstitutor(values);
|
||||
return substitutor.replace(template);
|
||||
}
|
||||
|
||||
private String retrieveEmailSubject(final OneTimeAuthTokenPurpose purpose) {
|
||||
LOGGER.debug("Retreving email subject...");
|
||||
final Locale locale = globalizationHelper.getNegotiatedLocale();
|
||||
LOGGER.debug("Negoiated locale is {}.", locale.toString());
|
||||
|
||||
final EmailTemplates emailTemplates = configurationManager
|
||||
.findConfiguration(EmailTemplates.class);
|
||||
|
|
|
|||
|
|
@ -67,17 +67,35 @@ public final class EmailTemplates {
|
|||
"Please follow the following link to finish the email verfication "
|
||||
+ "process:\n"
|
||||
+ "\n"
|
||||
+ "${link}"
|
||||
+ "\n\n"
|
||||
+ "Please be aware that your verification token expires"
|
||||
+ "${full_link}\n"
|
||||
+ "\n"
|
||||
+ "or go to\n"
|
||||
+ "\n"
|
||||
+ "${link}\n"
|
||||
+ "\n"
|
||||
+ "and enter your email address and the following verification "
|
||||
+ "token:\n"
|
||||
+ "\n"
|
||||
+ "${token}\n"
|
||||
+ "\n"
|
||||
+ "Please be aware that your verification token expires "
|
||||
+ "at ${expires_date}.");
|
||||
emailVerificationMail.getValue().addValue(
|
||||
Locale.GERMAN,
|
||||
"Bitte folgen Sie dem folgenden Link, um die Überprüfung ihrer E-"
|
||||
+ "Mail-Adresse abzuschließen:\n"
|
||||
+ "\n"
|
||||
+ "${link}"
|
||||
+ "\n\n"
|
||||
+ "${full_link}\n"
|
||||
+ "\n"
|
||||
+ "oder rufen Sie\n"
|
||||
+ "\n"
|
||||
+ "${link}\n"
|
||||
+ "\n"
|
||||
+ "auf und geben Sie Ihre E-Mail-Adresse und das folgende Token "
|
||||
+ "ein:\n"
|
||||
+ "\n"
|
||||
+ "${token}\n"
|
||||
+ "\n"
|
||||
+ "Bitte beachten Sie, dass Sie den Prozess bis zu folgendem "
|
||||
+ "Zeitpunkt abschließen müssen: ${expires_date}");
|
||||
|
||||
|
|
@ -95,17 +113,33 @@ public final class EmailTemplates {
|
|||
"Please follow the following link to complete the password recover "
|
||||
+ "process:\n"
|
||||
+ "\n"
|
||||
+ "${link}"
|
||||
+ "\n\n"
|
||||
+ "${full_link}\n"
|
||||
+ "\n"
|
||||
+ "or go to\n"
|
||||
+ "${link}\n"
|
||||
+ "\n"
|
||||
+ "and enter your email address and the following token:\n"
|
||||
+ "\n"
|
||||
+ "${token}\n"
|
||||
+ "\n"
|
||||
+ "Please be aware that you must complete the process until "
|
||||
+ "${expires_date}");
|
||||
+ "${expires_date}.");
|
||||
passwordRecoverMail.getValue().addValue(
|
||||
Locale.GERMAN,
|
||||
"Bitte folgen Sie dem folgenden Link um ein neues Passwort "
|
||||
+ "einzugeben:\n"
|
||||
+ "\n"
|
||||
+ "${link}"
|
||||
+ "\n\n"
|
||||
+ "${full_link}\n"
|
||||
+ "\n"
|
||||
+ "oder rufen Sie\n"
|
||||
+ "\n"
|
||||
+ "${link}\n"
|
||||
+ "\n"
|
||||
+ "auf und geben Sie Ihre E-Mail-adresse und der folgende Token"
|
||||
+ "ein:\n"
|
||||
+ "\n"
|
||||
+ "${token}\n"
|
||||
+ "\n"
|
||||
+ "Bitte beachten Sie, dass den den Prozess bis zu folgenden "
|
||||
+ "Zeitpunkt abschließen müsssen: ${expires_date}");
|
||||
|
||||
|
|
@ -122,8 +156,16 @@ public final class EmailTemplates {
|
|||
Locale.ENGLISH,
|
||||
"Please follow the following link to enable your new account:\n"
|
||||
+ "\n"
|
||||
+ "${link}"
|
||||
+ "\n\n"
|
||||
+ "${full_link}\n"
|
||||
+ "\n"
|
||||
+ "or got to\n"
|
||||
+ "\n"
|
||||
+ "${link}\n"
|
||||
+ "\n"
|
||||
+ "and enter your email address and the following token:\n"
|
||||
+ "\n"
|
||||
+ "${token}\n"
|
||||
+ "\n"
|
||||
+ "Please be aware that you must activate your account before "
|
||||
+ "${expires_date}.");
|
||||
accountActivationMail.getValue().addValue(
|
||||
|
|
@ -131,9 +173,18 @@ public final class EmailTemplates {
|
|||
"Bitte folgen Sie den folgendem Link, um ihr Benutzerkonto zu "
|
||||
+ "aktivieren:\n"
|
||||
+ "\n"
|
||||
+ "${link}"
|
||||
+ "\n\n"
|
||||
+ "Bitte beachten Sie, dass Sie ihr Benutzerkonto spätestens"
|
||||
+ "${full_link}\n"
|
||||
+ "\n"
|
||||
+ "oder rufen Sie\n"
|
||||
+ "\n"
|
||||
+ "${link}\n"
|
||||
+ "\n"
|
||||
+ "auf und geben Sie Ihre E-Mail-Adresse und das folgende Token "
|
||||
+ "ein:\n"
|
||||
+ "\n"
|
||||
+ "${token}\n"
|
||||
+ "\n"
|
||||
+ "Bitte beachten Sie, dass Sie ihr Benutzerkonto spätestens "
|
||||
+ "bis zu folgendem Zeitpunkt aktivieren müssen: ${expires_date}");
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ package org.libreccm.security;
|
|||
|
||||
import static org.libreccm.core.CoreConstants.*;
|
||||
|
||||
import org.libreccm.core.DefaultEntityGraph;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
|
@ -27,8 +29,12 @@ import java.util.Objects;
|
|||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.NamedAttributeNode;
|
||||
import javax.persistence.NamedEntityGraph;
|
||||
import javax.persistence.NamedEntityGraphs;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.NamedSubgraph;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
|
@ -53,6 +59,29 @@ import javax.xml.bind.annotation.XmlRootElement;
|
|||
query = "SELECT g FROM Group g "
|
||||
+ "WHERE LOWER(g.name) LIKE '%:name%'")
|
||||
})
|
||||
@NamedEntityGraphs({
|
||||
@NamedEntityGraph(
|
||||
name = "Group.withMembersAndRoleMemberships",
|
||||
attributeNodes = {
|
||||
@NamedAttributeNode(
|
||||
value = "memberships"),
|
||||
@NamedAttributeNode(
|
||||
value = "roleMemberships",
|
||||
subgraph = "role")},
|
||||
subgraphs = {
|
||||
@NamedSubgraph(
|
||||
name = "role",
|
||||
attributeNodes = {
|
||||
@NamedAttributeNode(value = "role",
|
||||
subgraph = "permissions")
|
||||
}),
|
||||
@NamedSubgraph(
|
||||
name = "permissions",
|
||||
attributeNodes = {
|
||||
@NamedAttributeNode(value = "permissions")})
|
||||
})
|
||||
})
|
||||
@DefaultEntityGraph("Group.withMembersAndRoleMemberships")
|
||||
@XmlRootElement(name = "user-group", namespace = CORE_XML_NS)
|
||||
public class Group extends Party implements Serializable {
|
||||
|
||||
|
|
@ -119,8 +148,6 @@ public class Group extends Party implements Serializable {
|
|||
return super.hashCode();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString(final String data) {
|
||||
return super.toString(String.format(", members = { %s }%s",
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public class GroupManager {
|
|||
* @param user The user to add to a group.
|
||||
* @param group The group to which the user is added.
|
||||
*/
|
||||
@Transactional(Transactional.TxType.REQUIRED)
|
||||
public void addMemberToGroup(final User user, final Group group) {
|
||||
if (user == null) {
|
||||
throw new IllegalArgumentException(
|
||||
|
|
|
|||
|
|
@ -205,7 +205,11 @@ public class OneTimeAuthManager {
|
|||
throw new IllegalArgumentException("Can't invalidate a token null");
|
||||
}
|
||||
|
||||
entityManager.remove(token);
|
||||
//Ensure that we have a none detached instance
|
||||
final OneTimeAuthToken delete = entityManager.find(
|
||||
OneTimeAuthToken.class, token.getTokenId());
|
||||
|
||||
entityManager.remove(delete);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,10 @@ public class OneTimeAuthTokenCleaner {
|
|||
// final long interval = 60 * 60 * 1000;
|
||||
|
||||
LOGGER.debug("Creating interval for {} s.", interval / 1000);
|
||||
timerService.createIntervalTimer(interval, interval, new TimerConfig());
|
||||
LOGGER.debug("First run cleaning process will be executed in 5 min.");
|
||||
timerService.createIntervalTimer(5 * 60 * 1000,
|
||||
interval,
|
||||
new TimerConfig());
|
||||
}
|
||||
|
||||
@Timeout
|
||||
|
|
@ -88,7 +91,7 @@ public class OneTimeAuthTokenCleaner {
|
|||
LOGGER.debug("Found {} one time auth tokens.", tokens.size());
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
|
||||
LOGGER.debug("Current time is: {}", now);
|
||||
LOGGER.debug("Current time (UTC) is: {}", now);
|
||||
tokens.forEach(t -> {
|
||||
if (oneTimeAuthManager.isValid(t)) {
|
||||
LOGGER.debug("OneTimeAuthToken with id {} is still valid. "
|
||||
|
|
@ -97,7 +100,7 @@ public class OneTimeAuthTokenCleaner {
|
|||
t.getValidUntil());
|
||||
} else {
|
||||
LOGGER.debug("OneTimeAuthToken with id {} is invalid. "
|
||||
+ "Expires at {}.",
|
||||
+ "Expires at {} UTC.",
|
||||
t.getTokenId(),
|
||||
t.getValidUntil());
|
||||
}
|
||||
|
|
@ -107,7 +110,7 @@ public class OneTimeAuthTokenCleaner {
|
|||
tokens.stream()
|
||||
.filter((token) -> (!oneTimeAuthManager.isValid(token)))
|
||||
.forEach((token) -> {
|
||||
LOGGER.debug("Token with id {} expired at {}. "
|
||||
LOGGER.debug("Token with id {} expired at {} UTC. "
|
||||
+ "Invalidating token.",
|
||||
token.getTokenId(), token.getValidUntil());
|
||||
oneTimeAuthManager.invalidate(token);
|
||||
|
|
|
|||
|
|
@ -74,7 +74,13 @@ import javax.xml.bind.annotation.XmlTransient;
|
|||
+ "LOWER(u.name) LIKE CONCAT(LOWER(:term), '%') "
|
||||
+ "OR LOWER(u.givenName) LIKE CONCAT(LOWER(:term), '%') "
|
||||
+ "OR LOWER(u.familyName) LIKE CONCAT(LOWER(:term), '%') "
|
||||
+ "OR LOWER(u.primaryEmailAddress.address) LIKE CONCAT('%', LOWER(:term), '%')")
|
||||
+ "OR LOWER(u.primaryEmailAddress.address) LIKE CONCAT('%', LOWER(:term), '%')"),
|
||||
@NamedQuery(
|
||||
name = "User.findAllOrderedByUsername",
|
||||
query = "SELECT u FROM User u ORDER BY u.name, "
|
||||
+ " u.familyName, "
|
||||
+ " u.givenName, "
|
||||
+ " u.primaryEmailAddress.address")
|
||||
})
|
||||
@NamedEntityGraphs({
|
||||
@NamedEntityGraph(
|
||||
|
|
@ -98,7 +104,6 @@ import javax.xml.bind.annotation.XmlTransient;
|
|||
@NamedAttributeNode(value = "permissions")}
|
||||
)
|
||||
})
|
||||
|
||||
})
|
||||
@DefaultEntityGraph("User.withGroupAndRoleMemberships")
|
||||
@XmlRootElement(name = "user", namespace = CORE_XML_NS)
|
||||
|
|
|
|||
|
|
@ -53,12 +53,13 @@ public class UserManager {
|
|||
* Creates a new user and saves the user in the database. The method also
|
||||
* creates the password hash.
|
||||
*
|
||||
* @param givenName The given name of the new user.
|
||||
* @param familyName The family name of the new user.
|
||||
* @param name The name of the new user.
|
||||
* @param givenName The given name of the new user.
|
||||
* @param familyName The family name of the new user.
|
||||
* @param name The name of the new user.
|
||||
* @param emailAddress The email address of the new user.
|
||||
* @param password The password of the new user. The password is hashed
|
||||
* using the algorithm configured in the {@link SecurityConfig}.
|
||||
* @param password The password of the new user. The password is hashed
|
||||
* using the algorithm configured in the
|
||||
* {@link SecurityConfig}.
|
||||
*
|
||||
* @return The new user.
|
||||
*/
|
||||
|
|
@ -77,7 +78,11 @@ public class UserManager {
|
|||
email.setAddress(emailAddress);
|
||||
user.setPrimaryEmailAddress(email);
|
||||
email.setVerified(true);
|
||||
user.setPassword(hashPassword(password));
|
||||
if (password == null) {
|
||||
user.setPassword(null);
|
||||
} else {
|
||||
user.setPassword(hashPassword(password));
|
||||
}
|
||||
|
||||
userRepository.save(user);
|
||||
|
||||
|
|
@ -90,9 +95,9 @@ public class UserManager {
|
|||
* the user can't login or that the authentication for this user is done by
|
||||
* an external system.
|
||||
*
|
||||
* @param user The user which password should be upgraded.
|
||||
* @param user The user which password should be upgraded.
|
||||
* @param newPassword The new password. The password is hashed using the
|
||||
* algorithm configured in the {@link SecurityConfig}.
|
||||
* algorithm configured in the {@link SecurityConfig}.
|
||||
*/
|
||||
public void updatePassword(@NotNull final User user,
|
||||
final String newPassword) {
|
||||
|
|
@ -105,11 +110,11 @@ public class UserManager {
|
|||
* Verifies the password of a user. This can be useful if you want to verify
|
||||
* the password of a user already logged in again.
|
||||
*
|
||||
* @param user The user against which the password is verified.
|
||||
* @param user The user against which the password is verified.
|
||||
* @param password The password to verify.
|
||||
*
|
||||
* @return {@code true} if the provided passworda matches the password from
|
||||
* the database, {@code false} otherwise.
|
||||
* the database, {@code false} otherwise.
|
||||
*/
|
||||
public boolean verifyPassword(final User user, final String password) {
|
||||
//Create a new Shiro PasswordMatcher instance
|
||||
|
|
@ -142,9 +147,10 @@ public class UserManager {
|
|||
//We want to use the Shiro1 format for storing the password. This
|
||||
//format includes the algorithm used, the salt and the number of
|
||||
//iterations used and the hashed password in special formatted string.
|
||||
final HashFormatFactory hashFormatFactory = new DefaultHashFormatFactory();
|
||||
final HashFormatFactory hashFormatFactory
|
||||
= new DefaultHashFormatFactory();
|
||||
final HashFormat hashFormat = hashFormatFactory.getInstance(
|
||||
Shiro1CryptFormat.class.getName());
|
||||
Shiro1CryptFormat.class.getName());
|
||||
|
||||
return hashFormat.format(hash);
|
||||
}
|
||||
|
|
@ -160,11 +166,13 @@ public class UserManager {
|
|||
|
||||
if (generatedSaltSize % 8 != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Salt length is not a multipe of 8");
|
||||
"Salt length is not a multipe of 8");
|
||||
}
|
||||
|
||||
final SecureRandomNumberGenerator generator = new SecureRandomNumberGenerator();
|
||||
final SecureRandomNumberGenerator generator
|
||||
= new SecureRandomNumberGenerator();
|
||||
final int byteSize = generatedSaltSize / 8; //generatedSaltSize is in *bits* - convert to byte size:
|
||||
return generator.nextBytes(byteSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,4 +153,10 @@ public class UserRepository extends AbstractEntityRepository<Long, User> {
|
|||
return query.getResultList();
|
||||
}
|
||||
|
||||
public List<User> findAllOrderdByUsername() {
|
||||
final TypedQuery<User> query = getEntityManager().createNamedQuery(
|
||||
"User.findAllOrderedByUsername", User.class);
|
||||
return query.getResultList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,3 +228,12 @@ ui.admin.new_user_form.error.username_already_in_use=The provided user name is a
|
|||
ui.admin.new_user_form.error.email_already_in_use=The provided email address is already assigned with an user account.
|
||||
ui.admin.new_user_form.error.password_do_not_match=Passwords do not match.
|
||||
ui.admin.new_user_form.error.failed_to_send_password=Failed to send password to new user.
|
||||
ui.admin.new_user_form.password_options.set_password=Set password
|
||||
ui.admin.user_details.groups=Groups
|
||||
ui.admin.user.groups.edit=Edit
|
||||
ui.admin.user.roles=Directly assigned Roles
|
||||
ui.admin.user.roles.edit=Edit
|
||||
ui.admin.user.all_roles=All roles
|
||||
ui.admin.user.groups=Groups
|
||||
ui.admin.user.edit_group_memberships=Edit group memberships for user {0}
|
||||
ui.admin.user.edit_group_memberships.back_to_user_details=Back to user details
|
||||
|
|
|
|||
|
|
@ -228,3 +228,12 @@ ui.admin.new_user_form.error.username_already_in_use=Der angegebene Benutzername
|
|||
ui.admin.new_user_form.error.email_already_in_use=Die angegebene E-Mail-Adresse ist bereits mit einem Benutzerkonto verbunden.
|
||||
ui.admin.new_user_form.error.password_do_not_match=Die eingegebenen Passw\u00f6rter stimmen nicht \u00fcberein.
|
||||
ui.admin.new_user_form.error.failed_to_send_password=Fehler beim Senden des Passworts an den neuen Benutzer.
|
||||
ui.admin.new_user_form.password_options.set_password=Passwert setzen
|
||||
ui.admin.user_details.groups=Gruppen
|
||||
ui.admin.user.groups.edit=Bearbeiten
|
||||
ui.admin.user.roles=Zugewiesene Rollen
|
||||
ui.admin.user.roles.edit=Bearbeiten
|
||||
ui.admin.user.all_roles=Alle Rollen
|
||||
ui.admin.user.groups=Gruppen
|
||||
ui.admin.user.edit_group_memberships=Gruppen f\u00fcr Benutzer {0} bearbeiten
|
||||
ui.admin.user.edit_group_memberships.back_to_user_details=Zur\u00fcck zu den Eigenschaften des Benutzers
|
||||
|
|
|
|||
|
|
@ -201,3 +201,12 @@ ui.admin.new_user_form.error.username_already_in_use=The provided user name is a
|
|||
ui.admin.new_user_form.error.email_already_in_use=The provided email address is already assigned with an user account.
|
||||
ui.admin.new_user_form.error.password_do_not_match=Passwords do not match.
|
||||
ui.admin.new_user_form.error.failed_to_send_password=Failed to send password to new user.
|
||||
ui.admin.new_user_form.password_options.set_password=Set password
|
||||
ui.admin.user_details.groups=Groups
|
||||
ui.admin.user.groups.edit=Edit
|
||||
ui.admin.user.roles=Directly assigned Roles
|
||||
ui.admin.user.roles.edit=Edit
|
||||
ui.admin.user.all_roles=All roles
|
||||
ui.admin.user.groups=Groups
|
||||
ui.admin.user.edit_group_memberships=Edit group memberships for user {0}
|
||||
ui.admin.user.edit_group_memberships.back_to_user_details=Back to user details
|
||||
|
|
|
|||
|
|
@ -192,3 +192,12 @@ ui.admin.new_user_form.error.username_already_in_use=The provided user name is a
|
|||
ui.admin.new_user_form.error.email_already_in_use=The provided email address is already assigned with an user account.
|
||||
ui.admin.new_user_form.error.password_do_not_match=Passwords do not match.
|
||||
ui.admin.new_user_form.error.failed_to_send_password=Failed to send password to new user.
|
||||
ui.admin.new_user_form.password_options.set_password=Set password
|
||||
ui.admin.user_details.groups=Groups
|
||||
ui.admin.user.groups.edit=Edit
|
||||
ui.admin.user.roles=Directly assigned Roles
|
||||
ui.admin.user.roles.edit=Edit
|
||||
ui.admin.user.all_roles=All roles
|
||||
ui.admin.user.groups=Groups
|
||||
ui.admin.user.edit_group_memberships=Edit group memberships for user {0}
|
||||
ui.admin.user.edit_group_memberships.back_to_user_details=Back to user details
|
||||
|
|
|
|||
|
|
@ -101,3 +101,9 @@ login.form.reset_password.auth_token.hint=Please provide the one time authentica
|
|||
login.form.account_activation.success=Your account has been activated.
|
||||
login.form.new_user.error.passwords_do_not_match=Password and confirmation do not match.
|
||||
login.form_new_user.error.creating_challenge_failed=Failed to send registration confirmation. Please contact the administrator.
|
||||
login.form.account_activation.success.login=Click here to login.
|
||||
login.form.reset_password.error=Error while resetting password.
|
||||
login.form.reset_password.error.password_mismatch=Password and confirmation do not match.
|
||||
login.form.new_user.error.username_already_in_use=The provided user name is already in use. Please choose another user name.
|
||||
login.form.new_user.error.email_already_registered=There is an account already registered for the provided email address.
|
||||
login.form.reset_password.scucess.login=Click here to login
|
||||
|
|
|
|||
|
|
@ -101,3 +101,9 @@ login.form.reset_password.auth_token.hint=Bitte geben Sie das Einmalpasswort, da
|
|||
login.form.account_activation.success=Ihr Benutzerkonto wurde aktiviert.
|
||||
login.form.new_user.error.passwords_do_not_match=Passwort und Best\u00e4tigung sind nicht gleich
|
||||
login.form_new_user.error.creating_challenge_failed=Fehler beim Senden der Anmeldebest\u00e4tigung. Bitte kontaktieren Sie den Systemadministrator.
|
||||
login.form.account_activation.success.login=Klicken Sie hier, um sich anzumelden.
|
||||
login.form.reset_password.error=Beim \u00c4ndern des Passwortes ist ein Fehler aufgetreten.
|
||||
login.form.reset_password.error.password_mismatch=Passwort und Best\u00e4tigung stimmen nicht \u00fcberein.
|
||||
login.form.new_user.error.username_already_in_use=Der eingegeben Benutzername ist bereits vergeben. Bitte w\u00e4hlen Sie einen anderen Benutzernamen.
|
||||
login.form.new_user.error.email_already_registered=Es gibt bereits ein Benutzerkonto f\u00fcr die eingebene E-Mail-Adresse
|
||||
login.form.reset_password.scucess.login=Zur Anmeldung
|
||||
|
|
|
|||
|
|
@ -101,3 +101,9 @@ login.form.reset_password.auth_token.hint=Please provide the one time authentica
|
|||
login.form.account_activation.success=Your account has been activated.
|
||||
login.form.new_user.error.passwords_do_not_match=Password and confirmation do not match.
|
||||
login.form_new_user.error.creating_challenge_failed=Failed to send registration confirmation. Please contact the administrator.
|
||||
login.form.account_activation.success.login=Click here to login.
|
||||
login.form.reset_password.error=Error while resetting password.
|
||||
login.form.reset_password.error.password_mismatch=Password and confirmation do not match.
|
||||
login.form.new_user.error.username_already_in_use=The provided user name is already in use. Please choose another user name.
|
||||
login.form.new_user.error.email_already_registered=There is an account already registered for the provided email address.
|
||||
login.form.reset_password.scucess.login=Click here to login
|
||||
|
|
|
|||
|
|
@ -101,3 +101,9 @@ login.form.reset_password.auth_token.hint=Please provide the one time authentica
|
|||
login.form.account_activation.success=Your account has been activated.
|
||||
login.form.new_user.error.passwords_do_not_match=Password and confirmation do not match.
|
||||
login.form_new_user.error.creating_challenge_failed=Failed to send registration confirmation. Please contact the administrator.
|
||||
login.form.account_activation.success.login=Click here to login.
|
||||
login.form.reset_password.error=Error while resetting password.
|
||||
login.form.reset_password.error.password_mismatch=Password and confirmation do not match.
|
||||
login.form.new_user.error.username_already_in_use=The provided user name is already in use. Please choose another user name.
|
||||
login.form.new_user.error.email_already_registered=There is an account already registered for the provided email address.
|
||||
login.form.reset_password.scucess.login=Click here to login
|
||||
|
|
|
|||
Loading…
Reference in New Issue