91 Commits

Author SHA1 Message Date
204456ce3c migrate to jakarta.mail 2025-09-07 13:39:16 +02:00
067d376948 migrate to jakarta.mail 2024-02-14 01:03:41 +01:00
31aea194df [maven-release-plugin] prepare for next development iteration 2023-12-10 22:29:25 +01:00
782a736cdc [maven-release-plugin] prepare release v2.0.0 2023-12-10 22:29:22 +01:00
c4a5f12511 feature/jakrtaee10 (#1)
Co-authored-by: Joern Muehlencord <joern.muehlencord@vitroconnect.com>
Reviewed-on: https://jomu.timelord.de/git/jomu/shared/pulls/1
2023-12-10 21:24:45 +00:00
b9482de3b1 switched distribution management to gitea 2023-04-02 10:49:32 +02:00
bc0493b094 [maven-release-plugin] prepare for next development iteration 2023-02-24 08:52:14 +01:00
f2387ffe92 [maven-release-plugin] prepare release v1.3.1 2023-02-24 08:52:12 +01:00
c844c7a504 [maven-release-plugin] prepare for next development iteration 2023-02-19 11:11:17 +01:00
5c74d12622 [maven-release-plugin] prepare release v1.3.0 2023-02-19 11:11:15 +01:00
62ceea63bc updated dependencies 2023-02-19 11:10:36 +01:00
32af3caf77 [maven-release-plugin] prepare for next development iteration 2022-06-12 01:13:28 +02:00
70302edc58 [maven-release-plugin] prepare release v1.2.1 2022-06-12 01:13:25 +02:00
fb1b3001ac [maven-release-plugin] prepare for next development iteration 2022-06-12 01:11:25 +02:00
9297be25d6 Merge remote-tracking branch 'origin/master' 2022-06-12 01:09:51 +02:00
ddeedfb3ad [maven-release-plugin] prepare release v1.2 2022-06-12 01:09:29 +02:00
3b4c214e3f [maven-release-plugin] prepare release v1.2 2022-06-12 01:07:15 +02:00
081af716d1 change remote to ssh 2022-06-12 01:03:56 +02:00
84ed78bcef Merge remote-tracking branch 'origin/master' 2022-06-12 01:01:21 +02:00
1d8ff8b02e improved whois 2022-06-12 01:01:08 +02:00
ffaf9a16c5 improved whois 2022-06-12 00:57:37 +02:00
698ddfd199 improved whois 2022-03-01 08:53:41 +01:00
ec82f06f88 improved whois 2022-02-25 13:53:11 +01:00
d427956422 improved whois 2022-02-25 13:13:27 +01:00
e82a4cadd4 updated dependencies 2022-01-23 13:57:51 +01:00
84b8b0545f dependency updates 2021-12-13 22:13:20 +01:00
cd2e3b0642 updated libraries 2021-02-21 16:30:23 +01:00
b129228b36 added addMessage(clientId, message, validationFailed) 2020-11-21 16:20:35 +01:00
57907d05e6 improved Audit 2020-09-30 20:01:20 +02:00
c983bde031 fixed NPE 2020-06-07 16:41:26 +02:00
0e21c9baf7 retrieve whois information and parse again without connection to server 2020-04-22 08:27:10 +02:00
e12127f6dd added validationFailed support 2020-02-26 23:08:16 +01:00
9090b2c66e added find by query method 2020-02-16 13:42:58 +01:00
799c7d52e3 made em configurable (required for unit testing) 2020-01-13 00:52:25 +01:00
6d9a87e15b added basic or clause support 2019-12-27 14:38:24 +01:00
4dddc1f3dc generalized StandardController 2019-12-25 23:04:55 +01:00
b4a28bb0b0 added subGraph support 2019-11-17 15:09:05 +01:00
d5dc39e8ff introduced StreamUtils 2019-11-17 15:08:07 +01:00
233164fb54 added UUID support 2019-10-28 14:51:59 +01:00
bea1d80f1e extended search by SearchFilter 2019-10-27 03:15:38 +01:00
571386046d started to add string filter support 2019-10-24 11:12:39 +01:00
103b8348d0 downgrade POI to 4.0.1 to avoid bug
https://bz.apache.org/bugzilla/show_bug.cgi?id=63845
2019-10-15 10:16:52 +02:00
06fe2231ec added getCommaListString method 2019-10-11 18:43:33 +02:00
113cb4a641 started to add searchFilter support 2019-10-04 13:50:22 +02:00
6d49dec89f prepared to support Enddatable in findAll 2019-10-04 07:32:00 +02:00
ee1a20836d added getStringValue method 2019-09-15 17:24:15 +02:00
626ab1b528 added missing gpg key configuration 2019-09-15 14:07:12 +02:00
aeab3a5ca9 updated API description 2019-09-15 13:58:16 +02:00
a2430f748f updated API description 2019-09-15 13:37:38 +02:00
af298c8060 removed pdf library 2019-09-15 13:37:30 +02:00
6348f81bed updated API description 2019-09-14 17:54:26 +02:00
13d16a1309 fixed project setup in pom.xml, fixed author tag 2019-09-13 09:15:19 +02:00
585b6d7d02 migrated shared-account into own project, updated license heaaders 2019-09-13 01:02:27 +02:00
a071cb5732 updated license header, merged shared-security 2019-09-12 23:43:14 +02:00
f804c11ceb update license header 2019-09-12 22:57:51 +02:00
218d7a7365 added getEnumString method 2019-09-12 19:03:08 +02:00
2128ad95bc removed deprecated API calls 2019-09-12 19:02:39 +02:00
53991b7f56 erged conflicts 2019-09-10 16:31:25 +01:00
59420af4a5 fixed author tag
fixed duplicate in taglib
2019-09-09 05:25:07 +02:00
fe8b0d272b removed broken sharepoint lib 2019-09-08 15:37:06 +02:00
89ddbbdbb2 upgrade to JUNIT5 2019-09-03 16:10:20 +02:00
c4d71f9614 added refresh method 2019-09-02 15:47:40 +02:00
97649c9306 enlarged config value size 2019-09-02 15:47:04 +02:00
0cbab859f8 made context root configurable 2019-08-28 07:53:05 +02:00
eb3bf3b71a introduced IdentifiableEntity 2019-08-19 13:04:24 +02:00
b138841faa fixed header 2019-08-19 13:04:06 +02:00
5a840dad7f updated libraries 2019-08-14 12:03:39 +02:00
0f98586434 fixed borken update (entity, updatedBy) method 2019-08-14 12:02:51 +02:00
08a0adcc6f added missing icons 2019-08-14 12:01:08 +02:00
8205ffaec3 fixed BLOCKED users are accepted 2019-08-14 12:00:45 +02:00
54f2e56a4c maded applications editable, made UUID visible 2019-08-14 10:34:23 +02:00
119fb04520 added support of multiple fallback suffixes 2019-08-02 08:45:34 +02:00
24dc927ab7 updated libraries
updated to JUNIT5
2019-07-12 15:07:13 +02:00
3ae4dba8fe added support for locked users 2019-06-25 13:06:53 +02:00
bf590223b8 introduced validity 2019-06-23 17:10:30 +02:00
1e5e15cda0 fixed entity duplication when trying to delete 2019-06-22 16:22:29 +02:00
40acbcd6ac introduced CommonAbstractController and StandardController 2019-06-22 01:00:56 +02:00
ab2a0e2301 added EntityUtil, ensured cloned entities are updated to represent a new entity 2019-06-21 09:45:16 +02:00
a8e0f9bd5f continued to add Auditable support 2019-06-20 16:09:09 +02:00
88d2509893 started to introduce embeded audit entity support 2019-06-20 13:11:07 +02:00
96892cf8f9 started to fix sharepoint API under JDK11 2019-06-17 14:21:11 +02:00
6829b65a2f Merge origin/master 2019-06-16 21:56:47 +02:00
a9e136d3ac enhanced enddateable support 2019-06-16 21:56:28 +02:00
aa478dbf9f added trace logging 2019-06-14 19:16:44 +02:00
2a75d2a1fe updated jackson to Wildfly 16 provided version 2019-06-12 16:21:10 +02:00
a8a609491f fixed log4j config 2019-06-12 16:20:41 +02:00
43f5401773 fixed broken imports 2019-06-10 23:04:57 +02:00
e9dede69cb excluded jackson which is provided by wildfly automatically 2019-06-10 14:45:28 +02:00
7a380dc214 added find method with support to init certain collections 2019-06-10 14:44:37 +02:00
212e4dad5d splitted database from account 2019-06-05 14:32:12 +02:00
d50f21f869 [maven-release-plugin] prepare for next development iteration 2019-06-05 12:37:24 +02:00
399 changed files with 7494 additions and 27279 deletions

1154
.editorconfig Normal file

File diff suppressed because it is too large Load Diff

197
.gitignore vendored
View File

@ -1,8 +1,191 @@
/**/.settings/
**/target/
.classpath
.project
**/nbproject/
*.dump
**/_dump
# ---> NetBeans
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
**/nb-configuration.xml
.nb-gradle/
**/faces-config.NavData
# ---> Eclipse
.project
.settings/
.classpath
# ---> Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# --> Idea
**/.idea
**/*.iml
# ---> Java
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# ---> TeX
## Core latex/pdflatex auxiliary files:
*.aux
*.lof
*.log
*.lot
*.fls
*.out
*.toc
## Intermediate documents:
*.dvi
*-converted-to.*
# these rules might exclude image files for figures etc.
# *.ps
# *.eps
# *.pdf
## Bibliography auxiliary files (bibtex/biblatex/biber):
*.bbl
*.bcf
*.blg
*-blx.aux
*-blx.bib
*.brf
*.run.xml
## Build tool auxiliary files:
*.fdb_latexmk
*.synctex
*.synctex.gz
*.synctex.gz(busy)
*.pdfsync
## Auxiliary and intermediate files from other packages:
# algorithms
*.alg
*.loa
# achemso
acs-*.bib
# amsthm
*.thm
# beamer
*.nav
*.snm
*.vrb
#(e)ledmac/(e)ledpar
*.end
*.[1-9]
*.[1-9][0-9]
*.[1-9][0-9][0-9]
*.[1-9]R
*.[1-9][0-9]R
*.[1-9][0-9][0-9]R
*.eledsec[1-9]
*.eledsec[1-9]R
*.eledsec[1-9][0-9]
*.eledsec[1-9][0-9]R
*.eledsec[1-9][0-9][0-9]
*.eledsec[1-9][0-9][0-9]R
# glossaries
*.acn
*.acr
*.glg
*.glo
*.gls
# gnuplottex
*-gnuplottex-*
# hyperref
*.brf
# knitr
*-concordance.tex
*.tikz
*-tikzDictionary
# listings
*.lol
# makeidx
*.idx
*.ilg
*.ind
*.ist
# minitoc
*.maf
*.mtc
*.mtc[0-9]
*.mtc[1-9][0-9]
# minted
_minted*
*.pyg
# morewrites
*.mw
# mylatexformat
*.fmt
# nomencl
*.nlo
# sagetex
*.sagetex.sage
*.sagetex.py
*.sagetex.scmd
# sympy
*.sout
*.sympy
sympy-plots-for-*.tex/
# TikZ & PGF
*.dpth
*.md5
*.auxlock
# todonotes
*.tdo
# xindy
*.xdy
# WinEdt
*.bak
*.sav
# localized versions of JBOSS command line interface
*.local.cli
## project specific
/source/vvh-access-import/src/main/resources/hibernate.cfg.xml
/source/office-parent/office-entities/src/main/resources/META-INF/persistence.xml

View File

@ -1,5 +0,0 @@
@ECHO OFF
setlocal
set BASEPATH=%~dp0%
cd %BASEPATH%\..
mvn release:clean release:prepare -Dmaven.test.skip=true -Darguments="-Dmaven.test.skip=true -DskipTests"

View File

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.muehlencord</groupId>
<artifactId>shared</artifactId>
<version>1.1</version>
</parent>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-account-dao</artifactId>
<packaging>jar</packaging>
<name>shared-account-dao</name>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-util</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
<type>jar</type>
</dependency>
</dependencies>
</project>

View File

@ -1,104 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.dao;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.google.gson.annotations.Expose;
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public class ApiKeyObject implements Serializable {
@Expose
private String userName;
@Expose
@JsonFormat(shape = JsonFormat.Shape.STRING, locale = "en_US", timezone = "UTC", pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private Date issuedOn;
@Expose
@JsonFormat(shape = JsonFormat.Shape.STRING, locale = "en_US", timezone = "UTC", pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private Date expiresOn;
@Expose
private String authToken;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Date getIssuedOn() {
return issuedOn;
}
public void setIssuedOn(Date issuedOn) {
this.issuedOn = issuedOn;
}
public Date getExpiresOn() {
return expiresOn;
}
public void setExpiresOn(Date expiresOn) {
this.expiresOn = expiresOn;
}
public String getAuthToken() {
return authToken;
}
public void setAuthToken(String authToken) {
this.authToken = authToken;
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + Objects.hashCode(this.userName);
hash = 53 * hash + Objects.hashCode(this.issuedOn);
hash = 53 * hash + Objects.hashCode(this.expiresOn);
hash = 53 * hash + Objects.hashCode(this.authToken);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ApiKeyObject other = (ApiKeyObject) obj;
if (!Objects.equals(this.userName, other.userName)) {
return false;
}
if (!Objects.equals(this.authToken, other.authToken)) {
return false;
}
return true;
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2019 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.dao;
import de.muehlencord.shared.util.DateUtil;
import java.util.Date;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public abstract class ApiKeyUtil {
private ApiKeyUtil() {
// hide constructor for abstract class - only static methods are used
}
public static boolean isValid(ApiKeyObject apiKeyObject) {
if (apiKeyObject == null) {
return false;
}
Date validToDate = apiKeyObject.getExpiresOn();
if (validToDate == null) {
return false;
}
Date now = DateUtil.getCurrentTimeInUTC();
return validToDate.after(now);
}
}

View File

@ -1,30 +0,0 @@
package de.muehlencord.shared.account.dao;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
/**
*
* @author joern.muehlencord
*/
public abstract class JacksonConfig {
private static ObjectMapper objectMapper = null;
private JacksonConfig() {
// hide public constructor for static only class
}
public static ObjectMapper getInstance() {
if (objectMapper == null) {
objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"));
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
objectMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
return objectMapper;
}
}

View File

@ -1,41 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.muehlencord.shared.account.dao;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Date;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public class ApiKeyObjectTest {
@Test
public void testJackson() throws JsonProcessingException, IOException {
ApiKeyObject apiKeyObject = new ApiKeyObject();
apiKeyObject.setUserName("web");
apiKeyObject.setIssuedOn(new Date());
apiKeyObject.setExpiresOn(new Date());
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(apiKeyObject);
System.out.println(json);
ApiKeyObject apiKeyObject2 = mapper.readValue (json, ApiKeyObject.class);
assertTrue (apiKeyObject.equals(apiKeyObject2));
}
}

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scene Scope="Project" version="2">
<Scope Scope="Faces Configuration Only"/>
<Scope Scope="Project"/>
<Scope Scope="All Faces Configurations"/>
</Scene>

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<libraries xmlns="http://www.netbeans.org/ns/cdnjs-libraries/1"/>
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-projectapi.jsf_2e_language>Facelets</org-netbeans-modules-projectapi.jsf_2e_language>
<org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>WildFly</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>
<netbeans.hint.license>apache20</netbeans.hint.license>
<org-netbeans-modules-web-clientproject-api.js_2e_libs_2e_folder>js/libs</org-netbeans-modules-web-clientproject-api.js_2e_libs_2e_folder>
</properties>
</project-shared-configuration>

View File

@ -1,150 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>shared</artifactId>
<groupId>de.muehlencord</groupId>
<version>1.1</version>
</parent>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-account-ui</artifactId>
<packaging>war</packaging>
<name>shared-account-ui</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<timestamp>${maven.build.timestamp}</timestamp>
<!-- default filter if not selected via profile -->
<applicationUuid>143a2bd3-7e0b-4162-a76e-3031331c7dfe</applicationUuid>
<filter.name>development</filter.name>
</properties>
<dependencies>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
</dependency>
<!-- Admin faces template -->
<dependency>
<groupId>com.github.adminfaces</groupId>
<artifactId>admin-template</artifactId>
</dependency>
<!-- Omnifaces, faces utils -->
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
</dependency>
<!-- Apache Shiro, Security API -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
</dependency>
<dependency>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-shiro-faces</artifactId>
</dependency>
<dependency>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-account</artifactId>
</dependency>
<dependency>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-util</artifactId>
</dependency>
<dependency>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-jeeutil</artifactId>
</dependency>
<dependency>
<groupId>de.muehlencord.sf</groupId>
<artifactId>filter</artifactId>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<filters>
<filter>${basedir}/src/main/filters/${filter.name}.properties</filter>
</filters>
<resources>
<!-- fill buildinformation file -->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<finalName>account</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<directory>${basedir}/src/main/webapp</directory>
<filtering>true</filtering>
<includes>
<include>WEB-INF/web.xml</include>
<include>WEB-INF/shiro.ini</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>development</id>
<properties>
<filter.name>development</filter.name>
</properties>
</profile>
<profile>
<id>production</id>
<properties>
<filter.name>production</filter.name>
</properties>
</profile>
</profiles>
</project>

View File

@ -1,7 +0,0 @@
jsf.projectStage=Development
shiro.contextFactory = # not defined
shiro.passwordMatcher= passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher${line.separator}passwordMatcher.passwordService = $passwordService
shiro.ldapRealm = # not defined
shiro.authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy
shiro.realms = $jdbcRealm

View File

@ -1,17 +0,0 @@
jsf.projectStage=Production
ldap.url = ldaps://host:port
## we will use provided username / password from webapplication
ldap.user = user
ldap.password = secret
ldap.suffix = @diebold.com
ldap.fallbackSuffix = @dieboldnixdorf.com
ldap.searchBase = dc=ad,dc=diebold,dc=com
ldap.searchFilter = (&(objectClass=*)(mail={0}))
## NO CHANGES BEHIND THIS LINE REQUIRED
shiro.contextFactory = contextFactory = org.apache.shiro.realm.ldap.JndiLdapContextFactory${line.separator}contextFactory.url = ${ldap.url}${line.separator}contextFactory.systemUsername = ${ldap.user}${line.separator}contextFactory.systemPassword = ${ldap.password}${line.separator}contextFactory.environment[java.naming.security.protocol] = ssl
shiro.passwordMatcher= passwordMatcher=org.apache.shiro.authc.credential.AllowAllCredentialsMatcher
shiro.ldapRealm = ldapRealm = de.muehlencord.shared.account.shiro.realm.UserNameActiveDirectoryRealm${line.separator}ldapRealm.principalSuffix = ${ldap.suffix}${line.separator}ldapRealm.fallbackPrincipalSuffix = ${ldap.fallbackSuffix}${line.separator}ldapRealm.ldapContextFactory = $contextFactory${line.separator}ldapRealm.searchBase = ${ldap.searchBase}${line.separator}ldapRealm.searchFilter = ${ldap.searchFilter}${line.separator}ldapRealm.permissionsLookupEnabled=false
shiro.authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy
shiro.realms=$jdbcRealm,$ldapRealm

View File

@ -1,80 +0,0 @@
/*
* Copyright 2018 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web;
import de.muehlencord.shared.account.business.account.boundary.AccountPermissions;
import de.muehlencord.shared.account.business.account.entity.AccountException;
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.ApplicationRoleControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import java.util.Arrays;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ApplicationScoped
public class EnsurePermissionsBean {
@Inject
ApplicationEntity application;
@Inject
ApplicationPermissionControl applicationPermissionControl;
@Inject
ApplicationRoleControl applicationRoleControl;
private static final Logger LOGGER = LoggerFactory.getLogger(EnsurePermissionsBean.class);
public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Ensure all permissions for {} are available", application.getApplicationName());
}
applicationPermissionControl.setupPermissions(Arrays.asList(ApplicationPermissions.values()));
applicationPermissionControl.setupPermissions(Arrays.asList(AccountPermissions.values()));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("All permissions added to application", application.getApplicationName());
}
// all permissions available - ensure permission is assigned to Admin role
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Ensuring Admin role for {} has all permissions", application.getApplicationName());
}
try {
applicationRoleControl.setupRolePermission(Arrays.asList(ApplicationPermissions.values()), "Admin"); // NOI18N
applicationRoleControl.setupRolePermission(Arrays.asList(AccountPermissions.values()), "Admin"); // NOI18N
} catch (AccountException ex) {
LOGGER.error("Error adding permission to Admin role. Reason={}", ex.getMessage());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("All permissions added to Admin role of {}", application.getApplicationName());
}
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.ContextNotActiveException;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ApplicationScoped
public class FacesContextProducer {
@Produces
@RequestScoped
public FacesContext getFacesContext() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx == null) {
throw new ContextNotActiveException("FacesContext is not active");
}
return ctx;
}
}

View File

@ -1,86 +0,0 @@
/*
* Copyright 2018 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web;
import de.muehlencord.shared.account.business.instance.boundary.ApplicationPermissions;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
/**
* TODO replace with omnifaces:importConstants currently problems with Netbeans
* to import omnifaces taglib
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Named(value = "permissionConstants")
@ApplicationScoped
public class PermissionConstants {
public String getApplicationListAll() {
return ApplicationPermissions.APP_LIST.getName();
}
public String getPermissionsCombined() {
return ApplicationPermissions.PERMISSION_ADD.getName() + ","
+ ApplicationPermissions.PERMISSION_EDIT.getName() + ","
+ ApplicationPermissions.PERMISSION_DELETE.getName();
}
public String getRolesCombined() {
return ApplicationPermissions.ROLE_ADD.getName() + ","
+ ApplicationPermissions.ROLE_EDIT.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

@ -1,69 +0,0 @@
package de.muehlencord.shared.account.web;
import de.muehlencord.shared.account.util.AccountPU;
import de.muehlencord.shared.account.util.ApplicationPU;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.persistence.SynchronizationType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ApplicationScoped
public class PersistenceContextFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceContextFactory.class);
// need to define 2nd database as TransactionJoinInterceptor requires it
// account UI is the only application where application and account is the same database
// account UI does not call this as it references all database access via accountPu
@PersistenceUnit (unitName = "accountPu")
EntityManagerFactory entityManagerFactory;
@Produces
@RequestScoped
@ApplicationPU
public EntityManager getPcdEntityManager() {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("getting entityManager for application");
}
EntityManager em = entityManagerFactory.createEntityManager(SynchronizationType.UNSYNCHRONIZED);
return em;
}
public void closePcdEntityManager (@Disposes @ApplicationPU EntityManager em) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("closing entityManager application database");
}
em.close();
}
@Produces
@RequestScoped
@AccountPU
public EntityManager getAccountEntityManager() {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("getting entityManager for account database");
}
EntityManager em = entityManagerFactory.createEntityManager(SynchronizationType.UNSYNCHRONIZED);
return em;
}
public void closeAccountEntityManager (@Disposes @AccountPU EntityManager em) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("closing entityManager for account database");
}
em.close();
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web;
import java.io.Serializable;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@RequestScoped
public class ResourceBundleProducer implements Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(ResourceBundleProducer.class);
private static final long serialVersionUID = 3764096270387408239L;
@Inject
private Locale locale;
@Inject
private FacesContext facesContext;
@Produces
public ResourceBundle getResourceBundle() {
ResourceBundle rb = ResourceBundle.getBundle("de.muehlencord.shared.account.web.presentation.messages", facesContext.getViewRoot().getLocale());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("ResourceBundle = "+rb);
}
return rb;
}
}

View File

@ -1,296 +0,0 @@
package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.account.control.AccountControl;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
import de.muehlencord.shared.account.business.account.entity.AccountStatus;
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.ApplicationRoleEntity;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.primefaces.event.SelectEvent;
import org.primefaces.event.UnselectEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author jomu
*/
@ViewScoped
@Named("accountView")
public class AccountView implements Serializable {
private static final long serialVersionUID = -8050582392249849438L;
private static final Logger LOGGER = LoggerFactory.getLogger(AccountView.class);
@Inject
private ApplicationView applicationView;
@EJB
private AccountControl accountService;
@EJB
private ApplicationRoleControl appliationRoleService;
/**
* boolean flag to determine wether disabled accounts should be shown
* accounts are not deleted but disabled and can be activated in case
*/
private boolean showDisabledAccounts = false;
// cached accounts
private List<AccountEntity> accountList = null;
// cached application roles
private List<ApplicationRoleEntity> applicationRoles = null;
// account currently on edit
private AccountEntity currentAccount;
private List<ApplicationRoleEntity> currentAccountRoles = null;
private AccountLoginEntity currentAccountLogin;
private String password = null;
private String repeatPassword = null;
public List<AccountEntity> getAccounts() {
if (accountList == null) {
accountList = accountService.getAllAccounts(showDisabledAccounts);
}
return accountList;
}
public List<ApplicationRoleEntity> getAllApplicationRoles() {
if (applicationRoles == null) {
ApplicationEntity application = applicationView.getCurrentApplication();
applicationRoles = appliationRoleService.getAllRoles(application);
}
return applicationRoles;
}
public void selectAccount(SelectEvent event) {
// nothing to do, currentAccountRoles are loaded before dialog is shown
}
public void unselectAccount(UnselectEvent event) {
applicationRoles = null;
currentAccountRoles = null;
}
public boolean getAccountSelected() {
return currentAccount != null;
}
public void newAccount() {
currentAccount = new AccountEntity();
currentAccount.setStatus("NEW"); // TODO add status enum
currentAccountRoles = new ArrayList<>();
}
public void editAccount() {
// function called by webpage
if (currentAccount == null) {
currentAccountRoles = null;
} else {
currentAccount = accountService.getAccountEntity(currentAccount.getUsername(), true);
this.currentAccountRoles = new ArrayList<>();
if (currentAccount.getApplicationRoleList() != null) {
currentAccountRoles.addAll(currentAccount.getApplicationRoleList());
}
}
}
public void cancelEditAccount() {
currentAccount = null;
currentAccountRoles = null;
}
public void saveEditAccount() {
String username = currentAccount.getUsername();
AccountEntity existingEntity = accountService.getAccountEntity(username, true);
// check if it is a new user (createdBy == null) but a user with same name already exists
if ((currentAccount.getCreatedBy() == null) && (existingEntity != null)) {
FacesUtil.addErrorMessage("editDialogMessaegs", "Create new account failed", "Account with username " + username + " already exists");
} else {
accountService.saveAccount(currentAccount, applicationView.getCurrentApplication(), currentAccountRoles);
// force accounts to be loaded from database again
accountList = null;
}
}
public void deleteAccount() {
try {
accountService.deleteAccount(currentAccount);
accountList.remove(currentAccount);
FacesUtil.addGlobalInfoMessage("Info", "Account " + currentAccount.getUsername() + " deleted");
currentAccount = null;
currentAccountRoles = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
FacesUtil.addGlobalErrorMessage("Error deleting account", ex.getMessage());
}
}
public void showDisabledAccountsChange() {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("show diabled accounts changed to {}", showDisabledAccounts);
}
this.accountList = null;
}
public List<String> getStatusList() {
return AccountStatus.getAllStatusNames();
}
/* **** account login methods **** */
public boolean validatePasswords(FacesContext context, List<UIInput> components, List<Object> values) {
String currentPassword = components.get(0).getSubmittedValue().toString();
String currentPasswordRepeat = components.get(1).getSubmittedValue().toString();
if ((currentPassword == null) || (currentPasswordRepeat == null)) {
return false;
}
boolean returnValue = currentPassword.equals(currentPasswordRepeat);
return returnValue;
}
public void addAccountLogin() {
if (currentAccount == null) {
// TODO add error handling
} else {
this.currentAccountLogin = accountService.createLoginWithRandomPassword();
}
}
public void editAccountLogin() {
if (currentAccount == null) {
// TODO add error handling
} else {
this.currentAccountLogin = currentAccount.getAccountLogin();
}
}
public void deleteAccountLogin() {
if (currentAccount == null) {
// TODO add error handling
} else {
accountService.deleteLogin(currentAccount);
currentAccount.setAccountLogin(null);
currentAccountLogin = null;
accountList = null; // force reload
FacesUtil.addGlobalInfoMessage("Account saved", "Login removed");
}
}
public void saveEditAccountLogin() {
// TODO move to account control - to much logic for the view
if ((currentAccountLogin == null) || (currentAccount == null)) {
// TODO add error handling
} else {
// overwrite password if provided
if ((password != null) && (!password.trim().equals(""))) {
// password has been specified
if (password.equals(repeatPassword)) {
currentAccountLogin.setAccountPassword(accountService.getHashedPassword(password));
FacesUtil.addGlobalInfoMessage("Info", "Password updated");
} else {
// TODO connect to IPRS
// frontend does validate passwords do match
// someone is trying to cheat
}
}
if (currentAccountLogin.getId() == null) {
accountService.addLogin(currentAccount, currentAccountLogin);
currentAccount.setAccountLogin(currentAccountLogin);
accountList = null; // force reload of accounts
} else {
accountService.updateLogin(currentAccountLogin);
}
currentAccountLogin = null;
FacesUtil.addGlobalInfoMessage("Account saved", "Login data updated");
}
}
public void cancelEditAccountLogin() {
this.currentAccountLogin = null;
}
public boolean getCurrentLoggedInUser() {
if (currentAccount == null) {
return false;
}
Subject currentUser = SecurityUtils.getSubject();
if (currentUser == null) {
// TODO - connect to IPRS - how can this method be called if no user is logged in
return false;
}
String currentUserName = currentUser.getPrincipal().toString();
return currentUserName.equals(currentAccount.getUsername());
}
/* **** getter / setter **** */
/**
* setter for managed property applicationView
*
* @param applicationView the applicaton view to inject
*/
public void setApplicationView(ApplicationView applicationView) {
this.applicationView = applicationView;
}
public AccountEntity getCurrentAccount() {
return currentAccount;
}
public void setCurrentAccount(AccountEntity currentAccount) {
this.currentAccount = currentAccount;
}
public boolean isShowDisabledAccounts() {
return showDisabledAccounts;
}
public void setShowDisabledAccounts(boolean showDisabledAccounts) {
this.showDisabledAccounts = showDisabledAccounts;
}
public List<ApplicationRoleEntity> getCurrentAccountRoles() {
return currentAccountRoles;
}
public void setCurrentAccountRoles(List<ApplicationRoleEntity> currentAccountRoles) {
this.currentAccountRoles = currentAccountRoles;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRepeatPassword() {
return repeatPassword;
}
public void setRepeatPassword(String repeatPassword) {
this.repeatPassword = repeatPassword;
}
}

View File

@ -1,151 +0,0 @@
package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.application.control.ApplicationControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.util.AccountSecurityException;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@SessionScoped
@Named("applicationView")
public class ApplicationView implements Serializable {
private static final long serialVersionUID = -5515249316880163539L;
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationView.class);
@Inject
ApplicationControl applicationService;
@Inject
InstanceView instanceView;
@Inject
Locale locale;
private ApplicationEntity currentApplication = null;
private ApplicationEntity editApplication = null;
private List<ApplicationEntity> applicationList = null;
@PostConstruct
public void selectDefaultCurrentApplication() {
// force applications to be loaded from database
getAllApplications();
if ((applicationList != null) && (!applicationList.isEmpty())) {
currentApplication = applicationList.get(0);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("post construct executed");
}
}
@PreDestroy
public void predestroy() {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Predestroy executed");
}
}
public List<ApplicationEntity> getAllApplications() {
if (applicationList == null) {
try {
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;
} catch (AccountSecurityException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
FacesUtil.addGlobalErrorMessage("Error " + ex.getErrorCode(), ex.getLocalizedMessage(locale));
return new ArrayList<>();
}
}
return applicationList;
}
public void selectApplication() {
if (currentApplication != null) {
LOGGER.info("selected application: {}", currentApplication.getApplicationName());
FacesUtil.addGlobalInfoMessage("Success", "Selected application " + currentApplication.getApplicationName());
}
}
public void newApplication() {
this.editApplication = new ApplicationEntity();
}
public void cancelEditApplication() {
this.editApplication = null;
}
public void saveEditApplication() {
if (editApplication == null) {
FacesUtil.addGlobalErrorMessage("Error", "Need to provide data");
} else if ((editApplication.getApplicationName() == null) || (editApplication.getApplicationName().trim().equals(""))) {
String hint;
if (editApplication.getId() == null) {
hint = "Cannot create application";
} else {
hint = "Cannot save application";
}
FacesUtil.addGlobalErrorMessage(hint, "Application name must not be empty");
} else {
currentApplication = applicationService.createOrUpdate(editApplication);
// force reload of to update view
applicationList = null;
FacesUtil.addGlobalInfoMessage("Info", "Application saved");
}
}
public void deleteApplication() {
if (currentApplication == null) {
FacesUtil.addGlobalErrorMessage("Error", "Need to provide data");
} else if (currentApplication.getId() == null) {
FacesUtil.addGlobalErrorMessage("Error", "Cannot delete non persistent data");
} else {
String applicationName = currentApplication.getApplicationName();
applicationService.delete(currentApplication);
applicationList = null; // force reload to update view
currentApplication = null;
selectDefaultCurrentApplication();
FacesUtil.addGlobalInfoMessage("Info", "Application " + applicationName + " deleted");
}
}
/* *** getter / setter *** */
public ApplicationEntity getCurrentApplication() {
return currentApplication;
}
public void setCurrentApplication(ApplicationEntity currentApplication) {
this.currentApplication = currentApplication;
}
public ApplicationEntity getEditApplication() {
return editApplication;
}
public void setEditApplication(ApplicationEntity editApplication) {
this.editApplication = editApplication;
}
}

View File

@ -1,55 +0,0 @@
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.entity.ConfigException;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* TODO - move to shared-account and remove from all applications and archetype
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Named(value = "instanceView")
@ApplicationScoped
public class InstanceView {
private static final Logger LOGGER = LoggerFactory.getLogger(InstanceView.class);
@Inject
ConfigService configService;
@Inject
ApplicationController applicationController;
public boolean isDevelopmentVersion() {
String instanceName = getInstanceName();
return !instanceName.equals("Production");
}
public String getInstanceName() {
String instanceName;
try {
instanceName = configService.getConfigValue("base.instance");
} catch (ConfigException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
instanceName = "unknown (" + ex.toString() + ")";
}
if (instanceName == null) {
return "unknown";
} else {
return instanceName;
}
}
public ApplicationEntity getInstanceApplication() {
return applicationController.getApplication();
}
}

View File

@ -1,143 +0,0 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web.presentation;
import de.muehlencord.shared.account.business.account.entity.AccountException;
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.ApplicationPermissionEntity;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ViewScoped
@Named("permissionView")
public class PermissionView implements Serializable {
private static final long serialVersionUID = -1469453490360990772L;
private static final Logger LOGGER = LoggerFactory.getLogger(PermissionView.class);
@Inject
private ApplicationView applicationView;
@EJB
ApplicationPermissionControl applicationPermissionService;
private ApplicationPermissionEntity currentPermission;
public List<ApplicationPermissionEntity> getAppPermissions() {
return applicationPermissionService.getApplicationPermissions(applicationView.getCurrentApplication());
}
public void saveEditPermission() throws AccountException {
if (currentPermission != null) {
String newPermissionName = currentPermission.getPermissionName();
String newPermissionDescription = currentPermission.getPermissionDescription();
if ((newPermissionName == null) || (newPermissionName.trim().length() == 0)) {
FacesUtil.addErrorMessage("editDialogMessages", "Error", "Permission name must not be null");
} else if ((newPermissionDescription == null) || (newPermissionDescription.trim().length() == 0)) {
FacesUtil.addErrorMessage("editDialogMessages", "Error", "Permission name must not be null");
} else {
if (currentPermission.getId() == null) {
applicationPermissionService.create(applicationView.getCurrentApplication(), newPermissionName, newPermissionDescription);
FacesUtil.addGlobalInfoMessage("Info", "Permission " + newPermissionName + " created");
} else {
applicationPermissionService.update(currentPermission);
FacesUtil.addGlobalInfoMessage("Info", "Permission " + newPermissionName + " updated");
}
}
}
}
public ApplicationEntity getCurrentApplication() {
if (applicationView.getCurrentApplication() == null) {
return null;
} else {
return applicationView.getCurrentApplication();
}
}
public void cancelEditPermission() {
this.currentPermission = null;
}
public void newPermission() {
this.currentPermission = new ApplicationPermissionEntity();
}
public void editPermission() {
if (currentPermission == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission to edit");
}
}
public void deletePermission() {
if (currentPermission == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission to edit");
} else {
try {
applicationPermissionService.delete(currentPermission);
currentPermission = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
FacesUtil.addGlobalErrorMessage("Error while deleting permission.", ex.toString());
}
}
}
public boolean getCanEdit() {
return isPermissionSelected();
}
public boolean getCanDelete() {
return isPermissionSelected();
}
/* *** getter / setter *** */
/**
* required setter for managedProperty
*
*
* @param applicationView the injected applicationView
*/
public void setApplicationView(ApplicationView applicationView) {
this.applicationView = applicationView;
}
public ApplicationPermissionEntity getCurrentPermission() {
return currentPermission;
}
public void setCurrentPermission(ApplicationPermissionEntity newCurrentPermission) {
this.currentPermission = newCurrentPermission;
}
public boolean isPermissionSelected() {
return currentPermission != null;
}
}

View File

@ -1,236 +0,0 @@
/*
* Copyright 2017 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.web.presentation;
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.ApplicationRoleEntity;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.primefaces.event.SelectEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ViewScoped
@Named("roleView")
public class RoleView implements Serializable {
private static final long serialVersionUID = 1669321020398119007L;
private static final Logger LOGGER = LoggerFactory.getLogger(RoleView.class);
@Inject
private ApplicationView applicationView;
@EJB
ApplicationRoleControl applicationRoleControl;
private List<ApplicationRoleEntity> allRoles = null;
private List<ApplicationPermissionEntity> currentRolePermissions = null;
private List<ApplicationPermissionEntity> missingApplicationsPermissions = null;
private ApplicationRoleEntity currentRole;
private ApplicationPermissionEntity currentPermission;
private ApplicationPermissionEntity newPermission;
public ApplicationEntity getCurrentApplication() {
return applicationView.getCurrentApplication();
}
public List<ApplicationRoleEntity> getAllRoles() {
if (allRoles == null) {
allRoles = applicationRoleControl.getAllRoles(applicationView.getCurrentApplication());
}
return allRoles;
}
public void startNewRole() {
this.currentRole = new ApplicationRoleEntity(applicationView.getCurrentApplication());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Created new current role: {}", currentRole.toString());
}
}
public void cancelEditRole() {
this.currentRole = null;
}
public void saveEditRole() {
if ((currentRole == null) || (currentRole.getRoleName() == null) || (currentRole.getRoleName().trim().length() == 0)) {
FacesUtil.addGlobalErrorMessage("Error", "Permission name must not be null");
} else if (currentRole.getId() == null) {
applicationRoleControl.create(currentRole);
allRoles = null; // force reload
FacesUtil.addGlobalInfoMessage("Info", "Role " + currentRole.getRoleName() + " created");
} else {
applicationRoleControl.update(currentRole);
allRoles = null; // force reload
FacesUtil.addGlobalInfoMessage("Info", "Role " + currentRole.getRoleName() + " updated");
}
}
public void deleteRole() {
if (currentRole == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission to edit");
} else {
try {
applicationRoleControl.delete(currentRole);
allRoles = null; // force reload
currentRole = null;
currentRolePermissions = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
FacesUtil.addGlobalErrorMessage("Error while deleting permission.", ex.toString());
}
}
}
public boolean getRoleSelected() {
return currentRole != null;
}
public boolean getPermissionSelected() {
return currentPermission != null;
}
public boolean getMissingPermissionAvailable() {
return ((missingApplicationsPermissions != null) && (!missingApplicationsPermissions.isEmpty()));
}
public void onRoleSelect(SelectEvent event) {
currentRolePermissions = null;
currentRolePermissions = getRolePermissions();
missingApplicationsPermissions = null;
missingApplicationsPermissions = getMissingPermissions();
}
public List<ApplicationPermissionEntity> getRolePermissions() {
if (currentRole == null) {
currentRolePermissions = new ArrayList<>();
return currentRolePermissions;
} else {
if (currentRolePermissions == null) {
try {
currentRolePermissions = applicationRoleControl.getRolePermissions(currentRole);
} catch (AccountException ex) {
LOGGER.error(ex.getMessage());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
FacesUtil.addGlobalErrorMessage("Error while fetching role permissions", "see log for details");
currentRolePermissions = new ArrayList<>();
}
}
return currentRolePermissions;
}
}
public List<ApplicationPermissionEntity> getMissingPermissions() {
if (currentRole == null) {
missingApplicationsPermissions = new ArrayList<>();
return missingApplicationsPermissions;
} else {
if (missingApplicationsPermissions == null) {
missingApplicationsPermissions = applicationRoleControl.getNotAssignedApplicationPermissions(currentRole);
}
return missingApplicationsPermissions;
}
}
public void addRolePermission() {
if (newPermission == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a new permission first");
} else {
try {
applicationRoleControl.addPermission(currentRole, newPermission);
currentRolePermissions = null;
missingApplicationsPermissions = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
FacesUtil.addGlobalErrorMessage("Error while adding permission", ex.getMessage());
}
}
}
public void removeRolePermission() {
if (currentPermission == null) {
FacesUtil.addGlobalErrorMessage("Error", "Please select a permission first");
} else {
try {
applicationRoleControl.removePermission(currentRole, currentPermission);
currentRolePermissions = null;
missingApplicationsPermissions = null;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
}
FacesUtil.addGlobalErrorMessage("Error while adding permission", ex.getMessage());
}
}
}
/* *** getter / setter *** */
public void setApplicationView(ApplicationView applicationView) {
this.applicationView = applicationView;
}
public ApplicationRoleEntity getCurrentRole() {
return currentRole;
}
public void setCurrentRole(ApplicationRoleEntity currentRole) {
this.currentRole = currentRole;
}
public ApplicationPermissionEntity getCurrentPermission() {
return currentPermission;
}
public void setCurrentPermission(ApplicationPermissionEntity currentPermission) {
this.currentPermission = currentPermission;
}
public ApplicationPermissionEntity getNewPermission() {
return newPermission;
}
public void setNewPermission(ApplicationPermissionEntity newPermission) {
this.newPermission = newPermission;
}
}

View File

@ -1,69 +0,0 @@
package de.muehlencord.shared.account.web.presentation;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;
import javax.persistence.EntityManager;
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.ApplicationRoleEntity;
import de.muehlencord.shared.account.util.AccountPU;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@FacesValidator("uniqueApplicationRoleNameValidator")
public class UniqueApplicationRoleNameValidator implements Validator, Serializable {
private static final long serialVersionUID = 8165013107453616719L;
@Inject
@AccountPU
EntityManager em;
@Inject
ApplicationRoleControl applicationRoleControl;
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
Object oldRoleNameObj = ((UIInput) component).getValue();
String oldRoleName = "";
if (oldRoleNameObj != null) {
oldRoleName = oldRoleNameObj.toString();
}
Object applicationObj = component.getAttributes().get("application");
if ((applicationObj != null) && (applicationObj instanceof ApplicationEntity)) {
ApplicationEntity application = (ApplicationEntity) applicationObj;
if (value == null) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Role name invalid", "Role name must not be empty"));
}
if (value instanceof String) {
String roleName = (String) value;
ApplicationRoleEntity existingRole = applicationRoleControl.findByName(application, roleName);
if (existingRole != null) {
if (!oldRoleName.equals(roleName)) {
// name of role changed and there is another role with the new name already --> this must not happen
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Role name invalid", "Role already exists"));
}
}
} else {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Role name invalid", "Role name must be a string value"));
// TODO add IPRS logger - someone is trying to cheat
}
} else {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Application not set", "Permission name cannot be set if application is unknown"));
}
}
}

View File

@ -1,63 +0,0 @@
package de.muehlencord.shared.account.web.presentation;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.muehlencord.shared.account.business.application.control.ApplicationControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@FacesValidator("uniqueApplicationValidator")
public class UniqueApplicationValidator implements Validator, Serializable {
private static final long serialVersionUID = 2526409681909574670L;
private static final Logger LOGGER = LoggerFactory.getLogger(UniqueApplicationValidator.class);
@Inject
ApplicationControl applicationService;
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
Object oldAppNameObj = ((UIInput) component).getValue();
String oldAppName = "";
if (oldAppNameObj != null) {
oldAppName = oldAppNameObj.toString();
}
if (value == null) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Application name invalid", "Application name must not be empty"));
}
if (value instanceof String) {
String applicationname = (String) value;
ApplicationEntity existingApplication = applicationService.findByApplicationName(applicationname);
if (existingApplication != null) {
if (!oldAppName.equals(applicationname)) {
// name of application changed and there is another application with the new
// name already --> this must not happen
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Application name invalid", "Application already exists"));
}
}
LOGGER.info("Name = {}", applicationname);
} else {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Application name invalid", "Application name must be a string value"));
// TODO add IPRS logger - someone is trying to cheat
}
}
}

View File

@ -1,68 +0,0 @@
package de.muehlencord.shared.account.web.presentation;
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.entity.ApplicationEntity;
import de.muehlencord.shared.account.util.AccountPU;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;
import javax.persistence.EntityManager;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@FacesValidator("uniquePermissionNameValidator")
public class UniquePermissionNameValidator implements Validator, Serializable {
private static final long serialVersionUID = 2526409681909574670L;
@Inject
@AccountPU
EntityManager em;
@Inject
ApplicationPermissionControl applicationPermissionControl;
@Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
Object oldPermissionNameObj = ((UIInput) component).getValue();
String oldPermissionName = "";
if (oldPermissionNameObj != null) {
oldPermissionName = oldPermissionNameObj.toString();
}
Object applicationObj = component.getAttributes().get("application");
if ((applicationObj != null) && (applicationObj instanceof ApplicationEntity)) {
ApplicationEntity application = (ApplicationEntity) applicationObj;
if (value == null) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Permission name invalid", "Permission name must not be empty"));
}
if (value instanceof String) {
String permissionName = (String) value;
ApplicationPermissionEntity existingPermission = applicationPermissionControl.findPermissionByName(application, permissionName);
if (existingPermission != null) {
if ((!oldPermissionName.equals (permissionName))) {
// name of permission changed and there is another permission with the new
// name already --> this must not happen
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Permission name invalid", "Permission already exists"));
}
}
} else {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Permission name invalid", "Permission name must be a string value"));
// TODO add IPRS logger - someone is trying to cheat
}
} else {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Application not set", "Permission name cannot be set if application is unknown"));
}
}
}

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="accountPu" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/jboss/accountDs</jta-data-source>
<class>de.muehlencord.shared.account.business.account.entity.AccountEntity</class>
<class>de.muehlencord.shared.account.business.account.entity.AccountHistoryEntity</class>
<class>de.muehlencord.shared.account.business.account.entity.AccountLoginEntity</class>
<class>de.muehlencord.shared.account.business.account.entity.ApiKeyEntity</class>
<class>de.muehlencord.shared.account.business.application.entity.ApplicationEntity</class>
<class>de.muehlencord.shared.account.business.application.entity.ApplicationPermissionEntity</class>
<class>de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity</class>
<class>de.muehlencord.shared.account.business.config.entity.ConfigEntity</class>
<class>de.muehlencord.shared.account.business.mail.entity.MailTemplateEntity</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<validation-mode>NONE</validation-mode>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL94Dialect"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
</properties>
</persistence-unit>
</persistence>

View File

@ -1,32 +0,0 @@
admin.loginPage=login.xhtml
admin.indexPage=web/index.xhtml
#admin.dateFormat=
#admin.breadcrumbSize=5
admin.renderMessages=true
#admin.renderAjaxStatus=true
## disable filter to redirect to login page - shiro security filter is already doing this
admin.disableFilter=true
#admin.renderBreadCrumb=true
#admin.enableSlideMenu=true
#admin.enableRipple=true
#admin.rippleElements= .ripplelink,button.ui-button,.ui-selectlistbox-item,.ui-multiselectlistbox-item,.ui-selectonemenu-label,.ui-selectcheckboxmenu,\
#.ui-autocomplete-dropdown, .ui-autocomplete-item ... (the list goes on)
admin.skin=skin-purple-light
#admin.autoShowNavbar=true
#admin.ignoredResources=
#admin.loadingImage=ajaxloadingbar.gif
#admin.extensionLessUrls=false
admin.renderControlSidebar=false
#admin.controlSidebar.showOnMobile=false
#admin.controlSidebar.leftMenuTemplate=true
#admin.controlSidebar.fixedLayout=false
#admin.controlSidebar.boxedLayout=false
#admin.controlSidebar.sidebarCollapsed=false
#admin.controlSidebar.expandOnHover=false
#admin.controlSidebar.fixed=false
#admin.controlSidebar.darkSkin=true
#admin.rippleMobileOnly=true
admin.renderMenuSearch=false
## do not autohide
admin.autoHideMessages=false
#admin.messagesHideTimeout=2500

View File

@ -1,3 +0,0 @@
build.version=${project.version}
build.timestamp=${timestamp}
application.uuid=${applicationUuid}

View File

@ -1,133 +0,0 @@
header_login=Login
header_reset_password=Reset password
message_username_password=Please enter your user name and a new password
button_login=Login
button_cancel=Cancel
button_password_lost=Password lost?
label_username=Username
label_password=Password
label_new_password=New Password
button_password_reset=Reset password
header_passwort_lost=Lost password
message_start_password_reset=Please enter your username to start the password recovery procedure
menu_dashboard=Dashboard
menu_events=Events
menu_administration=Administration
menu_overview=Overview
menu_emails=Emails
menu_account=Account
menu_config=Config
menu_logout=Logout
button_new=New
button_delete=Delete
button_edit=Edit
button_reload=Reload
label_name=Name
label_description=Description
label_event_date=Event Date
label_reservation=Reservation
label_reservation_from_to=Reservation from/to
label_actions=Actions
message_confirm=Are you sure?
button_setup=Setup
button_reservations=Reservations
label_event_name=Event Name
label_event_item_desc=Event Item Description
label_timezone=Timezone
label_event_start=Event Start
label_event_end=Event End
label_reservation_autostart=Reservation start
label_reservation_autoend=Reservation end
label_reservation_active=Reservation active
label_reservation_max_items=Max Items
label_booking_deadline=Booking deadline
label_template_validation=Email validation mail template
label_template_confirmation=Event confirmation mail template
label_template_waitlist=Event waitlist mail template
message_event_not_found=Event not found
label_items=Items
label_costs=Costs
label_all=All
label_yes=Yes
label_no=No
label_status=Status
label_firstname=Firstname
label_lastname=Lastname
label_emailaddress=Emailaddress
label_comment=Comment
label_email_confirmed=Email confirmed
label_booking_number=Booking Number
label_booking_executed=booking executed
tt_log_entries=Show log entries
tt_cancel_reservation=Cancel the current reservation
tt_send_email_again=Send email again
tt_move_from_wl=Move from waitlist
tt_fix_reservation=Try to fix the current reservation
tt_edit_reservation=Edit the reservation
button_refresh_free=Refresh free
button_manual_reserve=Reserve
button_export=Export
label_amount=Amount
label_select=Select
label_created_by=Created by
label_ip=IP
label_ip_forwarded=IP (forwarded)
label_value=Value
label_useragent=Useragent
button_ok=Ok
message_comment=Please add a comment
menu_help=Help
label_event=Event
label_active=Active
label_waitlist=Waitlist
label_is_waitlist=Is waitlist
label_order=Order
message_dynamic_numbering=dynamic numbering (put %n as placeholder)
label_start_number=Start Number
label_end_number=End Number
header_item_def=Define items for event
message_no_event_items=No event item defined
button_overview=Overview
label_reservation_auto_start=Automatically switch on/off
label_item_public=Item public?
label_is_publicitem=Is public
label_customer_comment=Customer comment
label_change_comment=Change comment
label_existing_items=current items
label_new_items=new items
label_available_items=available items
label_no_records=No records found.
button_mail=Mail
header_email_distribution=Email distribution
label_template=Template
label_demomode=Demo mode
message_invalid_email=Please provide a valid email address
menu_permissions=Permissions
button_save=Save
menu_groups=Groups
message_email_sent=email sent
message_email_with_error=emails with error
message_no_email=no email address defined
message_email_not_sent=Error while sending emails
label_seating=Seating
label_attachments=Attachments
label_language=Language
label_subject=Subject
label_bytes=Bytes
label_upload=Upload
header_export=Export
label_export_type=Export Type
label_filtered=Filtered
label_include_deleted=Include deleted
label_include_log=Include Logs
label_template_booking_executed=Booking executed template
label_street=Street
label_zipCode=ZIP Code
label_city=City
label_groupName=Groupname
label_phoneNumber=Phone Number
label_template_waitlist_cancelled=Waitlist cancelled mail template
msgs_menu_status=Status
menu_status=Status
button_add=Add
passwords_different=Passwords do not match, please check input

View File

@ -1,134 +0,0 @@
header_login=Anmeldung
header_reset_password=Passwort zur\u00fccksetzten
message_username_password=Bitte geben Deinen Benutzernamen und dein Passwort ein
button_login=Anmelden
button_cancel=Abbruch
button_password_lost=Passwort vergessen?
label_username=Benutzername
label_password=Passwort
label_new_password=Neues Passwort
button_password_reset=Passwort zur\u00fccksetzten
header_passwort_lost=Passwort vergessen
message_start_password_reset=Bitte gib deinen Benutzernamen ein um das Zur\u00fccksetzten des Passworts zu starten.
menu_dashboard=Dashbaord
menu_events=Veranstaltungen
menu_administration=Administration
menu_overview=\u00dcbersicht
menu_emails=E-Mails
menu_account=Benutzer
menu_config=Konfiguration
menu_logout=Abmelden
button_new=Neu
button_delete=L\u00f6schen
button_edit=Bearbeiten
button_reload=Aktualisieren
label_name=Name
label_description=Beschreibung
label_event_date=Veranstaltungsdatum
label_reservation=Reservierung
label_reservation_from_to=Reservierung von/bis
label_actions=Aktionen
message_confirm=Bist du sicher?
button_setup=Setup
button_reservations=Reservierungen
label_event_name=Veranstaltungsname
label_event_item_desc=Veranstaltungsobjekte
label_timezone=Zeitzone
label_event_start=Veranstaltungsbeginn
label_event_end=Veranstaltungsende
label_reservation_autostart=Reservierung von
label_reservation_autoend=Reservierung bis
label_reservation_active=Reservierung aktiv
label_reservation_max_items=Maximale Objekte
label_booking_deadline=Buchungsfrist
label_template_validation=Vorlage Emailvalidierung
label_template_confirmation=Vorlage Reservierungsbest\u00e4tigung
label_template_waitlist=Vorlage Wartelist
message_event_not_found=Veranstaltung nicht gefunden
label_items=Objekte
label_costs=Kosten
label_all=Alle
label_yes=Ja
label_no=Nein
label_status=Status
label_firstname=Vorname
label_lastname=Nachname
label_emailaddress=E-Mail-Adresse
label_comment=Kommentar
label_email_confirmed=E-Mail best\u00e4tigt
label_booking_number=Buchungsnummer
label_booking_executed=Buchungs ausgef\u00fchrt
tt_log_entries=Logbucheintr\u00e4ge
tt_cancel_reservation=Storniere die Reservierung
tt_send_email_again=Sende E-Mail erneut
tt_move_from_wl=Schiebe von Warteliste
tt_fix_reservation=Versuche den Fehler zu beheben
tt_edit_reservation=Bearbeite die Reservierung
button_refresh_free=Frei aktualisieren
button_manual_reserve=Reservieren
button_export=Exportieren
label_amount=Anzahl
label_select=W\u00e4hlen
label_created_by=Erzeugt durch
label_ip=IP
label_ip_forwarded=IP (forwarded)
label_value=Wert
label_useragent=Useragent
button_ok=Ok
message_comment=Bitte geben Sie einen Kommentar an
menu_help=Hilfe
label_event=Veranstaltung
label_active=Aktiv
label_waitlist=Warteliste
label_is_waitlist=Ist Warteliste
label_order=Reihenfolge
message_dynamic_numbering=Dynamische Nummerierung (%n als Platzhalter)
label_start_number=Startnummer
label_end_number=Endnummer
header_item_def=Objekte f\u00fcr Veranstaltung
message_no_event_items=Keine Objekte definiert
button_overview=\u00dcbersicht
label_reservation_auto_start=Automatisch ein/ausschalten
label_item_public=\u00d6ffentlich verf\u00fcgar?
label_is_publicitem=\u00d6ffentlich
label_customer_comment=Kundenkommentar
label_change_comment=\u00c4nderungskommentar
label_existing_items=aktuelle Objekte
label_new_items=neue Objekte
label_available_items=verf\u00fcgbare Objekte
label_no_records=Keine Daten gefunden.
button_mail=E-Mail
header_email_distribution=Emailversand
label_template=Vorlage
label_demomode=Demomodus
message_invalid_email=Bitte geben Sie eine g\u00fcltige Emailadresse an
menu_permissions=Berechtigungen
button_save=Speichern
menu_groups=Gruppen
message_email_sent=Email gesendet
message_email_with_error=Emails mit Fehler
message_no_email=keine Emailadresse verf\u00fcgbar
message_email_not_sent=Fehler beim Versenden der Email
label_seating=Saalplan Platz
label_attachments=Attachments
label_language=Sprache
label_subject=Betreff
label_bytes=Bytes
label_upload=Upload
header_export=Exportieren
label_export_type=Export Art
label_filtered=Gefiltert
label_include_deleted=Einschlie\u00dflich gel\u00f6scht
label_include_log=mit Logbuch
label_template_booking_executed=Vorlage Buchung durchgef\u00fchrt
label_street=Stra\u00dfe
label_zipCode=PLZ
label_city=Ort
label_groupName=Gruppenname
label_phoneNumber=Telefonnummer
label_template_waitlist_cancelled=Vorlage Warteliste Abbruch
msgs_menu_status=Status
menu_status=Status
button_add=Hinzuf\u00fcgen
passwords_different=Passw\u00f6rter stimmen \u00fcberein, bitte \u00fcberpr\u00fcfen Sie ihre Eingabe

View File

@ -1,134 +0,0 @@
header_login=Login
header_reset_password=Reset password
message_username_password=Please enter your user name and a new password
button_login=Login
button_cancel=Cancel
button_password_lost=Password lost?
label_username=Username
label_password=Password
label_new_password=New Password
button_password_reset=Reset password
header_passwort_lost=Lost password
message_start_password_reset=Please enter your username to start the password recovery procedure
menu_dashboard=Dashboard
menu_events=Events
menu_administration=Administration
menu_overview=Overview
menu_emails=Emails
menu_account=Account
menu_config=Config
menu_logout=Logout
button_new=New
button_delete=Delete
button_edit=Edit
button_reload=Reload
label_name=Name
label_description=Description
label_event_date=Event Date
label_reservation=Reservation
label_reservation_from_to=Reservation from/to
label_actions=Actions
message_confirm=Are you sure?
button_setup=Setup
button_reservations=Reservations
label_event_name=Event Name
label_event_item_desc=Event Item Description
label_timezone=Timezone
label_event_start=Event Start
label_event_end=Event End
label_reservation_autostart=Reservation Start
label_reservation_autoend=Reservation End
label_reservation_active=Reservation active
label_reservation_max_items=Max Items
label_booking_deadline=Booking deadline
label_template_validation=Email validation mail template
label_template_confirmation=Event confirmation mail template
label_template_waitlist=Event waitlist mail template
message_event_not_found=Event not found
label_items=Items
label_costs=Costs
label_all=All
label_yes=Yes
label_no=No
label_status=Status
label_firstname=Firstname
label_lastname=Lastname
label_emailaddress=Emailaddress
label_comment=Comment
label_email_confirmed=Email confirmed
label_booking_number=Booking Number
label_booking_executed=booking executed
tt_log_entries=Show log entries
tt_cancel_reservation=Cancel the current reservation
tt_send_email_again=Send email again
tt_move_from_wl=Move from waitlist
tt_fix_reservation=Try to fix the current reservation
tt_edit_reservation=Edit the reservation
button_refresh_free=Refresh free
button_manual_reserve=Reserve
button_export=Export
label_amount=Amount
label_select=Select
label_created_by=Created by
label_ip=IP
label_ip_forwarded=IP (forwarded)
label_value=Value
label_useragent=Useragent
button_ok=Ok
message_comment=Please add a comment
menu_help=Help
label_event=Event
label_active=Active
label_waitlist=Waitlist
label_is_waitlist=Is waitlist
label_order=Reservation Order
message_dynamic_numbering=dynamic numbering (put %n as placeholder)
label_start_number=Start Number
label_end_number=End Number
header_item_def=Define items for event
message_no_event_items=No event item defined
button_overview=Overview
label_reservation_auto_start=Automatically switch on/off
label_item_public=Item public?
label_is_publicitem=Is public
label_customer_comment=Customer comment
label_change_comment=Change comment
label_existing_items=current items
label_new_items=new items
label_available_items=available items
label_no_records=No records found.
button_mail=Mail
header_email_distribution=Email distribution
label_template=Template
label_demomode=Demo mode
message_invalid_email=Please provide a valid email address
menu_permissions=Permissions
button_save=Save
menu_groups=Groups
message_email_sent=email sent
message_email_with_error=emails with error
message_no_email=no email address defined
message_email_not_sent=Error while sending emails
label_seating=Seating
label_attachments=Anh\u00e4nge
label_language=Language
label_subject=Subject
label_bytes=Bytes
label_upload=Hochladen
header_export=Export
label_export_type=Export Type
label_filtered=Filtered
label_include_deleted=Include deleted
label_include_log=Include Logs
label_template_booking_executed=Booking executed template
label_street=Street
label_zipCode=ZIP Code
label_city=City
label_groupName=Groupname
label_phoneNumber=Phone Number
label_template_waitlist_cancelled=Waitlist cancelled mail template
msgs_menu_status=Status
menu_status=Status
button_add=Add
passwords_different=Passwords do not match, please check input

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1"
bean-discovery-mode="all">
</beans>

View File

@ -1,22 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
<application>
<el-resolver>org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolver</el-resolver>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>en</supported-locale>
<supported-locale>de</supported-locale>
</locale-config>
<!-- register own messages for general i18n support -->
<resource-bundle>
<base-name>de.muehlencord.shared.account.web.presentation.messages</base-name>
<var>msgs</var>
</resource-bundle>
</application>
</faces-config>

View File

@ -1,59 +0,0 @@
[main]
# Context factory required for LDAP
${shiro.contextFactory}
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
# DataSource Setup
datasource = org.apache.shiro.jndi.JndiObjectFactory
datasource.resourceName = java:/jboss/accountDs
datasource.resourceRef = true
# HashService
hashService = org.apache.shiro.crypto.hash.DefaultHashService
hashService.hashIterations = 500000
hashService.hashAlgorithmName = SHA-512
hashService.generatePublicSalt = true
# Password service
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordService.hashService = $hashService
# Required password matcher
${shiro.passwordMatcher}
# LDAP Realm setup
${shiro.ldapRealm}
# JDBC Realm setup
jdbcRealm = de.muehlencord.shared.account.shiro.realm.AccountRealm
jdbcRealm.applicationId = ${applicationUuid}
jdbcRealm.credentialsMatcher = $passwordMatcher
jdbcRealm.dataSource = $datasource
# Activate realms
authcStrategy = ${shiro.authcStrategy}
securityManager.realms = ${shiro.realms}
securityManager.authenticator.authenticationStrategy = $authcStrategy
# Setup authentication filter
authc = de.muehlencord.shirofaces.filter.FacesAjaxAwarePassThruAuthenticationFilter
authc.loginUrl = /login.xhtml
authc.successUrl = /web/index.xhtml
roles.unauthorizedUrl = /error/accessDenied.xhtml
#
# filter setup
#
[urls]
/public/**=anon
/resources/**=anon
/fonts/**=anon
/javax.faces.resource/**=anon
/login.xhtml=authc
/logout.xhtml=logout
/**=authc
# /web/**=authc

View File

@ -1,123 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>reservation-system-backed</display-name>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>${jsf.projectStage}</param-value>
</context-param>
<context-param>
<param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
<param-value>1048576</param-value>
</context-param>
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>admin</param-value>
</context-param>
<context-param>
<param-name>primefaces.FONT_AWESOME</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>primefaces.MOVE_SCRIPTS_TO_BOTTOM</param-name>
<param-value>true</param-value>
</context-param>
<servlet>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>web/index.xhtml</welcome-file>
</welcome-file-list>
<!-- Shiro Web Environment -->
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<display-name>ShiroFilter</display-name>
<filter-name>shiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<!-- Faces Exception Filter -->
<filter>
<display-name>FacesExceptionFilter</display-name>
<filter-name>facesExceptionFilter</filter-name>
<filter-class>org.omnifaces.filter.FacesExceptionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>facesExceptionFilter</filter-name>
<servlet-name>FacesServlet</servlet-name>
</filter-mapping>
<!-- Content Security Policy headers -->
<filter>
<filter-name>contentSecurityFilter</filter-name>
<filter-class>de.muehlencord.sf.filter.ContentSecurityPolicyFilter</filter-class>
<init-param>
<param-name>report-only</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>default-src</param-name>
<param-value>'none'</param-value>
</init-param>
<init-param>
<param-name>img-src</param-name>
<param-value>'self'</param-value>
</init-param>
<init-param>
<param-name>script-src</param-name>
<param-value>'self' 'unsafe-inline' 'unsafe-eval'</param-value>
</init-param>
<init-param>
<param-name>style-src</param-name>
<param-value>'self' 'unsafe-inline'</param-value>
</init-param>
<init-param>
<param-name>connect-src</param-name>
<param-value>'self'</param-value>
</init-param>
<init-param>
<param-name>font-src</param-name>
<param-value>'self'</param-value>
</init-param>
<init-param>
<param-name>object-src</param-name>
<param-value>'none'</param-value>
</init-param>
<init-param>
<param-name>media-src</param-name>
<param-value>'none'</param-value>
</init-param>
<init-param>
<param-name>child-src</param-name>
<param-value>'none'</param-value>
</init-param>
</filter>
<!-- Security related headers -->
<filter>
<display-name>OwaspStandardFilter</display-name>
<filter-name>owaspStandardFilter</filter-name>
<filter-class>de.muehlencord.sf.filter.OwaspStandardFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>owaspStandardFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

View File

@ -1,96 +0,0 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Login Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="shortcut icon" href="#{resource['images/favicon/favicon.ico']}" />
<h:outputStylesheet name="css/admin.css" />
<style type="text/css">
/* below css hides growls in small screens and makes messages visible */
@media (max-width: 768px) {
body div.ui-growl {
display: none;
}
body div.ui-messages {
display: block;
}
}
/* below css hides messages in medium/big devices and makes growl visible in such devices */
@media (min-width: 769px) {
body div.ui-growl {
display: block;
}
body div.ui-messages {
display: none;
}
}
body.login-page {
background-color: transparent;
}
html {
background: url(#{resource[ 'images:login-bg.png' ]}) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
</style>
</h:head>
<h:body styleClass="hold-transition login-page">
<p:growl sticky="true">
<p:autoUpdate />
</p:growl>
<div id="loader" class="load-bar" style="display: none">
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
</div>
<div class="login-box">
<div class="login-logo">
<p:link href="/web/accounts.xhtml"><b>Account&nbsp;</b>Management</p:link>
<h:outputLabel rendered="#{instanceView.developmentVersion}" value="#{instanceView.instanceName}" />
</div>
<!-- /.login-logo -->
<div class="box login-box-body">
<h:form>
<p:focus context="panel" for="username" />
<p class="login-box-msg">Sign in to start your session</p>
<p:messages closable="true" />
<div id="panel" class="form-group has-feedback">
<p:inputText id="username" value="#{loginView.username}" styleClass="form-control" placeholder="Username"
required="true" autocomplete="off"
requiredMessage="Username is required."/>
<i class="fa fa-user form-control-feedback"></i>
</div>
<div class="form-group has-feedback">
<p:inputText value="#{loginView.password}" type="password" styleClass="form-control"
placeholder="Password" required="true" autocomplete="off" size="40"
requiredMessage="Password is required."/>
<i class="fa fa-lock form-control-feedback" style="font-size: 18px" ></i>
</div>
<div class="row">
<p:spacer height="10"/>
<div class="col-xs-12">
<p:commandButton styleClass="btn btn-success btn-block" onclick="showBar()"
action="#{loginView.authenticate}" oncomplete="if(args.validationFailed) { hideBar()}"
value="Sign In" process="@form" update="@form" icon="fa fa-sign-in" iconPos="left"/>
</div>
</div>
</h:form>
</div>
<!-- /.login-box-body -->
</div>
</h:body>
</html>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml">
<ui:define name="title">
Logout
</ui:define>
<ui:define name="body">
<h2>You are logged out. </h2>
</ui:define>
</ui:composition>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui">
<composite:interface />
<composite:implementation>
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade" styleClass="box-solid box-danger">
<p:commandButton value="Yes" type="button" styleClass="btn-material btn-primary ui-confirmdialog-yes"
icon="fa fa-check"/>
<p:commandButton value="No" type="button" styleClass="btn-material btn-danger ui-confirmdialog-no"
icon="fa fa-close"/>
</p:confirmDialog>
</composite:implementation>
</html>

View File

@ -1,18 +0,0 @@
/*
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
*/
/*
Created on : 24.10.2018, 19:31:57
Author : Joern Muehlencord <joern at muehlencord.de>
*/
.watermark {
position: absolute;
opacity: 0.25;
font-size: 3em;
width: 100%;
text-align: center;
z-index: 1000;
}

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Account Management</title>
</head>
<body>
<ui:composition>
&copy; Joern Muehlencord - Account Management - version ${applicationController.version} - build date ${applicationController.buildDate}
</ui:composition>
</body>
</html>

View File

@ -1,62 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:shiro="http://shiro.apache.org/tags">
<shiro:authenticated>
<h:form id="menuform">
<ul class="sidebar-menu tree" data-widget="tree">
<li>
<p:link outcome="/web/index.xhtml">
<i class="fa fa-home"></i>
<span>Home</span>
</p:link>
</li>
<shiro:hasPermission name="#{permissionConstants.applicationListAll}">
<li>
<p:link outcome="/web/applications.xhtml">
<i class="fa fa-tablet"></i>
<span>Applications</span>
</p:link>
</li>
</shiro:hasPermission>
<shiro:hasAnyPermission name="#{permissionConstants.permissionsCombined}">
<li>
<p:link outcome="/web/permissions.xhtml">
<i class="fa fa-list-ul"></i>
<span>Permissions</span>
</p:link>
</li>
</shiro:hasAnyPermission>
<shiro:hasAnyPermission name="#{permissionConstants.rolesCombined}">
<li>
<p:link outcome="/web/roles.xhtml">
<i class="fa fa-circle"></i>
<span>Roles</span>
</p:link>
</li>
</shiro:hasAnyPermission>
<li>
<p:link outcome="/web/accounts.xhtml">
<i class="fa fa-user"></i>
<span>Accounts</span>
</p:link>
</li>
<li>
<p:commandLink target="/logout.xhtml" actionListener="#{loginView.logout}">
<i class="fa fa-sign-out"></i>
<span>Logout</span>
</p:commandLink>
</li>
</ul>
</h:form>
</shiro:authenticated>
</ui:composition>

View File

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2018 joern@muehlencord.de
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/admin.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<ui:define name="head">
<title>Account UI</title>
<link rel="shortcut icon" href="#{resource['images/favicon/favicon.ico']}" />
<h:outputStylesheet name="css/admin.css" />
</ui:define>
<ui:define name="logo-lg">
Account Management
</ui:define>
<ui:define name="logo-mini">
AM
</ui:define>
<ui:define name="menu">
<ui:include src="/resources/template/leftmenu.xhtml"/>
</ui:define>
<ui:define name="footer">
<ui:include src="/resources/template/footer.xhtml"/>
</ui:define>
<ui:define name="content-end">
<h:outputLabel styleClass="watermark" rendered="#{instanceView.developmentVersion}" value="#{instanceView.instanceName}" />
</ui:define>
</ui:composition>

View File

@ -1,341 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:o="http://omnifaces.org/ui"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite"
xmlns:shiro="http://shiro.apache.org/tags">
<ui:define name="title">
Account Overview
</ui:define>
<ui:define name="description">
for #{applicationView.currentApplication.applicationName}
</ui:define>
<ui:define name="body">
<p:panel styleClass="box-solid" rendered="#{! empty applicationView.currentApplication}">
<h:form id="accountForm" prependId="false">
<p:dataTable id="accountTable" value="#{accountView.accounts}" var="account" rowKey="#{account.username}" selectionMode="single" selection="#{accountView.currentAccount}"
styleClass="box-primary">
<p:ajax event="rowSelect" update="buttonPanel" listener="#{accountView.selectAccount}" />
<p:ajax event="rowUnselect" update="buttonPanel" listener="#{accountView.unselectAccount}" />
<p:column headerText="Username">
<h:outputText value="#{account.username}" />
</p:column>
<p:column headerText="Lastname">
<h:outputText value="#{account.lastname}" />
</p:column>
<p:column headerText="Firstname">
<h:outputText value="#{account.firstname}" />
</p:column>
<p:column headerText="Email">
<h:outputText value="#{account.emailaddress}" />
</p:column>
<p:column headerText="Status">
<h:outputText value="#{account.status}" />
</p:column>
<p:column headerText="Can login" >
<p:selectBooleanCheckbox id="canLogin" disabled="true" value="#{!empty account.accountLogin}" />
</p:column>
<p:column headerText="CreatedOn">
<h:outputText value="#{account.createdOn}" >
<f:convertDateTime type="both" dateStyle="full" timeStyle="short" timeZone="Europe/Berlin"/>
</h:outputText>
</p:column>
<p:column headerText="CreatedBy">
<h:outputText value="#{account.createdBy}" />
</p:column>
<p:column headerText="LastUpdatedOn">
<h:outputText value="#{account.lastUpdatedOn}">
<f:convertDateTime type="both" dateStyle="full" timeStyle="short" timeZone="Europe/Berlin"/>
</h:outputText>
</p:column>
<p:column headerText="LastUpdatedBy">
<h:outputText value="#{account.lastUpdatedBy}" />
</p:column>
</p:dataTable>
<p:spacer height="10px" />
<p:panel id="buttonPanel" styleClass="box-primary" style="margin-bottom:20px">
<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="ui-inputgroup" >
<h:outputLabel for="includeDisabledCheckbox" value="Include disabled accounts?" />
<p:inputSwitch id="includeDisabledCheckbox" value="#{accountView.showDisabledAccounts}" styleClass="btn-teal btn-block" >
<p:ajax listener="#{accountView.showDisabledAccountsChange}" update="accountTable" />
</p:inputSwitch>
</div>
</div>
</shiro:hasPermission>
<shiro:hasPermission name="#{permissionConstants.accountAdd}">
<div class="col-sm-12 col-md-2">
<p:commandButton value="New" id="newButton" icon="fa fa-plus"
update="editDialog" oncomplete="PF('editDialogVar').show();"
actionListener="#{accountView.newAccount}" styleClass="btn-primary btn-block" />
</div>
</shiro:hasPermission>
<shiro:hasPermission name="#{permissionConstants.accountEdit}">
<div class="col-sm-12 col-md-2">
<p:commandButton value="Edit" id="editButton" icon="fa fa-pencil"
update="editDialog" oncomplete="PF('editDialogVar').show();"
actionListener="#{accountView.editAccount}" disabled="#{!accountView.accountSelected}" styleClass="btn-teal btn-block" />
</div>
</shiro:hasPermission>
<shiro:hasPermission name="#{permissionConstants.accountDelete}">
<div class="col-sm-12 col-md-2">
<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">
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:commandButton>
</div>
</shiro:hasPermission>
<shiro:hasAnyPermission name="#{permissionConstants.accountsCombined}">
<div class="col-sm-12 col-md-2">
<shiro:hasPermission name="#{permissionConstants.accountLoginAdd}">
<c:if test="#{empty accountView.currentAccount.accountLogin}">
<p:commandButton value="Add login" id="addLoginButton" icon="fa fa-plus" disabled="#{!accountView.accountSelected}"
update="editLoginDialog" oncomplete="PF('editLoginDialogVar').show();"
action="#{accountView.addAccountLogin}" styleClass="btn-teal btn-block">
</p:commandButton>
</c:if>
</shiro:hasPermission>
<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}"
update="accountTable,buttonPanel" styleClass="btn-danger btn-block"
action="#{accountView.deleteAccountLogin}" >
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:menuitem>
</shiro:hasPermission>
</p:splitButton>
</c:if>
</div>
</shiro:hasAnyPermission>
</div>
</p:panel>
<composite:confirmationDialog />
</h:form>
</p:panel>
<p:dialog id="editDialog" widgetVar="editDialogVar" header="Edit account" width="600"
modal="true" appendTo="@(body)" showEffect="fade" hideEffect="fade" styleClass="box-solid box-primary" >
<h:form id="editDialogForm">
<p:messages id="editDialogMessages" showDetail="true" showIcon="true" showSummary="true">
<p:autoUpdate />
</p:messages>
<div class="ui-g ui-fluid">
<div class="col-sm-12 col-md-3">
<p:outputLabel for="username" value="Username" />
</div>
<div class="col-sm-12 col-md-6">
<c:if test="#{accountView.currentAccount.createdBy != null}">
<h:outputText id="username" value="#{accountView.currentAccount.username}" />
</c:if>
<c:if test="#{accountView.currentAccount.createdBy == null}">
<p:inputText id="username" value="#{accountView.currentAccount.username}" />
</c:if>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="username"><p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="lastname" value="Lastname" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="lastname" value="#{accountView.currentAccount.lastname}" size="40" maxlength="100"/>
</div>
<div class="col-sm-12 col-md-3 ">
<p:message for="lastname"> <p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="firstname" value="Firstname" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="firstname" value="#{accountView.currentAccount.firstname}" size="40" maxlength="100" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="firstname"> <p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="emailaddress" value="emailaddress" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="emailaddress" value="#{accountView.currentAccount.emailaddress}" size="40" maxlength="200">
<f:validator validatorId="de.muehlencord.shared.jeeutil.validator.EmailValidator" />
</p:inputText>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="emailaddress"> <p:autoUpdate /></p:message>
</div>
<c:if test="#{accountView.currentAccount.username != null}">
<div class="col-sm-12 col-md-3">
<p:outputLabel for="status" value="Status" />
</div>
<div class="col-sm-12 col-md-6">
<p:selectOneMenu id="status" value="#{accountView.currentAccount.status}" >
<f:selectItems value="#{accountView.statusList}" />
</p:selectOneMenu>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="status" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="createdon" value="Created on" />
</div>
<div class="col-sm-12 col-md-6">
<h:outputText id="createdon" value="#{accountView.currentAccount.createdOn}" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="createdon" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="createdby" value="Created by" />
</div>
<div class="col-sm-12 col-md-6">
<h:outputText id="createdby" value="#{accountView.currentAccount.createdBy}" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="createdby" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="lastupdatedon" value="Last updated on" />
</div>
<div class="col-sm-12 col-md-6">
<h:outputText id="lastupdatedon" value="#{accountView.currentAccount.lastUpdatedOn}" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="lastupdatedon" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="lastupdatedby" value="Last updated by" />
</div>
<div class="col-sm-12 col-md-6">
<h:outputText id="lastupdatedby" value="#{accountView.currentAccount.lastUpdatedBy}" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="lastupdatedby" />
</div>
</c:if>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="roles" value="Roles" />
</div>
<div class="col-sm-12 col-md-6">
<p:selectManyMenu id="roles" var="role" label="#{role.roleName}" value="#{accountView.currentAccountRoles}" converter="omnifaces.SelectItemsConverter" required="false" >
<f:selectItems value="#{accountView.allApplicationRoles}" var="roleItem" itemValue="#{roleItem}" />
<p:column>
<h:outputText value="#{role.application.applicationName}-#{role.roleName}"/>
</p:column>
</p:selectManyMenu>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="roles" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Save" action="#{accountView.saveEditAccount}" styleClass="btn-primary btn-block"
oncomplete="if (args &amp;&amp; !args.validationFailed) PF('editDialogVar').hide();" update=":accountForm:accountTable" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Cancel" action="#{accountView.cancelEditAccount}" immediate="true" styleClass="btn-teal btn-block"
oncomplete="PF('editDialogVar').hide();" />
</div>
</div>
</h:form>
</p:dialog>
<p:dialog id="editLoginDialog" widgetVar="editLoginDialogVar" header="Edit account login" width="600"
modal="true" appendTo="@(body)" showEffect="fade" hideEffect="fade" styleClass="box-solid box-primary" >
<h:form id="editLoginDialogForm">
<p:messages id="editLoginDialogMessages" showDetail="true" showIcon="true" showSummary="true">
<p:autoUpdate />
</p:messages>
<div class="ui-g ui-fluid">
<o:validateMultiple id="myId" components="password repeatPassword"
validator="#{accountView.validatePasswords}" message="#{msgs.passwords_different}" />
<div class="col-sm-12">
<p:outputLabel value="Enter a new password or keep values empty to keep existing / autogenrated value" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="password" value="Password" />
</div>
<div class="col-sm-12 col-md-6">
<p:password id="password" value="#{accountView.password}" maxlength="32" size="32" required="false"/>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="password" />
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="repeatPassword" value="repeat Password" />
</div>
<div class="col-sm-12 col-md-6">
<p:password id="repeatPassword" value="#{accountView.repeatPassword}" maxlength="32" size="32" required="false"/>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="repeatPassword" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Save" action="#{accountView.saveEditAccountLogin}" styleClass="btn-primary btn-block"
oncomplete="if (args &amp;&amp; !args.validationFailed) PF('editLoginDialogVar').hide();" update=":accountForm:accountTable,:accountForm:buttonPanel" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Cancel" action="#{accountView.cancelEditAccountLogin}" immediate="true" styleClass="btn-teal btn-block"
oncomplete="PF('editLoginDialogVar').hide();" />
</div>
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite">
<ui:define name="title">
Applications
</ui:define>
<ui:define name="body" >
<p:panel styleClass="box-solid" rendered="#{! empty applicationView.currentApplication}">
<h:form id="applicationForm" prependId="false">
<div class="ui-g ui-fluid">
<div class="col-sm-12 col-md-6">
<p:selectOneMenu id="applicationSelect" value="#{applicationView.currentApplication}" converter="omnifaces.SelectItemsConverter" required="true">
<f:selectItems value="#{applicationView.allApplications}" var="app" itemLabel="#{app.applicationName}" itemValue="#{app}" />
</p:selectOneMenu>
</div>
<div class="col-sm-12 col-md-2">
<p:commandButton value="Select" styleClass="btn-primary btn-solid}" actionListener="#{applicationView.selectApplication}" />
</div>
<div class="col-sm-12 col-md-2">
<p:commandButton value="New" id="newButton" icon="fa fa-plus"
update="editDialog" oncomplete="PF('editDialogVar').show();"
actionListener="#{applicationView.newApplication}" styleClass="btn-teal btn-block" />
</div>
<div class="col-sm-12 col-md-2">
<p:commandButton id="deletePermissionButton" icon="fa fa-trash-o" value="#{msgs.button_delete}" actionListener="#{applicationView.deleteApplication}"
update="applicationSelect" styleClass="btn-danger btn-block" >
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:commandButton>
</div>
</div>
<composite:confirmationDialog />
</h:form>
</p:panel>
<p:dialog id="editDialog" widgetVar="editDialogVar" header="Edit account" width="600"
modal="true" appendTo="@(body)" showEffect="fade" hideEffect="fade" styleClass="box-solid box-primary" >
<h:form id="editDialogForm">
<p:messages id="editDialogMessages" showDetail="true" showIcon="true" showSummary="true">
<p:autoUpdate />
</p:messages>
<div class="ui-g ui-fluid">
<div class="col-sm-12 col-md-3">
<p:outputLabel for="applicationName" value="Application name" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="applicationName" value="#{applicationView.editApplication.applicationName}">
<f:validator validatorId="uniqueApplicationValidator"/>
</p:inputText>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="applicationName"><p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-3">
<p:spacer height="10px" />
<p:commandButton value="Save" action="#{applicationView.saveEditApplication}" styleClass="btn-primary btn-block"
oncomplete="if (args &amp;&amp; !args.validationFailed) PF('editDialogVar').hide();" update=":applicationForm" />
</div>
<div class="col-sm-12 col-md-3">
<p:spacer height="10px" />
<p:commandButton value="Cancel" action="#{applicationView.cancelEditApplication}" immediate="true" styleClass="btn-teal btn-block"
oncomplete="PF('editDialogVar').hide();" />
</div>
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/resources/template/template.xhtml">
<ui:define name="title">
Home
</ui:define>
<ui:define name="body" >
Home
</ui:define>
</ui:composition>

View File

@ -1,108 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite">
<ui:define name="title">
Permissions
</ui:define>
<ui:define name="description">
for #{applicationView.currentApplication.applicationName}
</ui:define>
<ui:define name="body">
<p:panel styleClass="box-solid" rendered="#{! empty applicationView.currentApplication}">
<h:form id="permissionForm">
<p:dataTable id="permissionTable" value="#{permissionView.appPermissions}" var="permission" rowKey="#{permission.id}"
selectionMode="single" selection="#{permissionView.currentPermission}" styleClass="box-primary">
<p:ajax event="rowSelect" update=":permissionForm:permissionTable:editPermissionButton,:permissionForm:permissionTable:deletePermissionButton" />
<p:ajax event="rowUnselect" update=":permissionForm:permissionTable:editPermissionButton,:permissionForm:permissionTable:deletePermissionButton" />
<p:column headerText="Permission name">
<h:outputText value="#{permission.permissionName}" />
</p:column>
<p:column headerText="Permission description">
<h:outputText value="#{permission.permissionDescription}" />
</p:column>
<f:facet name="footer">
<div class="ui-g-12 ui-md-2">
<p:commandButton id="newPermissionButton" icon="fa fa-plus" value="#{msgs.button_new}" action="#{permissionView.newPermission}"
oncomplete="PF('editDialogVar').show();" update="editDialog" styleClass="btn-primary btn-block" />
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton id="editPermissionButton" icon="fa fa-pencil" value="#{msgs.button_edit}" action="#{permissionView.editPermission}"
oncomplete="PF('editDialogVar').show();" update="editDialog" styleClass="btn-teal btn-block" disabled="#{!permissionView.canEdit}" />
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton id="deletePermissionButton" icon="fa fa-trash-o" value="#{msgs.button_delete}" actionListener="#{permissionView.deletePermission}"
update="permissionForm" styleClass="btn-danger btn-block" disabled="#{!permissionView.canDelete}">
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:commandButton>
</div>
</f:facet>
</p:dataTable>
<composite:confirmationDialog />
</h:form>
</p:panel>
<p:dialog id="editDialog" widgetVar="editDialogVar" header="Edit permission" width="600"
modal="true" appendTo="@(body)" showEffect="fade" hideEffect="fade" styleClass="box-solid box-primary" >
<h:form id="editDialogForm">
<p:messages id="editDialogMessages" showDetail="true" showIcon="true" showSummary="true">
<p:autoUpdate />
</p:messages>
<div class="ui-g ui-fluid">
<div class="ui-g-12 ui-md-3">
<div class="ui-inputgroup">
<span class="ui-inputgroup-addon"><i style="font-size: 20px" class="fa fa-edit"></i></span>
<p:inputText id="newName" value="#{permissionView.currentPermission.permissionName}" maxlength="80" size="30" placeholder="#{msgs.label_name}" >
<f:validator validatorId="uniquePermissionNameValidator"/>
<f:attribute name="application" value="#{permissionView.currentApplication}" />
</p:inputText>
</div>
</div>
<div class="col-sm-12 col-md-9">
<p:message for="newName"><p:autoUpdate /></p:message>
</div>
<div class="ui-g-12 ui-md-3">
<div class="ui-inputgroup">
<span class="ui-inputgroup-addon"><i style="font-size: 20px" class="fa fa-edit"></i></span>
<p:inputText id="newDescription" value="#{permissionView.currentPermission.permissionDescription}" maxlength="200" size="30" placeholder="#{msgs.label_description}" />
</div>
</div>
<div class="col-sm-12 col-md-9">
<p:message for="newDescription"><p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Save" action="#{permissionView.saveEditPermission}" styleClass="btn-primary btn-block"
oncomplete="if (args &amp;&amp; !args.validationFailed) PF('editDialogVar').hide();" update=":permissionForm:permissionTable" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Cancel" action="#{permissionView.cancelEditPermission}" immediate="true" styleClass="btn-teal btn-block"
oncomplete="PF('editDialogVar').hide();" />
</div>
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@ -1,135 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/resources/template/template.xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:co="http://java.sun.com/jsf/composite/composite"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:composite="http://xmlns.jcp.org/jsf/composite/composite">
<ui:define name="title">
Roles Overview
</ui:define>
<ui:define name="description">
for #{applicationView.currentApplication.applicationName}
</ui:define>
<ui:define name="body">
<p:panel styleClass="box-solid" rendered="#{! empty applicationView.currentApplication}">
<h:form id="roleForm">
<p:dataTable id="roleTable" value="#{roleView.allRoles}" var="role" rowKey="#{role.id}" styleClass="box-primary"
selectionMode="single" selection="#{roleView.currentRole}">
<p:ajax event="rowSelect" update=":roleForm:permissionTable, editRoleButton, deleteRoleButton" listener="#{roleView.onRoleSelect}"/>
<p:ajax event="rowUnselect" update=":roleForm:permissionTable, editRoleButton, deleteRoleButton" />
<p:column headerText="Role name">
<h:outputText value="#{role.roleName}" />
</p:column>
<p:column headerText="Role description">
<h:outputText value="#{role.roleDescription}" />
</p:column>
<f:facet name="footer">
<div class="ui-g ui-fluid">
<div class="col-sm-12 col-md-2" style="margin-top:10px">
<p:commandButton id="newRoleButton" icon="fa fa-plus" value="#{msgs.button_new}" actionListener="#{roleView.startNewRole}"
update="editDialog" oncomplete="PF('editDialogVar').show();" styleClass="btn-primary btn-block"/>
</div>
<div class="col-sm-12 col-md-2" style="margin-top:10px">
<p:commandButton id="editRoleButton" icon="fa fa-pencil" value="#{msgs.button_edit}" disabled="#{!roleView.roleSelected}"
update="editDialog" oncomplete="PF('editDialogVar').show();" styleClass="btn-teal btn-block"/>
</div>
<div class="col-sm-12 col-md-2" style="margin-top:10px">
<p:commandButton id="deleteRoleButton" icon="fa fa-trash-o" value="#{msgs.button_delete}" disabled="#{!roleView.roleSelected}"
action="#{roleView.deleteRole}" update=":roleForm:roleTable" styleClass="btn-danger btn-block">
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:commandButton>
</div>
</div>
</f:facet>
</p:dataTable>
<p:spacer height="15px;" />
<p:dataTable id="permissionTable" value="#{roleView.rolePermissions}" var="permission" rowKey="#{permission.id}" styleClass="box-teal"
selectionMode="single" selection="#{roleView.currentPermission}">
<p:ajax event="rowSelect" update="addPermissionButton, deletePermissionButton" />
<p:ajax event="rowUnselect" update="addPermissionButton, deletePermissionButton" />
<p:column headerText="Permission name">
<h:outputText value="#{permission.permissionName}" />
</p:column>
<p:column headerText="Permission description">
<h:outputText value="#{permission.permissionDescription}" />
</p:column>
<f:facet name="footer" >
<p:selectOneMenu value="#{roleView.newPermission}" converter="omnifaces.SelectItemsConverter" >
<f:selectItems id="permissionListItems" value="#{roleView.missingPermissions}" var="missingPermission" itemLabel="#{missingPermission.permissionName}" itemValue="#{missingPermission}" />
</p:selectOneMenu>
<div class="ui-g-12 ui-md-2">
<p:commandButton id="addPermissionButton" icon="fa fa-plus" value="#{msgs.button_add}" action="#{roleView.addRolePermission}"
update="permissionTable" styleClass="btn-primary btn-block" disabled="#{!roleView.missingPermissionAvailable}" />
</div>
<div class="ui-g-12 ui-md-2">
<p:commandButton id="deletePermissionButton" icon="fa fa-trash-o" value="#{msgs.button_delete}" update=":roleForm:permissionTable"
action="#{roleView.removeRolePermission}" styleClass="btn-danger btn-block"
disabled="#{!roleView.permissionSelected}" >
<p:confirm header="Confirmation" message="Are you sure?" icon="fa fa-exclamation-triangle" />
</p:commandButton>
</div>
</f:facet>
</p:dataTable>
<composite:confirmationDialog />
</h:form>
</p:panel>
<p:dialog id="editDialog" widgetVar="editDialogVar" header="Edit account" width="600"
modal="true" appendTo="@(body)" showEffect="fade" hideEffect="fade" styleClass="box-solid box-primary" >
<h:form id="editDialogForm">
<p:messages id="editDialogMessages" showDetail="true" showIcon="true" showSummary="true">
<p:autoUpdate />
</p:messages>
<div class="ui-g ui-fluid">
<div class="col-sm-12 col-md-3">
<p:outputLabel for="newName" value="Role name" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="newName" value="#{roleView.currentRole.roleName}" placeholder="#{msgs.label_name}" maxlength="80" size="40">
<f:validator validatorId="uniqueApplicationRoleNameValidator"/>
<f:attribute name="application" value="#{roleView.currentApplication}" />
</p:inputText>
</div>
<div class="col-sm-12 col-md-3">
<p:message for="newName"><p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-3">
<p:outputLabel for="newDescription" value="Description" />
</div>
<div class="col-sm-12 col-md-6">
<p:inputText id="newDescription" value="#{roleView.currentRole.roleDescription}" placeholder="#{msgs.label_description}" maxlength="200" size="40" />
</div>
<div class="col-sm-12 col-md-3">
<p:message for="newDescription"><p:autoUpdate /></p:message>
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Save" action="#{roleView.saveEditRole}" styleClass="btn-primary btn-block"
oncomplete="if (args &amp;&amp; !args.validationFailed) PF('editDialogVar').hide();" update=":roleForm:roleTable" />
</div>
<div class="col-sm-12 col-md-6">
<p:spacer height="10px" />
<p:commandButton value="Cancel" action="#{roleView.cancelEditRole}" immediate="true" styleClass="btn-teal btn-block"
oncomplete="PF('editDialogVar').hide();" />
</div>
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@ -1,112 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-account</artifactId>
<packaging>ejb</packaging>
<parent>
<artifactId>shared</artifactId>
<groupId>de.muehlencord</groupId>
<version>1.1</version>
</parent>
<name>shared-account</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>10</maven.compiler.source>
<maven.compiler.target>10</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shared-jeeutil</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>shared-account-dao</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.muehlencord.shared</groupId>
<artifactId>shared-util</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- create EJB version 3.1 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<configuration>
<ejbVersion>3.1</ejbVersion>
<excludes>
<exclude>**/persistence.xml</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,410 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
CAUTION: Do not modify this file unless you know what you are doing.
Unexpected results may occur if the code is changed deliberately.
-->
<dbmodel pgmodeler-ver="0.9.2-beta" last-position="0,0" last-zoom="0.9" max-obj-count="13"
default-owner="postgres">
<database name="account_test" encoding="UTF8" lc-collate="C" lc-ctype="C" is-template="false" allow-conns="true" sql-disabled="true">
</database>
<schema name="public" layer="0" fill-color="#e1e1e1" sql-disabled="true">
</schema>
<table name="config" layer="0" collapse-mode="1" max-obj-count="6">
<schema name="public"/>
<position x="1480" y="220"/>
<column name="application" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="config_key" not-null="true">
<type name="varchar" length="100"/>
</column>
<column name="config_key_account" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="config_key_group">
<type name="varchar" length="200"/>
</column>
<column name="config_value">
<type name="varchar" length="200"/>
</column>
<constraint name="config_pk" type="pk-constr" table="public.config">
<columns names="application,config_key,config_key_account" ref-type="src-columns"/>
</constraint>
</table>
<table name="application_role" layer="0" collapse-mode="1" max-obj-count="4">
<schema name="public"/>
<position x="100" y="260"/>
<column name="id" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="application" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="role_name" not-null="true">
<type name="character varying" length="80"/>
</column>
<column name="role_description" not-null="true">
<type name="character varying" length="200"/>
</column>
<constraint name="application_role_pk" type="pk-constr" table="public.application_role">
<columns names="id" ref-type="src-columns"/>
</constraint>
<constraint name="application_role_name_uidx" type="uq-constr" table="public.application_role">
<columns names="application,role_name" ref-type="src-columns"/>
</constraint>
</table>
<table name="account" layer="0" collapse-mode="1" max-obj-count="12">
<schema name="public"/>
<position x="1080" y="460"/>
<column name="id" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="username" not-null="true">
<type name="character varying" length="32"/>
</column>
<column name="emailaddress" not-null="true">
<type name="character varying" length="200"/>
</column>
<column name="firstname" not-null="true">
<type name="character varying" length="100"/>
</column>
<column name="lastname" not-null="true">
<type name="character varying" length="100"/>
</column>
<column name="status" not-null="true" default-value="'NEW'">
<type name="character varying" length="10"/>
</column>
<column name="created_on" not-null="true" default-value="timezone('utc'::text, now())">
<type name="timestamp with time zone" length="0" with-timezone="true"/>
</column>
<column name="created_by" not-null="true">
<type name="character varying" length="32"/>
</column>
<column name="last_updated_on" not-null="true" default-value="timezone('utc'::text, now())">
<type name="timestamp with time zone" length="0" with-timezone="true"/>
</column>
<column name="last_updated_by" not-null="true">
<type name="character varying" length="32"/>
</column>
<constraint name="pk_account" type="pk-constr" table="public.account">
<columns names="id" ref-type="src-columns"/>
</constraint>
<constraint name="uidx_username" type="uq-constr" table="public.account">
<columns names="username" ref-type="src-columns"/>
</constraint>
</table>
<table name="account_history" layer="0" collapse-mode="1" max-obj-count="8">
<schema name="public"/>
<position x="180" y="640"/>
<column name="id" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="account_id" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="message">
<type name="character varying" length="200"/>
</column>
<column name="failure_count" not-null="true" default-value="0">
<type name="integer" length="0"/>
</column>
<column name="status" not-null="true">
<type name="character varying" length="20"/>
</column>
<column name="last_updated_on" not-null="true" default-value="timezone('utc'::text, now())">
<type name="timestamp with time zone" length="0" with-timezone="true"/>
</column>
<column name="last_updated_by" not-null="true">
<type name="character varying" length="32"/>
</column>
<constraint name="pk_account_history" type="pk-constr" table="public.account_history">
<columns names="id" ref-type="src-columns"/>
</constraint>
</table>
<table name="account_role" layer="0" collapse-mode="1" max-obj-count="3">
<schema name="public"/>
<position x="480" y="440"/>
<column name="account" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="account_role" not-null="true">
<type name="uuid" length="0"/>
</column>
<constraint name="pk_account_role" type="pk-constr" table="public.account_role">
<columns names="account,account_role" ref-type="src-columns"/>
</constraint>
</table>
<table name="application_permission" layer="0" collapse-mode="1" max-obj-count="4">
<schema name="public"/>
<position x="1080" y="100"/>
<column name="id" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="application" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="permission_name" not-null="true">
<type name="character varying" length="80"/>
</column>
<column name="permission_description" not-null="true">
<type name="character varying" length="200"/>
</column>
<constraint name="pk_application_permission" type="pk-constr" table="public.application_permission">
<columns names="id" ref-type="src-columns"/>
</constraint>
<constraint name="application_permission_name_uidx" type="uq-constr" table="public.application_permission">
<columns names="application,permission_name" ref-type="src-columns"/>
</constraint>
</table>
<table name="role_permission" layer="0" collapse-mode="1" max-obj-count="3">
<schema name="public"/>
<position x="560" y="80"/>
<column name="application_role" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="role_permission" not-null="true">
<type name="uuid" length="0"/>
</column>
<constraint name="pk_role_permission_role_permission_name" type="pk-constr" table="public.role_permission">
<columns names="application_role,role_permission" ref-type="src-columns"/>
</constraint>
</table>
<table name="mail_template" layer="0" collapse-mode="1" max-obj-count="2">
<schema name="public"/>
<position x="120" y="940"/>
<column name="template_name" not-null="true">
<type name="character varying" length="40"/>
</column>
<column name="template_value" not-null="true">
<type name="text" length="0"/>
</column>
<constraint name="mail_template_pk" type="pk-constr" table="public.mail_template">
<columns names="template_name" ref-type="src-columns"/>
</constraint>
</table>
<table name="application" layer="0" collapse-mode="1" max-obj-count="2">
<schema name="public"/>
<position x="720" y="320"/>
<column name="id" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="application_name" not-null="true">
<type name="varchar" length="200"/>
</column>
<constraint name="application_pk" type="pk-constr" table="public.application">
<columns names="id" ref-type="src-columns"/>
</constraint>
</table>
<extension name="uuid-ossp" sql-disabled="true">
<schema name="public"/>
</extension>
<table name="account_login" layer="0" collapse-mode="1" max-obj-count="15">
<schema name="public"/>
<position x="1520" y="680"/>
<column name="id" not-null="true" default-value="uuid_generate_v4()">
<type name="uuid" length="0"/>
</column>
<column name="account" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="account_password" not-null="true">
<type name="varchar" length="200"/>
</column>
<column name="last_login">
<type name="timestamptz" length="0"/>
</column>
<column name="last_failed_login">
<type name="timestamptz" length="0"/>
</column>
<column name="failure_count" not-null="true" default-value="0">
<type name="integer" length="0"/>
</column>
<column name="password_reset_ongoing" not-null="true" default-value="false">
<type name="boolean" length="0"/>
</column>
<column name="password_reset_valid_to">
<type name="timestamptz" length="0"/>
</column>
<column name="password_reset_hash">
<type name="varchar" length="200"/>
</column>
<column name="created_on" not-null="true" default-value="timezone('utc'::text, now())">
<type name="timestamptz" length="0"/>
</column>
<column name="created_by" not-null="true">
<type name="varchar" length="32"/>
</column>
<column name="last_updated_on" not-null="true" default-value="timezone('utc'::text, now())">
<type name="timestamptz" length="0"/>
</column>
<column name="last_updated_by" not-null="true">
<type name="varchar" length="32"/>
</column>
<constraint name="account_login_pk" type="pk-constr" table="public.account_login">
<columns names="id" ref-type="src-columns"/>
</constraint>
<constraint name="account_login_uidx" type="uq-constr" table="public.account_login">
<columns names="account" ref-type="src-columns"/>
</constraint>
</table>
<table name="api_key" layer="0" collapse-mode="1" max-obj-count="7">
<schema name="public"/>
<position x="680" y="760"/>
<column name="id" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="account" not-null="true">
<type name="uuid" length="0"/>
</column>
<column name="api_key" not-null="true">
<type name="varchar" length="200"/>
</column>
<column name="issued_on" not-null="true" default-value="timezone('utc'::text, now())">
<type name="timestamptz" length="0"/>
</column>
<column name="expiration">
<type name="smallint" length="0"/>
</column>
<column name="expires_on" not-null="true">
<type name="timestamptz" length="0"/>
</column>
<constraint name="api_key_pk" type="pk-constr" table="public.api_key">
<columns names="id" ref-type="src-columns"/>
</constraint>
</table>
<constraint name="config_key_account_fk" type="fk-constr" comparison-type="MATCH FULL"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.account" table="public.config">
<columns names="config_key_account" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="config_application_fk" type="fk-constr" comparison-type="MATCH FULL"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.application" table="public.config">
<columns names="application" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="application_role_app_fk" type="fk-constr" comparison-type="MATCH FULL"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.application" table="public.application_role">
<columns names="application" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="fk_account_history_username_fk" type="fk-constr" comparison-type="MATCH SIMPLE"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.account" table="public.account_history">
<columns names="account_id" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="fk_account_role_account" type="fk-constr" comparison-type="MATCH SIMPLE"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.account" table="public.account_role">
<columns names="account" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="fk_account_role_role_name" type="fk-constr" comparison-type="MATCH SIMPLE"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.application_role" table="public.account_role">
<columns names="account_role" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="application_permission_app_fk" type="fk-constr" comparison-type="MATCH FULL"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.application" table="public.application_permission">
<columns names="application" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="fk_role_permission_application_role" type="fk-constr" comparison-type="MATCH SIMPLE"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.application_role" table="public.role_permission">
<columns names="application_role" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="fk_role_permission_role_permission" type="fk-constr" comparison-type="MATCH SIMPLE"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.application_permission" table="public.role_permission">
<columns names="role_permission" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="account_login_fk" type="fk-constr" comparison-type="MATCH FULL"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.account" table="public.account_login">
<columns names="account" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<constraint name="api_key_account_fk" type="fk-constr" comparison-type="MATCH FULL"
upd-action="NO ACTION" del-action="NO ACTION" ref-table="public.account" table="public.api_key">
<columns names="account" ref-type="src-columns"/>
<columns names="id" ref-type="dst-columns"/>
</constraint>
<relationship name="rel_config_account" type="relfk" layer="0"
src-table="public.config"
dst-table="public.account" reference-fk="config_key_account_fk"
src-required="false" dst-required="false"/>
<relationship name="rel_config_application" type="relfk" layer="0"
src-table="public.config"
dst-table="public.application" reference-fk="config_application_fk"
src-required="false" dst-required="false"/>
<relationship name="rel_application_role_application" type="relfk" layer="0"
src-table="public.application_role"
dst-table="public.application" reference-fk="application_role_app_fk"
src-required="false" dst-required="false"/>
<relationship name="rel_account_history_account" type="relfk" layer="0"
src-table="public.account_history"
dst-table="public.account" reference-fk="fk_account_history_username_fk"
src-required="false" dst-required="false"/>
<relationship name="rel_account_role_account" type="relfk" layer="0"
src-table="public.account_role"
dst-table="public.account" reference-fk="fk_account_role_account"
src-required="false" dst-required="false"/>
<relationship name="rel_account_role_application_role" type="relfk" layer="0"
src-table="public.account_role"
dst-table="public.application_role" reference-fk="fk_account_role_role_name"
src-required="false" dst-required="false"/>
<relationship name="rel_application_permission_application" type="relfk" layer="0"
src-table="public.application_permission"
dst-table="public.application" reference-fk="application_permission_app_fk"
src-required="false" dst-required="false"/>
<relationship name="rel_role_permission_application_role" type="relfk" layer="0"
src-table="public.role_permission"
dst-table="public.application_role" reference-fk="fk_role_permission_application_role"
src-required="false" dst-required="false"/>
<relationship name="rel_role_permission_application_permission" type="relfk" layer="0"
src-table="public.role_permission"
dst-table="public.application_permission" reference-fk="fk_role_permission_role_permission"
src-required="false" dst-required="false"/>
<relationship name="rel_account_login_account" type="relfk" layer="0"
src-table="public.account_login"
dst-table="public.account" reference-fk="account_login_fk"
src-required="false" dst-required="false"/>
<relationship name="rel_api_key_account" type="relfk" layer="0"
src-table="public.api_key"
dst-table="public.account" reference-fk="api_key_account_fk"
src-required="false" dst-required="false"/>
</dbmodel>

View File

@ -1,251 +0,0 @@
-- Database generated with pgModeler (PostgreSQL Database Modeler).
-- pgModeler version: 0.9.2-beta
-- PostgreSQL version: 9.6
-- Project Site: pgmodeler.io
-- Model Author: ---
-- Database creation must be done outside a multicommand file.
-- These commands were put in this file only as a convenience.
-- -- object: account_test | type: DATABASE --
-- -- DROP DATABASE IF EXISTS account_test;
-- CREATE DATABASE account_test
-- ENCODING = 'UTF8'
-- LC_COLLATE = 'C'
-- LC_CTYPE = 'C';
-- -- ddl-end --
--
-- object: public.config | type: TABLE --
DROP TABLE IF EXISTS public.config CASCADE;
CREATE TABLE public.config (
application uuid NOT NULL,
config_key varchar(100) NOT NULL,
config_key_account uuid NOT NULL,
config_key_group varchar(200),
config_value varchar(200),
CONSTRAINT config_pk PRIMARY KEY (application,config_key,config_key_account)
);
-- ddl-end --
-- object: public.application_role | type: TABLE --
DROP TABLE IF EXISTS public.application_role CASCADE;
CREATE TABLE public.application_role (
id uuid NOT NULL,
application uuid NOT NULL,
role_name character varying(80) NOT NULL,
role_description character varying(200) NOT NULL,
CONSTRAINT application_role_pk PRIMARY KEY (id),
CONSTRAINT application_role_name_uidx UNIQUE (application,role_name)
);
-- ddl-end --
-- object: public.account | type: TABLE --
DROP TABLE IF EXISTS public.account CASCADE;
CREATE TABLE public.account (
id uuid NOT NULL,
username character varying(32) NOT NULL,
emailaddress character varying(200) NOT NULL,
firstname character varying(100) NOT NULL,
lastname character varying(100) NOT NULL,
status character varying(10) NOT NULL DEFAULT 'NEW',
created_on timestamp with time zone NOT NULL DEFAULT timezone('utc'::text, now()),
created_by character varying(32) NOT NULL,
last_updated_on timestamp with time zone NOT NULL DEFAULT timezone('utc'::text, now()),
last_updated_by character varying(32) NOT NULL,
CONSTRAINT pk_account PRIMARY KEY (id),
CONSTRAINT uidx_username UNIQUE (username)
);
-- ddl-end --
-- object: public.account_history | type: TABLE --
DROP TABLE IF EXISTS public.account_history CASCADE;
CREATE TABLE public.account_history (
id uuid NOT NULL,
account_id uuid NOT NULL,
message character varying(200),
failure_count integer NOT NULL DEFAULT 0,
status character varying(20) NOT NULL,
last_updated_on timestamp with time zone NOT NULL DEFAULT timezone('utc'::text, now()),
last_updated_by character varying(32) NOT NULL,
CONSTRAINT pk_account_history PRIMARY KEY (id)
);
-- ddl-end --
-- object: public.account_role | type: TABLE --
DROP TABLE IF EXISTS public.account_role CASCADE;
CREATE TABLE public.account_role (
account uuid NOT NULL,
account_role uuid NOT NULL,
CONSTRAINT pk_account_role PRIMARY KEY (account,account_role)
);
-- ddl-end --
-- object: public.application_permission | type: TABLE --
DROP TABLE IF EXISTS public.application_permission CASCADE;
CREATE TABLE public.application_permission (
id uuid NOT NULL,
application uuid NOT NULL,
permission_name character varying(80) NOT NULL,
permission_description character varying(200) NOT NULL,
CONSTRAINT pk_application_permission PRIMARY KEY (id),
CONSTRAINT application_permission_name_uidx UNIQUE (application,permission_name)
);
-- ddl-end --
-- object: public.role_permission | type: TABLE --
DROP TABLE IF EXISTS public.role_permission CASCADE;
CREATE TABLE public.role_permission (
application_role uuid NOT NULL,
role_permission uuid NOT NULL,
CONSTRAINT pk_role_permission_role_permission_name PRIMARY KEY (application_role,role_permission)
);
-- ddl-end --
-- object: public.mail_template | type: TABLE --
DROP TABLE IF EXISTS public.mail_template CASCADE;
CREATE TABLE public.mail_template (
template_name character varying(40) NOT NULL,
template_value text NOT NULL,
CONSTRAINT mail_template_pk PRIMARY KEY (template_name)
);
-- ddl-end --
-- object: public.application | type: TABLE --
DROP TABLE IF EXISTS public.application CASCADE;
CREATE TABLE public.application (
id uuid NOT NULL,
application_name varchar(200) NOT NULL,
CONSTRAINT application_pk PRIMARY KEY (id)
);
-- ddl-end --
-- -- object: "uuid-ossp" | type: EXTENSION --
-- -- DROP EXTENSION IF EXISTS "uuid-ossp" CASCADE;
-- CREATE EXTENSION "uuid-ossp"
-- WITH SCHEMA public;
-- -- ddl-end --
--
-- object: public.account_login | type: TABLE --
DROP TABLE IF EXISTS public.account_login CASCADE;
CREATE TABLE public.account_login (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
account uuid NOT NULL,
account_password varchar(200) NOT NULL,
last_login timestamptz,
last_failed_login timestamptz,
failure_count integer NOT NULL DEFAULT 0,
password_reset_ongoing boolean NOT NULL DEFAULT false,
password_reset_valid_to timestamptz,
password_reset_hash varchar(200),
created_on timestamptz NOT NULL DEFAULT timezone('utc'::text, now()),
created_by varchar(32) NOT NULL,
last_updated_on timestamptz NOT NULL DEFAULT timezone('utc'::text, now()),
last_updated_by varchar(32) NOT NULL,
CONSTRAINT account_login_pk PRIMARY KEY (id),
CONSTRAINT account_login_uidx UNIQUE (account)
);
-- ddl-end --
-- object: public.api_key | type: TABLE --
DROP TABLE IF EXISTS public.api_key CASCADE;
CREATE TABLE public.api_key (
id uuid NOT NULL,
account uuid NOT NULL,
api_key varchar(200) NOT NULL,
issued_on timestamptz NOT NULL DEFAULT timezone('utc'::text, now()),
expiration smallint,
expires_on timestamptz NOT NULL,
CONSTRAINT api_key_pk PRIMARY KEY (id)
);
-- ddl-end --
-- object: config_key_account_fk | type: CONSTRAINT --
-- ALTER TABLE public.config DROP CONSTRAINT IF EXISTS config_key_account_fk CASCADE;
ALTER TABLE public.config ADD CONSTRAINT config_key_account_fk FOREIGN KEY (config_key_account)
REFERENCES public.account (id) MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: config_application_fk | type: CONSTRAINT --
-- ALTER TABLE public.config DROP CONSTRAINT IF EXISTS config_application_fk CASCADE;
ALTER TABLE public.config ADD CONSTRAINT config_application_fk FOREIGN KEY (application)
REFERENCES public.application (id) MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: application_role_app_fk | type: CONSTRAINT --
-- ALTER TABLE public.application_role DROP CONSTRAINT IF EXISTS application_role_app_fk CASCADE;
ALTER TABLE public.application_role ADD CONSTRAINT application_role_app_fk FOREIGN KEY (application)
REFERENCES public.application (id) MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: fk_account_history_username_fk | type: CONSTRAINT --
-- ALTER TABLE public.account_history DROP CONSTRAINT IF EXISTS fk_account_history_username_fk CASCADE;
ALTER TABLE public.account_history ADD CONSTRAINT fk_account_history_username_fk FOREIGN KEY (account_id)
REFERENCES public.account (id) MATCH SIMPLE
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: fk_account_role_account | type: CONSTRAINT --
-- ALTER TABLE public.account_role DROP CONSTRAINT IF EXISTS fk_account_role_account CASCADE;
ALTER TABLE public.account_role ADD CONSTRAINT fk_account_role_account FOREIGN KEY (account)
REFERENCES public.account (id) MATCH SIMPLE
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: fk_account_role_role_name | type: CONSTRAINT --
-- ALTER TABLE public.account_role DROP CONSTRAINT IF EXISTS fk_account_role_role_name CASCADE;
ALTER TABLE public.account_role ADD CONSTRAINT fk_account_role_role_name FOREIGN KEY (account_role)
REFERENCES public.application_role (id) MATCH SIMPLE
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: application_permission_app_fk | type: CONSTRAINT --
-- ALTER TABLE public.application_permission DROP CONSTRAINT IF EXISTS application_permission_app_fk CASCADE;
ALTER TABLE public.application_permission ADD CONSTRAINT application_permission_app_fk FOREIGN KEY (application)
REFERENCES public.application (id) MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: fk_role_permission_application_role | type: CONSTRAINT --
-- ALTER TABLE public.role_permission DROP CONSTRAINT IF EXISTS fk_role_permission_application_role CASCADE;
ALTER TABLE public.role_permission ADD CONSTRAINT fk_role_permission_application_role FOREIGN KEY (application_role)
REFERENCES public.application_role (id) MATCH SIMPLE
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: fk_role_permission_role_permission | type: CONSTRAINT --
-- ALTER TABLE public.role_permission DROP CONSTRAINT IF EXISTS fk_role_permission_role_permission CASCADE;
ALTER TABLE public.role_permission ADD CONSTRAINT fk_role_permission_role_permission FOREIGN KEY (role_permission)
REFERENCES public.application_permission (id) MATCH SIMPLE
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: account_login_fk | type: CONSTRAINT --
-- ALTER TABLE public.account_login DROP CONSTRAINT IF EXISTS account_login_fk CASCADE;
ALTER TABLE public.account_login ADD CONSTRAINT account_login_fk FOREIGN KEY (account)
REFERENCES public.account (id) MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --
-- object: api_key_account_fk | type: CONSTRAINT --
-- ALTER TABLE public.api_key DROP CONSTRAINT IF EXISTS api_key_account_fk CASCADE;
ALTER TABLE public.api_key ADD CONSTRAINT api_key_account_fk FOREIGN KEY (account)
REFERENCES public.account (id) MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- ddl-end --

View File

@ -1,29 +0,0 @@
DELETE FROM config;
DELETE FROM account_role;
DELETE FROM account_login;
DELETE FROM account;
DELETE FROM role_permission;
DELETE FROM application_role;
DELETE FROM application_permission;
DELETE FROM application;
INSERT INTO application (id, application_name) values ('143a2bd3-7e0b-4162-a76e-3031331c7dfe', 'Account UI');
-- add roles to Account UI application
INSERT INTO application_role (id, application, role_name, role_description) values ('5cd0aca0-5466-483d-8f3e-c369f8061131','143a2bd3-7e0b-4162-a76e-3031331c7dfe', 'Admin', 'Admin role');
INSERT INTO application_role (id, application, role_name, role_description) values ('da30060e-fd23-4016-a506-4e12e9322148','143a2bd3-7e0b-4162-a76e-3031331c7dfe', 'User', 'Standard user role');
-- create accounts
INSERT INTO account (id, username, firstname, lastname, emailaddress, created_by, last_updated_by) values ('2a712ed4-30f8-47b4-a002-7d87441b7013', 'system', 'system', 'system', 'n/a', 'system', 'system');
INSERT INTO account (id, username, emailaddress, firstname, lastname, created_by, last_updated_by) values('ab5c8337-6872-4aea-a9b9-78ea63706b8f','admin', 'joern@muehlencord.de', 'Joern', 'Muehlencord','system','system');
-- assign AccountUI.Admin role to admin user
INSERT INTO account_role (account, account_role) values ('ab5c8337-6872-4aea-a9b9-78ea63706b8f', '5cd0aca0-5466-483d-8f3e-c369f8061131');
-- create login for user admin (login admin, password secret)
INSERT INTO account_login (account, account_password, created_by, last_updated_by) VALUES ('ab5c8337-6872-4aea-a9b9-78ea63706b8f', '$shiro1$SHA-256$500000$4bHPNH9k539UjdFLgm/HOA==$T/n8skgoGSOtNw/c9ScDlXCiGrx2cZF0Esrvf6WPq6g=', 'system', 'system'); --admin/secret
-- config
INSERT INTO config (application, config_key, config_key_account, config_value) VALUES ('143a2bd3-7e0b-4162-a76e-3031331c7dfe', 'account.maxFailedLogins', '2a712ed4-30f8-47b4-a002-7d87441b7013', '5');

View File

@ -1,4 +0,0 @@
echo off
SET BACKUPFOLDER=%~dp0
"C:\Program Files\PostgreSQL\10\bin\pg_dump.exe" -U jomu -n public --column-inserts --attribute-inserts --no-owner --no-privileges --no-acl --clean account > %BACKUPFOLDER%\account.dump
pause;

View File

@ -1,4 +0,0 @@
echo off
SET BACKUPFOLDER=%~dp0
"C:\Program Files\PostgreSQL\10\bin\pg_dump.exe" -U jomu -n public --column-inserts --attribute-inserts --no-owner --no-privileges --no-acl --clean account_test > %BACKUPFOLDER%\account_test.dump
pause;

View File

@ -1,9 +0,0 @@
@ECHO OFF
set BASEDIR=%~dp0%
set PGMODELER_DIR=c:\app\pgmodeler
setlocal
cd %PGMODELER_DIR%
pgmodeler-cli -if %BASEDIR%/account.dbm -ef -do -of %BASEDIR%/account.sql
pause

View File

@ -1,10 +0,0 @@
DROP TABLE IF EXISTS config CASCADE;
DROP TABLE IF EXISTS account_role CASCADE;
DROP TABLE IF EXISTS account_login CASCADE;
DROP TABLE IF EXISTS account CASCADE;
DROP TABLE IF EXISTS role_permission CASCADE;
DROP TABLE IF EXISTS application_role CASCADE;
DROP TABLE IF EXISTS application_permission CASCADE;
DROP TABLE IF EXISTS application CASCADE;
DROP TABLE IF EXISTS account_history CASCADE;
DROP TABLE IF EXISTS mail_template CASCADE;

View File

@ -1,5 +0,0 @@
@ECHO OFF
SET BACKUPFOLDER=%~dp0
"C:\Program Files\PostgreSQL\10\bin\psql.exe" -U jomu --set ON_ERROR_STOP=on account < %BACKUPFOLDER%\drop_all_tables.sql
"C:\Program Files\PostgreSQL\10\bin\psql.exe" -U jomu --set ON_ERROR_STOP=on account < %BACKUPFOLDER%\restore.dump
pause;

View File

@ -1,5 +0,0 @@
@ECHO OFF
SET BACKUPFOLDER=%~dp0
"C:\Program Files\PostgreSQL\10\bin\psql.exe" -U jomu --set ON_ERROR_STOP=on account_test < %BACKUPFOLDER%\drop_all_tables.sql
"C:\Program Files\PostgreSQL\10\bin\psql.exe" -U jomu --set ON_ERROR_STOP=on account_test < %BACKUPFOLDER%\restore.dump
pause;

View File

@ -1,305 +0,0 @@
/*
* Copyright 2016 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business;
import de.muehlencord.shared.account.business.account.entity.Account;
import de.muehlencord.shared.account.util.ApplicationPU;
import de.muehlencord.shared.account.util.Updateable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
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.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.IdentifiableType;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.metamodel.SingularAttribute;
import javax.transaction.Transactional;
import org.apache.shiro.util.StringUtils;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
* @param <T>
*/
public abstract class AbstractController<T> {
@Inject
@ApplicationPU
protected EntityManager em;
@Inject
protected Account account;
private final Class<T> entityClass;
public AbstractController(Class<T> clazz) {
this.entityClass = clazz;
}
protected Predicate getFilterCondition(CriteriaBuilder cb, Root<T> root, Map<String, Object> filters) {
return getFilterCondition(cb, root, filters, null);
}
protected Predicate getFilterCondition(CriteriaBuilder cb, Root<T> root, Map<String, Object> filters, Map<String, Object> excludeFilters) {
Predicate filterCondition = null;
filterCondition = getFilterCondition(filterCondition, cb, root, filters, true);
filterCondition = getFilterCondition(filterCondition, cb, root, excludeFilters, false);
return filterCondition;
}
protected Predicate addFilterCondition(CriteriaBuilder cb, Predicate filterCondition, Predicate addCondition) {
if (addCondition == null) {
return filterCondition;
}
if (filterCondition == null) {
filterCondition = addCondition;
} else {
filterCondition = cb.and(filterCondition, addCondition);
}
return filterCondition;
}
/**
* extends the given filterCondition by the addtional filters
*
* @param filterCondition the current filter condition
* @param cb the criteria builder to use
* @param root the root of the object to search for
* @param filters the filters to apply
* @param include if set to true, the filter is used as include filter
* (equals, in). If set to false, the filter is inverted and used as exclude
* filter (not equals, not in etc)
* @return
*/
protected Predicate getFilterCondition(Predicate filterCondition, CriteriaBuilder cb, Root<T> root, Map<String, Object> filters, boolean include) {
String wildCard = "%";
if (filters != null) {
for (Map.Entry<String, Object> filter : filters.entrySet()) {
if (!"".equals(filter.getValue())) {
Path<String> path = getPathElement(root, filter);
// check for differnt types
// 1st String, either from Enum Status or from other free text string
if (String.class.equals(filter.getValue().getClass())) {
switch (filter.getKey()) {
default:
String filterValue = filter.getValue().toString();
Predicate predicate;
if (filterValue.equals("{NULL}")) {
if (include) {
predicate = cb.isNull(path);
} else {
predicate = cb.isNotNull(path);
}
} else {
filterValue = filterValue.trim();
filterValue = filterValue.replace("?", "_");
filterValue = filterValue.replace("*", "%");
String[] values = filterValue.split("\\s+"); // split by whitespaces
Predicate[] partSearchPredicates = new Predicate[values.length];
for (int i = 0; i < values.length; i++) {
String value = wildCard + values[i] + wildCard;
if (include) {
partSearchPredicates[i] = cb.like(cb.upper(path), value.toUpperCase(Locale.US), '\\');
} else {
partSearchPredicates[i] = cb.notLike(cb.upper(path), value.toUpperCase(Locale.US), '\\');
}
}
predicate = cb.and(partSearchPredicates); // all parts must be available
}
filterCondition = addFilterCondition(cb, filterCondition, predicate);
}
} // 2nd for arrays, received from e.g. project selections
else if (filter.getValue().getClass().isArray()) {
Predicate condition = null;
Object[] values = (Object[]) filter.getValue();
if (values.length > 0) {
for (Object value : values) {
if (include) {
Predicate equalPredicate = cb.equal(path, value);
if (condition == null) {
condition = equalPredicate;
} else {
condition = cb.or(condition, equalPredicate);
}
} else {
Predicate equalPredicate = cb.notEqual(path, value);
if (condition == null) {
condition = equalPredicate;
} else {
condition = cb.and(condition, equalPredicate);
}
}
}
filterCondition = addFilterCondition(cb, filterCondition, condition);
}
} else { // at last object comparison
if (include) {
filterCondition = addFilterCondition(cb, filterCondition, cb.equal(path, filter.getValue()));
} else {
filterCondition = addFilterCondition(cb, filterCondition, cb.notEqual(path, filter.getValue()));
}
}
}
}
}
return filterCondition;
}
private Path<String> getPathElement(Root<T> root, Map.Entry<String, Object> filter) {
String[] pathElements = StringUtils.split(filter.getKey(), '.');
Path<String> path = null;
for (String element : pathElements) {
if (path == null) {
path = root.get(element);
} else {
path = path.get(element);
}
}
return path;
}
public void applyUpdateableChanges(Updateable updateable, boolean onCreate) throws ControllerException {
if (onCreate) {
updateable.setCreatedBy(account.getUsername());
updateable.setCreatedOn(new Date());
}
updateable.setLastUpdatedBy(account.getUsername());
updateable.setLastUpdatedOn(new Date());
}
public T attach(T entity) {
return em.merge(entity);
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
public T create(T entity) throws ControllerException {
if (Updateable.class.isAssignableFrom(entity.getClass())) {
Updateable updateable = (Updateable) entity;
applyUpdateableChanges(updateable, true);
}
em.persist(entity);
return entity;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
public T update(T entity) throws ControllerException {
if (Updateable.class.isAssignableFrom(entity.getClass())) {
Updateable updateable = (Updateable) entity;
applyUpdateableChanges(updateable, false);
}
return em.merge(entity);
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
public void delete(T entity) throws ControllerException {
em.remove(attach(entity));
}
@Lock(LockType.READ)
public T find(Object id) {
return em.find(entityClass, id);
}
@Lock(LockType.READ)
public List<T> findAll() {
return findAll(new ArrayList<>());
}
@Lock(LockType.READ)
public List<T> findAll(String... orderFields) {
return findAll(Arrays.asList(orderFields));
}
@Lock(LockType.READ)
public List<T> findAll(List<String> orderFields) {
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<T> criteria = cb.createQuery(entityClass);
final Root<T> r = criteria.from(entityClass);
List<Order> orderList = new ArrayList<>();
orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(r.get(field))));
final TypedQuery<T> query = em.createQuery(criteria.orderBy(orderList));
return query.getResultList();
}
@Lock(LockType.READ)
public List<T> find(Map<String, Object> filters, List<String> orderFields) {
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<T> criteria = cb.createQuery(entityClass);
final Root<T> r = criteria.from(entityClass);
Predicate filterCondition = getFilterCondition(cb, r, filters);
if (filterCondition != null) {
criteria.where(filterCondition);
}
List<Order> orderList = new ArrayList<>();
orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(r.get(field))));
final TypedQuery<T> query = em.createQuery(criteria.orderBy(orderList));
return query.getResultList();
}
/**
* returns null, if the list is empty or null itself. Returns the one
* element if there is exactly one element in the list. Otherwise an
* exception is thrown
*
* @param resultList
* @return
* @throws ControllerException
*/
public T ensureSingleElement(List<T> resultList) throws ControllerException {
if ((resultList == null) || (resultList.isEmpty())) {
return null;
}
if (resultList.size() > 1) {
throw new ControllerException(ControllerException.CAUSE_TOO_MANY_ROWS, "More than one element found in list - expected exactly one");
}
return resultList.get(0);
}
private <T> SingularAttribute<? super T, ?> getIdAttribute() {
Metamodel m = em.getEntityManagerFactory().getMetamodel();
IdentifiableType<T> of = (IdentifiableType<T>) m.managedType(entityClass);
// of.getDeclaredId(entityClass).getJavaMember().
return of.getId(of.getIdType().getJavaType());
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright 2019 Joern Muehlencord <joern at muehlencord.de>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business;
import de.muehlencord.shared.account.util.EndDateable;
import de.muehlencord.shared.account.util.Updateable;
import de.muehlencord.shared.util.DateUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
* @param <T> an entity which needs to extend EndDateable
*/
public abstract class AbstractEnddateableController<T extends EndDateable<T>> extends AbstractController<T> {
private final Class<T> endDateableClass;
public AbstractEnddateableController(Class<T> clazz) {
super(clazz);
this.endDateableClass = clazz;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
@Override
public void delete(T entity) throws ControllerException {
T entityToUpdate = attach(entity);
if (Updateable.class.isAssignableFrom(entityToUpdate.getClass())) {
Updateable updateable = (Updateable) entityToUpdate;
applyUpdateableChanges(updateable, false);
}
entityToUpdate.setValidTo(DateUtil.getCurrentTimeInUTC());
em.merge(entityToUpdate);
}
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
public T create(T entity) throws ControllerException {
entity.setValidFrom(DateUtil.getCurrentTimeInUTC());
return super.create(entity);
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
@Override
public T update(T entity) throws ControllerException {
T newEntity = entity.cloneEndDateable();
delete(entity);
return create (newEntity);
}
@Lock(LockType.READ)
@Override
public List<T> findAll(List<String> orderFields) {
Date now = DateUtil.getCurrentTimeInUTC();
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<T> criteria = cb.createQuery(endDateableClass);
final Root<T> root = criteria.from(endDateableClass);
Predicate alreadyValid = cb.lessThanOrEqualTo(root.get("validFrom"), now);
Predicate validToNotSet = cb.isNull(root.get("validTo"));
Predicate isBeforeValidTo = cb.greaterThanOrEqualTo(root.get("validTo"), now);
Predicate stillValid = cb.or (isBeforeValidTo, validToNotSet);
Predicate isValid = cb.and(alreadyValid, stillValid);
criteria.where(isValid);
List<Order> orderList = new ArrayList<>();
orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(root.get(field))));
final TypedQuery<T> query = em.createQuery(criteria.orderBy(orderList));
return query.getResultList();
}
}

View File

@ -1,51 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.boundary;
import de.muehlencord.shared.account.util.Permission;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public enum AccountPermissions implements Permission {
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 create a login for a user"),
ACCOUNT_LOGIN_EDIT ("account:login:edit", "Allow to change a login for a user"),
ACCOUNT_LOGIN_DELETE ("account:login:delete", "Allow to delete a login for a user");
private final String name;
private final String description;
private AccountPermissions(String permissionName, String permissionDesc) {
this.name = permissionName;
this.description = permissionDesc;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
}

View File

@ -1,115 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.boundary;
import de.muehlencord.shared.account.business.account.control.AccountControl;
import de.muehlencord.shared.account.business.account.entity.Account;
import java.io.Serializable;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.ManagedBean;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Produces;
import javax.faces.context.FacesContext;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ManagedBean
@SessionScoped
public class AccountProducer implements Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(AccountProducer.class);
private static final long serialVersionUID = -3806204732038165311L;
private final Map<String, Object> objectMap = new ConcurrentHashMap<>();
@EJB
AccountControl accountController;
private Account account = null;
private Locale locale = null;
@PostConstruct
public void init() {
FacesContext currentInstance = FacesContext.getCurrentInstance();
if (currentInstance == null) {
locale = Locale.ENGLISH;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using default locale {}", locale);
}
} else {
locale = currentInstance.getExternalContext().getRequestLocale();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using browser locale {}", locale);
}
}
}
@Produces
public Account getAccount() {
String accountName;
if (account == null) {
Subject subject = SecurityUtils.getSubject();
if (subject == null) {
return null;
}
if ((subject.isAuthenticated() == false) && (subject.isRemembered() == false)) {
return null;
} else {
accountName = subject.getPrincipal().toString();
}
account = accountController.getAccountEntity(accountName, true);
// TODO introduce locale support to account and switch to pre-defined locale if set
}
return account;
}
public <T> T getValue(String key, Class<T> clazz) {
if (objectMap.containsKey(key)) {
Object obj = objectMap.get(key);
if (obj == null) {
return null;
}
try {
return clazz.cast(obj);
} catch (ClassCastException ex) {
return null;
}
} else {
return null;
}
}
public void setValue(String key, Object obj) {
objectMap.put(key, obj);
}
@Produces
public Locale getLocale() {
return locale;
}
}

View File

@ -1,54 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.boundary;
import de.muehlencord.shared.jeeutil.restexfw.APIError;
import javax.ws.rs.core.Response;
/**
*
* @author joern.muehlencord
*/
public enum ApiKeyError implements APIError {
JWT_NO_TOKEN(Response.Status.BAD_REQUEST, "1000", "jwt_no_token"),
JWT_TOKEN_INVALID (Response.Status.FORBIDDEN, "1001", "jwt_token_invalid");
private final Response.Status status;
private final String errorCode;
private final String messageKey;
private ApiKeyError(Response.Status status, String errorCode, String messageKey) {
this.status = status;
this.errorCode = errorCode;
this.messageKey = messageKey;
}
@Override
public Response.Status getStatus() {
return status;
}
@Override
public String getErrorCode() {
return this.errorCode;
}
@Override
public String getMessageKey() {
return this.messageKey;
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.boundary;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public class ApiKeyException extends Exception {
private static final long serialVersionUID = -8017749942111814929L;
/**
* Creates a new instance of <code>ApiKeyException</code> without detail message.
*/
public ApiKeyException() {
}
/**
* Constructs an instance of <code>ApiKeyException</code> with the specified detail message.
* @param msg the detail message.
*/
public ApiKeyException(String msg) {
super(msg);
}
/**
* Constructs an instance of <code>ApiKeyException</code> with the specified detail message and root cause.
* @param msg the detail message.
* @param th the root cause
*/
public ApiKeyException(String msg, Throwable th) {
super(msg,th);
}
}

View File

@ -1,339 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.boundary;
import de.muehlencord.shared.account.business.ControllerException;
import de.muehlencord.shared.account.business.account.control.AccountControl;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.account.entity.ApiKeyEntity;
import de.muehlencord.shared.account.business.account.entity.JWTObject;
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
import de.muehlencord.shared.account.business.config.entity.ConfigException;
import de.muehlencord.shared.account.dao.ApiKeyObject;
import de.muehlencord.shared.account.util.AccountPU;
import de.muehlencord.shared.jeeutil.jwt.JWTDecoder;
import de.muehlencord.shared.jeeutil.jwt.JWTEncoder;
import de.muehlencord.shared.jeeutil.jwt.JWTException;
import de.muehlencord.shared.util.DateUtil;
import de.muehlencord.shared.util.StringUtil;
import java.io.Serializable;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Stateless
public class ApiKeyService implements Serializable {
private static final long serialVersionUID = -6981864888118320228L;
private static final Logger LOGGER = LoggerFactory.getLogger(ApiKeyService.class);
@Inject
@AccountPU
EntityManager em;
@Inject
AccountControl accountControl;
@Inject
ConfigService configService;
private String password;
private String issuer;
private Short expirationInMinutes;
@PostConstruct
public void init() {
if (configService == null) {
password = null;
issuer = null;
} else {
try {
password = configService.getConfigValue("rest.password");
issuer = configService.getConfigValue("rest.issuer");
expirationInMinutes = Short.parseShort(configService.getConfigValue("rest.expiration_in_minutes", "120", true));
} catch (ConfigException | NumberFormatException | ControllerException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
password = null;
issuer = null;
expirationInMinutes = null;
}
}
}
public ApiKeyEntity getApiKeyFromString(String encodedJWT) throws ApiKeyException {
if (StringUtil.isEmpty(encodedJWT)) {
throw new ApiKeyException("Must provide authorization information");
}
JWTObject jwt = getJWTObject(encodedJWT);
Query query = em.createNamedQuery("ApiKeyEntity.findByApiKey");
query.setParameter("apiKey", jwt.getUnqiueId());
List<ApiKeyEntity> apiKeys = query.getResultList();
if ((apiKeys == null) || (apiKeys.isEmpty())) {
throw new ApiKeyException("ApiKey not found in database");
}
return apiKeys.get(0);
}
public List<ApiKeyEntity> getUsersApiKeys(AccountEntity account, boolean onlyValid) {
Date now = DateUtil.getCurrentTimeInUTC();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ApiKeyEntity> cq = cb.createQuery(ApiKeyEntity.class);
Root<ApiKeyEntity> root = cq.from(ApiKeyEntity.class);
Predicate accountPredicate = cb.equal(root.get("account"), account);
Predicate searchPredicate;
if (onlyValid) {
Predicate expiresOnPredicate = cb.greaterThanOrEqualTo(root.get("expiresOn"), now);
searchPredicate = cb.and(accountPredicate, expiresOnPredicate);
} else {
searchPredicate = accountPredicate;
}
cq.where(searchPredicate);
cq.orderBy(cb.desc(root.get("expiresOn")));
TypedQuery<ApiKeyEntity> query = em.createQuery(cq);
List<ApiKeyEntity> resultList = query.getResultList();
if (resultList == null) {
return new ArrayList<>();
} else {
return resultList;
}
}
public List<ApiKeyEntity> getUsersApiKeys(String userName) {
return getUsersApiKeys(accountControl.getAccountEntity(userName, false), false);
}
public List<ApiKeyEntity> getValidUsersApiKeys(String userName) {
return getUsersApiKeys(accountControl.getAccountEntity(userName, false), true);
}
@Transactional
@Lock(LockType.WRITE)
public ApiKeyObject createNewApiKey(String userName) throws ApiKeyException {
if (userName == null) {
throw new ApiKeyException("Username must not be null");
}
return createNewApiKey(userName, expirationInMinutes);
}
@Transactional
@Lock(LockType.WRITE)
public ApiKeyObject createNewApiKey(String userName, short expirationInMinutes) throws ApiKeyException {
if ((password == null || issuer == null) || (userName == null)) {
LOGGER.error("password, issuer or username not set in, please validate configuration");
}
Date now = DateUtil.getCurrentTimeInUTC();
ZonedDateTime issuedOn = ZonedDateTime.ofInstant(now.toInstant(), ZoneId.of("UTC"));
ZonedDateTime expiresOn = issuedOn.plusMinutes(expirationInMinutes);
Date expiresOnDate = Date.from(expiresOn.toInstant());
String apiKeyString = RandomStringUtils.randomAscii(50);
ApiKeyEntity apiKey = new ApiKeyEntity();
apiKey.setAccount(accountControl.getAccountEntity(userName, false));
apiKey.setApiKey(apiKeyString);
apiKey.setIssuedOn(now);
apiKey.setExpiresOn(expiresOnDate);
apiKey.setExpiration(expirationInMinutes);
return getApiKeyObject(apiKey);
}
public ApiKeyObject getApiKeyObject(ApiKeyEntity apiKey) throws ApiKeyException {
if (apiKey == null) {
throw new ApiKeyException("ApiKey must not be null");
}
ZonedDateTime issuedOn = ZonedDateTime.ofInstant(apiKey.getIssuedOn().toInstant(), ZoneId.of("UTC"));
ZonedDateTime expiresOn = issuedOn.plusMinutes(expirationInMinutes);
AccountEntity account = apiKey.getAccount();
if (account == null) {
throw new ApiKeyException("Account of apiKey must not be null");
}
String userName = account.getUsername();
try {
String jwtString = JWTEncoder.encode(password, issuer, issuedOn, userName, apiKey.getApiKey(), apiKey.getExpiration());
em.persist(apiKey);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Created API key for {}, valid for {} minutes", userName, expirationInMinutes);
}
ApiKeyObject apiKeyObject = new ApiKeyObject();
apiKeyObject.setUserName(userName);
apiKeyObject.setIssuedOn(Date.from(apiKey.getIssuedOn().toInstant()));
apiKeyObject.setExpiresOn(Date.from(expiresOn.toInstant()));
apiKeyObject.setAuthToken(jwtString);
return apiKeyObject;
} catch (JWTException ex) {
throw new ApiKeyException("Cannot create apiKey. Reason: " + ex.toString(), ex);
}
}
public boolean validateJWT(String encodedJWT) {
JWTDecoder decoder = new JWTDecoder(password, issuer, encodedJWT);
ApiKeyEntity validKey;
try {
validKey = getValidKey(decoder.getSubject(), decoder.getUniqueId(), encodedJWT);
} catch (JWTException ex) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace(ex.toString(), ex);
}
return false;
}
return validKey != null;
}
private ApiKeyEntity getValidKey(String userName, String apiKey, String authorizationHeader) throws JWTException {
AccountEntity userAccount = accountControl.getAccountEntity(userName, false);
if (userAccount == null) {
throw new JWTException("AccountControl exception");
}
List<ApiKeyEntity> apiKeys = getUsersApiKeys(userAccount, true);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Found {} keys for user {}", apiKeys.size(), userName);
}
Iterator<ApiKeyEntity> it = apiKeys.iterator();
ApiKeyEntity keyToLogout = null;
while (keyToLogout == null && it.hasNext()) {
ApiKeyEntity key = it.next();
if (key.getApiKey().equals(apiKey)) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Found API key in database");
}
ZonedDateTime issuedOn = ZonedDateTime.ofInstant(key.getIssuedOn().toInstant(), ZoneOffset.UTC);
String testString = JWTEncoder.encode(password, issuer, issuedOn, key.getAccount().getUsername(), key.getApiKey(), key.getExpiration());
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Successfully created validation JWT for user {}", userName);
}
if (authorizationHeader.equals(testString)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Found valid key for user {}", userName);
}
return key;
}
}
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No valid key for user {} found", userName);
}
return null;
}
public String getJWTFromApiKey(ApiKeyEntity apiKey) throws ApiKeyException {
ZonedDateTime issuedAt = ZonedDateTime.ofInstant(apiKey.getIssuedOn().toInstant(), ZoneOffset.UTC);
try {
return JWTEncoder.encode(password, issuer, issuedAt, apiKey.getAccount().getUsername(), apiKey.getApiKey(), apiKey.getExpiration());
} catch (JWTException ex) {
throw new ApiKeyException("Cannot retrieve JWT from key. Reason: " + ex.toString(), ex);
}
}
public JWTObject getJWTObject(String encodedJWT) {
JWTDecoder decoder = new JWTDecoder(password, issuer, encodedJWT);
JWTObject jwtObject = new JWTObject();
jwtObject.setUserName(decoder.getSubject());
jwtObject.setUnqiueId(decoder.getUniqueId());
jwtObject.setValid(true);
return jwtObject;
}
/**
*
* @param apiKey
* @deprecated use delete (jwtObject) instead
*/
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
@Deprecated
public void delete(ApiKeyEntity apiKey) {
em.remove(em.merge(apiKey));
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
public void delete(String authorizationHeader) throws ApiKeyException {
JWTObject jwtObject = getJWTObject(authorizationHeader);
if (jwtObject.isValid()) {
String userName = jwtObject.getUserName();
ApiKeyEntity keyToLogout;
try {
keyToLogout = getValidKey(userName, jwtObject.getUnqiueId(), authorizationHeader);
} catch (JWTException ex) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace(ex.getMessage(), ex);
}
keyToLogout = null;
}
if (keyToLogout == null) {
// no valid key found - must not happen, JWTVeryfingFIlter should have catched this
// FIXME - add logging / handle this problem
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No valid key found, probably user {} has already logged out", userName);
}
throw new ApiKeyException("No valid key found, probably user " + userName + " has already logged out");
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Found matching apiKey to logout");
}
em.remove(em.merge(keyToLogout));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Key deleted, user {} logged out from webservice", userName);
}
}
} else {
throw new ApiKeyException("Provided JWT is not valid");
}
}
}

View File

@ -1,427 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.control;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
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.ApplicationRoleEntity;
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
import de.muehlencord.shared.account.business.config.entity.ConfigException;
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.entity.MailException;
import de.muehlencord.shared.account.util.AccountPU;
import de.muehlencord.shared.account.util.SecurityUtil;
import de.muehlencord.shared.util.DateUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author joern.muehlencord
*/
@Stateless
public class AccountControl implements Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(AccountControl.class.getName());
private static final long serialVersionUID = 3424816272598108101L;
@EJB
private MailService mailService;
@Inject
private ApplicationEntity application;
@Inject
ConfigService configService;
@Inject
@AccountPU
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
*
* @return a list of active accounts
*/
private List<AccountEntity> getActiveAccounts() {
Query query = em.createNamedQuery("AccountEntity.findActiveAccounts");
query.setParameter("status", AccountStatus.DISABLED.name());
return query.getResultList();
}
/**
* returns a list of active accounts
*
* @return a list of active accounts
*/
private List<AccountEntity> getAllAccounts() {
Query query = em.createNamedQuery("AccountEntity.findAll");
return query.getResultList();
}
@Lock(LockType.READ)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public AccountEntity getAccountEntity(String userName, boolean loadRoles) {
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append("SELECT a FROM AccountEntity a ");
if (loadRoles) {
queryBuilder.append("LEFT JOIN FETCH a.applicationRoleList ");
}
queryBuilder.append("WHERE a.username = :username");
Query query = em.createQuery(queryBuilder.toString());
query.setParameter("username", userName);
try {
return (AccountEntity) query.getSingleResult();
} catch (NoResultException ex) {
return null;
}
}
@Transactional
public AccountEntity saveAccount(AccountEntity account, ApplicationEntity app, List<ApplicationRoleEntity> applicationRoles) {
Date now = DateUtil.getCurrentTimeInUTC();
Subject currentUser = SecurityUtils.getSubject();
String currentLoggedInUser = currentUser.getPrincipal().toString();
account.setLastUpdatedBy(currentLoggedInUser); // FIXME - should be done via updateable
account.setLastUpdatedOn(now);
boolean newAccount = (account.getCreatedOn() == null);
// new account
if (newAccount) {
account.setCreatedOn(now);
account.setCreatedBy(currentLoggedInUser);
em.persist(account);
} else {
em.merge(account);
// reload account from db and join roles
account = getAccountEntity(account.getUsername(), true);
}
// assign roles to account
if (account.getApplicationRoleList() == null) {
account.setApplicationRoleList(new ArrayList<>());
}
boolean roleSetupChanged = false;
// remove roles which are no longer listed
// ensure this is only done for the given application - keep the other applications untouched
List<ApplicationRoleEntity> assignedRoles = new ArrayList<>();
assignedRoles.addAll(account.getApplicationRoleList());
for (ApplicationRoleEntity currentlyAssignedRole : assignedRoles) {
if ((currentlyAssignedRole.getApplication().equals(app) && (!applicationRoles.contains(currentlyAssignedRole)))) {
account.getApplicationRoleList().remove(currentlyAssignedRole);
roleSetupChanged = true;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removed role {} ({}) from user {}", currentlyAssignedRole.getRoleName(), application.getApplicationName(), account.getUsername());
}
}
}
// add newly added roles to role list
for (ApplicationRoleEntity applicationRole : applicationRoles) {
if (!account.getApplicationRoleList().contains(applicationRole)) {
account.addApplicationRole(applicationRole);
roleSetupChanged = true;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Added role {} ({}) to account {}", applicationRole.getRoleName(), application.getApplicationName(), account.getUsername());
}
}
}
// update account in database if roles changed
if (roleSetupChanged) {
em.merge(account);
}
return account;
}
@Transactional
public void deleteAccount(AccountEntity account) throws AccountException {
Date now = DateUtil.getCurrentTimeInUTC();
Subject currentUser = SecurityUtils.getSubject();
String currentUserName = currentUser.getPrincipal().toString();
if (account.getUsername().equals(currentUserName)) {
throw new AccountException("Cannot delete own account");
} else {
account.setStatus(AccountStatus.DISABLED.name());
account.setLastUpdatedBy(currentUserName);
account.setLastUpdatedOn(now);
em.merge(account);
}
}
@Transactional
public boolean initPasswordReset(String userName) {
try {
AccountEntity account = getAccountEntity(userName, false);
if (account == null) {
LOGGER.warn("Account with name " + userName + " not found");
return false;
}
if (account.getAccountLogin() == null) {
LOGGER.error("No login for account {} defined, cannot reset password", userName);
return false;
}
if (account.getStatus().equals(AccountStatus.BLOCKED.name())) {
LOGGER.warn("Account " + userName + " is locked, cannot initialize password reset");
return false;
}
String randomString = RandomStringUtils.random(40, true, true);
Date validTo = DateUtil.getCurrentTimeInUTC();
validTo = new Date(validTo.getTime() + 1000 * 600); // 10 minutes to react
account.getAccountLogin().setPasswordResetHash(randomString);
account.getAccountLogin().setPasswordResetOngoing(true);
account.getAccountLogin().setPasswordResetValidTo(validTo);
mailService.sendPasswortResetStartEmail(account, randomString);
em.merge(account.getAccountLogin());
em.merge(account);
return true;
} catch (MailException | ConfigException ex) {
LOGGER.error("Error while sending password reset mail. " + ex.toString());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Error while sending password reset mail.", ex);
}
return false;
}
}
@Transactional
public boolean resetPassword(String userName, String newPassword, String resetPasswordToken) {
AccountEntity account = getAccountEntity(userName, false);
if (account == null) {
LOGGER.warn("Error while resetting password, no account with username " + userName + " found");
// TODO add extra logging for intrusion protection system like fail2ban
return false;
}
if (account.getAccountLogin() == null) {
// user has no defined login, cannot reset password
return false;
}
if (account.getAccountLogin().getPasswordResetOngoing() && (account.getAccountLogin().getPasswordResetHash() != null) && (account.getAccountLogin().getPasswordResetValidTo() != null)) {
Date now = DateUtil.getCurrentTimeInUTC();
String storedHash = account.getAccountLogin().getPasswordResetHash().trim();
if (account.getAccountLogin().getPasswordResetValidTo().after(now)) {
if (storedHash.equals(resetPasswordToken)) {
// everything ok, reset password
executePasswordReset(account, newPassword);
LOGGER.info("Updated password for user " + userName);
return true;
} else {
// token is not valid, refuse to change password
LOGGER.warn("Trying to reset password for user " + userName + " but wrong token " + resetPasswordToken + " provided");
addLoginError(account);
return false;
}
} else {
// password reset token no longer valid
LOGGER.warn("Trying to reset password for user " + userName + " but token is no longer valid");
addLoginError(account);
return false;
}
} else {
// user is not is password reset mode
LOGGER.warn("Trying to reset password for user " + userName + " but password reset was not requested");
addLoginError(account);
return false;
}
}
private void executePasswordReset(AccountEntity account, String newPassword) {
Date now = DateUtil.getCurrentTimeInUTC();
String hashedPassword = SecurityUtil.createPassword(newPassword);
if (account.getAccountLogin() == null) {
return;
}
account.getAccountLogin().setAccountPassword(hashedPassword);
account.getAccountLogin().setPasswordResetOngoing(false);
account.getAccountLogin().setPasswordResetHash(null);
account.getAccountLogin().setPasswordResetValidTo(null);
account.setLastUpdatedBy(account.getUsername());
account.setLastUpdatedOn(now);
em.merge(account);
}
@Transactional
public AccountLoginEntity updateSuccessFullLogin(AccountLoginEntity login, String byUser) {
Date now = DateUtil.getCurrentTimeInUTC();
// a scucessful login ends a password reset procedure
if (login.getPasswordResetOngoing()) {
login.setPasswordResetOngoing(false);
login.setPasswordResetHash(null);
login.setPasswordResetValidTo(null);
login.setLastUpdatedOn(now);
login.setLastUpdatedBy(byUser);
}
login.setLastLogin(now);
login.setFailureCount(0);
return updateLogin(login);
}
@Transactional
public AccountLoginEntity updateLogin(AccountLoginEntity login) {
return em.merge(login);
}
@Transactional
public void updateLogin(AccountEntity account) {
if (account.getAccountLogin() == null) {
// TODO connect to IPRS - how can an account ask for an updated login if the user cannot login
} else {
updateSuccessFullLogin(account.getAccountLogin(), account.getUsername());
}
}
@Transactional
public void addLoginError(AccountEntity account) {
if (account.getAccountLogin() == null) {
LOGGER.error("No login defined for {}", account.getUsername());
} else {
try {
Date now = DateUtil.getCurrentTimeInUTC();
account.getAccountLogin().setLastFailedLogin(now);
account.getAccountLogin().setFailureCount(account.getAccountLogin().getFailureCount() + 1);
int maxFailedLogins = Integer.parseInt(configService.getConfigValue("account.maxFailedLogins"));
if ((account.getAccountLogin().getFailureCount() >= maxFailedLogins) && (!account.getStatus().equals("LOCKED"))) { // TOD add status enum
// max failed logins reached, disabling user
LOGGER.info("Locking account " + account.getUsername() + " due to " + account.getAccountLogin().getFailureCount() + " failed logins");
account.setStatus(AccountStatus.BLOCKED.name());
}
// on a failed login request, disable password reset
account.getAccountLogin().setPasswordResetOngoing(false);
account.getAccountLogin().setPasswordResetHash(null);
account.getAccountLogin().setPasswordResetValidTo(null);
account.setLastUpdatedBy("system");
account.setLastUpdatedOn(now);
em.merge(account);
} catch (ConfigException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
}
}
}
public AccountLoginEntity createLoginWithRandomPassword() {
AccountLoginEntity login = new AccountLoginEntity();
String randomPassword = RandomStringUtils.random(20, true, true);
String hashedPassword = SecurityUtil.createPassword(randomPassword);
login.setAccountPassword(hashedPassword);
login.setLastLogin(null);
login.setLastFailedLogin(null);
login.setFailureCount(0);
return login;
}
public String getHashedPassword(String password) {
String hashedPassword = SecurityUtil.createPassword(password);
return hashedPassword;
}
@Transactional
public void addLogin(AccountEntity accountToAdd, AccountLoginEntity accountLogin) {
Date now = DateUtil.getCurrentTimeInUTC();
Subject currentUser = SecurityUtils.getSubject();
String currentLoggedInUser = currentUser.getPrincipal().toString();
AccountEntity account = em.merge(accountToAdd);
accountLogin.setAccount(account);
accountLogin.setCreatedBy(currentLoggedInUser);
accountLogin.setCreatedOn(now);
accountLogin.setLastUpdatedBy(currentLoggedInUser);
accountLogin.setLastUpdatedOn(now);
em.persist(accountLogin);
account.setAccountLogin(accountLogin);
em.merge(account);
}
@Transactional
public void deleteLogin(AccountEntity accountToDelete) {
AccountEntity account = em.merge(accountToDelete);
AccountLoginEntity login = account.getAccountLogin();
login.setAccount(null);
account.setAccountLogin(null);
em.remove(login);
em.merge(account);
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public enum AccountConfigurationKey {
// the base path of the application
BaseUrl,
// the full pass to the reset password page
PasswordResetUrl,
// injection handler
Producer;
}

View File

@ -1,40 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.enterprise.util.Nonbinding;
import javax.inject.Qualifier;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface AccountConfigurationValue {
@Nonbinding
AccountConfigurationKey key();
}

View File

@ -1,285 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity;
import de.muehlencord.shared.account.business.config.entity.ConfigEntity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
/**
* IMPORANT: DO NOT CACHE - e.g. password changes are not synchronized
* @author joern.muehlencord
*/
@Entity
@Table(name = "account")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "AccountEntity.findAll", query = "SELECT a FROM AccountEntity a ORDER by a.lastname, a.firstname"),
@NamedQuery(name = "AccountEntity.findByUsername", query = "SELECT a FROM AccountEntity a WHERE a.username = :username"),
@NamedQuery(name = "AccountEntity.findByStatus", query = "SELECT a FROM AccountEntity a WHERE a.status = :status"),
@NamedQuery(name = "AccountEntity.findActiveAccounts", query = "SELECT a FROM AccountEntity a WHERE a.status <> :status"),
@NamedQuery(name = "AccountEntity.findByCreatedOn", query = "SELECT a FROM AccountEntity a WHERE a.createdOn = :createdOn"),
@NamedQuery(name = "AccountEntity.findByCreatedBy", query = "SELECT a FROM AccountEntity a WHERE a.createdBy = :createdBy"),
@NamedQuery(name = "AccountEntity.findByLastUpdatedOn", query = "SELECT a FROM AccountEntity a WHERE a.lastUpdatedOn = :lastUpdatedOn"),
@NamedQuery(name = "AccountEntity.findByLastUpdatedBy", query = "SELECT a FROM AccountEntity a WHERE a.lastUpdatedBy = :lastUpdatedBy")
})
public class AccountEntity implements Serializable, Account {
private static final long serialVersionUID = 2174163529615355336L;
@Id
@Basic(optional = false)
@NotNull
@Column(name = "id")
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 32)
@Column(name = "username")
private String username;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 200)
@Column(name = "emailaddress")
private String emailaddress;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 100)
@Column(name = "firstname")
private String firstname;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 100)
@Column(name = "lastname")
private String lastname;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 10)
@Column(name = "status")
private String status;
@Basic(optional = false)
@NotNull
@Column(name = "created_on")
@Temporal(TemporalType.TIMESTAMP)
private Date createdOn;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 32)
@Column(name = "created_by")
private String createdBy;
@Basic(optional = false)
@NotNull
@Column(name = "last_updated_on")
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdatedOn;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 32)
@Column(name = "last_updated_by")
private String lastUpdatedBy;
@JoinTable(name = "account_role", joinColumns = {
@JoinColumn(name = "account", referencedColumnName = "id")}, inverseJoinColumns = {
@JoinColumn(name = "account_role", referencedColumnName = "id")})
@ManyToMany(fetch = FetchType.LAZY)
private List<ApplicationRoleEntity> applicationRoleList;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "accountId", fetch = FetchType.LAZY)
private List<AccountHistoryEntity> accountHistoryList;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "account")
private AccountLoginEntity accountLogin;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "account")
private List<ConfigEntity> configItems;
public AccountEntity() {
// empty constructor required for JPA
}
public void addApplicationRole(ApplicationRoleEntity applicationRole) {
if (applicationRoleList == null) {
applicationRoleList = new ArrayList<>();
}
applicationRoleList.add(applicationRole);
}
/* **** getter / setter **** */
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
@Override
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmailaddress() {
return emailaddress;
}
public void setEmailaddress(String emailaddress) {
this.emailaddress = emailaddress;
}
@Override
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Override
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Date getCreatedOn() {
return createdOn;
}
public void setCreatedOn(Date createdOn) {
this.createdOn = createdOn;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Date getLastUpdatedOn() {
return lastUpdatedOn;
}
public void setLastUpdatedOn(Date lastUpdatedOn) {
this.lastUpdatedOn = lastUpdatedOn;
}
public String getLastUpdatedBy() {
return lastUpdatedBy;
}
public void setLastUpdatedBy(String lastUpdatedBy) {
this.lastUpdatedBy = lastUpdatedBy;
}
public List<ApplicationRoleEntity> getApplicationRoleList() {
return applicationRoleList;
}
public void setApplicationRoleList(List<ApplicationRoleEntity> applicationRoleList) {
this.applicationRoleList = applicationRoleList;
}
public List<AccountHistoryEntity> getAccountHistoryList() {
return accountHistoryList;
}
public void setAccountHistoryList(List<AccountHistoryEntity> accountHistoryList) {
this.accountHistoryList = accountHistoryList;
}
public AccountLoginEntity getAccountLogin() {
return accountLogin;
}
public void setAccountLogin(AccountLoginEntity accountLogin) {
this.accountLogin = accountLogin;
}
public List<ConfigEntity> getConfigItems() {
return configItems;
}
public void setConfigItems(List<ConfigEntity> configItems) {
this.configItems = configItems;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof AccountEntity)) {
return false;
}
AccountEntity other = (AccountEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.entity.Account[ id=" + id + " ]";
}
}

View File

@ -1,44 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
/**
*
* @author Raimund
*/
public class AccountException extends Exception {
/**
* Creates a new instance of <code>AccountException</code> without detail
* message.
*/
public AccountException() {
}
/**
* Constructs an instance of <code>AccountException</code> with the
* specified detail message.
*
* @param msg the detail message.
*/
public AccountException(String msg) {
super(msg);
}
public AccountException(String entity_updated__deleted_please_reload, boolean b) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

View File

@ -1,189 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
/**
*
* @author joern.muehlencord
*/
@Entity
@Table(name = "account_history")
@Cacheable
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "AccountHistoryEntity.findAll", query = "SELECT a FROM AccountHistoryEntity a"),
@NamedQuery(name = "AccountHistoryEntity.findById", query = "SELECT a FROM AccountHistoryEntity a WHERE a.id = :id"),
@NamedQuery(name = "AccountHistoryEntity.findByMessage", query = "SELECT a FROM AccountHistoryEntity a WHERE a.message = :message"),
@NamedQuery(name = "AccountHistoryEntity.findByFailureCount", query = "SELECT a FROM AccountHistoryEntity a WHERE a.failureCount = :failureCount"),
@NamedQuery(name = "AccountHistoryEntity.findByStatus", query = "SELECT a FROM AccountHistoryEntity a WHERE a.status = :status"),
@NamedQuery(name = "AccountHistoryEntity.findByLastUpdatedOn", query = "SELECT a FROM AccountHistoryEntity a WHERE a.lastUpdatedOn = :lastUpdatedOn"),
@NamedQuery(name = "AccountHistoryEntity.findByLastUpdatedBy", query = "SELECT a FROM AccountHistoryEntity a WHERE a.lastUpdatedBy = :lastUpdatedBy")})
public class AccountHistoryEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@NotNull
@Column(name = "id")
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
@Size(max = 200)
@Column(name = "message")
private String message;
@Basic(optional = false)
@NotNull
@Column(name = "failure_count")
private int failureCount;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 20)
@Column(name = "status")
private String status;
@Basic(optional = false)
@NotNull
@Column(name = "last_updated_on")
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdatedOn;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 32)
@Column(name = "last_updated_by")
private String lastUpdatedBy;
@JoinColumn(name = "account_id", referencedColumnName = "id")
@ManyToOne(optional = false)
private AccountEntity accountId;
public AccountHistoryEntity() {
}
public AccountHistoryEntity(UUID id) {
this.id = id;
}
public AccountHistoryEntity(UUID id, int failureCount, String status, Date lastUpdatedOn, String lastUpdatedBy) {
this.id = id;
this.failureCount = failureCount;
this.status = status;
this.lastUpdatedOn = lastUpdatedOn;
this.lastUpdatedBy = lastUpdatedBy;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getFailureCount() {
return failureCount;
}
public void setFailureCount(int failureCount) {
this.failureCount = failureCount;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Date getLastUpdatedOn() {
return lastUpdatedOn;
}
public void setLastUpdatedOn(Date lastUpdatedOn) {
this.lastUpdatedOn = lastUpdatedOn;
}
public String getLastUpdatedBy() {
return lastUpdatedBy;
}
public void setLastUpdatedBy(String lastUpdatedBy) {
this.lastUpdatedBy = lastUpdatedBy;
}
public AccountEntity getAccountId() {
return accountId;
}
public void setAccountId(AccountEntity accountId) {
this.accountId = accountId;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof AccountHistoryEntity)) {
return false;
}
AccountHistoryEntity other = (AccountHistoryEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.entity.AccountHistory[ id=" + id + " ]";
}
}

View File

@ -1,255 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
/**
*
* @author jomu
*/
@Entity
@Table(name = "account_login")
@Cacheable
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "AccountLoginEntity.findAll", query = "SELECT a FROM AccountLoginEntity a"),
@NamedQuery(name = "AccountLoginEntity.findByAccountPassword", query = "SELECT a FROM AccountLoginEntity a WHERE a.accountPassword = :accountPassword"),
@NamedQuery(name = "AccountLoginEntity.findByLastLogin", query = "SELECT a FROM AccountLoginEntity a WHERE a.lastLogin = :lastLogin"),
@NamedQuery(name = "AccountLoginEntity.findByLastFailedLogin", query = "SELECT a FROM AccountLoginEntity a WHERE a.lastFailedLogin = :lastFailedLogin"),
@NamedQuery(name = "AccountLoginEntity.findByFailureCount", query = "SELECT a FROM AccountLoginEntity a WHERE a.failureCount = :failureCount"),
@NamedQuery(name = "AccountLoginEntity.findByPasswordResetOngoing", query = "SELECT a FROM AccountLoginEntity a WHERE a.passwordResetOngoing = :passwordResetOngoing"),
@NamedQuery(name = "AccountLoginEntity.findByPasswordResetValidTo", query = "SELECT a FROM AccountLoginEntity a WHERE a.passwordResetValidTo = :passwordResetValidTo"),
@NamedQuery(name = "AccountLoginEntity.findByPasswordResetHash", query = "SELECT a FROM AccountLoginEntity a WHERE a.passwordResetHash = :passwordResetHash"),
@NamedQuery(name = "AccountLoginEntity.findByCreatedOn", query = "SELECT a FROM AccountLoginEntity a WHERE a.createdOn = :createdOn"),
@NamedQuery(name = "AccountLoginEntity.findByCreatedBy", query = "SELECT a FROM AccountLoginEntity a WHERE a.createdBy = :createdBy"),
@NamedQuery(name = "AccountLoginEntity.findByLastUpdatedOn", query = "SELECT a FROM AccountLoginEntity a WHERE a.lastUpdatedOn = :lastUpdatedOn"),
@NamedQuery(name = "AccountLoginEntity.findByLastUpdatedBy", query = "SELECT a FROM AccountLoginEntity a WHERE a.lastUpdatedBy = :lastUpdatedBy")})
public class AccountLoginEntity implements Serializable {
private static final long serialVersionUID = -799045989045040077L;
@Id
@Basic(optional = false)
@NotNull
@Column(name = "id")
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 200)
@Column(name = "account_password")
private String accountPassword;
@Column(name = "last_login")
@Temporal(TemporalType.TIMESTAMP)
private Date lastLogin;
@Column(name = "last_failed_login")
@Temporal(TemporalType.TIMESTAMP)
private Date lastFailedLogin;
@Basic(optional = false)
@NotNull
@Column(name = "failure_count")
private int failureCount;
@Basic(optional = false)
@NotNull
@Column(name = "password_reset_ongoing")
private boolean passwordResetOngoing;
@Column(name = "password_reset_valid_to")
@Temporal(TemporalType.TIMESTAMP)
private Date passwordResetValidTo;
@Size(max = 200)
@Column(name = "password_reset_hash")
private String passwordResetHash;
@Basic(optional = false)
@NotNull
@Column(name = "created_on")
@Temporal(TemporalType.TIMESTAMP)
private Date createdOn;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 32)
@Column(name = "created_by")
private String createdBy;
@Basic(optional = false)
@NotNull
@Column(name = "last_updated_on")
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdatedOn;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 32)
@Column(name = "last_updated_by")
private String lastUpdatedBy;
@JoinColumn(name = "account", referencedColumnName = "id")
@OneToOne(optional = false)
private AccountEntity account;
public AccountLoginEntity() {
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getAccountPassword() {
return accountPassword;
}
public void setAccountPassword(String accountPassword) {
this.accountPassword = accountPassword;
}
public Date getLastLogin() {
return lastLogin;
}
public void setLastLogin(Date lastLogin) {
this.lastLogin = lastLogin;
}
public Date getLastFailedLogin() {
return lastFailedLogin;
}
public void setLastFailedLogin(Date lastFailedLogin) {
this.lastFailedLogin = lastFailedLogin;
}
public int getFailureCount() {
return failureCount;
}
public void setFailureCount(int failureCount) {
this.failureCount = failureCount;
}
public boolean getPasswordResetOngoing() {
return passwordResetOngoing;
}
public void setPasswordResetOngoing(boolean passwordResetOngoing) {
this.passwordResetOngoing = passwordResetOngoing;
}
public Date getPasswordResetValidTo() {
return passwordResetValidTo;
}
public void setPasswordResetValidTo(Date passwordResetValidTo) {
this.passwordResetValidTo = passwordResetValidTo;
}
public String getPasswordResetHash() {
return passwordResetHash;
}
public void setPasswordResetHash(String passwordResetHash) {
this.passwordResetHash = passwordResetHash;
}
public Date getCreatedOn() {
return createdOn;
}
public void setCreatedOn(Date createdOn) {
this.createdOn = createdOn;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Date getLastUpdatedOn() {
return lastUpdatedOn;
}
public void setLastUpdatedOn(Date lastUpdatedOn) {
this.lastUpdatedOn = lastUpdatedOn;
}
public String getLastUpdatedBy() {
return lastUpdatedBy;
}
public void setLastUpdatedBy(String lastUpdatedBy) {
this.lastUpdatedBy = lastUpdatedBy;
}
public AccountEntity getAccount() {
return account;
}
public void setAccount(AccountEntity account) {
this.account = account;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof AccountLoginEntity)) {
return false;
}
AccountLoginEntity other = (AccountLoginEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.business.account.entity.AccountLoginEntity[ id=" + id + " ]";
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author joern.muehlencord
*/
public enum AccountStatus {
NEW, // account is created but never used
NORMAL, // normal account, at least on login, neither blocked or disabled
BLOCKED, // account is blocked after too many login failures or other security related events
DISABLED; // account is disabled and cannot be used anymore
public static List<String> getAllStatusNames() {
List<String> statusNames = new ArrayList<>();
for (AccountStatus currentStatus : AccountStatus.values()) {
statusNames.add (currentStatus.name());
}
return statusNames;
}
}

View File

@ -1,171 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Entity
@Cacheable
@Table(name = "api_key")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "ApiKeyEntity.findAll", query = "SELECT a FROM ApiKeyEntity a"),
@NamedQuery(name = "ApiKeyEntity.findByApiKey", query = "SELECT a FROM ApiKeyEntity a WHERE a.apiKey = :apiKey",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ApiKeyEntity.findByIssuedOn", query = "SELECT a FROM ApiKeyEntity a WHERE a.issuedOn = :issuedOn"),
@NamedQuery(name = "ApiKeyEntity.findByAccount", query = "SELECT a FROM ApiKeyEntity a WHERE a.account = :account ORDER BY a.issuedOn DESC",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ApiKeyEntity.findByExpiration", query = "SELECT a FROM ApiKeyEntity a WHERE a.expiration = :expiration")})
public class ApiKeyEntity implements Serializable {
private static final long serialVersionUID = -1044658457228215810L;
@Id
@Basic(optional = false)
@NotNull
@Column(name = "id")
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 200)
@Column(name = "api_key")
private String apiKey;
@Basic(optional = false)
@NotNull
@Column(name = "issued_on")
@Temporal(TemporalType.TIMESTAMP)
private Date issuedOn;
@Column(name = "expiration")
private Short expiration;
@Basic(optional = false)
@NotNull
@Column(name = "expires_on")
@Temporal(TemporalType.TIMESTAMP)
private Date expiresOn;
@JoinColumn(name = "account", referencedColumnName = "id")
@ManyToOne(optional = false)
private AccountEntity account;
public ApiKeyEntity() {
// empty constructor required for JPA
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public Date getIssuedOn() {
return issuedOn;
}
public void setIssuedOn(Date issuedOn) {
this.issuedOn = issuedOn;
}
public Short getExpiration() {
return expiration;
}
public void setExpiration(Short expiration) {
this.expiration = expiration;
}
public Date getExpiresOn() {
return expiresOn;
}
public void setExpiresOn(Date expiresOn) {
this.expiresOn = expiresOn;
}
public AccountEntity getAccount() {
return account;
}
public void setAccount(AccountEntity account) {
this.account = account;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof ApiKeyEntity)) {
return false;
}
ApiKeyEntity other = (ApiKeyEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "com.wincornixdorf.pcd.business.account.ApiKeyEntity[ id=" + id + " ]";
}
}

View File

@ -1,57 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.account.entity;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public class JWTObject {
private String userName;
private String unqiueId;
private boolean valid;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUnqiueId() {
return unqiueId;
}
public void setUnqiueId(String unqiueId) {
this.unqiueId = unqiueId;
}
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.application.boundary;
import de.muehlencord.shared.account.util.SecurityError;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public enum ApplicationError implements SecurityError {
LIST_DENIED("1000", "list_denied");
private final String errorCode;
private final String messageKey;
private ApplicationError(String errorCode, String messageKey) {
this.errorCode = errorCode;
this.messageKey = messageKey;
}
@Override
public String getErrorCode() {
return errorCode;
}
@Override
public String getMessageKey() {
return messageKey;
}
}

View File

@ -1,130 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.application.control;
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.AccountSecurityException;
import de.muehlencord.shared.account.util.SecurityUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Stateless
public class ApplicationControl implements Serializable {
private static final long serialVersionUID = 4262608935325326191L;
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationControl.class);
@Inject
@AccountPU
EntityManager em;
public ApplicationEntity findById(UUID id) {
return em.find(ApplicationEntity.class, id);
}
public List<ApplicationEntity> getAllApplications() throws AccountSecurityException {
List<ApplicationEntity> resultList = new ArrayList<>();
Query query = em.createNamedQuery("ApplicationEntity.findAll");
List<ApplicationEntity> queryList = query.getResultList();
if ((queryList == null) || (queryList.isEmpty())) {
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
public ApplicationEntity createOrUpdate(ApplicationEntity app) {
if (app == null) {
// TODO add error handling
return null;
} else {
if (app.getId() == null) {
em.persist(app);
ApplicationEntity returnValue = findByApplicationName(app.getApplicationName());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Application {} created", app.getApplicationName());
}
return returnValue;
} else {
ApplicationEntity returnValue = em.merge(app);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Applicateion {} updated", app.getApplicationName());
}
return returnValue;
}
}
}
public ApplicationEntity findByApplicationName(String applicationName) {
Query query = em.createNamedQuery("ApplicationEntity.findByApplicationName");
query.setParameter("applicationName", applicationName);
List<ApplicationEntity> resultList = query.getResultList();
if ((resultList == null) || (resultList.isEmpty())) {
return null;
} else {
return resultList.get(0);
}
}
@Transactional
public void delete(ApplicationEntity app) {
ApplicationEntity attachedApp = em.find(ApplicationEntity.class, app.getId());
em.remove(attachedApp);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Application {} deleted", app.getApplicationName());
}
}
}

View File

@ -1,165 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.application.control;
import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationPermissionEntity;
import de.muehlencord.shared.account.util.AccountPU;
import de.muehlencord.shared.account.util.Permission;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.OptimisticLockException;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Stateless
public class ApplicationPermissionControl implements Serializable {
private static final long serialVersionUID = -3761100587901739481L;
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationPermissionControl.class);
@Inject
@AccountPU
EntityManager em;
@Inject
ApplicationEntity application;
public List<ApplicationPermissionEntity> getApplicationPermissions(ApplicationEntity app) {
if (application == null) {
return Collections.EMPTY_LIST;
}
Query query = em.createNamedQuery("ApplicationPermissionEntity.findAll");
query.setParameter("application", app);
List<ApplicationPermissionEntity> permissionList = query.getResultList();
if (permissionList == null) {
return new ArrayList<>();
} else {
return permissionList;
}
}
public ApplicationPermissionEntity findPermissionByName(ApplicationEntity application, String permissionName) {
Query query = em.createNamedQuery("ApplicationPermissionEntity.findByPermissionName");
query.setParameter("application", application);
query.setParameter("permissionName", permissionName);
List<ApplicationPermissionEntity> resultList = query.getResultList();
if ((resultList == null) || (resultList.isEmpty())) {
return null;
} else {
return resultList.get(0);
}
}
@Transactional
public void create(ApplicationEntity application, String name, String description) {
ApplicationPermissionEntity permission = new ApplicationPermissionEntity(application, name, description);
em.persist(permission);
}
@Transactional
public void update(ApplicationPermissionEntity permission) throws AccountException {
ApplicationPermissionEntity existing = attach(permission);
em.merge(existing);
}
@Transactional
public void createOrUpdate(ApplicationEntity application, String name, String description) {
ApplicationPermissionEntity permission = findByName(application, name);
if (permission == null) {
permission = new ApplicationPermissionEntity(name, description);
em.persist(permission);
} else {
permission.setPermissionDescription(description);
em.merge(permission);
}
}
@Transactional
public void delete(ApplicationPermissionEntity permission) throws AccountException {
ApplicationPermissionEntity existingPermission = attach(permission);
em.remove(existingPermission);
}
public ApplicationPermissionEntity attach(ApplicationPermissionEntity permission) throws AccountException {
try {
return em.merge(permission);
} catch (OptimisticLockException ex) {
throw new AccountException("Entity updated / deleted, please reload", true);
}
}
private ApplicationPermissionEntity findByName(ApplicationEntity application, String name) {
Query query = em.createNamedQuery("ApplicationPermissionEntity.findByPermissionName");
query.setParameter("application", application);
query.setParameter("permissionName", name);
List<ApplicationPermissionEntity> permissions = query.getResultList();
if ((permissions == null) || (permissions.isEmpty())) {
return null;
} else {
return permissions.get(0);
}
}
@Transactional
public void setupPermissions(List<Permission> permissions) {
if (application == null) {
LOGGER.error("Application not initialized, cannot setup permissions");
} else {
for (Permission permission : permissions) {
ApplicationPermissionEntity existingPermission = findByName(application, permission.getName());
if (existingPermission == null) {
// permission not available, create it
LOGGER.info("missing permission {} of {}", permission.getName(), application.getApplicationName());
existingPermission = new ApplicationPermissionEntity(permission.getName(), permission.getDescription());
existingPermission.setApplication(application);
em.persist(existingPermission);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("missing permission {} added to {}", permission.getName(), application.getApplicationName());
}
} else {
if (existingPermission.getPermissionDescription().equals(permission.getDescription())) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Permission {} for {} already exists, skipping", permission.getName(), application.getApplicationName());
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("description of permssion {} for {} differs, resetting to orignal value {}", permission.getName(), application.getApplicationName(), permission.getDescription());
}
existingPermission.setPermissionDescription(permission.getDescription());
em.merge(existingPermission);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("updated permission description {} for {}", permission.getName(), application.getApplicationName());
}
}
}
}
}
}
}

View File

@ -1,209 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.application.control;
import de.muehlencord.shared.account.business.account.entity.AccountException;
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.ApplicationRoleEntity;
import de.muehlencord.shared.account.util.AccountPU;
import de.muehlencord.shared.account.util.Permission;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.OptimisticLockException;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Stateless
public class ApplicationRoleControl implements Serializable {
private static final long serialVersionUID = 5962478269550134748L;
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationRoleControl.class);
@EJB
ApplicationPermissionControl applicationPermissionControl;
@Inject
@AccountPU
EntityManager em;
@Inject
ApplicationEntity application;
// TODO requires special role to maintain role for other allication
public List<ApplicationRoleEntity> getAllRoles(ApplicationEntity app) {
Query query = em.createNamedQuery("ApplicationRoleEntity.findAll");
query.setParameter("application", app);
List<ApplicationRoleEntity> roles = query.getResultList();
if (roles == null) {
return new ArrayList<>();
} else {
return roles;
}
}
@Transactional
// TODO requires special role to maintain role for other allication
public void createOrUpdate(ApplicationEntity app, String name, String description) {
ApplicationRoleEntity role = findByName(app, name);
if (role == null) {
role = new ApplicationRoleEntity(app, name, description);
em.persist(role);
} else {
role.setRoleDescription(description);
em.merge(role);
}
}
@Transactional
// TODO requires special role to maintain role for other allication
public void create(ApplicationRoleEntity role) {
em.persist(role);
}
@Transactional
// TODO requires special role to maintain role for other allication
public void update(ApplicationRoleEntity role) {
em.merge(role);
}
@Transactional
// TODO requires special role to maintain role for other allication
public void delete(ApplicationRoleEntity role) throws AccountException {
ApplicationRoleEntity existingRole = attach(role);
em.remove(existingRole);
}
public ApplicationRoleEntity attach(ApplicationRoleEntity role) throws AccountException {
try {
return em.merge(role);
} catch (OptimisticLockException ex) {
throw new AccountException("Entity updated / deleted, please reload", true);
}
}
public ApplicationRoleEntity findByName(String name) {
return findByName(application, name);
}
// TODO requires special role to maintain role for other allication
public ApplicationRoleEntity findByName(ApplicationEntity app, String name) {
Query query = em.createNamedQuery("ApplicationRoleEntity.findByRoleName");
query.setParameter("application", app);
query.setParameter("roleName", name);
List<ApplicationRoleEntity> permissions = query.getResultList();
if ((permissions == null) || (permissions.isEmpty())) {
return null;
} else {
return permissions.get(0);
}
}
public List<ApplicationPermissionEntity> getRolePermissions(ApplicationRoleEntity role) throws AccountException {
ApplicationRoleEntity existingRole = em.find(ApplicationRoleEntity.class, role.getId());
List<ApplicationPermissionEntity> permissions = existingRole.getApplicationPermissionList();
if ((permissions != null) && (permissions.isEmpty())) {
permissions.size(); // force list to load
}
return permissions;
}
public List<ApplicationPermissionEntity> getNotAssignedApplicationPermissions(ApplicationRoleEntity role) {
try {
List<ApplicationPermissionEntity> rolePermissions = getRolePermissions(role);
List<ApplicationPermissionEntity> allPermssions = applicationPermissionControl.getApplicationPermissions(role.getApplication());
List<ApplicationPermissionEntity> missingPermissions = new ArrayList<>();
allPermssions.stream().filter((perm) -> (!rolePermissions.contains(perm))).forEachOrdered((perm) -> {
missingPermissions.add(perm);
});
return missingPermissions;
} catch (AccountException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.debug(ex.toString());
}
return null;
}
}
@Transactional
// TODO requires special role to maintain role for other allication
public void addPermission(ApplicationRoleEntity role, ApplicationPermissionEntity permission) throws AccountException {
ApplicationRoleEntity existingRole = attach(role);
if (existingRole.getApplicationPermissionList() == null) {
existingRole.setApplicationPermissionList(new ArrayList<>());
}
existingRole.getApplicationPermissionList().add(permission);
em.merge(role);
}
@Transactional
// TODO requires special role to maintain role for other allication
public void removePermission(ApplicationRoleEntity role, ApplicationPermissionEntity permission) throws AccountException {
ApplicationRoleEntity existingRole = attach(role);
if ((existingRole.getApplicationPermissionList() != null) && (existingRole.getApplicationPermissionList().contains(permission))) {
existingRole.getApplicationPermissionList().remove(permission);
}
em.merge(role);
}
@Transactional
public void setupRolePermission(List<Permission> permissions, String roleName) throws AccountException {
ApplicationRoleEntity role = findByName(application, roleName);
if (role == null) {
LOGGER.error("A role with name " + roleName + " is not defined for application " + application.getApplicationName());
} else {
for (Permission permission : permissions) {
ApplicationPermissionEntity existingPermission = applicationPermissionControl.findPermissionByName(application, permission.getName());
if (existingPermission == null) {
LOGGER.error("Required permission " + permission.getName() + " of application " + application.getApplicationName() + " does not exist. Ensure to call setupPermissions first");
} else {
if (role.getApplicationPermissionList().contains(existingPermission)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Permission {} already assigned to role {} of {}, skipping", permission.getName(), roleName, application.getApplicationName());
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Permission {} not assigned to role {} of {}", permission.getName(), roleName, application.getApplicationName());
}
addPermission(role, existingPermission);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Added permission {} to role {} of {}", permission.getName(), roleName, application.getApplicationName());
}
}
}
}
}
}
}

View File

@ -1,155 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.application.entity;
import de.muehlencord.shared.account.business.config.entity.ConfigEntity;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Entity
@Table(name = "application")
@XmlRootElement
@Cacheable
@NamedQueries({
@NamedQuery(name = "ApplicationEntity.findAll", query = "SELECT a FROM ApplicationEntity a",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ApplicationEntity.findByApplicationName", query = "SELECT a FROM ApplicationEntity a WHERE a.applicationName = :applicationName",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")})
})
public class ApplicationEntity implements Serializable {
private static final long serialVersionUID = -6407525020014743727L;
@Id
@Basic(optional = false)
@NotNull
@Column(name = "id")
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 200)
@Column(name = "application_name", unique = true)
private String applicationName;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "application")
private List<ApplicationRoleEntity> applicationRoleEntityList;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "application")
private List<ApplicationPermissionEntity> applicationPermissions;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "application")
private List<ConfigEntity> configEntityList;
public ApplicationEntity() {
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
@XmlTransient
public List<ApplicationRoleEntity> getApplicationRoleEntityList() {
return applicationRoleEntityList;
}
public void setApplicationRoleEntityList(List<ApplicationRoleEntity> applicationRoleEntityList) {
this.applicationRoleEntityList = applicationRoleEntityList;
}
@XmlTransient
public List<ApplicationPermissionEntity> getApplicationPermissions() {
return applicationPermissions;
}
public void setApplicationPermissions(List<ApplicationPermissionEntity> applicationPermissions) {
this.applicationPermissions = applicationPermissions;
}
@XmlTransient
public List<ConfigEntity> getConfigEntityList() {
return configEntityList;
}
public void setConfigEntityList(List<ConfigEntity> configEntityList) {
this.configEntityList = configEntityList;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof ApplicationEntity)) {
return false;
}
ApplicationEntity other = (ApplicationEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.business.application.entity.ApplicationEntity[ id=" + id + " ]";
}
}

View File

@ -1,188 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.application.entity;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
/**
*
* @author joern.muehlencord
*/
@Entity
@Table(name = "application_permission")
@XmlRootElement
@Cacheable
@NamedQueries({
@NamedQuery(name = "ApplicationPermissionEntity.findAll", query = "SELECT a FROM ApplicationPermissionEntity a WHERE a.application=:application order by a.permissionName",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ApplicationPermissionEntity.findNotAssigned", query = "SELECT a FROM ApplicationPermissionEntity a LEFT OUTER JOIN a.applicationRoles r WHERE a.application=:application AND r NOT IN :permissions",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ApplicationPermissionEntity.findByPermissionName", query = "SELECT a FROM ApplicationPermissionEntity a WHERE a.application=:application AND a.permissionName = :permissionName",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ApplicationPermissionEntity.findByPermissionDescription", query = "SELECT a FROM ApplicationPermissionEntity a WHERE a.application=:application AND a.permissionDescription = :permissionDescription",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")})
})
public class ApplicationPermissionEntity implements Serializable {
private static final long serialVersionUID = -8985982754544829534L;
@Id
@Basic(optional = false)
@NotNull
@Column(name = "id")
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 80)
@Column(name = "permission_name")
private String permissionName;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 200)
@Column(name = "permission_description")
private String permissionDescription;
@JoinColumn(name = "application", referencedColumnName = "id")
@ManyToOne(optional = false)
private ApplicationEntity application;
@ManyToMany(mappedBy = "applicationPermissionList")
private List<ApplicationRoleEntity> applicationRoles;
public ApplicationPermissionEntity() {
}
public ApplicationPermissionEntity(UUID id) {
this.id = id;
}
public ApplicationPermissionEntity(String permissionName, String permissionDescription) {
this.id = null;
this.permissionName = permissionName;
this.permissionDescription = permissionDescription;
}
public ApplicationPermissionEntity(ApplicationEntity application, String permissionName, String permissionDescription) {
this.id = null;
this.application = application;
this.permissionName = permissionName;
this.permissionDescription = permissionDescription;
}
public ApplicationPermissionEntity(UUID id, ApplicationEntity application, String permissionName, String permissionDescription) {
this.id = id;
this.application = application;
this.permissionName = permissionName;
this.permissionDescription = permissionDescription;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getPermissionName() {
return permissionName;
}
public void setPermissionName(String permissionName) {
this.permissionName = permissionName;
}
public String getPermissionDescription() {
return permissionDescription;
}
public void setPermissionDescription(String permissionDescription) {
this.permissionDescription = permissionDescription;
}
@XmlTransient
public List<ApplicationRoleEntity> getApplicationRoles() {
return applicationRoles;
}
public void setApplicationRoles(List<ApplicationRoleEntity> applicationRoles) {
this.applicationRoles = applicationRoles;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof ApplicationPermissionEntity)) {
return false;
}
ApplicationPermissionEntity other = (ApplicationPermissionEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.entity.ApplicationPermission[ id=" + id + " ]";
}
public ApplicationEntity getApplication() {
return application;
}
public void setApplication(ApplicationEntity application) {
this.application = application;
}
}

View File

@ -1,198 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.application.entity;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
/**
*
* @author joern.muehlencord
*/
@Entity
@Table(name = "application_role")
@Cacheable
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "ApplicationRoleEntity.findAll", query = "SELECT a FROM ApplicationRoleEntity a WHERE a.application = :application ORDER BY a.roleName",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ApplicationRoleEntity.findByRoleName", query = "SELECT a FROM ApplicationRoleEntity a WHERE a.application = :application AND a.roleName = :roleName",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ApplicationRoleEntity.findByRoleDescription", query = "SELECT a FROM ApplicationRoleEntity a WHERE a.application = :application AND a.roleDescription = :roleDescription",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")})
})
public class ApplicationRoleEntity implements Serializable {
private static final long serialVersionUID = -8324054525780893823L;
@Id
@Basic(optional = false)
@NotNull
@Column(name = "id")
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Type(type = "pg-uuid")
private UUID id;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 80)
@Column(name = "role_name")
private String roleName;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 200)
@Column(name = "role_description")
private String roleDescription;
@ManyToMany(mappedBy = "applicationRoleList")
private List<AccountEntity> accountList;
@JoinTable(name = "role_permission", joinColumns = {
@JoinColumn(name = "application_role", referencedColumnName = "id")}, inverseJoinColumns = {
@JoinColumn(name = "role_permission", referencedColumnName = "id")})
@ManyToMany
private List<ApplicationPermissionEntity> applicationPermissionList;
@JoinColumn(name = "application", referencedColumnName = "id")
@ManyToOne(optional = false)
private ApplicationEntity application;
public ApplicationRoleEntity() {
}
public ApplicationRoleEntity(ApplicationEntity application) {
this.id = null;
this.application = application;
this.roleName = "";
this.roleDescription = "";
}
public ApplicationRoleEntity(ApplicationEntity application, String roleName, String roleDescription) {
this.id = null;
this.application = application;
this.roleName = roleName;
this.roleDescription = roleDescription;
}
public ApplicationRoleEntity(UUID id, ApplicationEntity application, String roleName, String roleDescription) {
this.id = id;
this.application = application;
this.roleName = roleName;
this.roleDescription = roleDescription;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDescription() {
return roleDescription;
}
public void setRoleDescription(String roleDescription) {
this.roleDescription = roleDescription;
}
@XmlTransient
public List<AccountEntity> getAccountList() {
return accountList;
}
public void setAccountList(List<AccountEntity> accountList) {
this.accountList = accountList;
}
@XmlTransient
public List<ApplicationPermissionEntity> getApplicationPermissionList() {
return applicationPermissionList;
}
public void setApplicationPermissionList(List<ApplicationPermissionEntity> applicationPermissionList) {
this.applicationPermissionList = applicationPermissionList;
}
public ApplicationEntity getApplication() {
return application;
}
public void setApplication(ApplicationEntity application) {
this.application = application;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof ApplicationRoleEntity)) {
return false;
}
ApplicationRoleEntity other = (ApplicationRoleEntity) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.entity.ApplicationRole[ id=" + id + " ]";
}
}

View File

@ -1,261 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.config.boundary;
import de.muehlencord.shared.account.business.ControllerException;
import de.muehlencord.shared.account.business.account.entity.Account;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.config.entity.ConfigEntity;
import de.muehlencord.shared.account.business.config.entity.ConfigEntityPK;
import de.muehlencord.shared.account.business.config.entity.ConfigException;
import de.muehlencord.shared.account.util.AccountPU;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import static javax.ejb.TransactionAttributeType.REQUIRES_NEW;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author joern.muehlencord
*/
@Singleton
@Startup
public class ConfigService implements Serializable {
private static final long serialVersionUID = -3195224653632853003L;
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigService.class);
@Inject
@AccountPU
EntityManager em;
@Inject
ApplicationEntity application;
/**
* returns global config key which is not assigned to any. If more than one value is defined for the given key, the
* key assigned to system is returned. If more than one key is defined but system key is not defined, an exception
* is thrown.
*
* @param configKey the key to return
* @return the configValue belonging to the given configKey
* @throws de.muehlencord.shared.account.business.config.entity.ConfigException if more than one value is defined
* for the given key but none of the values is defined for the system user
*/
@Lock(LockType.READ)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public String getConfigValue(String configKey) throws ConfigException {
Query query = em.createNamedQuery("ConfigEntity.findByConfigKey");
query.setParameter("application", application);
query.setParameter("configKey", configKey);
List<ConfigEntity> configList = query.getResultList();
if ((configList == null) || (configList.isEmpty())) {
// key is not found in the database at all
return null;
} else if (configList.size() == 1) {
// exact one element found, return this one
return configList.get(0).getConfigValue();
} else {
// if more than one result found, return the one which is assigned to system if present
// if not present, throw exception
Optional<ConfigEntity> firstItem = configList.stream()
.filter(config -> config.getConfigPK().getConfigKeyAccount().getUsername().equals("system"))
.findFirst();
if (firstItem.isPresent()) {
return firstItem.get().getConfigValue();
} else {
throw new ConfigException("ConfigKey " + configKey + " not unique and system value not defined");
}
}
}
// TODO replace with DAO?
@Lock(LockType.READ)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<ConfigEntity> getApplicationConfigItems() {
Query query = em.createNamedQuery("ConfigEntity.findByApplication");
query.setParameter("application", application);
List<ConfigEntity> configList = query.getResultList();
return configList;
}
@Lock(LockType.READ)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public String getConfigValue(String configKey, String defaultValue) throws ConfigException, ControllerException {
return getConfigValue(configKey, defaultValue, false);
}
@Transactional
@Lock(LockType.WRITE)
@TransactionAttribute(REQUIRES_NEW)
public String getConfigValue(String configKey, String defaultValue, boolean storeDefaultValue) throws ConfigException, ControllerException {
// get configValue as usual
String configValue = getConfigValue(configKey);
// if config value is not found null has been returned
// in this case the value to return is the defaultValue
if (configValue == null) {
configValue = defaultValue;
}
// check if the default value should be stored in the database
if (storeDefaultValue) {
AccountEntity account = getAccount("system");
updateConfigValue(configKey, account, configValue);
}
return configValue;
}
@Lock(LockType.READ)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public String getConfigValue(String configKey, Account account, boolean fallbackToSystem) throws ConfigException {
Query query = em.createNamedQuery("ConfigEntity.findByConfigKeyAndAccount");
query.setParameter("application", application);
query.setParameter("configKey", configKey);
query.setParameter("account", account);
List<ConfigEntity> configList = query.getResultList();
if ((configList == null) || (configList.isEmpty())) {
// fallback to default / system value
if (fallbackToSystem) {
return getConfigValue(configKey);
} else {
return null;
}
} else if (configList.size() == 1) {
// exact one element found, return this one
return configList.get(0).getConfigValue();
} else {
// more than one value must not happen - this is not possible per the defintion of the datamodel
throw new ConfigException("Cannot have more than one value for the the given key " + configKey + " and the given account " + account.getUsername());
}
}
@Transactional
@Lock(LockType.WRITE)
@TransactionAttribute(REQUIRES_NEW)
public String getConfigValue(String configKey, String defaultValue, boolean storeDefaultValue, Account account, boolean fallbackToSystem) throws ConfigException, ControllerException {
String configValue = getConfigValue(configKey, account, fallbackToSystem);
if (configValue == null) {
// value not found for given account and if allowed also not found for system user
configValue = defaultValue;
}
// check if the default value should be stored in the database
if (storeDefaultValue) {
updateConfigValue(configKey, account, configValue);
}
return configValue;
}
@Transactional
@Lock(LockType.WRITE)
@TransactionAttribute(REQUIRES_NEW)
public boolean updateConfigValue(String configKey, String configValue) throws ConfigException, ControllerException {
Account account = getAccount("system");
return updateConfigValue(configKey, account, configValue);
}
@Transactional
@Lock(LockType.WRITE)
@TransactionAttribute(REQUIRES_NEW)
public boolean updateConfigValue(String configKey, String accountName, String configValue) throws ControllerException {
Account account = getAccount(accountName);
if (accountName == null) {
return false;
}
if (account == null) {
LOGGER.error("Account for userName {} not found", accountName);
return false;
}
return updateConfigValue(configKey, account, configValue);
}
@Transactional
@Lock(LockType.WRITE)
@TransactionAttribute(REQUIRES_NEW)
public boolean updateConfigValue(String configKey, Account account, String configValue) throws ControllerException {
if ((configKey == null) || (configKey.equals(""))) {
// null or empty key
return false;
}
if (account == null) {
throw new ControllerException(ControllerException.CAUSE_CANNOT_PERSIST, "Account must not be null, not updating");
}
AccountEntity accountEntity = getAccount(account.getUsername());
ConfigEntityPK pk = new ConfigEntityPK(application, configKey, accountEntity);
ConfigEntity currentEntity = em.find(ConfigEntity.class, pk);
if (currentEntity == null) {
currentEntity = new ConfigEntity(pk);
currentEntity.setConfigValue(configValue);
em.persist(currentEntity);
return true; // config item created - udpate performed
} else {
if ((currentEntity.getConfigValue() != null) && (currentEntity.getConfigValue().equals(configValue))) {
// value is the same - no update
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("configValue {} not changed, keeping {}", configKey, currentEntity.getConfigValue());
}
return false;
} else {
String oldValue = currentEntity.getConfigValue();
currentEntity.setConfigValue(configValue);
em.merge(currentEntity);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("configValue for {} updated from {} to {}", configKey, oldValue, configValue);
}
return true;
}
}
}
private AccountEntity getAccount(String accountName) {
Query query = em.createNamedQuery("AccountEntity.findByUsername");
query.setParameter("username", accountName);
List<AccountEntity> accountList = query.getResultList();
if ((accountList == null) || (accountList.isEmpty())) {
return null;
} else {
return accountList.get(0);
}
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
public void delete(ConfigEntity config) throws ControllerException {
em.remove(em.merge(config));
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.config.boundary;
import de.muehlencord.shared.account.business.account.entity.AccountConfigurationKey;
import de.muehlencord.shared.account.business.account.entity.AccountConfigurationValue;
import de.muehlencord.shared.account.business.config.entity.ConfigException;
import javax.ejb.EJB;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.Annotated;
import javax.enterprise.inject.spi.InjectionPoint;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Dependent
public class ConfigurationProducer {
@EJB
ConfigService configService;
@Produces
@AccountConfigurationValue(key = AccountConfigurationKey.Producer)
public String produceConfigurationValue(InjectionPoint injectionPoint) {
Annotated annotated = injectionPoint.getAnnotated();
AccountConfigurationValue annotation = annotated.getAnnotation(AccountConfigurationValue.class);
if (annotation != null) {
AccountConfigurationKey key = annotation.key();
if (key != null) {
try {
switch (key) {
case BaseUrl:
return configService.getConfigValue("base.url");
case PasswordResetUrl:
return configService.getConfigValue("base.url") + "/login.xhtml";
default:
throw new IllegalStateException("Invalid key " + key + " for injection point: " + injectionPoint);
}
} catch (ConfigException ex) {
throw new IllegalStateException("Invalid key " + key + " for injection point: " + injectionPoint + ". Exception: " + ex.getMessage());
}
}
}
throw new IllegalStateException("No key for injection point: " + injectionPoint);
}
}

View File

@ -1,163 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.config.entity;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import java.io.Serializable;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Entity
@Table(name = "config")
@XmlRootElement
@Cacheable(true)
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "Configuration")
@NamedQueries({
@NamedQuery(name = "ConfigEntity.findAll", query = "SELECT c FROM ConfigEntity c ORDER BY c.configPK.configKey",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ConfigEntity.findByApplication", query = "SELECT c FROM ConfigEntity c WHERE c.configPK.application = :application",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ConfigEntity.findByConfigKey", query = "SELECT c FROM ConfigEntity c WHERE c.configPK.application = :application AND c.configPK.configKey = :configKey",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ConfigEntity.findByConfigKeyAndAccount", query = "SELECT c FROM ConfigEntity c WHERE c.configPK.application = :application AND c.configPK.configKey = :configKey AND c.configPK.configKeyAccount = :account",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "ConfigEntity.findByConfigValue", query = "SELECT c FROM ConfigEntity c WHERE c.configPK.application = :application AND c.configValue = :configValue",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")})
})
public class ConfigEntity implements Serializable {
private static final long serialVersionUID = -2013982316933782223L;
@EmbeddedId
protected ConfigEntityPK configPK;
@Size(max = 200)
@Column(name = "config_value")
private String configValue;
@Size(max = 200)
@Column(name = "config_key_group")
private String configKeyGroup;
@JoinColumn(name = "config_key_account", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private AccountEntity account;
@JoinColumn(name = "application", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private ApplicationEntity application;
public ConfigEntity() {
}
public ConfigEntity(ApplicationEntity application, String configKey, AccountEntity account) {
this.configPK = new ConfigEntityPK(application, configKey, account);
}
public ConfigEntity(ConfigEntityPK configPK) {
this.configPK = configPK;
}
public ConfigEntityPK getConfigPK() {
return configPK;
}
public void setConfigPK(ConfigEntityPK configPK) {
this.configPK = configPK;
}
public String getConfigValue() {
return configValue;
}
public void setConfigValue(String configValue) {
this.configValue = configValue;
}
public String getConfigKeyGroup() {
return configKeyGroup;
}
public void setConfigKeyGroup(String configKeyGroup) {
this.configKeyGroup = configKeyGroup;
}
@Override
public int hashCode() {
int hash = 0;
hash += (configPK != null ? configPK.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof ConfigEntity)) {
return false;
}
ConfigEntity other = (ConfigEntity) object;
if ((this.configPK == null && other.configPK != null) || (this.configPK != null && !this.configPK.equals(other.configPK))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.business.config.entity.Config[ configPK=" + configPK + " ]";
}
public AccountEntity getAccount() {
return account;
}
public void setAccount(AccountEntity account) {
this.account = account;
}
public ApplicationEntity getApplication() {
return application;
}
public void setApplication(ApplicationEntity application) {
this.application = application;
}
}

View File

@ -1,113 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.config.entity;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Embeddable
public class ConfigEntityPK implements Serializable {
private static final long serialVersionUID = 8133795368429249008L;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 100)
@Column(name = "config_key")
private String configKey;
@JoinColumn(name = "config_key_account", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private AccountEntity configKeyAccount;
@JoinColumn(name = "application", referencedColumnName = "id", insertable = false, updatable = false)
@ManyToOne(optional = false)
private ApplicationEntity application;
public ConfigEntityPK() {
// empty constructor required for JPA
}
public ConfigEntityPK(ApplicationEntity application, String configKey, AccountEntity configKeyAccount) {
this.application = application;
this.configKey = configKey;
this.configKeyAccount = configKeyAccount;
}
public String getConfigKey() {
return configKey;
}
public void setConfigKey(String configKey) {
this.configKey = configKey;
}
public AccountEntity getConfigKeyAccount() {
return configKeyAccount;
}
public void setConfigKeyAccount(AccountEntity configKeyAccount) {
this.configKeyAccount = configKeyAccount;
}
public ApplicationEntity getApplication() {
return application;
}
public void setApplication(ApplicationEntity application) {
this.application = application;
}
@Override
public int hashCode() {
int hash = 0;
hash += (configKey != null ? configKey.hashCode() : 0);
hash += (configKeyAccount != null ? configKeyAccount.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof ConfigEntityPK)) {
return false;
}
ConfigEntityPK other = (ConfigEntityPK) object;
if ((this.configKey == null && other.configKey != null) || (this.configKey != null && !this.configKey.equals(other.configKey))) {
return false;
}
if ((this.configKeyAccount == null && other.configKeyAccount != null) || (this.configKeyAccount != null && !this.configKeyAccount.equals(other.configKeyAccount))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.business.config.entity.ConfigPK[ configKey=" + configKey + ", configKeyAccount=" + configKeyAccount + " ]";
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.config.entity;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public class ConfigException extends Exception {
private static final long serialVersionUID = 7246584814637280123L;
/**
* Creates a new instance of <code>ConfigException</code> without detail
* message.
*/
public ConfigException() {
}
/**
* Constructs an instance of <code>ConfigException</code> with the specified
* detail message.
*
* @param msg the detail message.
*/
public ConfigException(String msg) {
super(msg);
}
/**
* Constructs an instance of <code>ConfigException</code> with the specified
* detail message and root cause.
*
* @param msg the detail message.
* @param th the root cause
*/
public ConfigException(String msg, Throwable th) {
super(msg, th);
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.instance.boundary;
import de.muehlencord.shared.account.util.Permission;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public enum ApplicationPermissions implements Permission {
APP_LIST("application:list", "Allows to list all avaiable applications"),
APP_ADD("application:add", "Allow to add a new application"),
APP_EDIT("application:edit", "Allow to edit an application"),
APP_DELETE("application:delete", "Allow to delete an application"),
PERMISSION_ADD("permission:add", "Allow to add a permission to an application"),
PERMISSION_EDIT("permission:edit", "Allow to edit a permission"),
PERMISSION_DELETE("permmission:delete", "Allow to delete a permission"),
ROLE_ADD("role:add", "Allow to add a role to an application"),
ROLE_EDIT("role:edit", "Allow to edit 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_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 description;
private ApplicationPermissions(String permissionName, String permissionDesc) {
this.name = permissionName;
this.description = permissionDesc;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
}

View File

@ -1,76 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.instance.boundary;
import de.muehlencord.shared.account.business.ControllerException;
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.entity.ConfigException;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@ApplicationScoped
public class StartupBean {
private static final Logger LOGGER = LoggerFactory.getLogger(StartupBean.class);
@Inject
ConfigService configService;
@Inject
ApplicationEntity application;
public void init(@Observes @Initialized(ApplicationScoped.class) Object init) {
if (application == null) {
LOGGER.error("Application not initialized");
throw new RuntimeException ("Application not initilized, validate applicationUID mapping");
} else {
try {
LOGGER.info("Starting application {}", application.getApplicationName());
String instanceName = configService.getConfigValue("base.instance", "Development System", true);
LOGGER.info("instanceName={}", instanceName);
// ensure maxFailedLogins is available
configService.getConfigValue("account.maxFailedLogins", "5", true);
LOGGER.info("Application startup complete");
} catch (ConfigException | ControllerException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
}
}
}
@PreDestroy
public void shutdown() {
LOGGER.info("Shutting down application {}", application.getApplicationName());
LOGGER.info("Application shutdown complete");
}
}

View File

@ -1,121 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.instance.control;
import de.muehlencord.shared.account.business.application.control.ApplicationControl;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.UUID;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Named;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
@Named("applicationController")
@ApplicationScoped
public class ApplicationController {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationController.class);
@EJB
ApplicationControl applicationService;
private String version;
private String buildDate;
private UUID uuid;
private ApplicationEntity application = null;
@PostConstruct
public void readBuildInfoProperties() {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Trying to read buildInfo.properties");
}
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("buildInfo.properties");
if (in == null) {
return;
}
Properties props = new Properties();
try {
props.load(in);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("properties read from buildInfo.properties");
}
version = props.getProperty("build.version");
buildDate = props.getProperty("build.timestamp");
String uuidString = props.getProperty("application.uuid");
if (StringUtils.isEmpty(uuidString)) {
throw new RuntimeException("ApplicationId not defined, please check database setup");
} else {
uuid = UUID.fromString(uuidString);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("buildInfo.properties parsed successfully");
}
} catch (IOException ex) {
LOGGER.error("Cannot find buildInfo.properties. ", ex);
version = "??";
buildDate = "??";
uuid = null;
throw new RuntimeException("Application id not readable, application will not be able to run");
}
if (uuid != null) {
this.application = applicationService.findById(uuid);
if (application == null) {
throw new RuntimeException("ApplicationId " + uuid.toString() + " not readable, application will not be able to run. You need to setup application in account database first.");
} else {
LOGGER.info("Found application {} with id {}", application.getApplicationName(), uuid.toString());
}
}
}
/**
* needs to return link to "Account UI" and not to current selected application TODO: ensure only Account UI can
* call functions where application can be handed in - all other applications need to call the function which use
* the injected application
*/
@Produces
public ApplicationEntity getApplication() {
return application;
}
public String getVersion() {
return version;
}
public String getBuildDate() {
return buildDate;
}
public UUID getApplicationId() {
return uuid;
}
}

View File

@ -1,235 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.mail.boundary;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
import de.muehlencord.shared.account.business.config.entity.ConfigException;
import de.muehlencord.shared.account.business.mail.entity.MailDatamodel;
import de.muehlencord.shared.account.business.mail.entity.MailException;
import de.muehlencord.shared.account.business.mail.entity.MailTemplateException;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author joern.muehlencord
*/
@Stateless
public class MailService implements Serializable {
private static final long serialVersionUID = -1937218474908356747L;
private static final Logger LOGGER = LoggerFactory.getLogger(MailService.class);
@Inject
private MailTemplateService mailTemplateService;
@Inject
ConfigService configService;
// @Inject
// @AccountConfigurationValue(key = AccountConfigurationKey.BaseUrl)
// private String baseUrl;
// @Inject
// @AccountConfigurationValue(key = AccountConfigurationKey.PasswordResetUrl)
// private String passwordResetUrl;
// TODO make this configurable by injection from the application it uses it, fall back to defaul mail setup if not available
@Resource(lookup = "java:jboss/mail/ssgMail")
private Session mailSession;
public String sendTestEmail(String recipient) throws MailException {
return sendMail(recipient, "Test email", "This is a test email");
}
public String sendTestHtmlEmail(String recipient) throws MailException {
Date now = new Date();
AccountEntity account = new AccountEntity();
account.setId(UUID.randomUUID());
account.setFirstname("Jörn");
account.setLastname("Mühlencord");
AccountLoginEntity accountLogin = new AccountLoginEntity();
accountLogin.setAccountPassword("secret");
accountLogin.setAccount(account);
account.setAccountLogin(accountLogin);
MailDatamodel dataModel = new MailDatamodel(account);
dataModel.addParameter("url", "http://url.de");
dataModel.addParameter("resetUrl", "http://reseturl.de");
return sendHTMLMail(recipient, "Test HTML Email", dataModel, "password_reset_html");
}
public String sendMail(String recipient, String subject, String body) throws MailException {
try {
MimeMessage message = new MimeMessage(mailSession);
message.setSubject(subject, "UTF-8");
message.setFrom();
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient, false));
message.setText(body, "UTF-8");
return transportMail(message);
} catch (MessagingException ex) {
throw new MailException("Error while sending email.", ex);
}
}
public String sendHTMLMail(String recipient, String subject, MailDatamodel dataModel, String templateName) throws MailException {
return sendHTMLMail(recipient, subject, dataModel, templateName, null);
}
public String sendHTMLMail(String recipient, String subject, MailDatamodel dataModel, String htmlTemplateName, String plainTemplateName) throws MailException {
return sendHTMLMail(recipient, null, null, subject, dataModel, htmlTemplateName, plainTemplateName, "UTF-8", new ArrayList<>());
}
public String sendHTMLMail(String recipient, String ccRecipient, String bccRecipient, String subject, MailDatamodel dataModel, String htmlTemplateName, String plainTemplateName) throws MailException {
return sendHTMLMail(recipient, ccRecipient, bccRecipient, subject, dataModel, htmlTemplateName, plainTemplateName, "UTF-8", new ArrayList<>());
}
public String sendHTMLMail(String recipient, String ccRecipient, String bccRecipient, String subject,
MailDatamodel dataModel, String htmlTemplateName, String plainTemplateName, String encoding, List<File> attachments) throws MailException {
try {
String htmlBody = mailTemplateService.getStringFromTemplate(htmlTemplateName, dataModel);
String plainBody;
if (plainTemplateName != null) {
plainBody = mailTemplateService.getStringFromTemplate(plainTemplateName, dataModel);
} else {
plainBody = null;
}
return sendHTMLMail(recipient, ccRecipient, bccRecipient, subject, htmlBody, plainBody, encoding, attachments);
} catch (MailTemplateException ex) {
throw new MailException("Error while sending email.", ex);
}
}
public String sendHTMLMail(String recipient, String ccRecipient, String bccRecipient, String subject, String htmlBody, String plainBody, String encoding, List<File> attachments) throws MailException {
try {
MimeMessage message = new MimeMessage(mailSession);
message.setFrom(); // use default from
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient, false));
if (ccRecipient != null) {
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccRecipient, false));
}
if (bccRecipient != null) {
message.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(bccRecipient, false));
}
message.setSubject(subject, encoding);
Multipart contentMultiPart = new MimeMultipart("alternative");
MimeBodyPart htmlBodyPart = new MimeBodyPart();
htmlBodyPart.setContent(htmlBody, "text/html; charset=UTF-8");
contentMultiPart.addBodyPart(htmlBodyPart);
if (plainBody != null) {
MimeBodyPart plainBodyPart = new MimeBodyPart();
plainBodyPart.setText(plainBody, "UTF-8");
contentMultiPart.addBodyPart(plainBodyPart);
}
if ((attachments == null) || (attachments.isEmpty())) {
message.setContent(contentMultiPart);
} else {
MimeBodyPart contentBodyPart = new MimeBodyPart();
contentBodyPart.setContent(contentMultiPart);
MimeMultipart messageMultipart = new MimeMultipart("related");
messageMultipart.addBodyPart(contentBodyPart);
for (File attachment : attachments) {
try {
MimeBodyPart attachmentBodyPart = new MimeBodyPart();
attachmentBodyPart.attachFile(attachment);
String contentType = Files.probeContentType(attachment.toPath());
if (contentType != null) {
attachmentBodyPart.setHeader("Content-Type", contentType);
}
messageMultipart.addBodyPart(attachmentBodyPart);
} catch (IOException ex) {
throw new MailException("Cannot attach " + attachment.toString() + " to email. Reason: " + ex.toString(), ex);
}
}
message.setContent(messageMultipart);
}
return transportMail(message);
} catch (MessagingException ex) {
throw new MailException("Error while sending email.", ex);
}
}
public String sendPasswortResetStartEmail(AccountEntity account, String token) throws MailException, ConfigException {
MailDatamodel model = new MailDatamodel(account);
/* old aproach via FacesContext - add this back as fallback if injection point if not configured
try {
// String absoluteWebPath = FacesContext.getCurrentInstance().getExternalContext().getApplicationContextPath();
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
String resetPage = "/login.xhtml?token=" + token;
URL baseUrl;
// TODO move out of this class, this is not mandatorily connected to a form
baseUrl = new URL(externalContext.getRequestScheme(),
externalContext.getRequestServerName(),
externalContext.getRequestServerPort(),
externalContext.getRequestContextPath());
model.addParameter("url", baseUrl.toString());
model.addParameter("resetUrl", baseUrl.toString() + resetPage);
} catch (MalformedURLException ex) {
throw new MailException("Error while sending email.", ex);
}
String resetUrlWithToken = baseUrl + "/login.xhtml?token=" + token;
*/
String passwordResetUrl = configService.getConfigValue("backend.passwordreset.url");
String baseUrl = configService.getConfigValue("backend.base.url");
String resetUrlWithToken = passwordResetUrl + "?token=" + token;
model.addParameter("url", baseUrl);
model.addParameter("resetUrl", resetUrlWithToken);
return sendHTMLMail(account.getEmailaddress(), "Reset your password", model, "password_reset_html");
}
private String transportMail(Message message) throws MessagingException {
message.setSentDate(new Date());
Transport.send(message);
String messageId = message.getHeader("Message-ID")[0];
LOGGER.info("Mail sent to {}, messageid = {}", message.getAllRecipients()[0].toString(), messageId);
return messageId;
}
}

View File

@ -1,106 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.mail.boundary;
import de.muehlencord.shared.account.business.mail.entity.MailDatamodel;
import de.muehlencord.shared.account.business.mail.entity.MailTemplateEntity;
import de.muehlencord.shared.account.business.mail.entity.MailTemplateException;
import de.muehlencord.shared.account.util.AccountPU;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import java.io.IOException;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author jomu
*/
@Stateless
public class MailTemplateService implements Serializable {
private static final long serialVersionUID = -136113381443058697L;
private static final Logger LOGGER = LoggerFactory.getLogger(MailTemplateService.class.getName());
@Inject
@AccountPU
EntityManager em;
@Lock(LockType.READ)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public String getStringFromTemplate(String templateName, MailDatamodel dataModel) throws MailTemplateException {
try {
Query query = em.createNamedQuery("MailTemplateEntity.findByTemplateName");
query.setParameter("templateName", templateName);
MailTemplateEntity templateEntity = (MailTemplateEntity) query.getSingleResult();
if (templateEntity == null) {
LOGGER.error("Tempate with name " + templateName + " not found");
return null;
}
return fillTemplate(templateName, templateEntity.getTemplateValue(), dataModel);
} catch (MailTemplateException ex) {
String hint = "Error while processing template with name " + templateName + ".";
LOGGER.error(hint + " " + ex.toString());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(hint, ex);
}
throw new MailTemplateException(hint, ex);
}
}
@Lock(LockType.READ)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public String fillTemplate(String templateName, String templateString, MailDatamodel dataModel) throws MailTemplateException {
try {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
configuration.setDefaultEncoding("UTF-8"); // FIXME - make encoding configurable
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
StringTemplateLoader stringLoader = new StringTemplateLoader();
stringLoader.putTemplate(templateName, templateString);
configuration.setTemplateLoader(stringLoader);
Template template = configuration.getTemplate(templateName);
Writer out = new StringWriter();
template.process(dataModel, out);
String resultString = out.toString();
return resultString;
} catch (TemplateException | IOException ex) {
String hint = "Error while processing template with name " + templateName + ".";
LOGGER.error(hint + " " + ex.toString());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(hint, ex);
}
throw new MailTemplateException(hint, ex);
}
}
}

View File

@ -1,55 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.mail.entity;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author jomu
*/
public class MailDatamodel {
private final AccountEntity account;
private final Map<String,Object> parameter;
public MailDatamodel() {
this.account = null;
this.parameter = new HashMap<>();
}
public MailDatamodel(AccountEntity account) {
this.parameter = new HashMap<>();
this.account = account;
}
public void addParameter(String name, Object value) {
this.parameter.put(name, value);
}
/* **** getter / setter **** */
public AccountEntity getAccount() {
return account;
}
public Map<String, Object> getParameter() {
return parameter;
}
}

View File

@ -1,51 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.mail.entity;
/**
*
* @author Raimund
*/
public class MailException extends Exception {
/**
* Creates a new instance of <code>MailException</code> without detail
* message.
*/
public MailException() {
}
/**
* Constructs an instance of <code>MailException</code> with the specified
* detail message.
*
* @param msg the detail message.
*/
public MailException(String msg) {
super(msg);
}
/**
* Constructs an instance of <code>MailException</code> with the specified
* detail message.
*
* @param msg the detail message.
* @param th the root cause
*/
public MailException(String msg, Throwable th) {
super(msg, th);
}
}

View File

@ -1,122 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.mail.entity;
import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.QueryHint;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author joern.muehlencord
*/
@Entity
@Cacheable
@Table(name = "mail_template")
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "MailTemplateEntity.findAll", query = "SELECT m FROM MailTemplateEntity m",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "MailTemplateEntity.findByTemplateName", query = "SELECT m FROM MailTemplateEntity m WHERE m.templateName = :templateName",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")}),
@NamedQuery(name = "MailTemplateEntity.findByTemplateValue", query = "SELECT m FROM MailTemplateEntity m WHERE m.templateValue = :templateValue",
hints = {
@QueryHint(name = "org.hibernate.cacheable", value = "true"),
@QueryHint(name = "org.hibernate.cacheRegion", value = "Queries")})})
public class MailTemplateEntity implements Serializable {
private static final long serialVersionUID = 4527399247302581555L;
@Id
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 40)
@Column(name = "template_name")
private String templateName;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 2147483647)
@Column(name = "template_value")
private String templateValue;
public MailTemplateEntity() {
}
public MailTemplateEntity(String templateName) {
this.templateName = templateName;
}
public MailTemplateEntity(String templateName, String templateValue) {
this.templateName = templateName;
this.templateValue = templateValue;
}
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
public String getTemplateValue() {
return templateValue;
}
public void setTemplateValue(String templateValue) {
this.templateValue = templateValue;
}
@Override
public int hashCode() {
int hash = 0;
hash += (templateName != null ? templateName.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof MailTemplateEntity)) {
return false;
}
MailTemplateEntity other = (MailTemplateEntity) object;
if ((this.templateName == null && other.templateName != null) || (this.templateName != null && !this.templateName.equals(other.templateName))) {
return false;
}
return true;
}
@Override
public String toString() {
return "de.muehlencord.shared.account.entity.MailTemplate[ templateName=" + templateName + " ]";
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.business.mail.entity;
/**
*
* @author jomu
*/
public class MailTemplateException extends Exception {
/**
* Creates a new instance of <code>MailTemplateException</code> without
* detail message.
*/
public MailTemplateException() {
}
/**
* Constructs an instance of <code>MailTemplateException</code> with the
* specified detail message.
*
* @param msg the detail message.
*/
public MailTemplateException(String msg) {
super(msg);
}
/**
* Constructs an instance of <code>MailTemplateException</code> with the
* specified detail message.
*
* @param msg the detail message.
* @param th the root cause
*/
public MailTemplateException(String msg, Throwable th) {
super(msg, th);
}
}

View File

@ -1,202 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.presentation;
import de.muehlencord.shared.account.business.account.control.AccountControl;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.IOException;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author joern.muehlencord
*/
@Named(value = "loginView")
@ViewScoped
public class LoginView implements Serializable {
private static final long serialVersionUID = -1164860380769648432L;
@EJB
private AccountControl accountService;
private String username = null;
private String password = null;
private boolean rememberMe = false;
private String resetPasswordToken = null;
private static final Logger LOGGER = LoggerFactory.getLogger(LoginView.class.getName());
public void authenticate() {
// Example using most common scenario of username/password pair:
UsernamePasswordToken token = new UsernamePasswordToken(getUsername(), getPassword());
// "Remember Me" built-in:
token.setRememberMe(rememberMe);
Subject currentUser = SecurityUtils.getSubject();
LOGGER.info("Trying to login user {}", username);
try {
currentUser.login(token);
LOGGER.info("User {} logged in", username);
// user logged in, update account entity
AccountEntity account = accountService.getAccountEntity(username, true);
accountService.updateLogin(account);
// redirect to home
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
ServletResponse servletResponse = (ServletResponse) ec.getResponse();
String fallbackUrl = "/web/index.xhtml"; // TODO make configurable
// ec.redirect(url);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("redirecting to {}, fallbackUrl={}", servletResponse.toString(), fallbackUrl);
}
WebUtils.redirectToSavedRequest((ServletRequest) ec.getRequest(), servletResponse, fallbackUrl);
} catch (IOException | AuthenticationException ex) {
// Could catch a subclass of AuthenticationException if you like
String hint = "Error while authenticating user " + username;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(hint, ex);
}
if (ex.getMessage() != null) {
hint += "Reason: " + ex.getMessage();
} else {
hint += "Reason: " + ex.toString();
}
if ((ex.getCause() != null) && (ex.getCause().getMessage() != null)) {
hint += "Rootcause: " + ex.getMessage();
LOGGER.error(hint);
}
FacesUtil.addGlobalErrorMessage("Login failed", hint);
AccountEntity account = accountService.getAccountEntity(username, false);
if (account != null) {
accountService.addLoginError(account);
}
} finally {
token.clear();
}
}
public void logout() {
Subject currentUser = SecurityUtils.getSubject();
try {
currentUser.logout();
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
// ensure faces session is invalidated so beans are destroyed
ec.invalidateSession();
// check if redirect shall be executed
// default setting is yes to /login.xhtml
// can be overwritten using parameters
// de.muehlencord.shared.account.loginview.executeredirect boolean true/false
// de.muehlencord.shared.account.loginview.redirecttarget path to redirect to (without external context, will be added automatically)
String executeRedirectString = ec.getInitParameter("de.muehlencord.shared.account.loginview.executeredirect");
boolean executeRedirect = true;
if (executeRedirectString != null) {
executeRedirect = Boolean.parseBoolean(executeRedirectString);
}
String redirectTarget = ec.getInitParameter("de.muehlencord.shared.account.loginview.redirecttarget");
if ((redirectTarget == null) || (redirectTarget.equals(""))) {
redirectTarget = "/login.xhtml";
}
if (executeRedirect) {
String url = ec.getRequestContextPath() + redirectTarget;
ec.redirect(url);
}
} catch (Exception e) {
LOGGER.warn(e.toString());
}
}
public String executePasswordReset() {
boolean passwordResetted = accountService.resetPassword(username, password, resetPasswordToken);
if (passwordResetted) {
// TODO add email notification on updated user account
FacesUtil.addGlobalInfoMessage("Password resetted", null);
return login();
} else {
// TODO add email notificaton on failed password reset
FacesUtil.addGlobalErrorMessage("Password reset failed", null);
return login();
}
}
/* **** naviation rules **** */
public String login() {
return "/login.xhtml"; // TODO make configurable
}
/* *** getter / setter */
public String getUsername() {
return username;
}
public void setUsername(String un) {
this.username = un;
}
public String getPassword() {
return password;
}
public void setPassword(String pw) {
this.password = pw;
}
public boolean isRememberMe() {
return rememberMe;
}
public void setRememberMe(boolean rememberMe) {
this.rememberMe = rememberMe;
}
public String getResetPasswordToken() {
return resetPasswordToken;
}
public void setResetPasswordToken(String resetPasswordToken) {
this.resetPasswordToken = resetPasswordToken;
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.presentation;
import de.muehlencord.shared.account.business.account.control.AccountControl;
import de.muehlencord.shared.jeeutil.FacesUtil;
import java.io.Serializable;
import javax.ejb.EJB;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
/**
*
* @author joern@muehlencord.de
*/
@Named (value = "lostPasswordView")
@ViewScoped
public class LostPasswordView implements Serializable {
private static final long serialVersionUID = -1793445795465830069L;
@EJB
private AccountControl accountService;
private String userName;
private boolean passwordResetStarted = false;
public String initPasswordReset() {
if (accountService.initPasswordReset(userName)) {
passwordResetStarted = true;
FacesUtil.addGlobalInfoMessage("Password reset started.", "Please check your email account.");
} else {
FacesUtil.addGlobalErrorMessage("Error while resetting password.", "Please contact your administrator.");
}
return "/login.xhtml"; // TODO make configurable, get from LoginView?
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public boolean getPasswordResetStarted() {
return passwordResetStarted;
}
}

View File

@ -1,119 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.shiro.authc;
import de.muehlencord.shared.account.business.account.boundary.ApiKeyService;
import de.muehlencord.shared.account.business.account.entity.JWTObject;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author joern.muehlencord
*/
public class JwtMatcher implements CredentialsMatcher {
private static final Logger LOGGER = LoggerFactory.getLogger(JwtMatcher.class);
private final ApiKeyService apiKeyService = lookupApiKeyServiceBean();
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
if (token == null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No token available - cannot match credentials");
}
return false;
}
if ((info == null) || (info.getCredentials() == null)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No authenticationInfo available - cannot match credentials");
}
return false;
}
Object submittedJwtObj = token.getCredentials();
Object storedCredentials = getStoredPassword(info);
if ((submittedJwtObj != null) && (submittedJwtObj.getClass().isAssignableFrom(String.class))) {
String submittedJwt = (String) submittedJwtObj;
if (apiKeyService.validateJWT(submittedJwt)) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("JWT is valid, checking if it comes from the correct user");
}
JWTObject jwtObject = apiKeyService.getJWTObject(submittedJwt);
String storedUsername = info.getPrincipals().getPrimaryPrincipal().toString();
if (jwtObject.getUserName().equals(storedUsername)) {
if (jwtObject.getUnqiueId().equals (storedCredentials)) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("JWT matches user and password is correct");
}
return true;
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("JWT password does not match provided password");
}
return false;
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("JWT belongs to user {}, but authinfo is from user {} - JWT does not match");
}
return false;
}
} else {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("JWT is invalid");
}
return false;
}
} else {
LOGGER.error("Unexpected authInfoFormat - please check your configuration");
return false;
}
}
protected Object getStoredPassword(AuthenticationInfo storedAccountInfo) {
Object stored = storedAccountInfo != null ? storedAccountInfo.getCredentials() : null;
//fix for https://issues.apache.org/jira/browse/SHIRO-363
if (stored instanceof char[]) {
stored = new String((char[]) stored);
}
return stored;
}
// TODO - can this be injected?
private ApiKeyService lookupApiKeyServiceBean() {
try {
Context c = new InitialContext();
return (ApiKeyService) c.lookup("java:module/ApiKeyService"); // NOI18N
} catch (NamingException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
throw new RuntimeException(ex);
}
}
}

View File

@ -1,172 +0,0 @@
/*
* Copyright 2018 joern.muehlencord.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.muehlencord.shared.account.shiro.filter;
import java.io.IOException;
import java.io.StringReader;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.LoggerFactory;
import de.muehlencord.shared.account.business.account.boundary.ApiKeyService;
import de.muehlencord.shared.account.business.account.entity.JWTObject;
import de.muehlencord.shared.account.shiro.token.JWTAuthenticationToken;
import de.muehlencord.shared.account.util.AccountSecurityException;
import de.muehlencord.shared.jeeutil.restexfw.APIException;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public final class JWTAuthenticationFilter extends AuthenticatingFilter {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
protected static final String AUTHORIZATION_HEADER = "Authorization"; // NOI18N
protected static final String USERNAME = "username"; // NOI18N
protected static final String PASSWORD = "password"; // NOI18N
private final ApiKeyService apiKeyService = lookupApiKeyServiceBean();
public JWTAuthenticationFilter() {
// FIXME - logging in via JWTAuthenticationFilter does not yet work. Need to set login to anonymous to execute login in rest service
setLoginUrl("/rest/account/login");
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
boolean loggedIn = false;
if (isLoginRequest(request, response) || isLoggedAttempt(request, response)) {
loggedIn = executeLogin(request, response);
}
if (!loggedIn) {
HttpServletResponse httpResponse = WebUtils.toHttp(response);
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
return loggedIn;
}
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
String json = IOUtils.toString(request.getInputStream(), "UTF-8"); // FIXME - check charset in request
if (json != null && !json.isEmpty()) {
try (JsonReader jr = Json.createReader(new StringReader(json))) {
JsonObject object = jr.readObject();
String username = object.getString(USERNAME);
String password = object.getString(PASSWORD);
return new UsernamePasswordToken(username, password);
}
}
}
if (isLoggedAttempt(request, response)) {
String jwtToken = getAuthzHeader(request);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("found jwtToke in header = {}", jwtToken);
}
if (jwtToken != null) {
JWTObject jwtObject = apiKeyService.getJWTObject(jwtToken);
return new JWTAuthenticationToken(jwtObject.getUserName(), jwtToken);
}
}
return new UsernamePasswordToken();
}
private boolean isLoggedAttempt(ServletRequest request, ServletResponse response) {
String authzHeader = getAuthzHeader(request);
return authzHeader != null;
}
private String getAuthzHeader(ServletRequest request) {
HttpServletRequest httpRequest = WebUtils.toHttp(request);
return httpRequest.getHeader(AUTHORIZATION_HEADER);
}
/**
* Overwrite cleanup to ensure no exception is thrown if an
* AccountSecurityException / APIException is raised during login. As long
* as the user is not logged in JERSEYs ExceptionMapper and intercepor
* classes are overruled by Shiro.
*
* @param request the incoming request
* @param response the response to return
* @param existing the raised exception
* @throws ServletException may be thrown by AuthenticatingFilter.cleanup if
* existing is not a AccountSecurityException
* @throws IOException may be thrown by AuthenticatingFilter.cleanup if
* existing is not a AccountSecurityException
*/
@Override
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing) throws ServletException, IOException {
if ((existing != null) && (existing.getClass().isAssignableFrom(AccountSecurityException.class))) {
HttpServletResponse httpResponse = WebUtils.toHttp(response);
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
} else if ((existing != null) && (existing.getClass().isAssignableFrom(APIException.class))) {
APIException apiException = (APIException) existing;
HttpServletResponse httpResponse = WebUtils.toHttp(response);
httpResponse.setStatus(apiException.getHttpResponse().getStatus());
httpResponse.addHeader(APIException.HTTP_HEADER_X_ERROR, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ERROR));
httpResponse.addHeader(APIException.HTTP_HEADER_X_ERROR_CODE, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ERROR_CODE));
if (apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ROOT_CAUSE) != null) {
httpResponse.addHeader(APIException.HTTP_HEADER_X_ROOT_CAUSE, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ROOT_CAUSE));
}
} else {
super.cleanup(request, response, existing);
}
}
// TODO - can this be injected?
private ApiKeyService lookupApiKeyServiceBean() {
try {
Context c = new InitialContext();
return (ApiKeyService) c.lookup("java:module/ApiKeyService"); // NOI18N
} catch (NamingException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
throw new RuntimeException(ex);
}
}
}

Some files were not shown because too many files have changed in this diff Show More