restructured code

enhanced permission system
This commit is contained in:
2019-01-10 18:08:36 +01:00
parent b552e0b8bc
commit ecedc1872b
25 changed files with 1158 additions and 1033 deletions

View File

@ -17,7 +17,7 @@ package de.muehlencord.shared.account.web;
import de.muehlencord.shared.account.business.account.boundary.AccountPermissions; import de.muehlencord.shared.account.business.account.boundary.AccountPermissions;
import de.muehlencord.shared.account.business.account.entity.AccountException; import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.application.boundary.ApplicationPermissions; import de.muehlencord.shared.account.business.instance.boundary.ApplicationPermissions;
import de.muehlencord.shared.account.business.application.control.ApplicationPermissionControl; import de.muehlencord.shared.account.business.application.control.ApplicationPermissionControl;
import de.muehlencord.shared.account.business.application.control.ApplicationRoleControl; import de.muehlencord.shared.account.business.application.control.ApplicationRoleControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
@ -65,12 +65,11 @@ public class EnsurePermissionsBean {
applicationRoleControl.setupRolePermission(Arrays.asList(ApplicationPermissions.values()), "Admin"); // NOI18N applicationRoleControl.setupRolePermission(Arrays.asList(ApplicationPermissions.values()), "Admin"); // NOI18N
applicationRoleControl.setupRolePermission(Arrays.asList(AccountPermissions.values()), "Admin"); // NOI18N applicationRoleControl.setupRolePermission(Arrays.asList(AccountPermissions.values()), "Admin"); // NOI18N
} catch (AccountException ex) { } catch (AccountException ex) {
LOGGER.error("Error adding permission to Admin role"); LOGGER.error("Error adding permission to Admin role. Reason={}", ex.getMessage());
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.error(ex.toString());
} }
} }
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("All permissions added to Admin role of {}", application.getApplicationName()); LOGGER.debug("All permissions added to Admin role of {}", application.getApplicationName());

View File

@ -15,7 +15,7 @@
*/ */
package de.muehlencord.shared.account.web; package de.muehlencord.shared.account.web;
import de.muehlencord.shared.account.business.application.boundary.ApplicationPermissions; import de.muehlencord.shared.account.business.instance.boundary.ApplicationPermissions;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named; import javax.inject.Named;
@ -30,7 +30,7 @@ import javax.inject.Named;
public class PermissionConstants { public class PermissionConstants {
public String getApplicationListAll() { public String getApplicationListAll() {
return ApplicationPermissions.APP_LISTALL.getName(); return ApplicationPermissions.APP_LIST.getName();
} }
public String getPermissionsCombined() { public String getPermissionsCombined() {
@ -45,4 +45,42 @@ public class PermissionConstants {
+ ApplicationPermissions.ROLE_DELETE.getName(); + ApplicationPermissions.ROLE_DELETE.getName();
} }
public String getAccountsCombined() {
return ApplicationPermissions.ACCOUNT_ADD.getName() + ","
+ ApplicationPermissions.ACCOUNT_DELETE.getName() + ","
+ ApplicationPermissions.ACCOUNT_EDIT.getName() + ","
+ ApplicationPermissions.ACCOUNT_LIST.getName() + ","
+ ApplicationPermissions.ACCOUNT_LOGIN_ADD.getName() + ","
+ ApplicationPermissions.ACCOUNT_LOGIN_DELETE.getName() + ","
+ ApplicationPermissions.ACCOUNT_LOGIN_EDIT.getName();
}
public String getAccountAdd() {
return ApplicationPermissions.ACCOUNT_ADD.getName();
}
public String getAccountDelete() {
return ApplicationPermissions.ACCOUNT_DELETE.getName();
}
public String getAccountEdit() {
return ApplicationPermissions.ACCOUNT_EDIT.getName();
}
public String getAccountList() {
return ApplicationPermissions.ACCOUNT_LIST.getName();
}
public String getAccountLoginAdd() {
return ApplicationPermissions.ACCOUNT_LOGIN_ADD.getName();
}
public String getAccountLoginDelete() {
return ApplicationPermissions.ACCOUNT_LOGIN_DELETE.getName();
}
public String getAccountLoginEdit() {
return ApplicationPermissions.ACCOUNT_LOGIN_EDIT.getName();
}
} }

View File

@ -63,7 +63,7 @@ public class AccountView implements Serializable {
public List<AccountEntity> getAccounts() { public List<AccountEntity> getAccounts() {
if (accountList == null) { if (accountList == null) {
accountList = accountService.getAccounts(showDisabledAccounts); accountList = accountService.getAllAccounts(showDisabledAccounts);
} }
return accountList; return accountList;
} }
@ -136,11 +136,8 @@ public class AccountView implements Serializable {
currentAccountRoles = null; currentAccountRoles = null;
} catch (AccountException ex) { } catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.error(ex.toString());
} }
FacesUtil.addGlobalErrorMessage("Error deleting account", ex.getMessage()); FacesUtil.addGlobalErrorMessage("Error deleting account", ex.getMessage());
} }
} }
@ -158,13 +155,13 @@ public class AccountView implements Serializable {
/* **** account login methods **** */ /* **** account login methods **** */
public boolean validatePasswords(FacesContext context, List<UIInput> components, List<Object> values) { public boolean validatePasswords(FacesContext context, List<UIInput> components, List<Object> values) {
String password = components.get(0).getSubmittedValue().toString(); String currentPassword = components.get(0).getSubmittedValue().toString();
String passwordRepeat = components.get(1).getSubmittedValue().toString(); String currentPasswordRepeat = components.get(1).getSubmittedValue().toString();
if ((password == null) || (passwordRepeat == null)) { if ((currentPassword == null) || (currentPasswordRepeat == null)) {
return false; return false;
} }
boolean returnValue = password.equals(passwordRepeat); boolean returnValue = currentPassword.equals(currentPasswordRepeat);
return returnValue; return returnValue;
} }

View File

@ -1,6 +1,6 @@
package de.muehlencord.shared.account.web.presentation; package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.application.boundary.ApplicationService; import de.muehlencord.shared.account.business.application.control.ApplicationControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.util.AccountSecurityException; import de.muehlencord.shared.account.util.AccountSecurityException;
import de.muehlencord.shared.jeeutil.FacesUtil; import de.muehlencord.shared.jeeutil.FacesUtil;
@ -10,9 +10,9 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped; import javax.enterprise.context.SessionScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -28,7 +28,10 @@ public class ApplicationView implements Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationView.class); private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationView.class);
@Inject @Inject
ApplicationService applicationService; ApplicationControl applicationService;
@Inject
InstanceView instanceView;
@Inject @Inject
Locale locale; Locale locale;
@ -61,12 +64,17 @@ public class ApplicationView implements Serializable {
if (applicationList == null) { if (applicationList == null) {
try { try {
applicationList = applicationService.getAllApplications(); applicationList = applicationService.getAllApplications();
// if no role is assigned to user, ensure that at least current application is added
if ((applicationList == null) || (applicationList.isEmpty())) {
applicationList = new ArrayList<>();
applicationList.add(instanceView.getInstanceApplication());
}
return applicationList; return applicationList;
} catch (AccountSecurityException ex) { } catch (AccountSecurityException ex) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.error(ex.toString());
} }
FacesUtil.addGlobalErrorMessage("Error " + ex.getErrorCode(), ex.getLocalizedMessage(locale)); FacesUtil.addGlobalErrorMessage("Error " + ex.getErrorCode(), ex.getLocalizedMessage(locale));
return new ArrayList<>(); return new ArrayList<>();

View File

@ -1,15 +1,18 @@
package de.muehlencord.shared.account.web.presentation; package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.instance.control.ApplicationController;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.config.boundary.ConfigService; import de.muehlencord.shared.account.business.config.boundary.ConfigService;
import de.muehlencord.shared.account.business.config.entity.ConfigException; import de.muehlencord.shared.account.business.config.entity.ConfigException;
import javax.ejb.EJB;
import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* TODO - move to shared-account and remove from all applications and archetype * TODO - move to shared-account and remove from all applications and archetype
*
* @author Joern Muehlencord <joern at muehlencord.de> * @author Joern Muehlencord <joern at muehlencord.de>
*/ */
@Named(value = "instanceView") @Named(value = "instanceView")
@ -18,9 +21,12 @@ public class InstanceView {
private static final Logger LOGGER = LoggerFactory.getLogger(InstanceView.class); private static final Logger LOGGER = LoggerFactory.getLogger(InstanceView.class);
@EJB @Inject
ConfigService configService; ConfigService configService;
@Inject
ApplicationController applicationController;
public boolean isDevelopmentVersion() { public boolean isDevelopmentVersion() {
String instanceName = getInstanceName(); String instanceName = getInstanceName();
return !instanceName.equals("Production"); return !instanceName.equals("Production");
@ -32,9 +38,7 @@ public class InstanceView {
instanceName = configService.getConfigValue("base.instance"); instanceName = configService.getConfigValue("base.instance");
} catch (ConfigException ex) { } catch (ConfigException ex) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.error(ex.toString());
} }
instanceName = "unknown (" + ex.toString() + ")"; instanceName = "unknown (" + ex.toString() + ")";
} }
@ -44,4 +48,8 @@ public class InstanceView {
return instanceName; return instanceName;
} }
} }
public ApplicationEntity getInstanceApplication() {
return applicationController.getApplication();
}
} }

View File

@ -16,16 +16,16 @@
package de.muehlencord.shared.account.web.presentation; package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.account.entity.AccountException; import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.application.entity.ApplicationPermissionEntity;
import de.muehlencord.shared.account.business.application.control.ApplicationPermissionControl; import de.muehlencord.shared.account.business.application.control.ApplicationPermissionControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationPermissionEntity;
import de.muehlencord.shared.jeeutil.FacesUtil; import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.inject.Named;
import javax.faces.view.ViewScoped; import javax.faces.view.ViewScoped;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -102,9 +102,7 @@ public class PermissionView implements Serializable {
currentPermission = null; currentPermission = null;
} catch (AccountException ex) { } catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.debug(ex.toString());
} }
FacesUtil.addGlobalErrorMessage("Error while deleting permission.", ex.toString()); FacesUtil.addGlobalErrorMessage("Error while deleting permission.", ex.toString());
} }

View File

@ -15,19 +15,19 @@
*/ */
package de.muehlencord.shared.account.web.presentation; package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.application.control.ApplicationRoleControl;
import de.muehlencord.shared.account.business.account.entity.AccountException; import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.application.control.ApplicationRoleControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationPermissionEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationPermissionEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.jeeutil.FacesUtil; import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.faces.view.ViewScoped; import javax.faces.view.ViewScoped;
import javax.inject.Named;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import org.primefaces.event.SelectEvent; import org.primefaces.event.SelectEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -105,10 +105,9 @@ public class RoleView implements Serializable {
currentRolePermissions = null; currentRolePermissions = null;
} catch (AccountException ex) { } catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.debug(ex.toString());
} }
FacesUtil.addGlobalErrorMessage("Error while deleting permission.", ex.toString()); FacesUtil.addGlobalErrorMessage("Error while deleting permission.", ex.toString());
} }
} }
@ -142,11 +141,11 @@ public class RoleView implements Serializable {
try { try {
currentRolePermissions = applicationRoleControl.getRolePermissions(currentRole); currentRolePermissions = applicationRoleControl.getRolePermissions(currentRole);
} catch (AccountException ex) { } catch (AccountException ex) {
LOGGER.error(ex.getMessage());
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.debug(ex.toString());
} }
FacesUtil.addGlobalErrorMessage("Error while fetching role permissions", "see log for details"); FacesUtil.addGlobalErrorMessage("Error while fetching role permissions", "see log for details");
currentRolePermissions = new ArrayList<>(); currentRolePermissions = new ArrayList<>();
} }
@ -178,10 +177,9 @@ public class RoleView implements Serializable {
missingApplicationsPermissions = null; missingApplicationsPermissions = null;
} catch (AccountException ex) { } catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.debug(ex.toString());
} }
FacesUtil.addGlobalErrorMessage("Error while adding permission", ex.getMessage()); FacesUtil.addGlobalErrorMessage("Error while adding permission", ex.getMessage());
} }
} }
@ -198,9 +196,7 @@ public class RoleView implements Serializable {
missingApplicationsPermissions = null; missingApplicationsPermissions = null;
} catch (AccountException ex) { } catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex); LOGGER.debug("Detailed stacktrace", new Object[]{ex});
} else {
LOGGER.debug(ex.toString());
} }
FacesUtil.addGlobalErrorMessage("Error while adding permission", ex.getMessage()); FacesUtil.addGlobalErrorMessage("Error while adding permission", ex.getMessage());
} }

View File

@ -1,6 +1,6 @@
package de.muehlencord.shared.account.web.presentation; package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.application.boundary.ApplicationService; import de.muehlencord.shared.account.business.application.control.ApplicationControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import java.io.Serializable; import java.io.Serializable;
import java.util.UUID; import java.util.UUID;
@ -26,7 +26,7 @@ public class UniqueApplicationValidator implements Validator, Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(UniqueApplicationValidator.class); private static final Logger LOGGER = LoggerFactory.getLogger(UniqueApplicationValidator.class);
@Inject @Inject
ApplicationService applicationService; ApplicationControl applicationService;
@Override @Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {

View File

@ -41,6 +41,7 @@
<i class="fa fa-circle"></i> <i class="fa fa-circle"></i>
<span>Roles</span> <span>Roles</span>
</p:link> </p:link>
<a href="footer.xhtml"></a>
</li> </li>
</shiro:hasAnyPermission> </shiro:hasAnyPermission>
<li> <li>

View File

@ -8,7 +8,8 @@
xmlns:co="http://java.sun.com/jsf/composite/composite" xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:o="http://omnifaces.org/ui" xmlns:o="http://omnifaces.org/ui"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite"> xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite"
xmlns:shiro="http://shiro.apache.org/tags">
<ui:define name="title"> <ui:define name="title">
Account Overview Account Overview
@ -64,6 +65,8 @@
<p:spacer height="10px" /> <p:spacer height="10px" />
<p:panel id="buttonPanel" styleClass="box-primary" style="margin-bottom:20px"> <p:panel id="buttonPanel" styleClass="box-primary" style="margin-bottom:20px">
<div class="ui-g ui-fluid"> <div class="ui-g ui-fluid">
<shiro:hasPermission name="#{permissionConstants.accountDelete}">
<div class="col-sm-12 col-md-4" style="margin-top:10px"> <div class="col-sm-12 col-md-4" style="margin-top:10px">
<div class="ui-inputgroup" > <div class="ui-inputgroup" >
<h:outputLabel for="includeDisabledCheckbox" value="Include disabled accounts?" /> <h:outputLabel for="includeDisabledCheckbox" value="Include disabled accounts?" />
@ -72,45 +75,67 @@
</p:inputSwitch> </p:inputSwitch>
</div> </div>
</div> </div>
</shiro:hasPermission>
<shiro:hasPermission name="#{permissionConstants.accountAdd}">
<div class="col-sm-12 col-md-2"> <div class="col-sm-12 col-md-2">
<p:commandButton value="New" id="newButton" icon="fa fa-plus" <p:commandButton value="New" id="newButton" icon="fa fa-plus"
update="editDialog" oncomplete="PF('editDialogVar').show();" update="editDialog" oncomplete="PF('editDialogVar').show();"
actionListener="#{accountView.newAccount}" styleClass="btn-primary btn-block" /> actionListener="#{accountView.newAccount}" styleClass="btn-primary btn-block" />
</div> </div>
</shiro:hasPermission>
<shiro:hasPermission name="#{permissionConstants.accountEdit}">
<div class="col-sm-12 col-md-2"> <div class="col-sm-12 col-md-2">
<p:commandButton value="Edit" id="editButton" icon="fa fa-pencil" <p:commandButton value="Edit" id="editButton" icon="fa fa-pencil"
update="editDialog" oncomplete="PF('editDialogVar').show();" update="editDialog" oncomplete="PF('editDialogVar').show();"
actionListener="#{accountView.editAccount}" disabled="#{!accountView.accountSelected}" styleClass="btn-teal btn-block" /> actionListener="#{accountView.editAccount}" disabled="#{!accountView.accountSelected}" styleClass="btn-teal btn-block" />
</div> </div>
</shiro:hasPermission>
<shiro:hasPermission name="#{permissionConstants.accountDelete}">
<div class="col-sm-12 col-md-2"> <div class="col-sm-12 col-md-2">
<p:commandButton value="Delete" id="deleteButton" icon="fa fa-trash-o" <p:commandButton value="Delete" id="deleteButton" icon="fa fa-trash-o"
update=":accountForm:accountTable" action="#{accountView.deleteAccount}" disabled="#{accountView.accountSelected eq false or accountView.currentLoggedInUser eq true}" styleClass="btn-danger btn-block"> update=":accountForm:accountTable" action="#{accountView.deleteAccount}" disabled="#{accountView.accountSelected eq false or accountView.currentLoggedInUser eq true}" styleClass="btn-danger btn-block">
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" /> <p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:commandButton> </p:commandButton>
</div> </div>
</shiro:hasPermission>
<shiro:hasPermission name="#{permissionConstants.accountsCombined}">
<div class="col-sm-12 col-md-2"> <div class="col-sm-12 col-md-2">
<shiro:hasPermission name="#{permissionConstants.accountLoginAdd}">
<c:if test="#{empty accountView.currentAccount.accountLogin}"> <c:if test="#{empty accountView.currentAccount.accountLogin}">
<p:commandButton value="Add login" id="addLoginButton" icon="fa fa-plus" disabled="#{!accountView.accountSelected}" <p:commandButton value="Add login" id="addLoginButton" icon="fa fa-plus" disabled="#{!accountView.accountSelected}"
update="editLoginDialog" oncomplete="PF('editLoginDialogVar').show();" update="editLoginDialog" oncomplete="PF('editLoginDialogVar').show();"
action="#{accountView.addAccountLogin}" styleClass="btn-teal btn-block"> action="#{accountView.addAccountLogin}" styleClass="btn-teal btn-block">
</p:commandButton> </p:commandButton>
</c:if> </c:if>
<c:if test="#{!empty accountView.currentAccount.accountLogin}"> </shiro:hasPermission>
<p:splitButton value="Edit login" id="editLoginButton" icon="fa fa-pencil" disabled="#{!accountView.accountSelected}"
update="editLoginDialog" oncomplete="PF('editLoginDialogVar').show();"
action="#{accountView.editAccountLogin}" styleClass="btn-success btn-block">
<c:if test="#{!empty accountView.currentAccount.accountLogin}">
<p:splitButton value="Edit login" id="editLoginButton" icon="fa fa-pencil" disabled="#{!accountView.accountSelected}" styleClass="btn-success btn-block">
<shiro:hasPermission name="#{permissionConstants.accountLoginEdit}">
<p:menuitem value="Edit login" icon="fa fa-pencil" disabled="#{!accountView.accountSelected}"
update="editLoginDialog" oncomplete="PF('editLoginDialogVar').show();"
action="#{accountView.editAccountLogin}" >
</p:menuitem>
</shiro:hasPermission>
<shiro:hasPermission name="#{permissionConstants.accountLoginDelete}">
<p:menuitem value="Delete login" icon="fa fa-trash-o" disabled="#{accountView.currentLoggedInUser}" <p:menuitem value="Delete login" icon="fa fa-trash-o" disabled="#{accountView.currentLoggedInUser}"
update="accountTable,buttonPanel" styleClass="btn-danger btn-block" update="accountTable,buttonPanel" styleClass="btn-danger btn-block"
action="#{accountView.deleteAccountLogin}" > action="#{accountView.deleteAccountLogin}" >
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" /> <p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:menuitem> </p:menuitem>
</shiro:hasPermission>
</p:splitButton> </p:splitButton>
</c:if> </c:if>
</div> </div>
</shiro:hasPermission>
</div> </div>
</p:panel> </p:panel>

View File

@ -21,6 +21,7 @@ import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
import de.muehlencord.shared.account.business.account.entity.AccountStatus; import de.muehlencord.shared.account.business.account.entity.AccountStatus;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity;
import de.muehlencord.shared.account.business.instance.boundary.ApplicationPermissions;
import de.muehlencord.shared.account.business.mail.boundary.MailService; import de.muehlencord.shared.account.business.mail.boundary.MailService;
import de.muehlencord.shared.account.business.mail.entity.MailException; import de.muehlencord.shared.account.business.mail.entity.MailException;
import de.muehlencord.shared.account.util.AccountPU; import de.muehlencord.shared.account.util.AccountPU;
@ -30,6 +31,7 @@ import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.ejb.Stateless; import javax.ejb.Stateless;
import javax.inject.Inject; import javax.inject.Inject;
@ -63,12 +65,31 @@ public class AccountControl implements Serializable {
@AccountPU @AccountPU
EntityManager em; EntityManager em;
public List<AccountEntity> getAllAccounts(boolean includeDisabled) {
List<AccountEntity> resultList;
if (includeDisabled) {
resultList = getAllAccounts();
} else {
resultList = getActiveAccounts();
}
if (SecurityUtil.checkPermission(ApplicationPermissions.ACCOUNT_LIST)) {
return resultList;
} else {
String currentUserName = SecurityUtils.getSubject().getPrincipal().toString();
return resultList.stream()
.filter(account -> account.getAccountLogin() != null)
.filter (account -> account.getUsername().equals (currentUserName))
.collect(Collectors.toList());
}
}
/** /**
* returns a list of active accounts * returns a list of active accounts
* *
* @return a list of active accounts * @return a list of active accounts
*/ */
public List<AccountEntity> getActiveAccounts() { private List<AccountEntity> getActiveAccounts() {
Query query = em.createQuery("SELECT a FROM AccountEntity a WHERE a.status <> :status", AccountEntity.class); Query query = em.createQuery("SELECT a FROM AccountEntity a WHERE a.status <> :status", AccountEntity.class);
query.setParameter("status", AccountStatus.DISABLED.name()); query.setParameter("status", AccountStatus.DISABLED.name());
return query.getResultList(); return query.getResultList();
@ -79,18 +100,11 @@ public class AccountControl implements Serializable {
* *
* @return a list of active accounts * @return a list of active accounts
*/ */
public List<AccountEntity> getAllAccounts() { private List<AccountEntity> getAllAccounts() {
Query query = em.createNamedQuery("AccountEntity.findAll"); Query query = em.createNamedQuery("AccountEntity.findAll");
return query.getResultList(); return query.getResultList();
} }
public List<AccountEntity> getAccounts(boolean includeDisabled) {
if (includeDisabled) {
return getAllAccounts();
} else {
return getActiveAccounts();
}
}
public AccountEntity getAccountEntity(String userName, boolean loadRoles) { public AccountEntity getAccountEntity(String userName, boolean loadRoles) {
StringBuilder queryBuilder = new StringBuilder(); StringBuilder queryBuilder = new StringBuilder();

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.muehlencord.shared.account.business.accountconfig.entity; package de.muehlencord.shared.account.business.account.entity;
/** /**
* *

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.muehlencord.shared.account.business.accountconfig.entity; package de.muehlencord.shared.account.business.account.entity;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;

View File

@ -21,14 +21,14 @@ import de.muehlencord.shared.account.util.SecurityError;
* *
* @author Joern Muehlencord <joern at muehlencord.de> * @author Joern Muehlencord <joern at muehlencord.de>
*/ */
public enum ApplicationServiceError implements SecurityError { public enum ApplicationError implements SecurityError {
LISTALL_DENIED("1000", "listall_denied"); LIST_DENIED("1000", "list_denied");
private final String errorCode; private final String errorCode;
private final String messageKey; private final String messageKey;
private ApplicationServiceError(String errorCode, String messageKey) { private ApplicationError(String errorCode, String messageKey) {
this.errorCode = errorCode; this.errorCode = errorCode;
this.messageKey = messageKey; this.messageKey = messageKey;
} }

View File

@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.muehlencord.shared.account.business.application.boundary; package de.muehlencord.shared.account.business.application.control;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.instance.boundary.ApplicationPermissions;
import de.muehlencord.shared.account.util.AccountPU; import de.muehlencord.shared.account.util.AccountPU;
import de.muehlencord.shared.account.util.AccountSecurityException; import de.muehlencord.shared.account.util.AccountSecurityException;
import de.muehlencord.shared.account.util.SecurityUtil; import de.muehlencord.shared.account.util.SecurityUtil;
@ -28,6 +29,8 @@ import javax.inject.Inject;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.Query; import javax.persistence.Query;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -36,10 +39,10 @@ import org.slf4j.LoggerFactory;
* @author Joern Muehlencord <joern at muehlencord.de> * @author Joern Muehlencord <joern at muehlencord.de>
*/ */
@Stateless @Stateless
public class ApplicationService implements Serializable { public class ApplicationControl implements Serializable {
private static final long serialVersionUID = 4262608935325326191L; private static final long serialVersionUID = 4262608935325326191L;
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationService.class); private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationControl.class);
@Inject @Inject
@AccountPU @AccountPU
@ -50,14 +53,34 @@ public class ApplicationService implements Serializable {
} }
public List<ApplicationEntity> getAllApplications() throws AccountSecurityException { public List<ApplicationEntity> getAllApplications() throws AccountSecurityException {
SecurityUtil.checkPermission(ApplicationPermissions.APP_LISTALL, ApplicationServiceError.LISTALL_DENIED); List<ApplicationEntity> resultList = new ArrayList<>();
Query query = em.createNamedQuery("ApplicationEntity.findAll"); Query query = em.createNamedQuery("ApplicationEntity.findAll");
List<ApplicationEntity> resultList = query.getResultList(); List<ApplicationEntity> queryList = query.getResultList();
if (resultList == null) { if ((queryList == null) || (queryList.isEmpty())) {
return new ArrayList<>();
} else {
return resultList; return resultList;
} }
Subject currentUser = SecurityUtils.getSubject();
if (currentUser == null)
return resultList;
String userName = currentUser.getPrincipal().toString();
queryList.stream().forEach(app -> {
String applicationName = app.getApplicationName(); // TODO add unique short cut to db model
applicationName = applicationName.toLowerCase();
applicationName = applicationName.replace (" ", "");
String permissionName = ApplicationPermissions.APP_LIST.getName()+":"+applicationName;
boolean userHasPermissionToListApplication = SecurityUtil.checkPermission (permissionName);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("validating if user {} has permission {} = {}", userName, permissionName, userHasPermissionToListApplication);
}
if (userHasPermissionToListApplication) {
resultList.add (app);
}
});
return resultList;
} }
@Transactional @Transactional

View File

@ -15,8 +15,8 @@
*/ */
package de.muehlencord.shared.account.business.config.boundary; package de.muehlencord.shared.account.business.config.boundary;
import de.muehlencord.shared.account.business.accountconfig.entity.AccountConfigurationKey; import de.muehlencord.shared.account.business.account.entity.AccountConfigurationKey;
import de.muehlencord.shared.account.business.accountconfig.entity.AccountConfigurationValue; import de.muehlencord.shared.account.business.account.entity.AccountConfigurationValue;
import de.muehlencord.shared.account.business.config.entity.ConfigException; import de.muehlencord.shared.account.business.config.entity.ConfigException;
import javax.ejb.EJB; import javax.ejb.EJB;
import javax.enterprise.context.Dependent; import javax.enterprise.context.Dependent;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.muehlencord.shared.account.business.application.boundary; package de.muehlencord.shared.account.business.instance.boundary;
import de.muehlencord.shared.account.util.Permission; import de.muehlencord.shared.account.util.Permission;
@ -23,7 +23,7 @@ import de.muehlencord.shared.account.util.Permission;
*/ */
public enum ApplicationPermissions implements Permission { public enum ApplicationPermissions implements Permission {
APP_LISTALL("application:listall", "Allows to list all avaiable applications"), APP_LIST("application:list", "Allows to list all avaiable applications"),
APP_ADD("application:add", "Allow to add a new application"), APP_ADD("application:add", "Allow to add a new application"),
APP_EDIT("application:edit", "Allow to edit an application"), APP_EDIT("application:edit", "Allow to edit an application"),
APP_DELETE("application:delete", "Allow to delete an application"), APP_DELETE("application:delete", "Allow to delete an application"),
@ -34,7 +34,14 @@ public enum ApplicationPermissions implements Permission {
ROLE_EDIT("role:edit", "Allow to edit a role"), ROLE_EDIT("role:edit", "Allow to edit a role"),
ROLE_DELETE("role:delete", "Allow to delete a role"), ROLE_DELETE("role:delete", "Allow to delete a role"),
ROLE_PERMISSION_ASSIGN("role:permission:assign", "Allow to assign a permission to role"), ROLE_PERMISSION_ASSIGN("role:permission:assign", "Allow to assign a permission to role"),
ROLE_PERMISSION_REVOKE("role:permission:revoke", "All ow to revoke a permission from a role"); ROLE_PERMISSION_REVOKE("role:permission:revoke", "All ow to revoke a permission from a role"),
ACCOUNT_LIST ("account:list", "Allow to list all accounts of an application"),
ACCOUNT_ADD ("account:add", "Allow to create a new account"),
ACCOUNT_EDIT ("account:edit", "Allow to edit an existing account"),
ACCOUNT_DELETE ("account:delete", "Allow to delete an existing account"),
ACCOUNT_LOGIN_ADD ("account:login:add", "Allow to add a login to an account"),
ACCOUNT_LOGIN_EDIT ("account:login:edit", "Allow to overwrite the password of an account"),
ACCOUNT_LOGIN_DELETE ("account:login:delete", "Allow to delete the login of an account");
private final String name; private final String name;
private final String description; private final String description;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.muehlencord.shared.account.business.application.boundary; package de.muehlencord.shared.account.business.instance.boundary;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.config.boundary.ConfigService; import de.muehlencord.shared.account.business.config.boundary.ConfigService;

View File

@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package de.muehlencord.shared.account.business.application.control; package de.muehlencord.shared.account.business.instance.control;
import de.muehlencord.shared.account.business.application.boundary.ApplicationService; import de.muehlencord.shared.account.business.application.control.ApplicationControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity; import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -40,7 +40,7 @@ public class ApplicationController {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationController.class); private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationController.class);
@EJB @EJB
ApplicationService applicationService; ApplicationControl applicationService;
private String version; private String version;
private String buildDate; private String buildDate;

View File

@ -16,7 +16,7 @@
package de.muehlencord.shared.account.business.mail.boundary; package de.muehlencord.shared.account.business.mail.boundary;
import de.muehlencord.shared.account.business.mail.entity.MailTemplateException; import de.muehlencord.shared.account.business.mail.entity.MailTemplateException;
import de.muehlencord.shared.account.business.accountconfig.entity.AccountConfigurationKey; import de.muehlencord.shared.account.business.account.entity.AccountConfigurationKey;
import de.muehlencord.shared.account.business.account.entity.AccountEntity; import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity; import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
import de.muehlencord.shared.account.business.mail.entity.MailDatamodel; import de.muehlencord.shared.account.business.mail.entity.MailDatamodel;
@ -38,7 +38,7 @@ import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart; import javax.mail.internet.MimeMultipart;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import de.muehlencord.shared.account.business.accountconfig.entity.AccountConfigurationValue; import de.muehlencord.shared.account.business.account.entity.AccountConfigurationValue;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;

View File

@ -25,7 +25,6 @@ import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext; import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped; import javax.faces.view.ViewScoped;
import javax.inject.Named; import javax.inject.Named;
import javax.naming.NamingException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
@ -120,6 +119,9 @@ public class LoginView implements Serializable {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
// ensure faces session is invalidated so beans are destroyed
ec.invalidateSession();
// check if redirect shall be executed // check if redirect shall be executed
// default setting is yes to /login.xhtml // default setting is yes to /login.xhtml
// can be overwritten using parameters // can be overwritten using parameters

View File

@ -47,15 +47,24 @@ public class SecurityUtil {
return encryptedPassword; return encryptedPassword;
} }
public static void checkPermission(Permission permission, SecurityError error) throws AccountSecurityException { public static boolean checkPermission(Permission permission) {
Subject currentUser = SecurityUtils.getSubject(); return checkPermission (permission.getName());
if ((currentUser == null) || (!currentUser.isAuthenticated())) {
throw new AccountSecurityException(error); // TODO support special error for not logged in
} }
String requiredPermissions = permission.getName(); public static boolean checkPermission(String permissionName) {
if (!currentUser.isPermitted(requiredPermissions)) { Subject currentUser = SecurityUtils.getSubject();
if ((currentUser == null) || (!currentUser.isAuthenticated())) {
return false;
}
String requiredPermissions = permissionName;
return currentUser.isPermitted(requiredPermissions);
}
public static void checkPermission(Permission permission, SecurityError error) throws AccountSecurityException {
if (!checkPermission(permission)) {
throw new AccountSecurityException(error); throw new AccountSecurityException(error);
} }
} }
} }

View File

@ -13,4 +13,4 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
listall_denied=You are not allowed to list all applications list_denied=You are not allowed to list any application

View File

@ -13,4 +13,4 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
listall_denied=Sie haben nicht die n\u00f6tige Rechte alle Applikationen aufzulisten list_denied=Sie haben nicht die n\u00f6tige Rechte eine Applikationen aufzulisten.

View File

@ -13,4 +13,4 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
listall_denied=User not allowed to list all applications list_denied=User not allowed to list any application