/**
* (C) Copyright 2013 Jabylon (http://www.jabylon.org) and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.jabylon.rest.ui.wicket.config.sections.security;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.inject.Inject;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.RefreshingView;
import org.apache.wicket.markup.repeater.util.ModelIteratorAdapter;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CommitException;
import org.eclipse.emf.common.util.EList;
import org.jabylon.common.resolver.URIConstants;
import org.jabylon.common.resolver.URIResolver;
import org.jabylon.properties.Project;
import org.jabylon.properties.util.EObjectNameComparator;
import org.jabylon.rest.ui.model.EObjectModel;
import org.jabylon.rest.ui.security.RestrictedComponent;
import org.jabylon.rest.ui.wicket.BasicPanel;
import org.jabylon.rest.ui.wicket.components.UserImagePanel;
import org.jabylon.rest.ui.wicket.config.AbstractConfigSection;
import org.jabylon.security.CommonPermissions;
import org.jabylon.users.Permission;
import org.jabylon.users.Role;
import org.jabylon.users.User;
import org.jabylon.users.UserManagement;
import org.jabylon.users.UsersFactory;
import org.jabylon.users.UsersPackage;
import org.osgi.service.prefs.Preferences;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProjectPermissionsConfigSection extends BasicPanel<Project> implements RestrictedComponent {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(ProjectPermissionsConfigSection.class);
@Inject
private URIResolver resolver;
private IModel<UserManagement> userManagement;
private List<UserPermission> userPermissions;
private List<IModel<User>> assignableUsers;
private List<RolePermission> rolePermissions;
private List<IModel<Role>> assignableRoles;
public ProjectPermissionsConfigSection(String id, IModel<Project> model, PageParameters params) {
super(id, model, params);
}
@Override
protected void preConstruct() {
Object resolved = resolver.resolve(URIConstants.SECURITY_URI_PREFIX);
if (resolved instanceof UserManagement) {
UserManagement management = (UserManagement) resolved;
userManagement = new EObjectModel<UserManagement>(management);
assignableUsers = new ArrayList<IModel<User>>();
userPermissions = createUserPermissions(getModel().getObject(), userManagement.getObject(), assignableUsers);
assignableRoles = new ArrayList<IModel<Role>>();
rolePermissions = createRolePermissions(getModel().getObject(), userManagement.getObject(), assignableRoles);
}
}
private List<UserPermission> createUserPermissions(Project project, UserManagement userManagement, List<IModel<User>> assignableUsers) {
EList<User> users = userManagement.getUsers();
Set<User> sortedUsers = new TreeSet<User>(new EObjectNameComparator<User>());
sortedUsers.addAll(users);
List<UserPermission> result = new ArrayList<UserPermission>();
for (User user : sortedUsers) {
boolean filterUser = user.hasPermission(CommonPermissions.WILDCARD);
PermissionSetting highestSetting = PermissionSetting.NONE;
EList<Permission> allPermissions = user.getPermissions();
for (Permission permission : allPermissions) {
String permissionName = permission.getName();
if (permissionName.startsWith(CommonPermissions.constructPermission(CommonPermissions.PROJECT, project.getName()))) {
// user already has permissions
if (permissionName.endsWith(CommonPermissions.ACTION_EDIT))
highestSetting = PermissionSetting.values()[Math.max(highestSetting.ordinal(),PermissionSetting.EDIT.ordinal())];
if (permissionName.endsWith(CommonPermissions.ACTION_SUGGEST))
highestSetting = PermissionSetting.values()[Math.max(highestSetting.ordinal(),PermissionSetting.SUGGEST.ordinal())];
else if (permissionName.endsWith(CommonPermissions.ACTION_VIEW))
highestSetting = PermissionSetting.values()[Math.max(highestSetting.ordinal(),PermissionSetting.READ.ordinal())];
else
highestSetting = PermissionSetting.CONFIG;
filterUser = true;
}
}
if(highestSetting!=PermissionSetting.NONE) {
UserPermission userPermission = new UserPermission(new EObjectModel<User>(user), highestSetting);
result.add(userPermission);
}
if (!filterUser)
assignableUsers.add(new EObjectModel<User>(user));
}
Collections.sort(result);
return result;
}
private List<RolePermission> createRolePermissions(Project project, UserManagement userManagement, List<IModel<Role>> assignableRoles) {
EList<Role> roles = userManagement.getRoles();
List<RolePermission> result = new ArrayList<RolePermission>();
Set<Role> sortedRoles = new TreeSet<Role>(new EObjectNameComparator<Role>());
sortedRoles.addAll(roles);
for (Role role : sortedRoles) {
boolean filterUser = hasPermission(role,CommonPermissions.WILDCARD);
PermissionSetting highestSetting = PermissionSetting.NONE;
EList<Permission> allPermissions = role.getPermissions();
for (Permission permission : allPermissions) {
String permissionName = permission.getName();
if (permissionName.startsWith(CommonPermissions.constructPermission(CommonPermissions.PROJECT, project.getName()))) {
// user already has permissions
if (permissionName.endsWith(CommonPermissions.ACTION_EDIT))
highestSetting = PermissionSetting.values()[Math.max(highestSetting.ordinal(),PermissionSetting.EDIT.ordinal())];
else if (permissionName.endsWith(CommonPermissions.ACTION_SUGGEST))
highestSetting = PermissionSetting.values()[Math.max(highestSetting.ordinal(),PermissionSetting.SUGGEST.ordinal())];
else if (permissionName.endsWith(CommonPermissions.ACTION_VIEW))
highestSetting = PermissionSetting.values()[Math.max(highestSetting.ordinal(),PermissionSetting.READ.ordinal())];
else
highestSetting = PermissionSetting.CONFIG;
filterUser = true;
}
}
if(highestSetting!=PermissionSetting.NONE) {
RolePermission rolePermission = new RolePermission(new EObjectModel<Role>(role), highestSetting);
result.add(rolePermission);
}
if (!filterUser)
assignableRoles.add(new EObjectModel<Role>(role));
}
Collections.sort(result);
return result;
}
private boolean hasPermission(Role role, String permissionName) {
EList<Permission> allPermissions = role.getAllPermissions();
for (Permission permission : allPermissions) {
if(permission.getName().equals(permissionName))
return true;
}
return false;
}
@Override
protected void onDetach() {
if(userManagement!=null)
userManagement.detach();
if(assignableUsers!=null)
{
for (IModel<User> user : assignableUsers) {
user.detach();
}
}
if(assignableRoles!=null)
{
for (IModel<Role> role : assignableRoles) {
role.detach();
}
}
super.onDetach();
}
@Override
protected void construct() {
setOutputMarkupId(true);
RefreshingView<RolePermission> roleDataView = new RefreshingView<RolePermission>("rolePermissionRow") {
private static final long serialVersionUID = 1L;
@Override
protected Iterator<IModel<RolePermission>> getItemModels() {
ModelIteratorAdapter<RolePermission> adapter = new ModelIteratorAdapter<RolePermission>(rolePermissions.iterator()) {
@Override
protected IModel<RolePermission> model(RolePermission object) {
return new CompoundPropertyModel<RolePermission>(object);
}
};
return adapter;
}
@Override
protected void populateItem(Item<RolePermission> item) {
item.add(new Label("registrant", item.getModelObject().getRegistrant().getObject().getName()));
final DropDownChoice<PermissionSetting> permissionChoice = new DropDownChoice<PermissionSetting>("permission", Arrays.asList(PermissionSetting
.values()), new PermissionSettingRenderer());
permissionChoice.setOutputMarkupId(true);
permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
protected void onUpdate(AjaxRequestTarget target) {
target.add(permissionChoice);
}
});
item.add(permissionChoice);
}
};
add(roleDataView);
addAddRolePermissionForm(assignableRoles);
RefreshingView<UserPermission> dataView = new RefreshingView<UserPermission>("userPermissionRow") {
private static final long serialVersionUID = 1L;
@Override
protected Iterator<IModel<UserPermission>> getItemModels() {
ModelIteratorAdapter<UserPermission> adapter = new ModelIteratorAdapter<UserPermission>(userPermissions.iterator()) {
@Override
protected IModel<UserPermission> model(UserPermission object) {
return new CompoundPropertyModel<UserPermission>(object);
}
};
return adapter;
}
@Override
protected void populateItem(Item<UserPermission> item) {
// item.add(new Label("registrant", item.getModelObject().getRegistrant().getObject().getName()));
item.add(new UserImagePanel("registrant", item.getModelObject().getRegistrant()));
final DropDownChoice<PermissionSetting> permissionChoice = new DropDownChoice<PermissionSetting>("permission", Arrays.asList(PermissionSetting
.values()), new PermissionSettingRenderer());
permissionChoice.setOutputMarkupId(true);
permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
protected void onUpdate(AjaxRequestTarget target) {
target.add(permissionChoice);
}
});
item.add(permissionChoice);
}
};
add(dataView);
addAddPermissionForm(assignableUsers);
}
protected void commit() {
UserManagement management = (UserManagement) resolver.resolveWithTransaction(userManagement.getObject().cdoID());
for (UserPermission permission : userPermissions) {
User user = permission.getRegistrant().getObject();
user = management.cdoView().getObject(user);
/*
* Issue #101
* first delete all permission in case they have been reduced
* http://github.com/jutzig/jabylon/issues/issue/101
*/
String prefix = CommonPermissions.constructPermission(CommonPermissions.PROJECT, getModel().getObject().getName());
EList<Permission> userPermissions = user.getPermissions();
Iterator<Permission> it = userPermissions.iterator();
while (it.hasNext()) {
if (it.next().getName().startsWith(prefix))
it.remove();
}
PermissionSetting permSetting = permission.getPermission();
if(permSetting!=PermissionSetting.NONE) {
Permission perm = getOrCreatePermission(
CommonPermissions.constructPermissionName(CommonPermissions.PROJECT, getModel().getObject().getName(), permSetting.getPermissionName()),
management);
user.getPermissions().add(perm);
}
}
//now the roles
for (RolePermission permission : rolePermissions) {
Role role = permission.getRegistrant().getObject();
role = management.cdoView().getObject(role);
/*
* Issue #101
* first delete all permission in case they have been reduced
* http://github.com/jutzig/jabylon/issues/issue/101
*/
String prefix = CommonPermissions.constructPermission(CommonPermissions.PROJECT, getModel().getObject().getName());
EList<Permission> userPermissions = role.getPermissions();
Iterator<Permission> it = userPermissions.iterator();
while (it.hasNext()) {
if (it.next().getName().startsWith(prefix))
it.remove();
}
PermissionSetting permSetting = permission.getPermission();
if(permSetting!=PermissionSetting.NONE) {
Permission perm = getOrCreatePermission(
CommonPermissions.constructPermissionName(CommonPermissions.PROJECT, getModel().getObject().getName(), permSetting.getPermissionName()),
management);
role.getPermissions().add(perm);
}
}
CDOTransaction transaction = (CDOTransaction) management.cdoView();
try {
transaction.commit();
} catch (CommitException e) {
logger.error("Failed to commit new permission settings",e);
}
}
private Permission getOrCreatePermission(String permissionName, UserManagement management) {
Permission permission = management.findPermissionByName(permissionName);
if(permission==null) {
permission = UsersFactory.eINSTANCE.createPermission();
management.getPermissions().add(permission);
permission.setName(permissionName);
}
return permission;
}
public static class ProjectPermissionsConfigSectionContributor extends AbstractConfigSection<Project> {
private static final long serialVersionUID = 1L;
private ProjectPermissionsConfigSection projectPermissionsConfigSection;
@Override
public WebMarkupContainer doCreateContents(String id, IModel<Project> input, Preferences config) {
projectPermissionsConfigSection = new ProjectPermissionsConfigSection(id, input, new PageParameters());
return projectPermissionsConfigSection;
}
@Override
public void commit(IModel<Project> input, Preferences config) {
projectPermissionsConfigSection.commit();
}
@Override
public String getRequiredPermission() {
String projectName = null;
if (getDomainObject() != null)
projectName = getDomainObject().getName();
return CommonPermissions.constructPermissionName(CommonPermissions.PROJECT, projectName, CommonPermissions.ACTION_CONFIG);
}
}
private void addAddPermissionForm(final List<IModel<User>> assignableUsers) {
/*
* Add permission form
*/
CompoundPropertyModel<UserPermission> addPermissionModel = new CompoundPropertyModel<UserPermission>(new UserPermission());
Form<UserPermission> addPermissionForm = new Form<UserPermission>("addUserPermissionForm", addPermissionModel);
DropDownChoice<IModel<User>> registrantChoice = new DropDownChoice<IModel<User>>("registrant", assignableUsers, new UserRenderer());
addPermissionForm.add(registrantChoice);
addPermissionForm.add(new DropDownChoice<PermissionSetting>("permission", Arrays.asList(PermissionSetting.values()), new PermissionSettingRenderer()));
AjaxButton button = new AjaxButton("addPermissionButton", addPermissionForm) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
UserPermission userPermission = (UserPermission) form.getModel().getObject();
if (userPermission.getPermission() == null) {
return;
}
UserPermission copy = new UserPermission(userPermission.getRegistrant(), userPermission.getPermission());
userPermissions.add(copy);
Collections.sort(userPermissions);
// remove registrant from available choices
assignableUsers.remove(userPermission.getRegistrant());
// force the panel to refresh
target.add(ProjectPermissionsConfigSection.this);
}
};
addPermissionForm.add(button);
// only show add permission form if we have a registrant choice
if (assignableUsers.isEmpty())
addPermissionForm.setVisible(false);
else
registrantChoice.setDefaultModelObject(assignableUsers.get(0));
add(addPermissionForm);
}
private void addAddRolePermissionForm(final List<IModel<Role>> assignableRoles) {
/*
* Add permission form
*/
CompoundPropertyModel<RolePermission> addPermissionModel = new CompoundPropertyModel<RolePermission>(new RolePermission());
Form<RolePermission> addPermissionForm = new Form<RolePermission>("addRolePermissionForm", addPermissionModel);
DropDownChoice<IModel<Role>> registrantChoice = new DropDownChoice<IModel<Role>>("registrant", assignableRoles, new RoleRenderer());
addPermissionForm.add(registrantChoice);
addPermissionForm.add(new DropDownChoice<PermissionSetting>("permission", Arrays.asList(PermissionSetting.values()), new PermissionSettingRenderer()));
AjaxButton button = new AjaxButton("addPermissionButton", addPermissionForm) {
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
RolePermission rolePermission = (RolePermission) form.getModel().getObject();
if (rolePermission.getPermission() == null) {
return;
}
RolePermission copy = new RolePermission(rolePermission.getRegistrant(), rolePermission.getPermission());
rolePermissions.add(copy);
Collections.sort(rolePermissions);
// remove registrant from available choices
assignableRoles.remove(rolePermission.getRegistrant());
// force the panel to refresh
target.add(ProjectPermissionsConfigSection.this);
}
};
addPermissionForm.add(button);
// only show add permission form if we have a registrant choice
if (assignableRoles.isEmpty())
addPermissionForm.setVisible(false);
else
registrantChoice.setDefaultModelObject(assignableRoles.get(0));
add(addPermissionForm);
}
@Override
public String getRequiredPermission() {
return CommonPermissions.constructPermissionName(CommonPermissions.PROJECT, getModelObject().getName(), CommonPermissions.ACTION_CONFIG);
}
}
enum PermissionSetting {
NONE(null), READ(CommonPermissions.ACTION_VIEW), SUGGEST(CommonPermissions.ACTION_SUGGEST), EDIT(CommonPermissions.ACTION_EDIT), CONFIG(CommonPermissions.ACTION_CONFIG);
String permissionName;
private PermissionSetting(String permissionName) {
this.permissionName = permissionName;
}
public String getPermissionName() {
return permissionName;
}
}
class PermissionSettingRenderer implements IChoiceRenderer<PermissionSetting> {
private static final long serialVersionUID = 1L;
@Override
public Object getDisplayValue(PermissionSetting object) {
switch (object) {
case NONE:
return "None";
case READ:
return "View";
case SUGGEST:
return "Suggest";
case EDIT:
return "Edit";
case CONFIG:
return "Configure";
}
return "None";
}
@Override
public String getIdValue(PermissionSetting object, int index) {
return object.name();
}
}
class UserRenderer implements IChoiceRenderer<IModel<User>> {
private static final long serialVersionUID = 1L;
@Override
public Object getDisplayValue(IModel<User> object) {
return object.getObject().getName();
}
@Override
public String getIdValue(IModel<User> object, int index) {
return object.getObject().cdoID().toString();
}
}
class RoleRenderer implements IChoiceRenderer<IModel<Role>> {
private static final long serialVersionUID = 1L;
@Override
public Object getDisplayValue(IModel<Role> object) {
return object.getObject()==null ? "" : object.getObject().getName();
}
@Override
public String getIdValue(IModel<Role> object, int index) {
return object.getObject().cdoID().toString();
}
}
class UserPermission implements Serializable, Comparable<UserPermission> {
private static final long serialVersionUID = 1L;
private IModel<User> registrant;
private PermissionSetting permission;
private EObjectNameComparator<User> comparator;
public UserPermission(IModel<User> registrant, PermissionSetting permission) {
super();
this.registrant = registrant;
this.permission = permission;
this.comparator = new EObjectNameComparator<User>(UsersPackage.Literals.USER__DISPLAY_NAME.getName());
}
public UserPermission() {
}
public void setPermission(PermissionSetting permission) {
this.permission = permission;
}
public void setRegistrant(IModel<User> registrant) {
this.registrant = registrant;
}
public IModel<User> getRegistrant() {
return registrant;
}
public PermissionSetting getPermission() {
return permission;
}
@Override
public int compareTo(UserPermission o) {
if (registrant == null)
return -1;
if (o.getRegistrant().getObject().getName() == null)
return 1;
return comparator.compare(registrant.getObject(), o.getRegistrant().getObject());
}
}
class RolePermission implements Serializable, Comparable<RolePermission> {
private static final long serialVersionUID = 1L;
private IModel<Role> registrant;
private PermissionSetting permission;
private EObjectNameComparator<Role> comparator;
public RolePermission(IModel<Role> registrant, PermissionSetting permission) {
super();
this.registrant = registrant;
this.permission = permission;
this.comparator = new EObjectNameComparator<Role>();
}
public RolePermission() {
}
public void setPermission(PermissionSetting permission) {
this.permission = permission;
}
public void setRegistrant(IModel<Role> registrant) {
this.registrant = registrant;
}
public IModel<Role> getRegistrant() {
return registrant;
}
public PermissionSetting getPermission() {
return permission;
}
@Override
public int compareTo(RolePermission o) {
if (registrant == null)
return -1;
if (o.getRegistrant().getObject().getName() == null)
return 1;
return comparator.compare(registrant.getObject(), o.getRegistrant().getObject());
}
}