initial Commit
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8550c70 --- /dev/null +++ b/.gitignore
@@ -0,0 +1,15 @@ +.git +.idea/**/*.xml +.settings +.classpath +target +/.idea/compiler.xml +/.idea/*.xml +/.idea/modules.xml +/.idea/vcs.xml +/bin/ +.iml +.project +.classpath +.idea +/portal.iml
diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml new file mode 100644 index 0000000..c506da6 --- /dev/null +++ b/api/swagger/swagger.yaml
@@ -0,0 +1,13 @@ +swagger: "2.0" +info: + version: "1.0.0" + title: eLogbook API +host: localhost:3000 +basePath: / +schemes: + - http +consumes: + - application/json +produces: + - application/json +paths: \ No newline at end of file
diff --git a/deploy/HowToDeploy.txt b/deploy/HowToDeploy.txt new file mode 100644 index 0000000..4e9ec6f --- /dev/null +++ b/deploy/HowToDeploy.txt
@@ -0,0 +1,31 @@ +Deployment der Anwendung oK Betriebstagebuch +________________________________________________ +22.03.2017 _fd first Version +________________________________________________ + + +Allgemein +_________________________________________________ + +Datenbank einrichten +____________________ + +.... + +Datenquelle auf Apache Tomcat einrichten +________________________________________ +Im "conf"-Unterverzeichnis des Tomcat (<TOMCAT>/conf) befindet sich die Datei context.xml. +Diese muss um den Bereich "<Resource>..." aus der Datei (/deploy/context.xml) ergänzt werden. +Der Datenbank-Treiber (deploy/lib/postgresql-xxx.jar) muss nach ""<TOMCAT>/lib" kopiert werden. + + +Backend-Installieren +____________________ +Die Datei "betriebstagebuch.war" muss in das Verzeichnis "<TOMCAT>/webapps" kopiert werden. Sollte +dort bereits ein Verzeichnis "betriebstagebuch" vorhanden sein, so muss dieses zuvor gelöscht werden. + + + +Frontend-Installieren +_____________________ +.... \ No newline at end of file
diff --git a/deploy/conf/context.xml b/deploy/conf/context.xml new file mode 100644 index 0000000..eff12ed --- /dev/null +++ b/deploy/conf/context.xml
@@ -0,0 +1,43 @@ +<?xml version='1.0' encoding='utf-8'?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. +--> +<!-- The contents of this file will be loaded for each web application --> + + +<!-- jdbc:oracle:thin:@entbwora1:1521:dboetng4 --> +<Context> + + <!-- Default set of monitored resources --> + <WatchedResource>WEB-INF/web.xml</WatchedResource> + + <!-- Uncomment this to disable session persistence across Tomcat restarts --> + + <!--Manager pathname=""/> + + + <Parameter name="environment" override="false" value="Development"/--> + + <Parameter name="OK_PORTAL_ENVIRONMENT" override="false" value="DevLocal"/> + + + <!-- Uncomment this to enable Comet connection tacking (provides events + on session expiration as well as webapp lifecycle) --> + <!-- + <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" /> + --> + +</Context>
diff --git a/deploy/lib/postgresql-42.0.0.jar b/deploy/lib/postgresql-42.0.0.jar new file mode 100644 index 0000000..b89509b --- /dev/null +++ b/deploy/lib/postgresql-42.0.0.jar Binary files differ
diff --git a/doc/build.txt b/doc/build.txt new file mode 100644 index 0000000..737e8a3 --- /dev/null +++ b/doc/build.txt
@@ -0,0 +1,23 @@ +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +Backend: +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +Voraussetzungen: +---------------- +Java 1.8 JDK +Maven + +Bauen: +------ +Im Rootpath des Backend-Projektes: +>mvn clean install + +(Erzeugt in Target das WAR, die surefire-reports und das jacoco.exec für die Codecoverage-Analyse) +Im Sonarqube schließen wir folgende Files von der CodeCoverageAnalyse aus: + + +**/de/pta/openkonsequenz/betriebstagebuch/common/Globals.java +**/rest/*.java +**/LoggerUtil.java +**/dao/*.java +**/dao/interfaces/*.java
diff --git a/doc/doc_eLogbook_Rest.docx b/doc/doc_eLogbook_Rest.docx new file mode 100644 index 0000000..14201c8 --- /dev/null +++ b/doc/doc_eLogbook_Rest.docx Binary files differ
diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..cfc62a9 --- /dev/null +++ b/pom.xml
@@ -0,0 +1,314 @@ +<?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>openk.pta.de</groupId> + <artifactId>portal</artifactId> + <version>1.0.0</version> + <packaging>war</packaging> + + <properties> + <skip.asciidoc>false</skip.asciidoc> + <httpclient.version>4.5.3</httpclient.version> + <jersey-bundle.version>1.19.3</jersey-bundle.version> + <org.json.version>20160810</org.json.version> + <jersey.server.version>1.19.3</jersey.server.version> + <gson.version>2.8.0</gson.version> + <log4j.version>1.2.17</log4j.version> + <commons-io.version>2.5</commons-io.version> + <junit.version>4.12</junit.version> + <easymock.version>3.4</easymock.version> + <powermock-api-easymock.version>1.6.6</powermock-api-easymock.version> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <servlet-api>2.5</servlet-api> + <maven.test.skip>false</maven.test.skip> + <jacoco-maven-plugin.version>0.7.9</jacoco-maven-plugin.version> + <sonar-maven-plugin.version>3.0.2</sonar-maven-plugin.version> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>${httpclient.version}</version> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>${org.json.version}</version> + </dependency> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-jaxrs</artifactId> + <version>3.0.21.Final</version> + </dependency> + <dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>jaxrs-api</artifactId> + <version>3.0.12.Final</version> + </dependency> + + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>3.0.1</version> + </dependency> + <dependency> + <groupId>com.auth0</groupId> + <artifactId>java-jwt</artifactId> + <version>3.2.0</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-core</artifactId> + <version>3.2.0.Final</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-adapter-core</artifactId> + <version>3.2.0.Final</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-adapter-spi</artifactId> + <version>3.2.0.Final</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-servlet-adapter-spi</artifactId> + <version>3.2.0.Final</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-servlet-filter-adapter</artifactId> + <version>3.2.0.Final</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-common</artifactId> + <version>3.2.0.Final</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-model-jpa</artifactId> + <version>3.2.0.Final</version> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-services</artifactId> + <version>3.2.0.Final</version> + </dependency> + + + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>${gson.version}</version> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>${log4j.version}</version> + <exclusions> + <exclusion> + <groupId>com.sun.jmx</groupId> + <artifactId>jmxri</artifactId> + </exclusion> + + <exclusion> + <groupId>com.sun.jdmk</groupId> + <artifactId>jmxtools</artifactId> + </exclusion> + + <exclusion> + <groupId>javax.jms</groupId> + <artifactId>jms</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>${commons-io.version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.persistence</groupId> + <artifactId>eclipselink</artifactId> + <version>2.6.4</version> + </dependency> + <dependency> + <groupId>postgresql</groupId> + <artifactId>postgresql</artifactId> + <version>9.1-901-1.jdbc4</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <version>${easymock.version}</version> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>${powermock-api-easymock.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-easymock</artifactId> + <version>${powermock-api-easymock.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco-maven-plugin.version}</version> + </dependency> + + </dependencies> + + + <build> + <finalName>${project.artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>3.0.2</version> + <configuration> + <archive> + <manifest> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> + </manifest> + </archive> + </configuration> + </plugin> + <plugin> + <artifactId>maven-war-plugin</artifactId> + <version>2.1</version> + <configuration> + <archive> + <manifest> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> + </manifest> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-project-info-reports-plugin</artifactId> + <version>2.7</version> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>sonar-maven-plugin</artifactId> + <version>${sonar-maven-plugin.version}</version> + </plugin> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco-maven-plugin.version}</version> + <configuration> + <skip>${maven.test.skip}</skip> + <output>file</output> + <append>true</append> + <excludes> + <exclude>**/Globals.*</exclude> + <exclude>**/dao/**/*Dao*.java</exclude> + <exclude>**/controller/BackendController.java</exclude> + </excludes> + </configuration> + <executions> + <execution> + <id>jacoco-initialize</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>jacoco-site</id> + <phase>verify</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.asciidoctor</groupId> + <artifactId>asciidoctor-maven-plugin</artifactId> + <version>1.5.3</version> + <dependencies> + <dependency> + <groupId>org.asciidoctor</groupId> + <artifactId>asciidoctorj-pdf</artifactId> + <version>1.5.0-alpha.11</version> + </dependency> + <dependency> + <groupId>org.jruby</groupId> + <artifactId>jruby-complete</artifactId> + <version>1.7.21</version> + </dependency> + <dependency> + <groupId>org.asciidoctor</groupId> + <artifactId>asciidoctorj</artifactId> + <version>1.5.4</version> + </dependency> + <dependency> + <groupId>org.asciidoctor</groupId> + <artifactId>asciidoctorj-diagram</artifactId> + <version>1.5.4.1</version> + </dependency> + </dependencies> + <configuration> + <sourceDirectory>src/main/asciidoc</sourceDirectory> + <requires> + <require>asciidoctor-diagram</require> + </requires> + <attributes> + <imagesoutdir>${project.build.directory}/generated-docs/images</imagesoutdir> + <imagesDir>${project.build.directory}/generated-docs/images</imagesDir> + </attributes> + </configuration> + <executions> + + <execution> + <id>output-html</id> + <phase>generate-resources</phase> + <goals> + <goal>process-asciidoc</goal> + </goals> + <configuration> + <skip>${skip.asciidoc}</skip> + <imagesDir>${project.build.directory}/generated-docs/images</imagesDir> + <requires> + <require>asciidoctor-diagram</require> + </requires> + <sourceHighlighter>coderay</sourceHighlighter> + <backend>html</backend> + <doctype>book</doctype> + <imagesDir>./images</imagesDir> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project>
diff --git a/src/main/asciidoc/architectureDocumentation/auth_n_auth_architectureDocumentation.adoc b/src/main/asciidoc/architectureDocumentation/auth_n_auth_architectureDocumentation.adoc new file mode 100644 index 0000000..f19fa9a --- /dev/null +++ b/src/main/asciidoc/architectureDocumentation/auth_n_auth_architectureDocumentation.adoc
@@ -0,0 +1,925 @@ +openKonsequenz - Architecture of the module "portal@openK" +========================================================== +:Author: Frank Dietrich +:Email: frank.dietrich@pta.de +:Date: 2017-09-18 +:Revision: 1 +:icons: +:source-highlighter: highlightjs +:highlightjs-theme: solarized_dark + +This documentation bases on ARC42-Template (v7.0): + +*About arc42* + +arc42, the Template for documentation of software and system architecture. + +By Dr. Gernot Starke, Dr. Peter Hruschka and contributors. + +Template Revision: 7.0 EN (based on asciidoc), January 2017 + +© We acknowledge that this document uses material from the arc 42 architecture template, http://www.arc42.de. +Created by Dr. Peter Hruschka & Dr. Gernot Starke. + +<<< + +== Introduction and Goals + +=== Requirements Overview + + [...] + + +=== Quality Goals + + [...] + +=== Stakeholders + +.Stakeholders +[options="header,footer"] +|========================================================= +|Role/Name|Contact|Expectations +|Product Owner (represents the Distribution System Operators)|Gordon Pickford, Oliver Tantu|The software must fulfil their functional and nonfunctional Requirements. +|Module Developer|Michel Allessandrini, Jonas Tewolde, Frank Dietrich|All relevant business and technical information must be available for implementing the software. +|External Reviewer (represents the AC/QC)|Martin Jung, Anja Berschneider|The software and the documentation is realized according the Quality and Architecture Handbook of openKONSEQUENZ. +|System Integrator||A documentation for the integration of the module in the DSO specific environments must be available. +|========================================================= + +== Architecture Constraints + +The main architecture constraints are: + + [...] + +=== Technical Constraints + +The following technical constraints are given: + +.Technical Contraints +[options="header,footer"] +|======================================================== +|Component|Constraints +|Basis components of the reference platform| +- Application Server Tomcat +- JPA EclipseLink +- Database PostgreSQL + +|Enterprise Service Bus| +* ESB Talend +* Communication via RESTful Webservices + +|Programming Language Frontend +a|* Angular +* Bootstrap +* jQuery +* REST/JSON Interfaces + +|GUI design +a|* According to oK-GUI-Styleguide + +|Java QA environment|Sonarqube 5.6.6 + +|Programming Language +a|* Backend: Java 1.8 +* Frontend: Angular 4.0.0 (Javascript, Typescript, HTML5, CSS3) + +|IDE +a|* Not restricted (Eclipse, IntelliJ, Microsoft Developer Studio, Microsoft Visual Code ...) + +|Build system +a|* Backend: Maven +* Frontend: NodeJS + Angular/cli + +|Libraries, Frameworks,Components +a|* Used Libraries/Frameworks have to be compatible to the Eclipse Public License +|Architecture Documentation|* According ARC42-Template +|======================================================== + + +=== Technical Dependencies + +The following libraries are used: + +.Libraries +[options="header,footer"] +|========================================================= +|Name of the library|Version|Artefact-id|Usage|License|Tier +|org.apache.httpcomponents.httpclient|4.5.3 +a| +[source,xml] +---- +<dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.5.3</version> +</dependency> +---- +|Backend, Http-Client|Apache 2.0|Backend + +|org.json.json|20160810 + +a| +[source,xml] +---- +<dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20160810</version> +</dependency> +---- +|Backend - Json functionality|Json|Backend + +|org.jboss.resteasy.resteasy-jaxrs|3.0.21_Final +a| +[source,xml] +---- +<dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>resteasy-jaxrs</artifactId> + <version>3.0.21.Final</version> +</dependency> +---- +|Backend - RestServer|Apache 2.0 / CC0.1.0/ Public|Backend + +|org.jboss.resteasy.jaxrs-api|3.0.12.Final +a| +[source,xml] +---- +<dependency> + <groupId>org.jboss.resteasy</groupId> + <artifactId>jaxrs-api</artifactId> + <version>3.0.12.Final</version> +</dependency> +---- +|Rest-Server|Apache 2.0|Backend + +|javax.servlet.servlet-api|3.0.1 +a| +[source,xml] +---- +<dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>3.0.1</version> +</dependency> +---- +|Backend - Logging Servlet |CDDL GLP 2.0|Backend + +|com.google.code.gson.gson|2.8.0 +a| +[source,xml] +---- +<dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.8.0</version> +</dependency> +---- +|Backend Json de-serialization|Apache 2.0|Backend + +|log4j.log4j|1.2.17 +a| +[source,xml] +---- +<dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>1.2.17</version> +</dependency> +---- +|Backend logging|Apache 2.0|Backend + +|commons-io|2.5 +a| +[source,xml] +---- +<dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.5</version> +</dependency> +---- +|IO utils|Apache 2.0| Backend + +|junit.junit|4.12 + +a| +[source,xml] +---- +<dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> +</dependency> +---- +|Unit testing|EPL 1.0|Backend + +|org.easymock.easymock|3.4 +a| +[source,xml] +---- +<dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <version>3.4</version> +</dependency> +---- +|Unit testing|Apache 2.0|Backend + +|org.powermock.powermock-api-easymock|1.6.6 +a| +[source,xml] +---- +<dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-easymock</artifactId> + <version>1.6.6</version> +</dependency> +---- +|Unit testing|Apache 2.0|Backend + +|org.jacoco.jacoco-maven-plugin|0.7.9 +a| +[source,xml] +---- +<dependency> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.7.9</version> +</dependency> +---- +|Test coverage|EPL 1.0|Backend + +|========================================================= + +== System Scope and Context + +=== Business Context + + [...] + +=== Technical Context + + [...] + +=== Solution Strategy + +<TODO> + +== Building Block View + +=== Whitebox Overall System + +The module Auth&Auth consists of the following components: + +.Module components +[plantuml] +.... +interface authAndAuthAPI + +node AuthAndAuthEnvironment { + + component portalBE [ + portalBackend + ] + + component portalFE [ + portalFrontend + ] + + component keycloak [ + KeyCloak + ] + + portalFE-(0-portalBE + portalBE-(0-keycloak +} + +node openKModule [ + openKonsequenz module +] + + +portalBE #--authAndAuthAPI +openKModule->authAndAuthAPI + +.... + + +. *portalFrontend* - The user interface of the portal. Consists of the login page and the module overview grid +. *portalBackend* - Provides the services for its frontend. +. *authAndAuthAPI* - Additionally the portalBackend provides general user and security services for +for all openKonsequenz-Modules. +. *KeyCloak* - KeyCloak implements most of the security aspects for the portal application and the modules. +It provides an userinterface for user and role management of the modules and generates the JSON Web Token (JWT) +for the session and access control. + + + +==== Auth&Auth-API + +The Auth&Auth needs information from the system Keycloak. Therefore, it must provide an interface for receiving the according data, see figure 1. + +=== Level 2 + +==== portalFE – SPA (Frontend tier) + + +The frontend component implements the concept of a single-page application (SPA). The framework used is Angular2. It divides the portalFE into three layers: + + +1.Components - The components (Pages, Lists, Dialogs, Common Comp.) represent the presentation layer and the control layer. A component contains the control logic (.ts-file), an HTML-fragment as presentation description (.html-file) and a style definition (.css-file). + + +2.Services - The service component communicates with the interfaces of the backend via HTTP requests by using the model component. + + +3.Model - The model corresponds to the View-Model of the backend tier. + +.Frontend tier +[plantuml] +.... + +node Backend-portalBE { + + component RESTServices + component ViewModel +} + +RESTServices.>ViewModel + +node Frontend-portalFE { + + component services + + node Components { + component pages + component commonComp + component dialogs + + } + component model + + +} + +services-(0-RESTServices +model<->ViewModel +services.>model +Components.>services + +.... + + + +==== portal.war (Backend tier) + +The backend tier contains five components which can be summarized in three layers: + +. *Presentation layer* - Represented by + .. REST-Srv + .. View Model +. *Controller layer* - Represented by + .. Controller +. *Model layer* - Represented by + .. auth2 (Connection to "KeyCloak") + + +.Backend tier +[plantuml] +.... + +node PortalFrontend [ + PortalFrontend +] + +node ESB { + interface Auth_n_auth +} + + +node BackendLAN { + left to right direction + + node KeyCloak { + component KeyCloakImplementation + } + + node Backend-Portal { + + skinparam rectangle { + roundCorner 25 + } + rectangle "Presentation layer" { + component RESTServices + component ViewModel + } + rectangle "Controller layer" { + component Controller + } + rectangle "Model layer" { + component auth2 + } + + RESTServices.>Controller + RESTServices.>ViewModel + Controller.>auth2 + + } + + RESTServices -- Auth_n_auth + + + + interface OAuth2 + interface KeyCloakAdmin + + KeyCloak -- KeyCloakAdmin + KeyCloak -- OAuth2 + + + auth2 -> OAuth2 + auth2 -> KeyCloakAdmin + +} + + + + +PortalFrontend-->Auth_n_auth + + +node openKModule [ + openKModule +] + + +openKModule --> Auth_n_auth + +.... + +KeyCloak provides different interfaces. The backend uses the *OAuth2*-Interface for authentication +and the *KeyCloak-admin* interface for other tasks (for example for getting users). The component *auth2* provides +functionality for the access to KeyCloak. The Presentation layer consists of the *RESTServices* and the +*ViewModel*. The *RESTServices* access the *Controller layer* in order to perform their tasks. + +The whole backend provides the *Auth&Auth* interface which is used by the *portalFrontend* and +other *openKonsequenz-Modules* for authentication and other related tasks. The *Auth&Auth* interface is +to be exported via ESB. + + + +== Runtime View +=== Login / Authentication + +.Login sequence +[plantuml] +.... +actor User +participant PortalFrontend +participant PortalBackend +participant KeyCloak + +User->PortalFrontend: Login page +PortalFrontend->PortalBackend: /login(loginCredentials) +PortalBackend->KeyCloak: /.../realms/.../protocol/openid-connect/token(?loginInfo) +KeyCloak --> PortalBackend: return JWT +PortalBackend -> PortalBackend: Create Session with JWT +PortalBackend --> PortalFrontend: return JWT +PortalFrontend -> PortalFrontend: store JWT +PortalFrontend --> User: Navigate to ModuleGrid + +.... + +=== Logout + +.Logout sequence +[plantuml] +.... +actor User +participant oK_Module +participant PortalBackend + + +User->oK_Module: logout +oK_Module->PortalBackend: /logout with JWT +PortalBackend->PortalBackend: Remove Session with JWT +PortalBackend-->oK_Module: +oK_Module->oK_Module: Navigate to Logout/closing page +oK_Module-->User + +.... + +=== Check authorization + +.CheckAuth sequence +[plantuml] +.... +actor User +participant oK_Module +participant PortalBackend + + +User->oK_Module: Any action that requires an auth check +oK_Module->PortalBackend: /checkAuth with JWT + +group authorize + PortalBackend->PortalBackend: Check if valid session with JWT exists + + group check failed + PortalBackend-->oK_Module: raise HttpCode "Unauthorized 401" + end + + group check succeeded + PortalBackend-->oK_Module: return HttpCode "Success 200" + end +end + +oK_Module->oK_Module: react on HttpCode +oK_Module-->User: + +.... + +=== Get users for role +.GetUsersForRole sequence +[plantuml] +.... +actor User + +participant oK_Module +participant KeyCloak +participant PortalBackend + +actor Timer_cycl + +group refresh usersWithRoles cache + Timer_cycl->PortalBackend: Get userWithRoles + + PortalBackend->KeyCloak: Login with admin user + KeyCloak-->PortalBackend + PortalBackend->KeyCloak: Get realm users + KeyCloak-->PortalBackend + + group repeat for each user + PortalBackend->KeyCloak:Get role-mapping for user + KeyCloak-->PortalBackend + end + PortalBackend->PortalBackend: update cache + PortalBackend-->Timer_cycl +end +... + + +User->oK_Module: Any action that needs all users having a role +oK_Module->PortalBackend: /usersForRole/{userRole} +PortalBackend->PortalBackend: evaluate from usersWithRoles cache +PortalBackend-->oK_Module: return result +oK_Module-->User + +.... + + + +=== Open module in portal frontend +.Start module sequence +[plantuml] +.... +actor User + +participant PortalFE +participant openKModule + +User->PortalFE: User (logged in) opens module +PortalFE->openKModule: Open configured URL in new browser tab, providing the JWT +.... + + + +== Deployment View + +The Auth&Auth application consists of 3 parts regarding the deployment. + +. Frontend: "portalFE"-Directory +. Backend: "portal.war" +. Keycloak: OAuth2 and JWT Service implementation + +=== Deployment of the application components + +==== Deployment of the frontend + +The Frontend SPA is built as a folder, that contains all the required files for +the application. When deploying the frontend application, the content of the "dist"-folder +within the Frontend development-directory has to be copied into the +target-directory of the apache-tomcat: + + <Apache-Tomcat>/webapps/portalFE + +If the target folder does not exist, it has to be created manually. + +==== Deployment of the backend +The backend REST-services are built in form of a "WAR"-file (to be found +in the "target"-directory of the MAVEN-directory structure). +For deployment, this file has to be copied to the directory + + <Apache-Tomcat>/webapps + +==== Deployment of Keycloak + + +. Get "Keycloak 3.2.1 Final" ("keycloak-3.2.1.Final.zip") from the Keycloak download page. + +Download "Server Standalone server distribution": http://www.keycloak.org/archive/downloads-3.2.1.html + +. Extract the content. +. To create an initial admin account for Keycloak run the script `add-user-keycloak.sh` with username 'admin' +and a strong password. + + <Keycloak-Directory>/bin/add-user-keycloak.sh -r master -u <username> -p <password> + +. To start Keycloak create a *Linux-Service which executes* the `standalone.sh` script to be found in the Keycloak `bin` +directory. + + <Keycloak-Directory>/bin/standalone.sh + + +TIP: Keycloaks default port is 8080 you can change it to for example to port 1234 with the following +execution parameter: -Djboss.http.port=1234 + + <Keycloak-Directory>/bin/standalone.sh -Djboss.http.port=1234 + +==== Configuration of the system + +===== Configuration of the webserver + +There exists the file *context.xml* in the "conf" subdirectory (*<TOMCAT>/conf*) of the target apache tomcat installation. +Add the following parameter and resource in order to access the correct backend configurations and to +gain access to the database (see "Configuration of the backend" below): + +.context.xml +[source,xml] +---- +[...] + <!-- Uncomment this to disable session persistence across Tomcat restarts --> + + <!--Manager pathname=""/> + + + <Parameter name="environment" override="false" value="Development"/--> + + <Parameter name="OK_PORTAL_ENVIRONMENT" override="false" value="Production"/> + + <!-- Uncomment this to enable Comet connection tacking (provides events + on session expiration as well as webapp lifecycle) --> +[...] +---- + + +===== Configuration of the backend + +After the backend war file has been deployed and unpacked inside of the *<TOMCAT>/webapps* folder there are different + backend config files to be found in the folder *<TOMCAT>/webapps/elogbook/WEB-INF/classes* + +* backendConfig*.json +* moduleConfig*.json + +The active configuration is chosen by parameter *OK_PORTAL_ENVIRONMENT* (see context.xml above). +Possible values are: + +* *Custom* (for backendConfigCustom.json and moduleConfigCustom.json) +* *DevLocal* (for backendConfigDevLocal.json and moduleConfigDevLocal.json) +* *DevServer* (for backendConfigDevServer.json and moduleConfigDevServer.json) +* *Production* (for backendConfigProduction.json and moduleConfigProduction.json) + +After choosing an environment the corresponding json files have to be configured: + +.backendConfigXXX.json +[source,json] +---- +{ + "internalSessionLengthMillis": 46800000, + "reloadUsersInSec": 300, + "authServerUrl": "http://localhost:8080/", + "keycloakRealm": "OpenKRealm", + "keycloakClient": "OpenKClient", + "keycloakAdmin": "admin", + "keycloakPW": "adminpwd" +} +---- +* *internalSessionLengthMillis* - Maximum allowed duration of inactivity, before a session ends +* *reloadUsersInSec* - Polling interval for getting all users from keycloak +* *authServerUrl* - Base url of the keycloak instance +* *keycloakRealm* - Configured realm on keycloak +* *keycloakClient* - Configured client on keycloak +* *keycloakAdmin* - user for admin access on keycloak +* *keycloakPW* - password of the admin user + + +.moduleConfigXXX.json +[source,json] +---- +[ + { + "name": "Betriebstagebuch", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "http://172.18.22.160:8880/elogbookFE", + "pictureLink": "https://www.openkonsequenz.de/.../m_logbuch_2443636.jpg", + "requiredRole": "elogbook-access" + + }, + { + "name": "Bereitschaftsplanung", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/..../94-bereitschaftsplan", + "pictureLink": "https://www.openkonsequenz.de/medien/.../l_bereitschaftsplan_57882047.jpg", + "requiredRole": "planning-access" + }, + + ... + +] + +---- + +* *name* - Name/description of the module +* *cols* - always "1" +* *rows* - always "1" +* *color* - always "#ffffff" +* *link* - URL for the module +* *pictureLink* - URL for picture belonging to the module +* *requiredRole* - Name of the role (on keycloak) the user must have to access the module + + +===== Configuration of Keycloak + +. Login in Keycloak + +.. Go to http://<KEYCLOAK-SERVER-IP>:<CONFIGURED-KEYCLOAK-PORT>/ + +Hit the `Administration Console` -Link and login with admin account created during the Keycloak-deployment +(see above). + +. Add a new realm: `MainDonauNetz` + +.Add a new realm overview +[options="header,footer"] +image::newRealm1.png[new Realm] + +.Add a new realm +[options="header,footer"] +image::newRealm2.png[new Realm] + +[start=3] +. Create a client with client ID `elogbook-backend`. + +.Create a client overview +[options="header,footer"] +image::createClient.png[create Client] + +.Add a client +[options="header,footer"] +image::addClient.png[add Client] + +[start=4] +. Set the client settings accordingly: + +.Client settings of elogbook-backend +[options="header,footer"] +image::clientSettings.png[Client settings] + +[start=5] +. Add the roles under `Roles` press `Add Role`. Add the following Roles: +- elogbook-normaluser +- elogbook-superuser +- elogbook-access +- planning-access +- feedin-management-access +- planned-policies-access + +. Configuring elogbook-superuser role. Hit elogbook-superuser or press `Edit` +.. Switch `Composite Roles` to on. +.. Add the Realm Role 'elogbook-normaluser' from the `Available Roles` +.. Select from the `Client Roles` Dropdown-List 'realm-management' and add the role 'view-users'. + +.Elogbook superuser composite role +[options="header,footer"] +image::rolesSuperUser.png[Elogbook superuser composite role] + +[start=7] +. Adding users under `Users` press `Add User`. + +.Add a user +[options="header,footer"] +image::addingUsers.png[Add a User] + +.. Fill in username, First Name, Last Name, else is default and save it. +.. Go to the `Credentials` tab and type in a new password and the confirmation as well, disable `Temporary`. Press `Reset Password`. +Press `Change Password`. + +.Credentials tab +[options="header,footer"] +image::credentials.png[Credentials tab] + +[start=3] +.. Go to the `Role Mappings` tab. + +Here you grant rights/roles to the users: +Select the from the previously created roles in `Available Roles` and hit `Add selected`. + +... User right in the distinct modul elogbook (`elogbook-access` required of course): +- elogbook-normaluser = standard user in the elogbook-app +- elogbook-superuser = admin user in the elogbook-app + +... Access rights to the specific modul: +- elogbook-access +- planning-access +- feedin-management-access +- planned-policies-access + +.Role Mappings tab +[options="header,footer"] +image::roleMappings.png[Role Mapping] + + +[start=4] +.. Go back to the `Details` tab and make sure `Recquired User Actions` is empty. Delete anything which is in there with a press on the little cross. + +[start=8] +. Add an admin user. (Mandatory) + +Same procedure like adding a User (see 7.) but with the role 'elogbook-superuser' instead of +'elogbook-normaluser'. + +IMPORTANT: We use this admin account (username & password) also to configure the backend. + +See "Configuration of the backend", +username & password from here is keycloakAdmin & keycloakPW there. + + + +=== CI- and CD-Components + +==== GIT-Repository + +<TODO> + +==== Hudson + +<TODO> + +==== Sonar + +<TODO> + +==== Code-Coverage of the Frontend - Karma-Istanbul-Output + +<TODO> + +=== Continuous Deployment + + + +== Design Decisions + +All architecture decisions based on the Architecture Committee Handbook. There are no deviations. + + +== Quality Requirements + +TODO: Muss noch beschrieben werden + +=== Quality Tree + +TODO: Muss noch beschrieben werden + +=== Quality Scenarios + +TODO: Muss noch beschrieben werden + + + +== Risks and Technical Debts + +(Muss noch beschrieben werden) + +<<< + +== Glossary + +=== Technical Constraints + +.Technical Contraints +[options="header,footer"] +|======================================================== +|Short|Long|German|Description +|AC|Architecture Committee|Architektur-Komittee|Gives Framework and Constraints according to architecture for oK projects. +|CNCU|Central Network Control Unit|| +|DAO|Data Access Objects|| +|DSO|Distribution System Operator|Verteilnetz-betreiber (VNB)|Manages the distribution network for energy, gas or water. +|EPL|Eclipse Public License||Underlying license model for Eclipse projects like elogbook@openK +|ESB|Enterprise Service Bus||Central instance for exchange of data to overcome point-to-point connections. +|oK|openKONSEQUENZ|openKONSEQUENZ|Name of the consortium of DSOs +|QC|Quality Committee|Qualitätskomitee|Gives framework and constraints according to quality for oK projects. +|SCADA|Supervisory Control and Data Acquisition|Netzleitsystem|System, that allows DSOs view/control actual parameters of their power grid. +|======================================================== + + +
diff --git a/src/main/asciidoc/images/BackendTier.png b/src/main/asciidoc/images/BackendTier.png new file mode 100644 index 0000000..3b626ec --- /dev/null +++ b/src/main/asciidoc/images/BackendTier.png Binary files differ
diff --git a/src/main/asciidoc/images/DatabaseTier.png b/src/main/asciidoc/images/DatabaseTier.png new file mode 100644 index 0000000..6225be2 --- /dev/null +++ b/src/main/asciidoc/images/DatabaseTier.png Binary files differ
diff --git a/src/main/asciidoc/images/DistributionOfComponents1.png b/src/main/asciidoc/images/DistributionOfComponents1.png new file mode 100644 index 0000000..44bd6c8 --- /dev/null +++ b/src/main/asciidoc/images/DistributionOfComponents1.png Binary files differ
diff --git a/src/main/asciidoc/images/FrontendTier.png b/src/main/asciidoc/images/FrontendTier.png new file mode 100644 index 0000000..d820cc5 --- /dev/null +++ b/src/main/asciidoc/images/FrontendTier.png Binary files differ
diff --git a/src/main/asciidoc/images/SolutionArchitecture.png b/src/main/asciidoc/images/SolutionArchitecture.png new file mode 100644 index 0000000..bc731ac --- /dev/null +++ b/src/main/asciidoc/images/SolutionArchitecture.png Binary files differ
diff --git a/src/main/asciidoc/images/SystemContext.png b/src/main/asciidoc/images/SystemContext.png new file mode 100644 index 0000000..cd194ce --- /dev/null +++ b/src/main/asciidoc/images/SystemContext.png Binary files differ
diff --git a/src/main/asciidoc/images/addClient.png b/src/main/asciidoc/images/addClient.png new file mode 100644 index 0000000..039414b --- /dev/null +++ b/src/main/asciidoc/images/addClient.png Binary files differ
diff --git a/src/main/asciidoc/images/addingUsers.png b/src/main/asciidoc/images/addingUsers.png new file mode 100644 index 0000000..5e3511c --- /dev/null +++ b/src/main/asciidoc/images/addingUsers.png Binary files differ
diff --git a/src/main/asciidoc/images/ba.png b/src/main/asciidoc/images/ba.png new file mode 100644 index 0000000..fdf8327 --- /dev/null +++ b/src/main/asciidoc/images/ba.png Binary files differ
diff --git a/src/main/asciidoc/images/clientSettings.png b/src/main/asciidoc/images/clientSettings.png new file mode 100644 index 0000000..44f80ab --- /dev/null +++ b/src/main/asciidoc/images/clientSettings.png Binary files differ
diff --git a/src/main/asciidoc/images/createClient.png b/src/main/asciidoc/images/createClient.png new file mode 100644 index 0000000..ea86c6d --- /dev/null +++ b/src/main/asciidoc/images/createClient.png Binary files differ
diff --git a/src/main/asciidoc/images/credentials.png b/src/main/asciidoc/images/credentials.png new file mode 100644 index 0000000..b15c2f8 --- /dev/null +++ b/src/main/asciidoc/images/credentials.png Binary files differ
diff --git a/src/main/asciidoc/images/icons/caution.png b/src/main/asciidoc/images/icons/caution.png new file mode 100644 index 0000000..9a8c515 --- /dev/null +++ b/src/main/asciidoc/images/icons/caution.png Binary files differ
diff --git a/src/main/asciidoc/images/icons/important.png b/src/main/asciidoc/images/icons/important.png new file mode 100644 index 0000000..be685cc --- /dev/null +++ b/src/main/asciidoc/images/icons/important.png Binary files differ
diff --git a/src/main/asciidoc/images/icons/note.png b/src/main/asciidoc/images/icons/note.png new file mode 100644 index 0000000..7c1f3e2 --- /dev/null +++ b/src/main/asciidoc/images/icons/note.png Binary files differ
diff --git a/src/main/asciidoc/images/icons/tip.png b/src/main/asciidoc/images/icons/tip.png new file mode 100644 index 0000000..f087c73 --- /dev/null +++ b/src/main/asciidoc/images/icons/tip.png Binary files differ
diff --git a/src/main/asciidoc/images/icons/warning.png b/src/main/asciidoc/images/icons/warning.png new file mode 100644 index 0000000..d41edb9 --- /dev/null +++ b/src/main/asciidoc/images/icons/warning.png Binary files differ
diff --git a/src/main/asciidoc/images/newRealm1.png b/src/main/asciidoc/images/newRealm1.png new file mode 100644 index 0000000..0c28a5e --- /dev/null +++ b/src/main/asciidoc/images/newRealm1.png Binary files differ
diff --git a/src/main/asciidoc/images/newRealm2.png b/src/main/asciidoc/images/newRealm2.png new file mode 100644 index 0000000..b039e1b --- /dev/null +++ b/src/main/asciidoc/images/newRealm2.png Binary files differ
diff --git a/src/main/asciidoc/images/roleMappings.png b/src/main/asciidoc/images/roleMappings.png new file mode 100644 index 0000000..5528b29 --- /dev/null +++ b/src/main/asciidoc/images/roleMappings.png Binary files differ
diff --git a/src/main/asciidoc/images/roleSuperUser.png b/src/main/asciidoc/images/roleSuperUser.png new file mode 100644 index 0000000..413d285 --- /dev/null +++ b/src/main/asciidoc/images/roleSuperUser.png Binary files differ
diff --git a/src/main/asciidoc/interfaceDocumentation/auth_n_auth_interfaceDocumentation.adoc b/src/main/asciidoc/interfaceDocumentation/auth_n_auth_interfaceDocumentation.adoc new file mode 100644 index 0000000..d72f38e --- /dev/null +++ b/src/main/asciidoc/interfaceDocumentation/auth_n_auth_interfaceDocumentation.adoc
@@ -0,0 +1,352 @@ +authAndAuth@openK - Backend REST-Service documentation +====================================================== +:Author: Frank Dietrich +:Email: frank.dietrich@pta.de +:Date: 2017-07-12 +:Revision: 1 +:icons: +:source-highlighter: highlightjs +:highlightjs-theme: solarized_dark + + +== Base-URL + +---- +http://<host>:<port>/<name-of-war>/rest/beservice +---- + +== Common Features +All services may return the following http status codes: + +.Http-Status-Codes +[options="header,footer"] +|========================================================= +|Code|Description|Usage within the application +|200|OK|- +|400|Bad Request|The structure of the request (for example a JSON within a post request) is not correct +|401|Unauthorized|Login-credentials are wrong or there is an invalid session token +|500|Internal Server Error|An unexpected error occurred +|========================================================= + +If there is a special service behavior regarding the returned http status code, then it will be explained within the service description. + +== Protection + +The protection of services is implemented by a security token following the JWT (JSON Web Token) specification: +https://jwt.io/ + +The *“login”*-service provides a JWT, when called with valid user-credentials. +The security token (access token) (which is part of the JWT) has always to be provided with the +HTTP-Header-Parameter "Authorization", in order to access a secured services later on. + + +=== JSON Web Token + +The token has several purposes. A typical client of the Auth&Auth-Service needs to use +the following features: + +. *access token* to access functions of a secured service +. *user-information* to get extended information about the own user +. *user-roles* of the own user. + +Even though JWT is a defined standard, we only will describe those features inside this document, +which are directly used by the Auth&Auth-Service. + +Generally JWT uses *base64-encoding*. The data, that is stored in a token is always +encoded with *base64*. + +[IMPORTANT] +==== +The data in the examples has been shortened. Real examples would be very long and hard to read. +==== + +==== Access token +The *access token* can be directly found in the field "access_token" within the JWT. + + + +Example: +[source,json] +---- +{ + "access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAixxxIn0.eyBBB.eydkk", + "expires_in":300, + "refresh_expires_in":1800, + "refresh_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAixxxIn0.eyJqdGwLTQyMTYtOD.eydkk", + "token_type":"bearer", + "id_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2l.eyJqdGkLTRjZTItYT.oUkke", + "not-before-policy":1502453751, + "session_state":"8b4e6979-1d51-4086-9db5-d296f70b4b65" +} + +---- + + +==== User-Information/UserRoles + +The 2nd part (between the first and the second period *"."* - in this example "'eyBBB'") of the access-token is called the *"access-token-payload"*. When decoded from Base64 it could +look like this: + +[source,json] +---- +{ + "jti":"a3d15ccf-c0e3-4534-a05a-f18b3a7c778b", + "exp":1505736257, + "nbf":0, + "iat":1505735957, + "iss":"http://authserver:8080/auth/realms/elogbook", + "aud":"elogbook-backend", + "sub":"c4b78aa7-91d2-45d7-8ca3-163156d9ee40", + "typ":"Bearer", + "azp":"elogbook-backend", + "auth_time":0, + "session_state":"59ae4a68-595b-4345-873d-aadf0a3efc94", + "acr":"1", + "allowed-origins":["*"], + "realm_access":{"roles":["elogbook-normaluser","uma_authorization"]}, + "resource_access":{"account":{"roles":["manage-account","manage-account-links","view-profile"]}}, + "name":"Hugo Boss", + "preferred_username":"hugo", + "given_name":"Hugo", + "family_name":"Boss" +} +---- + +The configured roles of the user can be determined from the json array: + + * *realm_access"* + +Extended +user information can be found in the fields: + + * *"name"* + * *"perferred_username"* + * *"given_name"* + * *"family_name"*. + + +== Services +=== Receive Version Information +This service returns the current version of the backend implementation and the version of the database structure. + +*URL:* /versionInfo + +*Method:* GET + +*Request-Headers*: + +*Produces*: application/json + +*Response*: +[source,json] +---- +{ + "backendVersion": "0.1.1-Snapshot" +} +---- + +*Protection*: none + +*Remarks*: + +=== Login +This service receives login credentials in order to perform the authentication. If the login succeeds, +it provides a valid JWT, used for accessing other services later on. + +*URL:* /login + +*Method:* POST + +*Request-Body*: +[source,json] +---- +{ + "userName": "Mustermann", + "password": "clearpassword" +} +---- + +*Produces*: application/json + +*Response*: + +JWT (JSON Web Token) + +*Remarks*: See chapter "*JWT*" for detailed informations about the features of the returned token. + + +=== Logout +This services kills the server session belonging to the the given session token. + +*URL:* /logout + +*Method:* POST + +*Request-Headers*: + +* Authorization – Existing access token + + +*Produces*: application/json + +*Response*: + +*Remarks*: + +=== CheckAuthorization +This services receives a JWT in the "Authorization" Http header and checks, if its still valid. +If it is valid, it resets the inactivity time for that token. + +*URL:* /checkAuth + +*Method:* GET + +*Request-Headers*: + +* Authorization – Existing access token + + +*Produces*: application/json + +*Response*: +[source,json] +---- +{ + "ret": "OK" +} +---- + +*Remarks*: This service return OK when the provided token is still valid. Otherwise it returns a 401 - "Unauthorized" Http Code. + +=== Get user modules for the current user +This service returns the modules for which the user is authorized. + +*URL:* /userModulesForUser + +*Method:* GET + +*Request-Headers*: + +* Authorization – Existing access token + + +*Produces*: application/json + +*Response*: +[source,json] +---- +[ + { + "name":"Betriebstagebuch", + "cols":1, + "rows":1, + "color":"#ffffff", + "link":"http://172.18.22.160:8880/elogbookFE", + "pictureLink":"https://www.openkonsequenz.de/xxxelogbuch_2443636.jpg", + "requiredRole":"elogbook_access" + } + , + { + "name":"Bereitschaftsplanung", + "cols":1, + "rows":1, + "color":"#ffffff", + "link":"https://www.openkonsequenz.de/anwender/xxxx/94-bereitschaftsplan", + "pictureLink":"https://www.openkonsequenz.de/medien/xxx/l_bereitschaftsplan_57882047.jpg", + "requiredRole":"planning_access" + } + , + { + ... + } +] +---- + +*Remarks*: This service checks if the currently logged in user has the role "requiredRole" in its JWT and +returns the modules he is authorized for. + + +=== Get all users for a specific role +This service returns all users belonging to the specified role. + +*URL:* /usersForRole/{userRole} + +*Method:* GET + +*Path-Parameter*: userRole + +* The role name like it is defined in Keycloak + +*Request-Headers*: + +* Authorization – Existing access token + + +*Produces*: application/json + +*Response*: +[source,json] +---- +[ + { + "id": "359ef9c9-77df-4a3d-a9c9-f96d837d2d57", + "createdTimestamp": 1501594173784, + "username": "admin", + "enabled": true, + "totp": false, + "emailVerified": false, + "firstName": "Administrator", + "lastName": "Administratowich", + "realmRoles": [ + "elogbook-superuser", + "elogbook_access", + "uma_authorization", + "elogbook-normaluser" + ], + "disableableCredentialTypes": [ + "password" + ], + "requiredActions": [], + "access": { + "manageGroupMembership": false, + "view": true, + "mapRoles": false, + "impersonate": false, + "manage": false + } + }, + { + "id": "c4b78aa7-91d2-45d7-8ca3-163156d9ee40", + "createdTimestamp": 1501594239066, + "username": "hugo", + "enabled": true, + "totp": false, + "emailVerified": false, + "firstName": "Hugo", + "lastName": "Boss", + "realmRoles": [ + "elogbook_access", + "elogbook-normaluser" + ], + "disableableCredentialTypes": [ + "password" + ], + "requiredActions": [], + "access": { + "manageGroupMembership": false, + "view": true, + "mapRoles": false, + "impersonate": false, + "manage": false + } + }, + { + ... + } +] +---- + +*Remarks*: + + +
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/JwtAccount.java b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtAccount.java new file mode 100644 index 0000000..09e655f --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtAccount.java
@@ -0,0 +1,12 @@ +package org.eclipse.openk.portal.auth2.model; + +import java.util.List; + +public class JwtAccount { + private List<String> roles; + + public List<String> getRoles() { + return roles; + } + public void setRoles(List<String> roles) { this.roles = roles; } +}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/JwtHeader.java b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtHeader.java new file mode 100644 index 0000000..7b53747 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtHeader.java
@@ -0,0 +1,14 @@ +package org.eclipse.openk.portal.auth2.model; + +public class JwtHeader { + private String alg; + private String typ; + private String kid; + + public String getAlg() { return alg; } + public void setAlg(String alg) { this.alg = alg; } + public String getTyp() { return typ; } + public void setTyp(String typ) { this.typ = typ; } + public String getKid() { return kid; } + public void setKid(String kid) { this.kid = kid; } +}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/JwtPayload.java b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtPayload.java new file mode 100644 index 0000000..5a516cd --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtPayload.java
@@ -0,0 +1,100 @@ +package org.eclipse.openk.portal.auth2.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + + +public class JwtPayload { + + //No Sonar because variables are wrong due to jwt definition + + private String jti; + private long exp; + private long nbf; + private long iat; + private String iss; + private String aud; + private String sub; + private String typ; + private String azp; + private String nonce; + private Integer auth_time; //NOSONAR + private String session_state; //NOSONAR + private String acr; + + @JsonProperty("allowed-origins") + private List<String> allowedOrigins; + private JwtRealmAccess realm_access; //NOSONAR + private JwtResourceAccess resource_access; //NOSONAR + + private String name; + private String preferred_username; //NOSONAR + private String given_name; //NOSONAR + private String family_name; //NOSONAR + + public String getJti() { return jti; } + public void setJti(String jti) { this.jti = jti; } + + public long getExp() { return exp; } + public void setExp(long exp) { this.exp = exp; } + + public long getNbf() { return nbf; } + public void setNbf(long nbf) { this.nbf = nbf; } + + public long getIat() { return iat; } + public void setIat(long iat) { this.iat = iat; } + + public String getiss() { return iss; } + public void setiss(String iss) { this.iss = iss; } + + public String getaud() { return aud; } + public void setaud(String aud) { this.aud = aud; } + + public String getsub() { return sub; } + public void setsub(String sub) { this.sub = sub; } + + public String gettyp() { return typ; } + public void settyp(String typ) { this.typ = typ; } + + public String getAzp() { return azp; } + public void setAzp(String azp) { this.azp = azp; } + + public String getNonce() { return nonce; } + public void setNonce(String nonce) { this.nonce = nonce; } + + public Integer getAuthTime() { return auth_time; } + public void setAuthTime(Integer auth_time) { this.auth_time = auth_time; } //NOSONAR + + public String getSessionState() { return session_state; } + public void setSessionState(String session_state) { this.session_state = session_state; } //NOSONAR + + public String getAcr() { return acr; } + public void setAcr(String acr) { this.acr = acr; } + + public List<String> getAllowedOrigins() { + return allowedOrigins; + } + public void setAllowedOrigins(List<String> allowedOrigins) { this.allowedOrigins = allowedOrigins; } + + public JwtRealmAccess getRealmAccess() { return realm_access; } + public void setRealmAccess(JwtRealmAccess realm_access) { this.realm_access = realm_access; } //NOSONAR + + public JwtResourceAccess getResourceAccess() { return resource_access; } + public void setResourceAccess(JwtResourceAccess resource_access) { this.resource_access = resource_access; } //NOSONAR + + public String getName() { return name; } + public void setName(String name) { this.name = name; } + + public String getPreferredUsername() { return preferred_username; } + public void setPreferredUsername(String preferred_username) { this.preferred_username = preferred_username; } //NOSONAR + + public String getGivenName() { return given_name; } + public void setGivenName(String given_name) { this.given_name = given_name; } //NOSONAR + + public String getFamilyName() { return family_name; } + public void setFamilyName(String family_name) { this.family_name = family_name; } //NOSONAR + + public boolean isInRole(String role) { + return this.realm_access != null && this.realm_access.isInRole(role); + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/JwtRealmAccess.java b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtRealmAccess.java new file mode 100644 index 0000000..1b689a9 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtRealmAccess.java
@@ -0,0 +1,17 @@ +package org.eclipse.openk.portal.auth2.model; + +import java.util.List; + +public class JwtRealmAccess { + private List<String> roles; + + public List<String> getRoles() { + return roles; + } + public void setRoles(List<String> roles) { this.roles = roles; } + + + public boolean isInRole(String role) { + return this.roles != null && this.roles.contains(role); + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/JwtResourceAccess.java b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtResourceAccess.java new file mode 100644 index 0000000..878b10e --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtResourceAccess.java
@@ -0,0 +1,8 @@ +package org.eclipse.openk.portal.auth2.model; + +public class JwtResourceAccess { + private JwtAccount account; + + public JwtAccount getAccount() { return account; } + public void setAccount(JwtAccount account) { this.account = account; } +}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/JwtToken.java b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtToken.java new file mode 100644 index 0000000..2580825 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/JwtToken.java
@@ -0,0 +1,32 @@ +package org.eclipse.openk.portal.auth2.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class JwtToken { + + //No Sonar because variables are wrong due to jwt definition + + private String access_token; //NOSONAR + private String refresh_token; //NOSONAR + private String token_type; //NOSONAR + private String session_state; //NOSONAR + private Integer expires_in; //NOSONAR + private Integer refresh_expires_in; //NOSONAR + @JsonProperty("not-before-policy") + private Integer not_before_policy; //NOSONAR + + public String getAccessToken() { return access_token; } + public void setAccessToken(String access_token) { this.access_token = access_token; } //NOSONAR + public String getRefreshToken() { return refresh_token; } + public void setRefreshToken(String refresh_token) { this.refresh_token = refresh_token; } //NOSONAR + public String getTokenType() { return token_type; } + public void setTokenType(String token_type) { this.token_type = token_type; } //NOSONAR + public String getSessionState() { return session_state; } + public void setSessionState(String session_state) { this.session_state = session_state; } //NOSONAR + public Integer getExpiresIn() { return expires_in; } + public void setExpiresIn(Integer expires_in) { this.expires_in = expires_in; } //NOSONAR + public Integer getRefreshExpiresIn() { return refresh_expires_in; } + public void setRefreshExpiresIn(Integer refresh_expires_in) { this.refresh_expires_in = refresh_expires_in; } //NOSONAR + public Integer getNotBeforePolicy() { return not_before_policy; } + public void setNotBeforePolicy(Integer not_before_policy) { this.not_before_policy = not_before_policy; } //NOSONAR +} \ No newline at end of file
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakRole.java b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakRole.java new file mode 100644 index 0000000..7b8e868 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakRole.java
@@ -0,0 +1,68 @@ +package org.eclipse.openk.portal.auth2.model; + +public class KeyCloakRole { + + private String id; + private String name; + private Boolean scopeParamRequired; + private Boolean composite; + private Boolean clientRole; + private String containerId; + + public KeyCloakRole(String id, String name, Boolean scopeParamRequired, Boolean composite, Boolean clientRole, String containerId) { + this.id = id; + this.name = name; + this.scopeParamRequired = scopeParamRequired; + this.composite = composite; + this.clientRole = clientRole; + this.containerId = containerId; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Boolean getScopeParamRequired() { + return scopeParamRequired; + } + + public void setScopeParamRequired(Boolean scopeParamRequired) { + this.scopeParamRequired = scopeParamRequired; + } + + public Boolean getComposite() { + return composite; + } + + public void setComposite(Boolean composite) { + this.composite = composite; + } + + public Boolean getClientRole() { + return clientRole; + } + + public void setClientRole(Boolean clientRole) { + this.clientRole = clientRole; + } + + public String getContainerId() { + return containerId; + } + + public void setContainerId(String containerId) { + this.containerId = containerId; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUser.java b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUser.java new file mode 100644 index 0000000..e9f8b10 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUser.java
@@ -0,0 +1,86 @@ +package org.eclipse.openk.portal.auth2.model; + +import java.util.List; +import java.util.Map; + +public class KeyCloakUser { + private String id; + private long createdTimestamp; + private String username; + private boolean enabled; + private boolean totp; + private boolean emailVerified; + private String firstName; + private String lastName; + private List<String> realmRoles; + private Map<String, List<String>> clientRoles; + + private List<String> disableableCredentialTypes; + private List<String> requiredActions; + private KeyCloakUserAccess access; + + public String getId() { return id; } + public void setId(String id) { this.id = id; } + + public long getCreatedTimestamp() { return createdTimestamp; } + public void setCreatedTimestamp(long createdTimestamp) { this.createdTimestamp = createdTimestamp; } + + public String getUsername() { return username; } + public void setUsername(String username) { this.username = username; } + + public boolean getEnabled() { return enabled; } + public void setEnabled(boolean enabled) { this.enabled = enabled; } + + public boolean getTotp() { return totp; } + public void setTotp(boolean totp) { this.totp = totp; } + + public boolean getEmailVerified() { return emailVerified; } + public void setEmailVerified(boolean emailVerified) { this.emailVerified = emailVerified; } + + public String getFirstName() { return firstName; } + public void setFirstName(String firstName) { this.firstName = firstName; } + + public String getLastName() { return lastName; } + public void setLastName(String lastName) { this.lastName = lastName; } + + public List<String> getDisableableCredentialTypes() { + return disableableCredentialTypes; + } + public void setDisableableCredentialTypes(List<String> disableableCredentialTypes) { this.disableableCredentialTypes = disableableCredentialTypes; } + + public List<String> getRequiredActions() { + return requiredActions; + } + public void setRequiredActions(List<String> requiredActions) { this.requiredActions = requiredActions; } + + public KeyCloakUserAccess getAccess() { return access; } + public void setAccess(KeyCloakUserAccess access) { this.access = access; } + + public boolean isEnabled() { + return enabled; + } + + public boolean isTotp() { + return totp; + } + + public boolean isEmailVerified() { + return emailVerified; + } + + public List<String> getRealmRoles() { + return realmRoles; + } + + public void setRealmRoles(List<String> realmRoles) { + this.realmRoles = realmRoles; + } + + public Map<String, List<String>> getClientRoles() { + return clientRoles; + } + + public void setClientRoles(Map<String, List<String>> clientRoles) { + this.clientRoles = clientRoles; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUserAccess.java b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUserAccess.java new file mode 100644 index 0000000..26020c3 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUserAccess.java
@@ -0,0 +1,20 @@ +package org.eclipse.openk.portal.auth2.model; + +public class KeyCloakUserAccess { + private boolean manageGroupMembership; + private boolean view; + private boolean mapRoles; + private boolean impersonate; + private boolean manage; + + public boolean getManageGroupMembership() { return manageGroupMembership; } + public void setManageGroupMembership(boolean manageGroupMembership) { this.manageGroupMembership = manageGroupMembership; } + public boolean getView() { return view; } + public void setView(boolean view) { this.view = view; } + public boolean getMapRoles() { return mapRoles; } + public void setMapRoles(boolean mapRoles) { this.mapRoles = mapRoles; } + public boolean getImpersonate() { return impersonate; } + public void setImpersonate(boolean impersonate) { this.impersonate = impersonate; } + public boolean getManage() { return manage; } + public void setManage(boolean manage) { this.manage = manage; } +}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java b/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java new file mode 100644 index 0000000..48e4855 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java
@@ -0,0 +1,180 @@ +package org.eclipse.openk.portal.auth2.util; + +import java.nio.charset.StandardCharsets; +import javax.ws.rs.core.MediaType; +import org.eclipse.openk.portal.auth2.model.JwtHeader; +import org.eclipse.openk.portal.auth2.model.JwtPayload; +import org.eclipse.openk.portal.auth2.model.JwtToken; +import org.eclipse.openk.portal.auth2.model.KeyCloakRole; +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Type; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Base64; +import java.util.List; +import org.apache.log4j.Logger; +import org.eclipse.openk.portal.common.BackendConfig; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.exceptions.PortalInternalServerError; + +public class JwtHelper { + + private static final Logger logger = Logger.getLogger(JwtHelper.class.getName()); + + private JwtHelper() { + } + + public static JwtToken login(String user, String password) throws PortalInternalServerError { + String token = sendPost(BackendConfig.getInstance().getAuthServerUrl() + "auth/realms/" + + BackendConfig.getInstance().getKeycloakRealm() + "/protocol/openid-connect/token", + "username=" + user + "&password=" + password + "&client_id=" + BackendConfig.getInstance().getKeycloakClient() + "&grant_type=password"); + return getJwtTokenFromJson(token); + } + + public static List<KeyCloakUser> getUsers(JwtToken jwtToken) throws PortalInternalServerError { + String users = sendGet(BackendConfig.getInstance().getAuthServerUrl() + "auth/admin/realms/" + BackendConfig.getInstance().getKeycloakRealm() + "/users", + MediaType.APPLICATION_JSON, jwtToken.getAccessToken()); + return getUserListFromJson(users); + } + + public static List<KeyCloakRole> getRolesForUser(JwtToken jwtToken, String id) throws PortalInternalServerError { + String roles = sendGet(BackendConfig.getInstance().getAuthServerUrl() + "auth/admin/realms/" + BackendConfig.getInstance().getKeycloakRealm() + "/users/" + id + "/role-mappings/realm", + MediaType.APPLICATION_JSON, jwtToken.getAccessToken()); + return getRolesListFromJson(roles); + } + + public static JwtHeader getJwtHeaderFromJson(String json) { + return JsonGeneratorBase.getGson().fromJson(json, JwtHeader.class); + } + + public static JwtPayload getJwtPayloadFromJson(String json) { + return JsonGeneratorBase.getGson().fromJson(json, JwtPayload.class); + } + + public static JwtToken getJwtTokenFromJson(String json) { + return JsonGeneratorBase.getGson().fromJson(json, JwtToken.class); + } + + public static List<KeyCloakUser> getUserListFromJson(String json) throws PortalInternalServerError { + try { + Type listType = new TypeToken<List<KeyCloakUser>>() { + }.getType(); + return JsonGeneratorBase.getGson().fromJson(json, listType); + } catch (JsonSyntaxException ex) { + logger.error("Error in getUserListFromJson", ex); + throw new PortalInternalServerError("JsonSyntaxException"); + } + } + + public static List<KeyCloakRole> getRolesListFromJson(String json) throws PortalInternalServerError { + try { + Type listType = new TypeToken<List<KeyCloakRole>>() { + }.getType(); + return JsonGeneratorBase.getGson().fromJson(json, listType); + } catch (JsonSyntaxException ex) { + logger.error("Error in getRolesListFromJson", ex); + throw new PortalInternalServerError("JsonSyntaxException"); + } + } + + public static JwtPayload getPayLoad(JwtToken token) { + String[] parts = token.getAccessToken().split("[.]"); + + //parts[0] is the jwtHeader + String jwtPayload = parts[1]; + //parts[2] is the jwtVerifySignature + + // decode + byte[] decoded = Base64.getDecoder().decode(jwtPayload); + jwtPayload = new String(decoded, StandardCharsets.UTF_8); + logger.info(jwtPayload); + return getJwtPayloadFromJson(jwtPayload); + } + + private static HttpURLConnection getHttpConnection(String targetUrl) throws PortalInternalServerError { + try { + URL url = new URL(targetUrl); + return (HttpURLConnection) url.openConnection(); + } catch (IOException e) { + logger.error(e); + throw new PortalInternalServerError("HttpURLConnection IOException"); + } + } + + private static String sendGet(String targetUrl, String accept, String token) throws PortalInternalServerError { + logger.info("sendGet"); + + HttpURLConnection con = getHttpConnection(targetUrl); + StringBuilder response = new StringBuilder(); // or StringBuffer if Java version 5+ + + try (AutoCloseable conc = con::disconnect) { + con.setRequestMethod("GET"); + con.setRequestProperty("Accept", accept); + con.setInstanceFollowRedirects(false); + if (token != null) // is authenticated + { + con.setRequestProperty("Authorization", "Bearer " + token); + } + InputStream is = con.getInputStream(); + try (BufferedReader rd = new BufferedReader(new InputStreamReader(is))) { + String line; + while ((line = rd.readLine()) != null) { + response.append(line); + response.append('\r'); + logger.info("Got line -> " + line); + } + } + logger.info("sendGet was successful"); + return response.toString(); + } catch (Exception e) { + logger.error("Error occured in sendGet: " + e); + return null; + } + } + + private static String sendPost(String targetUrl, String urlParameters) throws PortalInternalServerError { + logger.info("sendPost"); + + HttpURLConnection con = getHttpConnection(targetUrl); + StringBuilder response = new StringBuilder(); // or StringBuffer if Java version 5+ + + try (AutoCloseable conc = con::disconnect) { + con.setRequestMethod("POST"); + con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + con.setRequestProperty("Accept", MediaType.APPLICATION_JSON); + con.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); + con.setInstanceFollowRedirects(false); + con.setDoOutput(true); + // Send request + try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) { + wr.writeBytes(urlParameters); + } + // Get Response + InputStream is = con.getInputStream(); + + try (BufferedReader rd = new BufferedReader(new InputStreamReader(is))) { + String line; + while ((line = rd.readLine()) != null) { + response.append(line); + response.append('\r'); + } + } + + return response.toString(); + } catch (Exception e) { + logger.error("Error occured in sendPost: " + e); + return null; + } + } + + public static String formatToken(String accessToken) { + return accessToken != null ? accessToken.replace("Bearer", "").trim() : ""; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/BackendConfig.java b/src/main/java/org/eclipse/openk/portal/common/BackendConfig.java new file mode 100644 index 0000000..eec4219 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/BackendConfig.java
@@ -0,0 +1,65 @@ +package org.eclipse.openk.portal.common; + +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; + +public class BackendConfig { + private static String configFileName = "backendConfigDevLocal.json"; + private Integer internalSessionLengthMillis; + private Integer reloadUsersInSec; + private String authServerUrl; + private String keycloakRealm; + private String keycloakClient; + private String keycloakAdmin; + private String keycloakPW; + + private static BackendConfig instance; + + private BackendConfig() {} + + public static synchronized BackendConfig getInstance() { + if (instance == null) { + String jsonConfig = loadJsonConfig(); + instance = JsonGeneratorBase.getGson().fromJson(jsonConfig, BackendConfig.class); + } + + return instance; + } + + private static String loadJsonConfig() { + ResourceLoaderBase resourceLoaderBase = new ResourceLoaderBase(); + return resourceLoaderBase.loadStringFromResource(configFileName); + } + + public Integer getInternalSessionLengthMillis() { return internalSessionLengthMillis; } + + public Integer getReloadUsersInSec() { return reloadUsersInSec; } + + public String getAuthServerUrl() { + return authServerUrl; + } + + public String getKeycloakClient() { + return keycloakClient; + } + + public String getKeycloakAdmin() { + return keycloakAdmin; + } + + public String getKeycloakPW() { + return keycloakPW; + } + + public String getKeycloakRealm() { + return keycloakRealm; + } + + + public static String getConfigFileName() { + return configFileName; + } + + public static void setConfigFileName(String configFileName) { + BackendConfig.configFileName = configFileName; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/Globals.java b/src/main/java/org/eclipse/openk/portal/common/Globals.java new file mode 100644 index 0000000..db79c17 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/Globals.java
@@ -0,0 +1,41 @@ +package org.eclipse.openk.portal.common; + + +public final class Globals { + public static final String OK_STRING = "OK"; + public static final String SESSION_TOKEN_TAG = "X-XSRF-TOKEN"; + public static final String SESSION_COOKIE_TOKEN_TAG = "COOKIESESSION-TOKEN"; + public static final int MAX_CREDENTIALS_LENGTH = 500; + public static final int MAX_NOTIFICATION_LENGTH = 16384; + + public static final int HTTPSTATUS_OK = 200; + public static final int HTTPSTATUS_BAD_REQUEST = 400; + public static final int HTTPSTATUS_UNAUTHORIZED = 401; + public static final int HTTPSTATUS_FORBIDDEN = 403; + public static final int HTTPSTATUS_NOT_FOUND = 404; + public static final int HTTPSTATUS_GONE = 410; + public static final int HTTPSTATUS_LOCKED = 423; + public static final int HTTPSTATUS_INTERNAL_SERVER_ERROR = 500; + public static final int HTTPSTATUS_NOT_AVAILABLE = 503; + public static final int HTTPSTATUS_POLICY_NOT_FULFILLED = 420; + public static final int HTTPSTATUS_CONFLICT = 409; + public static final int HTTPSTATUS_DECISION = 900; + + //For Branches: for later use in a configurable json + public static final String ELECTRICITY_MARK = "S"; + public static final String GAS_MARK = "G"; + public static final String DISTRICT_HEAT_MARK = "F"; + public static final String WATER_MARK = "W"; + + //Errormessage + public static final String DATA_OUTDATED = "Data is outdated!"; + + //Suggestion: An input field on search mask as better solution? Can only be adapted by code changes. + public static final int FAST_SEARCH_NUMBER_OF_DAYS_BACK = -200; + + //KeyCloak configuration + public static final String KEYCLOAK_AUTH_TAG = "Authorization"; + + private Globals() {} + +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/GsonUTCDateAdapter.java b/src/main/java/org/eclipse/openk/portal/common/GsonUTCDateAdapter.java new file mode 100644 index 0000000..e049bc6 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/GsonUTCDateAdapter.java
@@ -0,0 +1,40 @@ +package org.eclipse.openk.portal.common; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import java.lang.reflect.Type; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +public class GsonUTCDateAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> { + + private final DateFormat dateFormat; + + public GsonUTCDateAdapter() { + dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); //This is the format I need + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); //This is the key line which converts the date to UTC which cannot be accessed with the default serializer + } + + @Override + public synchronized JsonElement serialize(Date date, Type type, JsonSerializationContext jsonSerializationContext) { + return new JsonPrimitive(dateFormat.format(date)); + } + + @Override + public synchronized Date deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) { + try { + return dateFormat.parse(jsonElement.getAsString()); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } +} \ No newline at end of file
diff --git a/src/main/java/org/eclipse/openk/portal/common/InitBackendConfig.java b/src/main/java/org/eclipse/openk/portal/common/InitBackendConfig.java new file mode 100644 index 0000000..74a2249 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/InitBackendConfig.java
@@ -0,0 +1,50 @@ +package org.eclipse.openk.portal.common; + +import org.apache.log4j.Logger; +import org.eclipse.openk.portal.viewmodel.UserModule; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; + +public class InitBackendConfig extends HttpServlet { + + private static final long serialVersionUID = -7882117179312471533L; + + private static final Logger LOGGER = Logger.getLogger(InitBackendConfig.class.getName()); + + @Override + public void init() throws ServletException { + String environment = getServletContext().getInitParameter("OK_PORTAL_ENVIRONMENT"); + setConfigFiles(environment); + } + + private void setConfigFiles(String environment ) { + String env = (environment == null ? "Production": environment); + + String backendConfigFile; + String moduleConfigFile; + switch (env){ + case "DevLocal": + backendConfigFile="backendConfigDevLocal.json"; + moduleConfigFile="moduleConfigDevLocal.json"; + break; + case "DevServer": + backendConfigFile="backendConfigDevServer.json"; + moduleConfigFile="moduleConfigDevServer.json"; + break; + case "Custom": + backendConfigFile="backendConfigCustom.json"; + moduleConfigFile="moduleConfigCustom.json"; + break; + default: + backendConfigFile="backendConfigProduction.json"; + moduleConfigFile="moduleConfigProduction.json"; + } + + BackendConfig.setConfigFileName(backendConfigFile); + UserModule.setConfigFileName(moduleConfigFile); + LOGGER.info("Portal backendendenviroment is: " +environment+ ". Setting backendConfig accordingly to: "+ backendConfigFile); + LOGGER.info("Portal backendendenviroment is: " +environment+ ". Setting moduleConfig accordingly to: "+ moduleConfigFile); + } + +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/InitUserCacheJob.java b/src/main/java/org/eclipse/openk/portal/common/InitUserCacheJob.java new file mode 100644 index 0000000..b98dba7 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/InitUserCacheJob.java
@@ -0,0 +1,23 @@ +package org.eclipse.openk.portal.common; + +import java.util.Timer; +import java.util.TimerTask; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import org.apache.log4j.Logger; + +public class InitUserCacheJob extends HttpServlet { + + private static final long serialVersionUID = 8671326157376987023L; + + private static final Logger LOGGER = Logger.getLogger(InitUserCacheJob.class.getName()); + + + @Override + public void init() throws ServletException { + LOGGER.info("InitUserCacheJob called"); + TimerTask timerTask = new UserCacheTimerTask(); + Timer timer = new Timer(); + timer.scheduleAtFixedRate(timerTask, 500, BackendConfig.getInstance().getReloadUsersInSec()*1000L); + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/JsonGeneratorBase.java b/src/main/java/org/eclipse/openk/portal/common/JsonGeneratorBase.java new file mode 100644 index 0000000..70d21cc --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/JsonGeneratorBase.java
@@ -0,0 +1,15 @@ +package org.eclipse.openk.portal.common; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.util.Date; + +public class JsonGeneratorBase { + private JsonGeneratorBase() {} + public static Gson getGson() { + return new GsonBuilder() + .registerTypeAdapter(Date.class, new GsonUTCDateAdapter()) + .disableHtmlEscaping() + .create(); + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/UserCacheTimerTask.java b/src/main/java/org/eclipse/openk/portal/common/UserCacheTimerTask.java new file mode 100644 index 0000000..abaf567 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/UserCacheTimerTask.java
@@ -0,0 +1,51 @@ +package org.eclipse.openk.portal.common; + +import java.util.ArrayList; +import java.util.List; +import java.util.TimerTask; +import org.apache.log4j.Logger; +import org.eclipse.openk.portal.auth2.model.JwtToken; +import org.eclipse.openk.portal.auth2.model.KeyCloakRole; +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; +import org.eclipse.openk.portal.auth2.util.JwtHelper; +import org.eclipse.openk.portal.controller.TokenManager; +import org.eclipse.openk.portal.exceptions.PortalInternalServerError; +import org.eclipse.openk.portal.viewmodel.UserCache; + +public class UserCacheTimerTask extends TimerTask { + + private static final Logger LOGGER = Logger.getLogger(TokenManager.class.getName()); + + @Override + public void run() { + LOGGER.debug("UserCacheTimerTask started"); + try { + JwtToken token = JwtHelper.login(BackendConfig.getInstance().getKeycloakAdmin(), BackendConfig.getInstance().getKeycloakPW()); + + List<KeyCloakUser> allUsersWithRoles = getKeyCloakUsersFromToken(token); + + UserCache.getInstance().setKeyCloakUsers(allUsersWithRoles); + + } catch (PortalInternalServerError portalInternalServerError) { + LOGGER.error(portalInternalServerError); + } + + LOGGER.debug("UserCacheTimerTask finished"); + } + + private List<KeyCloakUser> getKeyCloakUsersFromToken(JwtToken token) throws PortalInternalServerError { + List<KeyCloakUser> allUsers = JwtHelper.getUsers(token); + List<KeyCloakUser> allUsersWithRoles = new ArrayList<>(); + + for (KeyCloakUser user : allUsers) { + List<String> rolesList = new ArrayList<>(); + List<KeyCloakRole> rolesForUser = JwtHelper.getRolesForUser(token, user.getId()); + for (KeyCloakRole keyCloakRole : rolesForUser) { + rolesList.add(keyCloakRole.getName()); + } + user.setRealmRoles(rolesList); + allUsersWithRoles.add(user); + } + return allUsersWithRoles; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/util/HashingAlgo.java b/src/main/java/org/eclipse/openk/portal/common/util/HashingAlgo.java new file mode 100644 index 0000000..b562e01 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/util/HashingAlgo.java
@@ -0,0 +1,21 @@ +package org.eclipse.openk.portal.common.util; + +import java.security.MessageDigest; +import org.apache.commons.codec.binary.Hex; + +public final class HashingAlgo { + private HashingAlgo() {} + + public static String hashIt(String pwdClear) { + MessageDigest cript; + try { + cript = MessageDigest.getInstance("SHA-1"); + cript.reset(); + cript.update(pwdClear.getBytes("utf8")); + return new String(Hex.encodeHex(cript.digest())); + + } catch (Exception e) { //NOSONAR + return null; + } + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/util/LoggerUtil.java b/src/main/java/org/eclipse/openk/portal/common/util/LoggerUtil.java new file mode 100644 index 0000000..68098ad --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/util/LoggerUtil.java
@@ -0,0 +1,71 @@ +package org.eclipse.openk.portal.common.util; + +import java.io.IOException; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.log4j.Appender; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Layout; +import org.apache.log4j.Level; +import org.apache.log4j.PatternLayout; +import org.apache.log4j.net.SyslogAppender; +import org.apache.log4j.spi.RootLogger; +import org.apache.log4j.xml.DOMConfigurator; + +/** + * <b>LoggerConfig</b><br> + * Logging Implementierung + */ +public final class LoggerUtil extends HttpServlet { + /** + * serialVersionUID. + */ + private static final long serialVersionUID = 1L; + + /* + * (non-Javadoc) + * @see javax.servlet.GenericServlet#init() + */ + @Override + public void init() { + final ServletContext context = getServletContext(); + + if (Boolean.valueOf(context.getInitParameter("param.syslog.use"))) { + // configure for syslog using parameters specified in configuration descriptor + BasicConfigurator.resetConfiguration(); + + final String level = context.getInitParameter("param.syslog.level"); + RootLogger.getRootLogger().setLevel(Level.toLevel(level)); + + final String host = context.getInitParameter("param.syslog.host"); + final String facility = context.getInitParameter("param.syslog.facility"); + final Layout layout = new PatternLayout("[%d{yyyy.MM.dd HH:mm:ss}] [%p] [%c] %m%n"); + final Appender syslogAppender = new SyslogAppender(layout, host, + SyslogAppender.getFacility(facility)); + BasicConfigurator.configure(syslogAppender); + + } else { + // configure using parameters specified in xml file + final String prefix = context.getRealPath("/"); + final String file = getInitParameter("log4j-init-file"); + + if (prefix != null && file != null) { + DOMConfigurator.configure(prefix + file); + } + } + } + + /* + * (non-Javadoc) + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, + * javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) + throws ServletException, IOException { + // Nothing done on purpose. + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/common/util/ResourceLoaderBase.java b/src/main/java/org/eclipse/openk/portal/common/util/ResourceLoaderBase.java new file mode 100644 index 0000000..2ace7b3 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/common/util/ResourceLoaderBase.java
@@ -0,0 +1,25 @@ +package org.eclipse.openk.portal.common.util; + +import java.io.InputStream; +import java.io.StringWriter; +import org.apache.commons.io.IOUtils; + +public class ResourceLoaderBase { + private String stream2String(InputStream is) { + StringWriter writer = new StringWriter(); + try { + IOUtils.copy(is, writer, "UTF-8"); + } catch (Exception e) { // NOSONAR + return ""; + } + return writer.toString(); + + + } + + public String loadStringFromResource(String filename) { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream jsonstream = classLoader.getResourceAsStream(filename); + return stream2String(jsonstream); + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/controller/BackendController.java b/src/main/java/org/eclipse/openk/portal/controller/BackendController.java new file mode 100644 index 0000000..ad3ddfe --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/controller/BackendController.java
@@ -0,0 +1,110 @@ + +package org.eclipse.openk.portal.controller; + +import org.apache.log4j.Logger; +import org.eclipse.openk.portal.auth2.model.JwtToken; +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; +import org.eclipse.openk.portal.auth2.util.JwtHelper; +import org.eclipse.openk.portal.common.BackendConfig; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.exceptions.PortalException; +import org.eclipse.openk.portal.exceptions.PortalInternalServerError; +import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.eclipse.openk.portal.viewmodel.LoginCredentials; +import org.eclipse.openk.portal.viewmodel.UserCache; +import org.eclipse.openk.portal.viewmodel.UserModule; +import org.eclipse.openk.portal.viewmodel.VersionInfo; + +import java.util.ArrayList; +import java.util.List; + +public class BackendController { + private static final Logger LOGGER = Logger.getLogger(BackendController.class.getName()); + private final InputDataValuator inputDataValuator = new InputDataValuator(); + + public List<KeyCloakUser> getUsers() throws PortalInternalServerError { + JwtToken token = JwtHelper.login(BackendConfig.getInstance().getKeycloakAdmin(), + BackendConfig.getInstance().getKeycloakPW()); + return JwtHelper.getUsers(token); + } + + public List<KeyCloakUser> getUsersForRole(String roleToCheck) { + List<KeyCloakUser> usersWithRole = new ArrayList<>(); + List<KeyCloakUser> keyCloakUsers = UserCache.getInstance().getKeyCloakUsers(); + + for (KeyCloakUser user : keyCloakUsers) { + List<String> realmRoles = user.getRealmRoles(); + if (realmRoles == null) { + continue; + } + + for (String realmRole : realmRoles) { + if(realmRole.equals(roleToCheck)){ + usersWithRole.add(user); + break; + } + } + } + + return usersWithRole; + } + + + public JwtToken authenticate(String credentials) throws PortalException { + LOGGER.info("authenticate() is called"); + + // valuator will throw an exception if not valid + inputDataValuator.checkCredentials(credentials); + + LoginCredentials loginCredentials = JsonGeneratorBase.getGson().fromJson(credentials, LoginCredentials.class); + + JwtToken token = null; + String inputUsername = loginCredentials.getUserName().toLowerCase(); + String inputPassword = loginCredentials.getPassword(); + + // obtain a token from keycloak + token = JwtHelper.login(inputUsername, inputPassword); + + if( token == null ) { + LOGGER.debug(credentials); + throw new PortalUnauthorized("Unknown User/Password"); + } + + LOGGER.info("authenticate() succeeded."); + return token; + } + + public VersionInfo getVersionInfo() { + LOGGER.info("getVersionInfo() is called"); + + String version = getClass().getPackage().getImplementationVersion(); + VersionInfo vi = new VersionInfo(); + vi.setBackendVersion(version); + + LOGGER.info("getVersionInfo() is finished"); + return vi; + } + + public List<UserModule> getUserModuleList() { + LOGGER.info("getUserModuleList() is called"); + List<UserModule> umList = new ArrayList<>(); + + for (int i=0; i<UserModule.getInstance().length; i++) + { + UserModule um = new UserModule(); + um.setModuleName(UserModule.getInstance()[i].getModuleName()); + um.setCols(UserModule.getInstance()[i].getCols()); + um.setRows(UserModule.getInstance()[i].getRows()); + um.setColor(UserModule.getInstance()[i].getColor()); + um.setLink(UserModule.getInstance()[i].getLink()); + um.setPictureLink(UserModule.getInstance()[i].getPictureLink()); + um.setRequiredRole(UserModule.getInstance()[i].getRequiredRole()); + + umList.add(um); + } + + LOGGER.info("getUserModuleList() is finished"); + return umList; + } + +}
diff --git a/src/main/java/org/eclipse/openk/portal/controller/BackendInvokable.java b/src/main/java/org/eclipse/openk/portal/controller/BackendInvokable.java new file mode 100644 index 0000000..5ac8a63 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/controller/BackendInvokable.java
@@ -0,0 +1,28 @@ +package org.eclipse.openk.portal.controller; +import javax.ws.rs.core.Response; +import org.eclipse.openk.portal.exceptions.PortalException; + + +public abstract class BackendInvokable { + + private String modUser; + private int userId; + + public int getUserId() { + return userId; + } + + public void setUserId(int userId) { + this.userId = userId; + } + + public String getModUser() { + return modUser; + } + + public void setModUser(String modUser) { + this.modUser = modUser; + } + + public abstract Response invoke() throws PortalException; +}
diff --git a/src/main/java/org/eclipse/openk/portal/controller/BaseWebService.java b/src/main/java/org/eclipse/openk/portal/controller/BaseWebService.java new file mode 100644 index 0000000..cb027f0 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/controller/BaseWebService.java
@@ -0,0 +1,67 @@ +package org.eclipse.openk.portal.controller; + +import java.util.HashMap; +import java.util.Map; +import javax.ws.rs.core.Response; +import org.apache.log4j.Logger; +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.exceptions.PortalException; +import org.eclipse.openk.portal.exceptions.PortalExceptionMapper; + +public abstract class BaseWebService { + private final Map<String, Long> currentTimeMeasures = new HashMap<>(); + private final Logger logger; + + public BaseWebService(Logger logger) { + this.logger = logger; + } + + protected abstract void assertAndRefreshToken(String token, boolean refresh) throws PortalException; + + private void startProcessing(String methodName) { + Long lStartingTime = System.currentTimeMillis(); + String lookupName = buildLookupId(methodName); + currentTimeMeasures.put(lookupName, lStartingTime); + + logger.info(this.getClass().getName() + "." + lookupName + ": Start processing..."); + } + + protected AutoCloseable perform(final String methodName) { + startProcessing(methodName); + return () -> endProcessing(methodName); + } + + private String buildLookupId(String func) { + return func + "@@" + Thread.currentThread().getId(); + } + + private void endProcessing(String methodName) { + String lookupName = buildLookupId(methodName); + if (currentTimeMeasures.containsKey(lookupName)) { + Long lStartingTime = currentTimeMeasures.get(lookupName); + currentTimeMeasures.remove(lookupName); + + logger.info(this.getClass().getName() + "." + lookupName + ": Finished processing in " + (System.currentTimeMillis() - lStartingTime) + " ms"); + } + + } + + protected Response invoke(String sessionId, boolean refresh, BackendInvokable invokable) + { + try (AutoCloseable ignored = perform(invokable.getClass().getName() + ".Invoke()")) { // NOSONAR + + assertAndRefreshToken(sessionId, refresh); + + return invokable.invoke(); + } catch (PortalException bee) { + logger.info("Caught BackendException: " + bee.getClass().getSimpleName()); + return Response.status(bee.getHttpStatus()).entity(PortalExceptionMapper.toJson(bee)) + .build(); + + } catch (Exception e) { + logger.error("Unexpected exception", e); + return Response.status(Globals.HTTPSTATUS_INTERNAL_SERVER_ERROR).build(); + } + + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/controller/ControllerImplementations.java b/src/main/java/org/eclipse/openk/portal/controller/ControllerImplementations.java new file mode 100644 index 0000000..5618c0a --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/controller/ControllerImplementations.java
@@ -0,0 +1,102 @@ +package org.eclipse.openk.portal.controller; + + +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; +import java.util.List; +import javax.ws.rs.core.Response; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.exceptions.PortalException; +import org.eclipse.openk.portal.exceptions.PortalExceptionMapper; +import org.eclipse.openk.portal.viewmodel.UserCache; +import org.eclipse.openk.portal.viewmodel.UserModule; +import org.eclipse.openk.portal.viewmodel.VersionInfo; + + +public class ControllerImplementations +{ + private ControllerImplementations() {} + + public static class GetUsers extends BackendInvokable { + + public GetUsers() {} + + @Override + public Response invoke() throws PortalException { + List<KeyCloakUser> keyCloakUserList = UserCache.getInstance().getKeyCloakUsers(); + return ResponseBuilderWrapper.INSTANCE.buildOKResponse(JsonGeneratorBase.getGson().toJson(keyCloakUserList)); + } + } + + public static class GetVersionInfo extends BackendInvokable { + private BackendController backendController; + + public GetVersionInfo(BackendController backendController) { + this.backendController = backendController; + } + + @Override + public Response invoke() throws PortalException { + VersionInfo vi = backendController.getVersionInfo(); + return ResponseBuilderWrapper.INSTANCE.buildOKResponse(JsonGeneratorBase.getGson().toJson(vi)); + } + } + + public static class Logout extends BackendInvokable { + private String accessToken; + + public Logout(String accessToken) { + this.accessToken = accessToken; + } + + @Override + public Response invoke() throws PortalException { + TokenManager.getInstance().logout(accessToken); + return ResponseBuilderWrapper.INSTANCE.buildOKResponse(PortalExceptionMapper.getGeneralOKJson()); + } + } + + public static class CheckAuth extends BackendInvokable { + + public CheckAuth() { + /* the implemented invoke method is only called after a successfully + pass of assertAndRefreshToken method of the BaseWebService class which checks + if the Token is active and valid */ + } + + @Override + public Response invoke() throws PortalException { + //see constructor above + return ResponseBuilderWrapper.INSTANCE.buildOKResponse(PortalExceptionMapper.getGeneralOKJson()); + } + } + + public static class GetUserModulesForUser extends BackendInvokable { + private BackendController backendController; + + public GetUserModulesForUser(BackendController backendController) { + this.backendController = backendController; + } + + @Override + public Response invoke() throws PortalException { + List<UserModule> um = backendController.getUserModuleList(); + return ResponseBuilderWrapper.INSTANCE.buildOKResponse(JsonGeneratorBase.getGson().toJson(um)); + } + } + + public static class GetUsersForRole extends BackendInvokable { + private BackendController backendController; + private String userRole; + + public GetUsersForRole(BackendController backendController, String userRole) { + this.backendController = backendController; + this.userRole = userRole; + } + + @Override + public Response invoke() throws PortalException { + List<KeyCloakUser> keyCloakUserList = backendController.getUsersForRole(userRole); + return ResponseBuilderWrapper.INSTANCE.buildOKResponse(JsonGeneratorBase.getGson().toJson(keyCloakUserList)); + } + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/controller/InputDataValuator.java b/src/main/java/org/eclipse/openk/portal/controller/InputDataValuator.java new file mode 100644 index 0000000..3a15df5 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/controller/InputDataValuator.java
@@ -0,0 +1,58 @@ +package org.eclipse.openk.portal.controller; + +import org.apache.log4j.Logger; +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.exceptions.PortalBadRequest; +import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.eclipse.openk.portal.viewmodel.LoginCredentials; + +public class InputDataValuator { + private static final Logger LOGGER = Logger.getLogger(InputDataValuator.class.getName()); + + private static final String WHITELIST = "[^a-zA-ZäÄöÖüÜß?0-9().,-:;_+=!%§&/'#<>\" ]"; + + private void checkCredentialsRaw(String credentials) throws PortalUnauthorized { + if (credentials == null || credentials.isEmpty()) { + throw new PortalUnauthorized("No credentials provided"); + } + if (credentials.length() > Globals.MAX_CREDENTIALS_LENGTH) { + LOGGER.warn("MaxLength of credentials exceeded"); + + throw new PortalUnauthorized("Invalid credentials"); + } + } + + public void checkCredentials(String credentials) throws PortalUnauthorized { + checkCredentialsRaw(credentials); + + LoginCredentials obj; + try { + obj = JsonGeneratorBase.getGson().fromJson(credentials, LoginCredentials.class); + checkWhitelistChars(obj.getPassword()); + checkWhitelistChars(obj.getPassword()); + } catch (Exception e) { // NOSONAR + obj = null; + } + if (obj == null || obj.getUserName() == null || obj.getUserName().isEmpty()) { + LOGGER.warn("Invalid credentials provided. "); + throw new PortalUnauthorized("Invalid credentials"); + } + } + + private void checkWhitelistChars(String txt) throws PortalBadRequest { + checkWhitelistChars(txt, false); + } + + private void checkWhitelistChars(String txt, boolean logTextOnError) throws PortalBadRequest { + // empty String is ok + if (txt == null || txt.isEmpty()) { + return; + } + String tx2 = txt.replaceAll(WHITELIST, ""); + if (!tx2.equals(txt)) { + LOGGER.warn("Invalid text not matching whitelist" + (logTextOnError ? ":" + txt : "")); + throw new PortalBadRequest("Invalid text data"); + } + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/controller/ResponseBuilderWrapper.java b/src/main/java/org/eclipse/openk/portal/controller/ResponseBuilderWrapper.java new file mode 100644 index 0000000..2cb66ae --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/controller/ResponseBuilderWrapper.java
@@ -0,0 +1,49 @@ +package org.eclipse.openk.portal.controller; + +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.exceptions.PortalException; +import org.eclipse.openk.portal.exceptions.PortalInternalServerError; + +import javax.ws.rs.core.Response; +import java.io.UnsupportedEncodingException; + +public enum ResponseBuilderWrapper { + INSTANCE; + + public Response.ResponseBuilder getResponseBuilder( String json ) throws PortalInternalServerError { + return getResponseBuilder(jsonStringToBytes( json )); + + } + + private Response.ResponseBuilder getResponseBuilder(byte[] json) { + return Response.status(Globals.HTTPSTATUS_OK).entity(json) + .header("Content-Type", "application/json; charset=utf-8") + .header("X-XSS-Protection", "1; mode = block") + .header("X-DNS-Prefetch-Control", "off") + .header("X-Content-Type-Options", "nosniff") + .header("X-Frame-Options", "sameorigin") + .header("Strict-Transport-Security", "max-age=15768000; includeSubDomains") + .header("Cache-Control", "no-cache; no-store; must-revalidate") + .header("Pragma", "no-cache") + .header("Expires", "0") + .header("Access-Control-Allow-Origin", "*"); + } + + private byte[] jsonStringToBytes( String jsonString ) throws PortalInternalServerError { + try { + return jsonString.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new PortalInternalServerError("Unexpected Error", e); + } + } + + public Response buildOKResponse(String jsonString) throws PortalException { + return getResponseBuilder( jsonStringToBytes( jsonString)).build(); + } + + + public Response buildOKResponse(String jsonString, String sessionToken) throws PortalException { + return getResponseBuilder(jsonStringToBytes(jsonString)).header(Globals.SESSION_TOKEN_TAG, sessionToken).build(); + } + +}
diff --git a/src/main/java/org/eclipse/openk/portal/controller/TokenManager.java b/src/main/java/org/eclipse/openk/portal/controller/TokenManager.java new file mode 100644 index 0000000..6d9d68a --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/controller/TokenManager.java
@@ -0,0 +1,136 @@ +package org.eclipse.openk.portal.controller; + + +import org.eclipse.openk.portal.auth2.model.JwtPayload; +import org.eclipse.openk.portal.auth2.model.JwtToken; +import org.eclipse.openk.portal.auth2.util.JwtHelper; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.eclipse.openk.portal.common.BackendConfig; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.eclipse.openk.portal.viewmodel.UserAuthentication; + +public class TokenManager { + private static final Logger LOGGER = Logger.getLogger(TokenManager.class.getName()); + + private static long internalSessionLengthOffsetPerc = 0L; + + public static class SessionItem { + private long sessionCreationTime; + private long sessionLastAccessTime; + + private String sessionId; + private String cookieToken; + private UserAuthentication user; + private JwtToken jwtToken; + + public SessionItem(long sessionCreationTime) { + this.sessionCreationTime = this.sessionLastAccessTime = sessionCreationTime; + } + + public long getSessionCreationTime() { + return sessionCreationTime; + } + + public void setSessionCreationTime(long sessionCreationTime) { + this.sessionCreationTime = sessionCreationTime; + } + + public long getSessionLastAccessTime() { + return sessionLastAccessTime; + } + + public void setSessionLastAccessTime(long sessionLastAccessTime) { + this.sessionLastAccessTime = sessionLastAccessTime; + } + + public UserAuthentication getUser() { + return user; + } + + public void setUser(UserAuthentication user) { + this.user = user; + } + + public JwtToken getJwtToken() { + return jwtToken; + } + + public void setJwtToken(JwtToken jwtToken) { + this.jwtToken = jwtToken; + } + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public String getCookieToken() { + return cookieToken; + } + + public void setCookieToken(String cookieToken) { + this.cookieToken = cookieToken; + } + } + + private static final TokenManager INSTANCE = new TokenManager(); + private final HashMap<String, SessionItem> registry = new HashMap<>(); + + private TokenManager() { + } + + public static TokenManager getInstance() { + return INSTANCE; + } + + public void registerNewSession(JwtToken jwtToken) { + + String guid = jwtToken.getAccessToken(); + SessionItem sitem = new SessionItem(System.currentTimeMillis()); + sitem.setJwtToken(jwtToken); + sitem.setSessionId(guid); + + LOGGER.debug("Registered Session with JWT: " + JsonGeneratorBase.getGson().toJson(jwtToken)); + registry.put(guid, sitem); + } + + + private boolean sessionHasExpired(long now, SessionItem sitem) { + return (now - sitem.getSessionLastAccessTime()) > + BackendConfig.getInstance().getInternalSessionLengthMillis() * (1 + (internalSessionLengthOffsetPerc / 100L)); + } + + public void refreshSessionIsAlive(String token, boolean refresh) throws PortalUnauthorized { + String accesstoken = JwtHelper.formatToken(token); + SessionItem sitem = registry.get(accesstoken); + long now = System.currentTimeMillis(); + + if (sitem == null || sessionHasExpired(now, sitem)) { + if (sitem != null) { + JwtPayload payLoad = JwtHelper.getPayLoad(sitem.getJwtToken()); + String user = (payLoad != null ? payLoad.getPreferredUsername() : null); + LOGGER.info("Session expired for User " + user); + } + registry.remove(token); // we're done + LOGGER.info("Invalid Token: " + token); + throw new PortalUnauthorized("Invalid Token"); + } + + if (refresh) { + sitem.setSessionLastAccessTime(now); + } + } + + public void logout(String token) { + String accesstoken = JwtHelper.formatToken(token); + if (registry.containsKey(accesstoken)) { + registry.remove(accesstoken); + } + } + +}
diff --git a/src/main/java/org/eclipse/openk/portal/exceptions/PortalBadRequest.java b/src/main/java/org/eclipse/openk/portal/exceptions/PortalBadRequest.java new file mode 100644 index 0000000..8a59acf --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/exceptions/PortalBadRequest.java
@@ -0,0 +1,18 @@ +package org.eclipse.openk.portal.exceptions; + +import org.eclipse.openk.portal.common.Globals; + +public class PortalBadRequest extends PortalException { + public PortalBadRequest() { + super(); + } + + public PortalBadRequest(String message) { + super(message); + } + + @Override + public int getHttpStatus() { + return Globals.HTTPSTATUS_BAD_REQUEST; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/exceptions/PortalException.java b/src/main/java/org/eclipse/openk/portal/exceptions/PortalException.java new file mode 100644 index 0000000..4c88114 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/exceptions/PortalException.java
@@ -0,0 +1,17 @@ +package org.eclipse.openk.portal.exceptions; + +public abstract class PortalException extends Exception { // NOSONAR + public PortalException() { + super(); + } + + public PortalException(String message) { + super(message); + } + + public PortalException(String message, Throwable throwable) { + super(message, throwable); + } + + public abstract int getHttpStatus(); +}
diff --git a/src/main/java/org/eclipse/openk/portal/exceptions/PortalExceptionMapper.java b/src/main/java/org/eclipse/openk/portal/exceptions/PortalExceptionMapper.java new file mode 100644 index 0000000..c78883a --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/exceptions/PortalExceptionMapper.java
@@ -0,0 +1,32 @@ +package org.eclipse.openk.portal.exceptions; + +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.viewmodel.ErrorReturn; +import org.eclipse.openk.portal.viewmodel.GeneralReturnItem; + +public final class PortalExceptionMapper { + private PortalExceptionMapper() {} + + public static String unknownErrorToJson() { + ErrorReturn er = new ErrorReturn(); + er.setErrorText("Unknown Error"); + er.setErrorCode(Globals.HTTPSTATUS_INTERNAL_SERVER_ERROR); + return JsonGeneratorBase.getGson().toJson(er); + } + + public static String toJson(PortalException e) { + ErrorReturn er = new ErrorReturn(); + er.setErrorText(e.getMessage()); + er.setErrorCode(e.getHttpStatus()); + return JsonGeneratorBase.getGson().toJson(er); + } + + public static String getGeneralErrorJson() { + return JsonGeneratorBase.getGson().toJson(new GeneralReturnItem("NOK")); + } + + public static String getGeneralOKJson() { + return JsonGeneratorBase.getGson().toJson(new GeneralReturnItem("OK")); + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/exceptions/PortalForbidden.java b/src/main/java/org/eclipse/openk/portal/exceptions/PortalForbidden.java new file mode 100644 index 0000000..d43a5df --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/exceptions/PortalForbidden.java
@@ -0,0 +1,18 @@ +package org.eclipse.openk.portal.exceptions; + +import org.eclipse.openk.portal.common.Globals; + +public class PortalForbidden extends PortalException { + public PortalForbidden() { + super(); + } + + public PortalForbidden(String message) { + super(message); + } + + @Override + public int getHttpStatus() { + return Globals.HTTPSTATUS_FORBIDDEN; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/exceptions/PortalInternalServerError.java b/src/main/java/org/eclipse/openk/portal/exceptions/PortalInternalServerError.java new file mode 100644 index 0000000..74a1220 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/exceptions/PortalInternalServerError.java
@@ -0,0 +1,18 @@ +package org.eclipse.openk.portal.exceptions; + +import org.eclipse.openk.portal.common.Globals; + +public class PortalInternalServerError extends PortalException { + public PortalInternalServerError(String message) { + super(message); + } + + public PortalInternalServerError(String message, Throwable throwable) { + super(message, throwable); + } + + @Override + public int getHttpStatus() { + return Globals.HTTPSTATUS_INTERNAL_SERVER_ERROR; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/exceptions/PortalNotFound.java b/src/main/java/org/eclipse/openk/portal/exceptions/PortalNotFound.java new file mode 100644 index 0000000..4e82e2b --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/exceptions/PortalNotFound.java
@@ -0,0 +1,18 @@ +package org.eclipse.openk.portal.exceptions; + +import org.eclipse.openk.portal.common.Globals; + +public class PortalNotFound extends PortalException { + public PortalNotFound() { + super(); + } + + public PortalNotFound(String message) { + super(message); + } + + @Override + public int getHttpStatus() { + return Globals.HTTPSTATUS_NOT_FOUND; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/exceptions/PortalUnauthorized.java b/src/main/java/org/eclipse/openk/portal/exceptions/PortalUnauthorized.java new file mode 100644 index 0000000..d172995 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/exceptions/PortalUnauthorized.java
@@ -0,0 +1,18 @@ +package org.eclipse.openk.portal.exceptions; + +import org.eclipse.openk.portal.common.Globals; + +public class PortalUnauthorized extends PortalException { + public PortalUnauthorized() { + super(); + } + + public PortalUnauthorized(String message) { + super(message); + } + + @Override + public int getHttpStatus() { + return Globals.HTTPSTATUS_UNAUTHORIZED; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/rest/BackendRestService.java b/src/main/java/org/eclipse/openk/portal/rest/BackendRestService.java new file mode 100644 index 0000000..f349071 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/rest/BackendRestService.java
@@ -0,0 +1,158 @@ +package org.eclipse.openk.portal.rest; + +import javax.ws.rs.PathParam; +import org.apache.log4j.Logger; +import org.eclipse.openk.portal.auth2.model.JwtToken; +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.controller.BackendController; +import org.eclipse.openk.portal.controller.BaseWebService; +import org.eclipse.openk.portal.controller.ControllerImplementations; +import org.eclipse.openk.portal.controller.ResponseBuilderWrapper; +import org.eclipse.openk.portal.controller.TokenManager; +import org.eclipse.openk.portal.exceptions.PortalException; +import org.eclipse.openk.portal.exceptions.PortalExceptionMapper; +import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.eclipse.openk.portal.viewmodel.VersionInfo; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; + +@Path("/beservice") +public class BackendRestService extends BaseWebService { + private static final Logger logger = Logger.getLogger(BackendRestService.class.getName()); + private static final boolean DEVELOP_MODE; + private static final String LET_ME_IN = "LET_ME_IN"; + + static { + // determine static VersionInfo + String versionString = BackendRestService.class.getPackage().getImplementationVersion().toUpperCase(); + DEVELOP_MODE = versionString.contains("DEVELOP") || versionString.contains("SNAPSHOT"); + } + @Context + private UriInfo uriInfo; + + public BackendRestService() { + super(logger); + } + + @POST + @Path("/login") + @Produces("application/json") + @Consumes("application/json") + public Response login(String loginCredentials) { + + try (AutoCloseable ignored = perform("login()")) { // NOSONAR + JwtToken jwtToken; + + if (loginCredentials == null || loginCredentials.isEmpty()) { + logger.info("Login Error. Empty Credentials"); + throw new PortalUnauthorized(); + } else { + // will throw exception if it fails + jwtToken = new BackendController().authenticate(loginCredentials); + TokenManager tokenManager = TokenManager.getInstance(); + tokenManager.registerNewSession(jwtToken); + logger.info("Login Success"); + } + + return createJsonResponse(jwtToken); + } catch (Exception e) { + logger.info("Login Error. Invalid KeyCloak Credentials/Settings"); + return responseFromException(e); + } + } + + private Response createJsonResponse(Object obj) throws PortalException { + Response.ResponseBuilder rb = ResponseBuilderWrapper.INSTANCE + .getResponseBuilder(obj != null ? JsonGeneratorBase.getGson().toJson(obj) : PortalExceptionMapper.getGeneralOKJson()); + + return rb.build(); + } + + @GET + @Path("/checkAuth") + @Produces("application/json") + public Response checkAuth(@HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String accessToken) { + logger.debug("checkAuth portal called"); + return invoke(accessToken, true, new ControllerImplementations.CheckAuth()); + } + + @GET + @Path("/logout") + @Produces("application/json") + public Response logout(@HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String accessToken) { + return invoke(accessToken, false, new ControllerImplementations.Logout(accessToken)); + } + + @GET + @Path("/versionInfo/") + @Produces("application/json") + public Response getVersionInfo() { + try (AutoCloseable ignored = perform("getVersionInfo()")) { // NOSONAR + VersionInfo versionInfo = new BackendController().getVersionInfo(); + return createJsonResponse(versionInfo); + } catch (Exception e) { + return responseFromException(e); + } + } + + @GET + @Path("/userModulesForUser/") + @Produces("application/json") + public Response getUserModulesForUser(@HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String accessToken) { + return invoke(accessToken, false, new ControllerImplementations.GetUserModulesForUser(new BackendController())); + } + + @GET + @Path("/usersForRole/{userRole}") + @Produces("application/json") + public Response getUsersForRole(@PathParam("userRole") String userRole, + @HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String accessToken) { + return invoke(accessToken, false, new ControllerImplementations.GetUsersForRole(new BackendController(),userRole)); + } + + @GET + @Path("/users") + @Produces("application/json") + public Response getUsers(@HeaderParam(value = Globals.KEYCLOAK_AUTH_TAG) String accessToken) { + return invoke(accessToken, false, new ControllerImplementations.GetUsers()); + } + + private boolean isBackdoor( String sessionId ) { + // backdoor is only available when the version(POM) contains "DEVELOP" or "SNAPSHOT" + return DEVELOP_MODE && LET_ME_IN.equals(sessionId); + } + + @Override + protected void assertAndRefreshToken(String token, boolean refresh) throws PortalUnauthorized { + if (isBackdoor(token)) { + return; + } + TokenManager.getInstance().refreshSessionIsAlive(token, refresh); + + } + + private Response responseFromException(Exception e) { + int errcode; + String retJson; + + if (e instanceof PortalException) { + logger.error("Caught BackendException", e); + errcode = ((PortalException) e).getHttpStatus(); + retJson = PortalExceptionMapper.toJson((PortalException) e); + return Response.status(errcode).entity(retJson).build(); + } else { + logger.error("Unexpected exception", e); + return Response.status(Globals.HTTPSTATUS_INTERNAL_SERVER_ERROR).entity(PortalExceptionMapper.getGeneralErrorJson()).build(); + } + } + +}
diff --git a/src/main/java/org/eclipse/openk/portal/rest/RestServiceConfiguration.java b/src/main/java/org/eclipse/openk/portal/rest/RestServiceConfiguration.java new file mode 100644 index 0000000..7914f9c --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/rest/RestServiceConfiguration.java
@@ -0,0 +1,18 @@ +package org.eclipse.openk.portal.rest; + + +import java.util.HashSet; +import java.util.Set; + +public class RestServiceConfiguration extends javax.ws.rs.core.Application { + public RestServiceConfiguration() { + // Standard Contstructor needed + } + + @Override + public Set<Class<?>> getClasses() { + Set<Class<?>> restServicesClasses = new HashSet<>(); + restServicesClasses.add(BackendRestService.class); + return restServicesClasses; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/viewmodel/ErrorReturn.java b/src/main/java/org/eclipse/openk/portal/viewmodel/ErrorReturn.java new file mode 100644 index 0000000..0cb403c --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/viewmodel/ErrorReturn.java
@@ -0,0 +1,23 @@ +package org.eclipse.openk.portal.viewmodel; + +import java.io.Serializable; + +public class ErrorReturn implements Serializable { + + private static final long serialVersionUID = -4653198875478337413L; + private String errorText; + private int errorCode; + + public String getErrorText() { + return errorText; + } + public void setErrorText(String errorText) { + this.errorText = errorText; + } + public int getErrorCode() { + return errorCode; + } + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/viewmodel/GeneralReturnItem.java b/src/main/java/org/eclipse/openk/portal/viewmodel/GeneralReturnItem.java new file mode 100644 index 0000000..5a23a95 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/viewmodel/GeneralReturnItem.java
@@ -0,0 +1,17 @@ +package org.eclipse.openk.portal.viewmodel; + + +public class GeneralReturnItem { + private String ret; + + public GeneralReturnItem( String ret ) { + this.ret = ret; +} + public String getRet() { + return ret; + } + + public void setRet(String ret) { + this.ret = ret; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/viewmodel/LoginCredentials.java b/src/main/java/org/eclipse/openk/portal/viewmodel/LoginCredentials.java new file mode 100644 index 0000000..c93a87f --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/viewmodel/LoginCredentials.java
@@ -0,0 +1,22 @@ +package org.eclipse.openk.portal.viewmodel; + +public class LoginCredentials { + private String userName; + private String password; + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/viewmodel/UserAuthentication.java b/src/main/java/org/eclipse/openk/portal/viewmodel/UserAuthentication.java new file mode 100644 index 0000000..028b4d1 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/viewmodel/UserAuthentication.java
@@ -0,0 +1,58 @@ +package org.eclipse.openk.portal.viewmodel; + +public class UserAuthentication { + + private int id; + private boolean selected; + private String username; + private String password; + private String name; + private boolean specialUser; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isSpecialUser() { + return specialUser; + } + + public void setSpecialUser(boolean specialUser) { + this.specialUser = specialUser; + } + + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/viewmodel/UserCache.java b/src/main/java/org/eclipse/openk/portal/viewmodel/UserCache.java new file mode 100644 index 0000000..42a4f13 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/viewmodel/UserCache.java
@@ -0,0 +1,31 @@ +package org.eclipse.openk.portal.viewmodel; + +import java.util.ArrayList; +import java.util.List; +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; + +public class UserCache { + + private static final UserCache USERCACHE_INSTANCE = new UserCache(); + private final List<KeyCloakUser> keyCloakUsers = new ArrayList<>(); + + private UserCache(){ + } + + public static UserCache getInstance() { + return USERCACHE_INSTANCE; + } + + public List<KeyCloakUser> getKeyCloakUsers() { + synchronized (keyCloakUsers){ + return keyCloakUsers; + } + } + + public void setKeyCloakUsers(List<KeyCloakUser> keyCloakUsers) { + synchronized (this.keyCloakUsers){ + this.keyCloakUsers.clear(); + this.keyCloakUsers.addAll(keyCloakUsers); + } + } +}
diff --git a/src/main/java/org/eclipse/openk/portal/viewmodel/UserModule.java b/src/main/java/org/eclipse/openk/portal/viewmodel/UserModule.java new file mode 100644 index 0000000..1270fab --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/viewmodel/UserModule.java
@@ -0,0 +1,69 @@ +package org.eclipse.openk.portal.viewmodel; + +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; + +public class UserModule { + + private static String configFileName = "moduleConfigDevLocal.json"; + private String name; + private Integer cols; + private Integer rows; + private String color; + private String link; + private String pictureLink; + private String requiredRole; + + private static UserModule[] instance; + + public static synchronized UserModule[] getInstance() { + if (instance == null) { + String jsonConfig = loadJsonConfig(); + instance = JsonGeneratorBase.getGson().fromJson(jsonConfig, UserModule[].class); + } + + return instance; + } + + private static String loadJsonConfig() { + ResourceLoaderBase resourceLoaderBase = new ResourceLoaderBase(); + return resourceLoaderBase.loadStringFromResource(configFileName); + } + + public String getModuleName() { return name; } + + public void setModuleName(String name) { this.name = name; } + + public Integer getCols() { return cols; } + + public void setCols(Integer cols) { this.cols = cols; } + + public Integer getRows() { return rows; } + + public void setRows(Integer rows) { this.rows = rows; } + + public String getColor() { return color; } + + public void setColor(String color) { this.color = color; } + + public String getLink() { return link; } + + public void setLink(String link) { this.link = link; } + + public String getPictureLink() { return pictureLink; } + + public void setPictureLink(String pictureLink) { this.pictureLink = pictureLink; } + + public String getRequiredRole() { return requiredRole; } + + public void setRequiredRole(String role) { this.requiredRole = role; } + + public static String getConfigFileName() { + return configFileName; + } + + public static void setConfigFileName(String configFileName) { + UserModule.configFileName = configFileName; + } + +}
diff --git a/src/main/java/org/eclipse/openk/portal/viewmodel/VersionInfo.java b/src/main/java/org/eclipse/openk/portal/viewmodel/VersionInfo.java new file mode 100644 index 0000000..a96ac02 --- /dev/null +++ b/src/main/java/org/eclipse/openk/portal/viewmodel/VersionInfo.java
@@ -0,0 +1,15 @@ +package org.eclipse.openk.portal.viewmodel; + +public class VersionInfo { + private String backendVersion; + + public String getBackendVersion() { + return backendVersion; + } + + public void setBackendVersion(String backendVersion) { + this.backendVersion = backendVersion; + } + + +}
diff --git a/src/main/resources/backendConfigCustom.json b/src/main/resources/backendConfigCustom.json new file mode 100644 index 0000000..6197068 --- /dev/null +++ b/src/main/resources/backendConfigCustom.json
@@ -0,0 +1,9 @@ +{ + "internalSessionLengthMillis": 3600000, + "reloadUsersInSec": 300, + "authServerUrl": "http://entjava002:8080/", + "keycloakRealm": "elogbook", + "keycloakClient": "elogbook-backend", + "keycloakAdmin": "admin", + "keycloakPW": "nimda" +} \ No newline at end of file
diff --git a/src/main/resources/backendConfigDevLocal.json b/src/main/resources/backendConfigDevLocal.json new file mode 100644 index 0000000..6197068 --- /dev/null +++ b/src/main/resources/backendConfigDevLocal.json
@@ -0,0 +1,9 @@ +{ + "internalSessionLengthMillis": 3600000, + "reloadUsersInSec": 300, + "authServerUrl": "http://entjava002:8080/", + "keycloakRealm": "elogbook", + "keycloakClient": "elogbook-backend", + "keycloakAdmin": "admin", + "keycloakPW": "nimda" +} \ No newline at end of file
diff --git a/src/main/resources/backendConfigDevServer.json b/src/main/resources/backendConfigDevServer.json new file mode 100644 index 0000000..17b73db --- /dev/null +++ b/src/main/resources/backendConfigDevServer.json
@@ -0,0 +1,9 @@ +{ + "internalSessionLengthMillis": 3600000, + "reloadUsersInSec": 300, + "authServerUrl": "http://localhost:8080/", + "keycloakRealm": "Elogbook", + "keycloakClient": "elogbook-backend", + "keycloakAdmin": "admin", + "keycloakPW": "admin" +} \ No newline at end of file
diff --git a/src/main/resources/backendConfigProduction.json b/src/main/resources/backendConfigProduction.json new file mode 100644 index 0000000..7fed7db --- /dev/null +++ b/src/main/resources/backendConfigProduction.json
@@ -0,0 +1,9 @@ +{ + "internalSessionLengthMillis": 46800000, + "reloadUsersInSec": 300, + "authServerUrl": "http://localhost:8090/", + "keycloakRealm": "MainDonauNetz", + "keycloakClient": "elogbook-backend", + "keycloakAdmin": "admin", + "keycloakPW": "Gfxt!T123" +} \ No newline at end of file
diff --git a/src/main/resources/moduleConfigCustom.json b/src/main/resources/moduleConfigCustom.json new file mode 100644 index 0000000..61e59f1 --- /dev/null +++ b/src/main/resources/moduleConfigCustom.json
@@ -0,0 +1,39 @@ +[ + { + "name": "Betriebstagebuch", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "http://localhost:8088/elogbookFE", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/m_logbuch_2443636.jpg", + "requiredRole": "elogbook-access" + + }, + { + "name": "Bereitschaftsplanung", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/94-bereitschaftsplan", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/l_bereitschaftsplan_57882047.jpg", + "requiredRole": "planning-access" + }, + { + "name": "Einspeisemanagement", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/20-eisman", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/l_ok_module6.jpg", + "requiredRole": "feedin-management-access" + }, + { + "name": "Geplante Maßnahmen", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/64-geplante-netzmassnahme", + "pictureLink": "https://www.openkonsequenz.de//components/com_flexicontent/librairies/phpthumb/phpThumb.php?src=/medien/cache/main_image/l_ok_module5.jpg", + "requiredRole": "planned-policies-access" + } +]
diff --git a/src/main/resources/moduleConfigDevLocal.json b/src/main/resources/moduleConfigDevLocal.json new file mode 100644 index 0000000..3e4e543 --- /dev/null +++ b/src/main/resources/moduleConfigDevLocal.json
@@ -0,0 +1,39 @@ +[ + { + "name": "Betriebstagebuch", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "http://localhost:4200/", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/m_logbuch_2443636.jpg", + "requiredRole": "elogbook-access" + + }, + { + "name": "Bereitschaftsplanung", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/94-bereitschaftsplan", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/l_bereitschaftsplan_57882047.jpg", + "requiredRole": "planning-access" + }, + { + "name": "Einspeisemanagement", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/20-eisman", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/l_ok_module6.jpg", + "requiredRole": "feedin-management-access" + }, + { + "name": "Geplante Maßnahmen", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/64-geplante-netzmassnahme", + "pictureLink": "https://www.openkonsequenz.de//components/com_flexicontent/librairies/phpthumb/phpThumb.php?src=/medien/cache/main_image/l_ok_module5.jpg", + "requiredRole": "planned-policies-access" + } +]
diff --git a/src/main/resources/moduleConfigDevServer.json b/src/main/resources/moduleConfigDevServer.json new file mode 100644 index 0000000..c9f70ad --- /dev/null +++ b/src/main/resources/moduleConfigDevServer.json
@@ -0,0 +1,39 @@ +[ + { + "name": "Betriebstagebuch", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "http://172.18.22.160:8880/elogbookFE", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/m_logbuch_2443636.jpg", + "requiredRole": "elogbook-access" + + }, + { + "name": "Bereitschaftsplanung", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/94-bereitschaftsplan", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/l_bereitschaftsplan_57882047.jpg", + "requiredRole": "planning-access" + }, + { + "name": "Einspeisemanagement", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/20-eisman", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/l_ok_module6.jpg", + "requiredRole": "feedin-management-access" + }, + { + "name": "Geplante Maßnahmen", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/64-geplante-netzmassnahme", + "pictureLink": "https://www.openkonsequenz.de//components/com_flexicontent/librairies/phpthumb/phpThumb.php?src=/medien/cache/main_image/l_ok_module5.jpg", + "requiredRole": "planned-policies-access" + } +]
diff --git a/src/main/resources/moduleConfigProduction.json b/src/main/resources/moduleConfigProduction.json new file mode 100644 index 0000000..2251e9a --- /dev/null +++ b/src/main/resources/moduleConfigProduction.json
@@ -0,0 +1,39 @@ +[ + { + "name": "Betriebstagebuch", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "http://159.122.103.182/elogbookFE", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/m_logbuch_2443636.jpg", + "requiredRole": "elogbook-access" + + }, + { + "name": "Bereitschaftsplanung", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/94-bereitschaftsplan", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/l_bereitschaftsplan_57882047.jpg", + "requiredRole": "planning-access" + }, + { + "name": "Einspeisemanagement", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/20-eisman", + "pictureLink": "https://www.openkonsequenz.de/medien/cache/main_image/l_ok_module6.jpg", + "requiredRole": "feedin-management-access" + }, + { + "name": "Geplante Maßnahmen", + "cols": 1, + "rows": 1, + "color": "#ffffff", + "link": "https://www.openkonsequenz.de/anwender/11-geplante-projekte/64-geplante-netzmassnahme", + "pictureLink": "https://www.openkonsequenz.de//components/com_flexicontent/librairies/phpthumb/phpThumb.php?src=/medien/cache/main_image/l_ok_module5.jpg", + "requiredRole": "planned-policies-access" + } +]
diff --git a/src/main/webapp/WEB-INF/keycloak.json b/src/main/webapp/WEB-INF/keycloak.json new file mode 100644 index 0000000..40ff32c --- /dev/null +++ b/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,9 @@ +{ + "realm": "elogbook", + "auth-server-url": "http://entjava002:8080/auth", + "ssl-required": "external", + "resource": "elogbook-backend", + "public-client": true, + "enable-cors": true, + "use-resource-role-mappings": true +} \ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/logger.xml b/src/main/webapp/WEB-INF/logger.xml new file mode 100644 index 0000000..a0b8f3b --- /dev/null +++ b/src/main/webapp/WEB-INF/logger.xml
@@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE log4j:configuration PUBLIC + "-//APACHE//DTD LOG4J 1.2//EN" + "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd"> +<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> + + <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> + <param name="Threshold" value="DEBUG"/> + <param name="Target" value="System.out"/> + <layout class="org.apache.log4j.PatternLayout"> + <param name="ConversionPattern" value="[%d{yyyy.MM.dd HH:mm:ss}] [%p] [%c] %m%n"/> + </layout> + </appender> + + <appender name="Socket" class="org.apache.log4j.net.SocketAppender"> + <param name="remoteHost" value="127.0.0.1"/> + <param name="port" value="4560"/> + <layout class="org.apache.log4j.PatternLayout"> + <param name="ConversionPattern" value="[%d{yyyy.MM.dd HH:mm:ss}] [%p] [%c] %m%n"/> + </layout> + </appender> + + <!-- Issue: das Verzeichnis muss existieren ... --> + <appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender"> + <param name="Threshold" value="TRACE"/> + <param name="File" value="${catalina.base}/logs/portal-openk.backend.log"/> + <param name="Append" value="true"/> + <param name="DatePattern" value="'.'yyyy-MM-dd"/> + <layout class="org.apache.log4j.PatternLayout"> + <param name="ConversionPattern" value="[%d{yyyy.MM.dd HH:mm:ss}] [%p] [%c] %m%n"/> + </layout> + </appender> + + <!-- Default Logging configuration beginnend mit org.eclipse (= alle Packages) --> + <category name="org.eclipse"> + <priority value="INFO"/> + <!--<priority value="DEBUG"/> --> + <!--<priority value="ERROR"/> --> + <appender-ref ref="CONSOLE"/> + <!--<appender-ref ref="Socket"/> --> + <!--<appender-ref ref="FILE"/> --> + <!--<appender-ref ref="SYSLOG"/> --> + <appender-ref ref="FILE"/> + </category> + <category name="org.jboss.resteasy"> + <priority value="WARN"/> + <!--<priority value="DEBUG"/> --> + <!--<priority value="ERROR"/> --> + <appender-ref ref="CONSOLE"/> + <!--<appender-ref ref="Socket"/> --> + <!--<appender-ref ref="FILE"/> --> + <!--<appender-ref ref="SYSLOG"/> --> + <appender-ref ref="FILE"/> + </category> + <category name="javax.persistence.Persistence"> + <priority value="INFO"/> + <!--<priority value="DEBUG"/> --> + <!--<priority value="ERROR"/> --> + <appender-ref ref="CONSOLE"/> + <!--<appender-ref ref="Socket"/> --> + <!--<appender-ref ref="FILE"/> --> + <!--<appender-ref ref="SYSLOG"/> --> + <appender-ref ref="FILE"/> + </category> + +</log4j:configuration> \ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..2b6bcdb --- /dev/null +++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,60 @@ +<web-app id="WebApp_ID" version="2.4" + xmlns="http://java.sun.com/xml/ns/j2ee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee + http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> + <display-name>Restful Web Application</display-name> + + <context-param> + <param-name>resteasy.servlet.mapping.prefix</param-name> + <param-value>/rest</param-value> + </context-param> + + <context-param> + <param-name>resteasy.scan</param-name> + <param-value>false</param-value> + </context-param> + + <listener> + <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class> + </listener> + + <servlet> + <servlet-name>Resteasy</servlet-name> + <servlet-class> + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + </servlet-class> + <init-param> + <param-name>javax.ws.rs.Application</param-name> + <param-value>org.eclipse.openk.portal.rest.RestServiceConfiguration</param-value> + </init-param> + </servlet> + + <servlet-mapping> + <servlet-name>Resteasy</servlet-name> + <url-pattern>/rest/*</url-pattern> + </servlet-mapping> + + <servlet> + <servlet-name>log4j-init</servlet-name> + <servlet-class>org.eclipse.openk.portal.common.util.LoggerUtil</servlet-class> + <init-param> + <param-name>log4j-init-file</param-name> + <param-value>WEB-INF/logger.xml</param-value> + </init-param> + <load-on-startup>0</load-on-startup> + </servlet> + + <servlet> + <servlet-name>InitBackendConfig</servlet-name> + <servlet-class>org.eclipse.openk.portal.common.InitBackendConfig</servlet-class> + <load-on-startup>2</load-on-startup> + </servlet> + + <servlet> + <servlet-name>InitUserCacheJob</servlet-name> + <servlet-class>org.eclipse.openk.portal.common.InitUserCacheJob</servlet-class> + <load-on-startup>3</load-on-startup> + </servlet> + +</web-app>
diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html new file mode 100644 index 0000000..97b5341 --- /dev/null +++ b/src/main/webapp/index.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="UTF-8"> +<title>Insert title here</title> +</head> +<body> +it works! +</body> +</html> \ No newline at end of file
diff --git a/src/test/java/org/eclipse/openk/portal/common/BackendConfigTest.java b/src/test/java/org/eclipse/openk/portal/common/BackendConfigTest.java new file mode 100644 index 0000000..64c9ace --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/common/BackendConfigTest.java
@@ -0,0 +1,23 @@ +package org.eclipse.openk.portal.common; + + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class BackendConfigTest { + @Test + public void testConfig() { + BackendConfig bc = BackendConfig.getInstance(); + assertEquals( (int)bc.getInternalSessionLengthMillis(), 3600000 ); + assertEquals( (int)bc.getReloadUsersInSec(), 300 ); + assertEquals( bc.getAuthServerUrl(), "http://entjava002:8080/"); + assertEquals( bc.getKeycloakRealm(), "elogbook"); + assertEquals( bc.getKeycloakClient(),"elogbook-backend"); + assertEquals( bc.getKeycloakAdmin(), "admin"); + assertEquals( bc.getKeycloakPW(), "nimda"); + assertEquals( BackendConfig.getConfigFileName(), "backendConfigDevLocal.json"); + BackendConfig.setConfigFileName("backendConfigProduction.json"); + assertEquals( BackendConfig.getConfigFileName(), "backendConfigProduction.json"); + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/common/GsonUTCDateAdapterTest.java b/src/test/java/org/eclipse/openk/portal/common/GsonUTCDateAdapterTest.java new file mode 100644 index 0000000..9d14aec --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/common/GsonUTCDateAdapterTest.java
@@ -0,0 +1,38 @@ +package org.eclipse.openk.portal.common; + +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import org.junit.Test; + +import java.lang.reflect.Type; +import java.util.Calendar; + +public class GsonUTCDateAdapterTest { + + @Test + public void serializeTest() { + GsonUTCDateAdapter gsonUTCDateAdapter = new GsonUTCDateAdapter(); + Calendar calendar = Calendar.getInstance(); + java.util.Date date = calendar.getTime(); + Type type = new Type() { + @Override + public String getTypeName() { + return null; + } + }; + JsonSerializationContext jsonSerializationContext = new JsonSerializationContext() { + @Override + public JsonElement serialize(Object o) { + return null; + } + + @Override + public JsonElement serialize(Object o, Type type) { + return null; + } + }; + + gsonUTCDateAdapter.serialize(date, type, jsonSerializationContext); + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/common/InitBackendConfigTest.java b/src/test/java/org/eclipse/openk/portal/common/InitBackendConfigTest.java new file mode 100644 index 0000000..d80fbda --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/common/InitBackendConfigTest.java
@@ -0,0 +1,38 @@ +package org.eclipse.openk.portal.common; + +import org.junit.Test; +import org.powermock.reflect.Whitebox; + +public class InitBackendConfigTest { + + private InitBackendConfig initBackendConfig = new InitBackendConfig(); + + @Test + public void testSetConfigFiles() throws Exception { + Whitebox.invokeMethod(initBackendConfig, "setConfigFiles", "DevLocal"); + } + + private void testGeneric(String environment ) throws Exception { + Whitebox.invokeMethod(initBackendConfig, "setConfigFiles", environment); + } + + @Test + public void testCombinations() throws Exception { + + testGeneric("DevLocal"); + testGeneric("DevLocal"); + + testGeneric("DevServer"); + testGeneric("DevServer"); + + testGeneric("Custom"); + testGeneric("Custom"); + + testGeneric(null); + testGeneric(null); + + testGeneric(""); + testGeneric(""); + +} +}
diff --git a/src/test/java/org/eclipse/openk/portal/common/InitUserCacheJobTest.java b/src/test/java/org/eclipse/openk/portal/common/InitUserCacheJobTest.java new file mode 100644 index 0000000..49a010d --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/common/InitUserCacheJobTest.java
@@ -0,0 +1,16 @@ +package org.eclipse.openk.portal.common; + +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.junit.Test; +import javax.servlet.ServletException; + +public class InitUserCacheJobTest extends ResourceLoaderBase { + + @Test + public void testInit() throws ServletException { + InitUserCacheJob job = new InitUserCacheJob(); + job.init(); + // Test only covers Code! + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/common/UserCacheTimerTaskTest.java b/src/test/java/org/eclipse/openk/portal/common/UserCacheTimerTaskTest.java new file mode 100644 index 0000000..4a9290e --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/common/UserCacheTimerTaskTest.java
@@ -0,0 +1,65 @@ +package org.eclipse.openk.portal.common; + +import static junit.framework.TestCase.assertTrue; +import static org.easymock.EasyMock.expect; +import static org.eclipse.openk.portal.common.JsonGeneratorBase.getGson; + +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Type; +import java.util.List; +import org.eclipse.openk.portal.auth2.model.JwtToken; +import org.eclipse.openk.portal.auth2.model.KeyCloakRole; +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; +import org.eclipse.openk.portal.auth2.util.JwtHelper; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.eclipse.openk.portal.viewmodel.UserCache; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.easymock.PowerMock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(JwtHelper.class) +public class UserCacheTimerTaskTest extends ResourceLoaderBase { + + private UserCacheTimerTask task; + + @Before + public void prepareTests() { + task = new UserCacheTimerTask(); + PowerMock.mockStatic(JwtHelper.class); + } + + @Test + public void testGetKeyCloakUsersFromToken() throws Exception { + String json = super.loadStringFromResource("JWTAdmin.json"); + JwtToken jwt = getGson().fromJson(json, JwtToken.class); + + String jsonKeyCloakUser = super.loadStringFromResource("testKeyCloakUsers.json"); + Type listTypeKeyCloakUser = new TypeToken<List<KeyCloakUser>>(){}.getType(); + List<KeyCloakUser> keyCloakUsersList = JsonGeneratorBase.getGson().fromJson(jsonKeyCloakUser, listTypeKeyCloakUser); + keyCloakUsersList.remove(1); + keyCloakUsersList.remove(1); + + String jsonKeyCloakRoles = super.loadStringFromResource("testKeyCloakRoles.json"); + Type listTypeKeyCloakRole = new TypeToken<List<KeyCloakRole>>(){}.getType(); + List<KeyCloakRole> keyCloakRolesList = JsonGeneratorBase.getGson().fromJson(jsonKeyCloakRoles, listTypeKeyCloakRole); + + expect(JwtHelper.login(BackendConfig.getInstance().getKeycloakAdmin(), BackendConfig.getInstance().getKeycloakPW())).andReturn(jwt); + expect(JwtHelper.getUsers(jwt)).andReturn(keyCloakUsersList); + expect(JwtHelper.getRolesForUser(jwt, keyCloakUsersList.get(0).getId())).andReturn(keyCloakRolesList); + + PowerMock.replayAll(); + task.run(); + PowerMock.verifyAll(); + + List<KeyCloakUser> keyCloakUsersResult = UserCache.getInstance().getKeyCloakUsers(); + + assertTrue(keyCloakUsersResult.size() == 1); + assertTrue(keyCloakUsersResult.get(0).getRealmRoles().size() == 8); + assertTrue(keyCloakUsersResult.get(0).getRealmRoles().get(0).equals("elogbook-superuser")); + assertTrue(keyCloakUsersResult.get(0).getRealmRoles().get(6).equals("elogbook-access")); + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/common/util/HashingAlgoTest.java b/src/test/java/org/eclipse/openk/portal/common/util/HashingAlgoTest.java new file mode 100644 index 0000000..699f644 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/common/util/HashingAlgoTest.java
@@ -0,0 +1,17 @@ +package org.eclipse.openk.portal.common.util; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Objects; +import org.junit.Test; + +public class HashingAlgoTest { + @Test + public void testHashIt() { + String hash = HashingAlgo.hashIt("TestMe"); + assertTrue("66d565a2eb74e1a20b6c12bb2cbf84ecaade84ec".equals(hash)); + assertTrue(!Objects.equals(HashingAlgo.hashIt("ThisIsTest"), HashingAlgo.hashIt("thisIsATest"))); + assertNull(HashingAlgo.hashIt(null)); + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/common/util/ResourceLoaderBaseTest.java b/src/test/java/org/eclipse/openk/portal/common/util/ResourceLoaderBaseTest.java new file mode 100644 index 0000000..ac2bbec --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/common/util/ResourceLoaderBaseTest.java
@@ -0,0 +1,15 @@ +package org.eclipse.openk.portal.common.util; + + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class ResourceLoaderBaseTest { + @Test + public void testloadStringFromResourceError() { + ResourceLoaderBase rlb = new ResourceLoaderBase(); + String str = rlb.loadStringFromResource("UNKNOWN_FILE"); + assertEquals(str, ""); + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/controller/BackendControllerTest.java b/src/test/java/org/eclipse/openk/portal/controller/BackendControllerTest.java new file mode 100644 index 0000000..ba61abe --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/controller/BackendControllerTest.java
@@ -0,0 +1,37 @@ +package org.eclipse.openk.portal.controller; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; +import java.util.List; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.eclipse.openk.portal.viewmodel.LoginCredentials; +import org.eclipse.openk.portal.viewmodel.UserAuthentication; +import org.eclipse.openk.portal.viewmodel.UserModule; +import org.eclipse.openk.portal.viewmodel.VersionInfo; +import org.junit.Ignore; +import org.junit.Test; + +public class BackendControllerTest extends ResourceLoaderBase { + + @Test + public void testGetVersionInfo() { + BackendController bec = new BackendController(); + VersionInfo vi = bec.getVersionInfo(); + + String vCurr = getClass().getPackage().getImplementationVersion(); + assertEquals( vi.getBackendVersion(), vCurr ); + } + + @Test + public void getUserModuleList_TemporaryOnly() { + //_fd only temporarily + List<UserModule> modList = new BackendController().getUserModuleList(); + assertTrue( !modList.isEmpty() ); + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/controller/BaseWebServiceTest.java b/src/test/java/org/eclipse/openk/portal/controller/BaseWebServiceTest.java new file mode 100644 index 0000000..f804fe6 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/controller/BaseWebServiceTest.java
@@ -0,0 +1,249 @@ +package org.eclipse.openk.portal.controller; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.lang.annotation.Annotation; +import java.net.URI; +import java.util.Date; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.ws.rs.core.EntityTag; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.Link; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.NewCookie; +import javax.ws.rs.core.Response; +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.exceptions.PortalBadRequest; +import org.eclipse.openk.portal.exceptions.PortalException; +import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +public class BaseWebServiceTest { + private static final org.apache.log4j.Logger EMPTYLOGGER = org.apache.log4j.Logger + .getLogger(BaseWebServiceTest.class.getName()); + + public static class TestWebService extends BaseWebService { + public String sessionId; + public boolean throwUnauthException = false; + + public TestWebService() { + super(EMPTYLOGGER); + } + + protected void assertAndRefreshToken(String sessionId, boolean refresh) throws PortalException { + if (throwUnauthException) { + throw new PortalUnauthorized(); + } else { + this.sessionId = sessionId; + } + } + } + + public static class TestInvokable extends BackendInvokable { + public boolean isInvoked = false; + public PortalException exceptionToThrow = null; + public boolean throwRuntime = false; + public Response response = null; + + @Override + public Response invoke() throws PortalException { + if (exceptionToThrow != null) { + throw exceptionToThrow; + } + if (throwRuntime) { + ((String) null).equals("error"); //NOSONAR + } + isInvoked = true; + return response; + } + } + + @Test + public void testInvokeException() { + TestWebService tws = new TestWebService(); + TestInvokable ti = new TestInvokable(); + + ti.exceptionToThrow = new PortalBadRequest(); + Response ret = tws.invoke("ssess", false, ti); + Assert.assertEquals(ret.getStatus(), Globals.HTTPSTATUS_BAD_REQUEST); + } + + @Test + public void testInvokeRuntimeException() { + TestWebService tws = new TestWebService(); + TestInvokable ti = new TestInvokable(); + + ti.throwRuntime = true; + Response ret = tws.invoke("ssess", false, ti); + assertEquals(ret.getStatus(), Globals.HTTPSTATUS_INTERNAL_SERVER_ERROR); + } + + @Test + public void testUnauthException() { + TestWebService tws = new TestWebService(); + TestInvokable ti = new TestInvokable(); + tws.throwUnauthException = true; + Response ret = tws.invoke("ssess", false, ti); + assertEquals(ret.getStatus(), Globals.HTTPSTATUS_UNAUTHORIZED); + } + + @Test + public void testSecureTypeNone() { + TestWebService tws = new TestWebService(); + TestInvokable ti = new TestInvokable(); + Response responseForTypeNONE = tws.invoke("ssess", false, ti); + assertNull(responseForTypeNONE); + } + + + @Test + public void testInvokation() { + TestWebService tws = new TestWebService(); + TestInvokable ti = new TestInvokable(); + ti.response = new Response() { + @Override + public Object getEntity() { + return null; + } + + @Override + public <T> T readEntity(Class<T> aClass) { + return null; + } + + @Override + public <T> T readEntity(GenericType<T> genericType) { + return null; + } + + @Override + public <T> T readEntity(Class<T> aClass, Annotation[] annotations) { + return null; + } + + @Override + public <T> T readEntity(GenericType<T> genericType, Annotation[] annotations) { + return null; + } + + @Override + public boolean hasEntity() { + return false; + } + + @Override + public boolean bufferEntity() { + return false; + } + + @Override + public void close() { + + } + + @Override + public MediaType getMediaType() { + return null; + } + + @Override + public Locale getLanguage() { + return null; + } + + @Override + public int getLength() { + return 0; + } + + @Override + public Set<String> getAllowedMethods() { + return null; + } + + @Override + public Map<String, NewCookie> getCookies() { + return null; + } + + @Override + public EntityTag getEntityTag() { + return null; + } + + @Override + public Date getDate() { + return null; + } + + @Override + public Date getLastModified() { + return null; + } + + @Override + public URI getLocation() { + return null; + } + + @Override + public Set<Link> getLinks() { + return null; + } + + @Override + public boolean hasLink(String s) { + return false; + } + + @Override + public Link getLink(String s) { + return null; + } + + @Override + public Link.Builder getLinkBuilder(String s) { + return null; + } + + @Override + public int getStatus() { + return 666; + } + + @Override + public StatusType getStatusInfo() { + return null; + } + + @Override + public MultivaluedMap<String, Object> getMetadata() { + return null; + } + + @Override + public MultivaluedMap<String, String> getStringHeaders() { + return null; + } + + @Override + public String getHeaderString(String s) { + return null; + } + }; + + Response ret = tws.invoke("ssess", false, ti); + assertTrue(ti.isInvoked); + assertEquals(tws.sessionId, "ssess"); + assertEquals(ret.getStatus(), 666); + + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/controller/ControllerImplementationsTest.java b/src/test/java/org/eclipse/openk/portal/controller/ControllerImplementationsTest.java new file mode 100644 index 0000000..0445e84 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/controller/ControllerImplementationsTest.java
@@ -0,0 +1,91 @@ +package org.eclipse.openk.portal.controller; + +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.eclipse.openk.portal.exceptions.PortalException; +import org.eclipse.openk.portal.viewmodel.UserModule; +import org.eclipse.openk.portal.viewmodel.VersionInfo; +import org.junit.Before; +import org.junit.Test; +import org.powermock.api.easymock.PowerMock; + +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.TestCase.assertEquals; +import static org.easymock.EasyMock.expect; + + +public class ControllerImplementationsTest extends ResourceLoaderBase { + private BackendController beMock; + @Before + public void prepareTests() { + beMock = PowerMock.createNiceMock(BackendController.class); + } + + @Test + public void testGetUsers() throws PortalException { + List<KeyCloakUser> userList = new ArrayList<>(); + ControllerImplementations.GetUsers controllerImpl = new ControllerImplementations.GetUsers(); + controllerImpl.setModUser("EgalUser"); + controllerImpl.setUserId(14); + + expect(beMock.getUsers()).andReturn(userList); + PowerMock.replay(beMock); + + assertEquals(controllerImpl.invoke().getStatus(), Globals.HTTPSTATUS_OK); + assertEquals(controllerImpl.getModUser(), "EgalUser"); + assertEquals(controllerImpl.getUserId(), 14); + } + + @Test + public void testGetVersionInfo() throws PortalException { + VersionInfo vi = new VersionInfo(); + ControllerImplementations.GetVersionInfo controllerImpl = new ControllerImplementations.GetVersionInfo(beMock); + + expect(beMock.getVersionInfo()).andReturn(vi); + PowerMock.replay(beMock); + + assertEquals(controllerImpl.invoke().getStatus(), Globals.HTTPSTATUS_OK); + } + + @Test + public void testLogOut() throws PortalException { + ControllerImplementations.Logout controllerImpl = new ControllerImplementations.Logout("LogMeOut"); + assertEquals(controllerImpl.invoke().getStatus(), Globals.HTTPSTATUS_OK); + } + + @Test + public void testCheckAuth() throws PortalException { + ControllerImplementations.CheckAuth controllerImpl = new ControllerImplementations.CheckAuth(); + assertEquals(controllerImpl.invoke().getStatus(), Globals.HTTPSTATUS_OK); + } + + @Test + public void testGetUserModulesForUser() throws PortalException { + List<UserModule> userModules = new ArrayList<>(); + ControllerImplementations.GetUserModulesForUser controllerImpl = new ControllerImplementations.GetUserModulesForUser(beMock); + controllerImpl.setModUser("EgalUser"); + + expect(beMock.getUserModuleList()).andReturn(userModules); + PowerMock.replay(beMock); + + assertEquals(controllerImpl.invoke().getStatus(), Globals.HTTPSTATUS_OK); + assertEquals(controllerImpl.getModUser(), "EgalUser"); + } + + @Test + public void testGetUserForRole() throws PortalException { + List<KeyCloakUser> keyCloakUsers = new ArrayList<>(); + String userRole = "theBestRole"; + ControllerImplementations.GetUsersForRole controllerImpl = new ControllerImplementations.GetUsersForRole(beMock, userRole); + controllerImpl.setModUser("EgalUser"); + + expect(beMock.getUsersForRole(userRole)).andReturn(keyCloakUsers); + PowerMock.replay(beMock); + + assertEquals(controllerImpl.invoke().getStatus(), Globals.HTTPSTATUS_OK); + assertEquals(controllerImpl.getModUser(), "EgalUser"); + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/controller/InputValidatorTest.java b/src/test/java/org/eclipse/openk/portal/controller/InputValidatorTest.java new file mode 100644 index 0000000..5a2bfc4 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/controller/InputValidatorTest.java
@@ -0,0 +1,72 @@ +package org.eclipse.openk.portal.controller; + +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.eclipse.openk.portal.exceptions.PortalBadRequest; +import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.junit.Test; +import org.powermock.reflect.Whitebox; + +public class InputValidatorTest extends ResourceLoaderBase { + + // Check Credentials ------------------------------------------------------- + + @Test(expected = PortalUnauthorized.class) + public void testCheckCredentials_Null() throws PortalUnauthorized { + new InputDataValuator().checkCredentials(null); + } + + @Test(expected = PortalUnauthorized.class) + public void testCheckCredentials_Empty() throws PortalUnauthorized { + new InputDataValuator().checkCredentials(""); + } + + @Test(expected = PortalUnauthorized.class) + public void testCheckCredentials_TooLong() throws PortalUnauthorized { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < Globals.MAX_CREDENTIALS_LENGTH; i++) { + sb.append("W"); + } + new InputDataValuator().checkCredentials(sb.toString()); + + } + + @Test(expected = PortalUnauthorized.class) + public void testCheckCredentials_Invalid() throws PortalUnauthorized { + new InputDataValuator().checkCredentials("{\"abc\":\"123\"}"); + } + + @Test(expected = PortalUnauthorized.class) + public void testCheckCredentials_InvalidNoJson() throws PortalUnauthorized { + new InputDataValuator().checkCredentials("123"); + } + + @Test(expected = PortalUnauthorized.class) + public void testCheckCredentials_tooLong() throws PortalUnauthorized { + StringBuilder sb = new StringBuilder(Globals.MAX_CREDENTIALS_LENGTH + 1); + for (int i = 0; i < Globals.MAX_CREDENTIALS_LENGTH + 1; i++) { + sb.append("@"); + } + new InputDataValuator().checkCredentials(sb.toString()); + + } + + @Test + public void checkWhitelistChars_ok() throws Exception { + callWhitelistCheck("AaBbCcäÄöÖüÜß ?0123456789(). _+ ,-:;=!§%&/'#<>\""); + } + + @Test(expected = PortalBadRequest.class) + public void checkWhitelistChars_nok() throws Exception { + callWhitelistCheck(null); + callWhitelistCheck(""); + callWhitelistCheck("AaBbCc.,{}"); + } + + private void callWhitelistCheck(String tst) throws Exception { + InputDataValuator idv = new InputDataValuator(); + Whitebox.invokeMethod(idv, "checkWhitelistChars", tst, false); + } + + +}
diff --git a/src/test/java/org/eclipse/openk/portal/controller/ResponseBuilderWrapperTest.java b/src/test/java/org/eclipse/openk/portal/controller/ResponseBuilderWrapperTest.java new file mode 100644 index 0000000..32b26be --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/controller/ResponseBuilderWrapperTest.java
@@ -0,0 +1,31 @@ +package org.eclipse.openk.portal.controller; + + +import static org.junit.Assert.assertEquals; + +import javax.ws.rs.core.Response; +import org.eclipse.openk.portal.common.Globals; +import org.eclipse.openk.portal.exceptions.PortalException; +import org.eclipse.openk.portal.exceptions.PortalInternalServerError; +import org.junit.Test; + + +public class ResponseBuilderWrapperTest { + @Test + public void testGetResponseBuilder() throws PortalInternalServerError { + String json = "{ 'ret' : 'OK' }"; + Response.ResponseBuilder rb = ResponseBuilderWrapper.INSTANCE.getResponseBuilder( json ); + Response resp = rb.build(); + assertEquals(resp.getStatus(), Globals.HTTPSTATUS_OK ); + } + + @Test + public void testBuildOkResponse() throws PortalException { + String json = "{ 'test' : 'Value' }"; + Response resp = ResponseBuilderWrapper.INSTANCE.buildOKResponse( json ); + assertEquals( resp.getStatus(), Globals.HTTPSTATUS_OK ); + + resp = ResponseBuilderWrapper.INSTANCE.buildOKResponse(json, "ssess"); + assertEquals( resp.getStatus(), Globals.HTTPSTATUS_OK); + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/controller/TokenManagerTest.java b/src/test/java/org/eclipse/openk/portal/controller/TokenManagerTest.java new file mode 100644 index 0000000..559fed1 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/controller/TokenManagerTest.java
@@ -0,0 +1,95 @@ +package org.eclipse.openk.portal.controller; + +import org.eclipse.openk.portal.auth2.model.JwtToken; +import org.eclipse.openk.portal.common.BackendConfig; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.eclipse.openk.portal.exceptions.PortalUnauthorized; +import org.junit.Before; +import org.junit.Test; +import org.powermock.reflect.Whitebox; + +import java.util.HashMap; +import static org.junit.Assert.*; + +public class TokenManagerTest extends ResourceLoaderBase { + + @Before + public void cleanUp() { + TokenManager sessione = TokenManager.getInstance(); + HashMap<String, TokenManager.SessionItem> regMap = Whitebox.getInternalState(sessione, "registry"); + regMap.clear(); + } + + @Test + public void testRegisterNewSession() { + final int COUNT = 1000; + + for (int i = 0; i < COUNT; i++) { + TokenManager.getInstance().registerNewSession(createJWT( "T"+i )); + } + } + + + @Test(expected = PortalUnauthorized.class) + public void testRefreshStatusIsAlive() throws InterruptedException, PortalUnauthorized { + TokenManager sessione = TokenManager.getInstance(); + JwtToken specialToken = createJWT(null); + + long timeNow = System.currentTimeMillis(); + sessione.registerNewSession(createJWT("HUGO1")); + sessione.registerNewSession(specialToken); + sessione.registerNewSession(createJWT("HUGO3")); + + HashMap<String, TokenManager.SessionItem> regMap = Whitebox.getInternalState(sessione, "registry"); + + assertEquals(regMap.size(), 3); + assertTrue(regMap.containsKey("HUGO1")); + assertTrue(regMap.containsKey(specialToken.getAccessToken())); + assertTrue(regMap.containsKey("HUGO3")); + + regMap.remove(specialToken.getAccessToken()); + regMap.put(specialToken.getAccessToken(), new TokenManager.SessionItem(timeNow - BackendConfig.getInstance().getInternalSessionLengthMillis() - 1)); + regMap.get(specialToken.getAccessToken()).setJwtToken(specialToken); + regMap.remove("HUGO3"); + regMap.put("HUGO3", null); + + Thread.sleep(50); // NOSONAR // LOCK is held + + TokenManager.getInstance().refreshSessionIsAlive("HUGO1", true); + + // create Time stays the same + TokenManager.SessionItem sit1 = regMap.get("HUGO1"); + assertTrue(sit1.getSessionLastAccessTime() > sit1.getSessionCreationTime()); + + sit1.setSessionCreationTime(sit1.getSessionLastAccessTime()-200); + assertEquals( sit1.getSessionCreationTime()+200, sit1.getSessionLastAccessTime()); + sit1.setUser(null); + assertNull(sit1.getUser()); + assertEquals(sit1.getSessionId(), "HUGO1"); + sit1.setCookieToken("CaptainCookie"); + assertEquals(sit1.getCookieToken(), "CaptainCookie"); + + TokenManager.getInstance().logout("HUGO1"); + assertEquals(regMap.size(), 2); + TokenManager.getInstance().logout( "FAKE"); + assertEquals(regMap.size(), 2); + + + // session out of time + TokenManager.getInstance().refreshSessionIsAlive(specialToken.getAccessToken(), true); + // fails with PortalUnauthorized + } + + private JwtToken createJWT(String accessToken ) { + String json = super.loadStringFromResource("JWTAdmin.json"); + JwtToken jwt = JsonGeneratorBase.getGson().fromJson(json, JwtToken.class); + + if( accessToken != null ) { + jwt.setAccessToken(accessToken); + } + return jwt; + } + + +}
diff --git a/src/test/java/org/eclipse/openk/portal/exceptions/PortalExceptionMapperTest.java b/src/test/java/org/eclipse/openk/portal/exceptions/PortalExceptionMapperTest.java new file mode 100644 index 0000000..65fa726 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/exceptions/PortalExceptionMapperTest.java
@@ -0,0 +1,44 @@ +package org.eclipse.openk.portal.exceptions; + + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.eclipse.openk.portal.viewmodel.ErrorReturn; +import org.junit.Test; + +public class PortalExceptionMapperTest extends ResourceLoaderBase { + @Test + public void testToJson() { + String json = PortalExceptionMapper.toJson(new PortalNotFound("lalilu")); + + ErrorReturn er = JsonGeneratorBase.getGson().fromJson(json, ErrorReturn.class); + assertEquals(er.getErrorCode(), 404); + assertTrue(er.getErrorText().equals("lalilu")); + } + + @Test + public void testUnknownErrorToJson() { + String json = PortalExceptionMapper.unknownErrorToJson(); + + ErrorReturn er = JsonGeneratorBase.getGson().fromJson(json, ErrorReturn.class); + assertEquals(er.getErrorCode(), 500); + } + + @Test + public void testGeneralOKJson() { + String ok = PortalExceptionMapper.getGeneralOKJson(); + assertTrue("{\"ret\":\"OK\"}".equals(ok)); + } + + @Test + public void testGeneralErrorJson() { + String nok = PortalExceptionMapper.getGeneralErrorJson(); + assertTrue("{\"ret\":\"NOK\"}".equals(nok)); + } + + + +}
diff --git a/src/test/java/org/eclipse/openk/portal/exceptions/PortalExceptionsTest.java b/src/test/java/org/eclipse/openk/portal/exceptions/PortalExceptionsTest.java new file mode 100644 index 0000000..7411aec --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/exceptions/PortalExceptionsTest.java
@@ -0,0 +1,29 @@ +package org.eclipse.openk.portal.exceptions; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.openk.portal.common.Globals; +import org.junit.Test; + +public class PortalExceptionsTest { + + @Test + public void testConstructors() { + assertEquals(new PortalBadRequest().getHttpStatus(), Globals.HTTPSTATUS_BAD_REQUEST); + assertEquals(new PortalForbidden().getHttpStatus(), Globals.HTTPSTATUS_FORBIDDEN); + assertEquals(new PortalInternalServerError(null, null).getHttpStatus(), Globals.HTTPSTATUS_INTERNAL_SERVER_ERROR); + assertEquals(new PortalNotFound().getHttpStatus(), Globals.HTTPSTATUS_NOT_FOUND); + assertEquals(new PortalUnauthorized().getHttpStatus(), Globals.HTTPSTATUS_UNAUTHORIZED); + } + + + @Test + public void testConstructors2() { + final String extext = "ExText"; + assertEquals(new PortalBadRequest(extext).getMessage(), extext); + assertEquals(new PortalForbidden(extext).getMessage(), extext); + assertEquals(new PortalInternalServerError(extext).getMessage(), extext); + assertEquals(new PortalNotFound(extext).getMessage(), extext); + assertEquals(new PortalUnauthorized(extext).getMessage(), extext); + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/viewmodel/ErrorReturnTest.java b/src/test/java/org/eclipse/openk/portal/viewmodel/ErrorReturnTest.java new file mode 100644 index 0000000..9fcfdb0 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/viewmodel/ErrorReturnTest.java
@@ -0,0 +1,30 @@ +package org.eclipse.openk.portal.viewmodel; + +import static org.eclipse.openk.portal.common.JsonGeneratorBase.getGson; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.junit.Test; + +public class ErrorReturnTest extends ResourceLoaderBase { + // IMPORTANT TEST!!! + // Make sure, our Interface produces a DEFINED Json! + // Changes in the interface will HOPEFULLY crash here!!! + + @Test + public void TestStructureAgainstJson() { + String json = super.loadStringFromResource("testErrorReturn.json"); + ErrorReturn errRet = getGson().fromJson(json, ErrorReturn.class); + assertFalse(errRet.getErrorText().isEmpty()); + assertEquals(errRet.getErrorCode(), 999); + } + + @Test + public void TestSetters() { + ErrorReturn errRet = new ErrorReturn(); + errRet.setErrorCode(1); + errRet.setErrorText("bla bla"); + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/viewmodel/GeneralReturnItemTest.java b/src/test/java/org/eclipse/openk/portal/viewmodel/GeneralReturnItemTest.java new file mode 100644 index 0000000..570e89b --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/viewmodel/GeneralReturnItemTest.java
@@ -0,0 +1,31 @@ +package org.eclipse.openk.portal.viewmodel; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.junit.Test; + +public class GeneralReturnItemTest extends ResourceLoaderBase { + // IMPORTANT TEST!!! + // Make sure, our Interface produces a DEFINED Json! + // Changes in the interface will HOPEFULLY crash here!!! + + @Test + public void TestStructureAgainstJson() { + String json = super.loadStringFromResource("testGeneralReturnItem.json"); + GeneralReturnItem gRRet = JsonGeneratorBase.getGson().fromJson(json, GeneralReturnItem.class); + assertEquals(gRRet.getRet(), "It works!"); + } + + @Test + public void TestSetters() { + GeneralReturnItem gri = new GeneralReturnItem("firstStrike"); + assertTrue("firstStrike".equals(gri.getRet())); + gri.setRet("Retour"); + assertTrue("Retour".equals(gri.getRet())); + + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/viewmodel/LoginCredentialsTest.java b/src/test/java/org/eclipse/openk/portal/viewmodel/LoginCredentialsTest.java new file mode 100644 index 0000000..1d82045 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/viewmodel/LoginCredentialsTest.java
@@ -0,0 +1,29 @@ +package org.eclipse.openk.portal.viewmodel; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.junit.Test; + +public class LoginCredentialsTest extends ResourceLoaderBase { + + @Test + public void testStructureAgainstJson() { + String json = super.loadStringFromResource("testLoginCredentials.json"); + LoginCredentials lc = JsonGeneratorBase.getGson().fromJson(json, LoginCredentials.class); + assertEquals(lc.getUserName(), "Carlo"); + assertEquals(lc.getPassword(), "Cottura"); + } + + @Test + public void testSetters() { + LoginCredentials lc = new LoginCredentials(); + lc.setPassword("pwd"); + assertTrue("pwd".equals(lc.getPassword())); + lc.setUserName("usr"); + assertTrue("usr".equals(lc.getUserName())); + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/viewmodel/UserAuthenticationTest.java b/src/test/java/org/eclipse/openk/portal/viewmodel/UserAuthenticationTest.java new file mode 100644 index 0000000..c476f36 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/viewmodel/UserAuthenticationTest.java
@@ -0,0 +1,36 @@ +package org.eclipse.openk.portal.viewmodel; + + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.junit.Test; + +public class UserAuthenticationTest extends ResourceLoaderBase { + + @Test + public void testStructureAgainstJson() { + String json = super.loadStringFromResource("testUserAuthentication.json"); + UserAuthentication ua = JsonGeneratorBase.getGson().fromJson(json, UserAuthentication.class); + assertTrue(ua.getId() == 1 ); + assertTrue(ua.getUsername().equals("Pedro")); + assertTrue(ua.getPassword().equals("pwd")); + assertTrue(ua.getName().equals("Pedro Pepito Sanchez")); + assertFalse(ua.isSpecialUser()); + assertTrue(ua.isSelected()); + } + + @Test + public void testSetters() { + UserAuthentication ua = new UserAuthentication(); + ua.setId(1); + ua.setName("Vamos-Namos"); + ua.setPassword("passoporto"); + ua.setUsername("VNAMOS"); + ua.setSpecialUser(true); + ua.setSelected(true); + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/viewmodel/UserCacheTest.java b/src/test/java/org/eclipse/openk/portal/viewmodel/UserCacheTest.java new file mode 100644 index 0000000..32fff14 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/viewmodel/UserCacheTest.java
@@ -0,0 +1,33 @@ +package org.eclipse.openk.portal.viewmodel; + + +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.eclipse.openk.portal.auth2.model.KeyCloakUser; +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.junit.Test; + +public class UserCacheTest extends ResourceLoaderBase { + // IMPORTANT TEST!!! + // Make sure, our Interface produces a DEFINED Json! + // Changes in the interface will HOPEFULLY crash here!!! + + @Test + public void testStructureAgainstJsonAndSettersAndGetters() { + String json = super.loadStringFromResource("testKeyCloakUsers.json"); + KeyCloakUser[] keyCloakUsers = JsonGeneratorBase.getGson().fromJson(json, KeyCloakUser[].class); + List<KeyCloakUser> keyCloakUsersList = new ArrayList<>(Arrays.asList(keyCloakUsers)); + UserCache uc = UserCache.getInstance(); + uc.setKeyCloakUsers(keyCloakUsersList); + + assertTrue(keyCloakUsers.length == 3); + assertTrue(uc.getKeyCloakUsers().get(0).getFirstName().equals("Administrator")); + assertTrue(uc.getKeyCloakUsers().get(2).getUsername().equals("otto")); + + } +}
diff --git a/src/test/java/org/eclipse/openk/portal/viewmodel/UserModuleTest.java b/src/test/java/org/eclipse/openk/portal/viewmodel/UserModuleTest.java new file mode 100644 index 0000000..3f27387 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/viewmodel/UserModuleTest.java
@@ -0,0 +1,25 @@ +package org.eclipse.openk.portal.viewmodel; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class UserModuleTest { + + @Test + public void testModuleConfigProduction() { + UserModule[] um = UserModule.getInstance(); + assertEquals( um[0].getModuleName(), "Betriebstagebuch"); + assertEquals( um[0].getColor(), "#ffffff"); + assertEquals( (long)um[0].getCols(), 1); + assertEquals( (long)um[0].getRows(), 1); + assertEquals( um[0].getLink(), "http://localhost:4200/"); + assertEquals( um[0].getPictureLink(), "https://www.openkonsequenz.de/medien/cache/main_image/m_logbuch_2443636.jpg"); + assertEquals( um[0].getRequiredRole(), "elogbook-access"); + + assertEquals( UserModule.getConfigFileName(), "moduleConfigDevLocal.json"); + UserModule.setConfigFileName("moduleConfigDevLocal.json"); + assertEquals( UserModule.getConfigFileName(), "moduleConfigDevLocal.json"); + } + +}
diff --git a/src/test/java/org/eclipse/openk/portal/viewmodel/VersionInfoTest.java b/src/test/java/org/eclipse/openk/portal/viewmodel/VersionInfoTest.java new file mode 100644 index 0000000..dba14f8 --- /dev/null +++ b/src/test/java/org/eclipse/openk/portal/viewmodel/VersionInfoTest.java
@@ -0,0 +1,30 @@ +package org.eclipse.openk.portal.viewmodel; + + +import static org.junit.Assert.assertTrue; + +import org.eclipse.openk.portal.common.JsonGeneratorBase; +import org.eclipse.openk.portal.common.util.ResourceLoaderBase; +import org.junit.Test; + +public class VersionInfoTest extends ResourceLoaderBase { + // IMPORTANT TEST!!! + // Make sure, our Interface produces a DEFINED Json! + // Changes in the interface will HOPEFULLY crash here!!! + + @Test + public void testStructureAgainstJson() { + String json = super.loadStringFromResource("VersionInfo.json"); + VersionInfo vi = JsonGeneratorBase.getGson().fromJson(json, VersionInfo.class); + + assertTrue(vi.getBackendVersion().equals("0x.0x.xx")); + } + + @Test + public void testSetters() { + VersionInfo vi = new VersionInfo(); + + vi.setBackendVersion("222"); + } + +}
diff --git a/src/test/resources/JWTAdmin.json b/src/test/resources/JWTAdmin.json new file mode 100644 index 0000000..dda65c5 --- /dev/null +++ b/src/test/resources/JWTAdmin.json
@@ -0,0 +1,8 @@ +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJodVl0eVByUEVLQ1phY3FfMW5sOGZscENETnFHdmZEZHctYUxGQXNoWHZVIn0.eyJqdGkiOiI4ZmY5NTlhZC02ODQ1LTRlOGEtYjRiYi02ODQ0YjAwMjU0ZjgiLCJleHAiOjE1MDY2MDA0NTAsIm5iZiI6MCwiaWF0IjoxNTA2NjAwMTUwLCJpc3MiOiJodHRwOi8vZW50amF2YTAwMjo4MDgwL2F1dGgvcmVhbG1zL2Vsb2dib29rIiwiYXVkIjoiZWxvZ2Jvb2stYmFja2VuZCIsInN1YiI6IjM1OWVmOWM5LTc3ZGYtNGEzZC1hOWM5LWY5NmQ4MzdkMmQ1NyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImVsb2dib29rLWJhY2tlbmQiLCJhdXRoX3RpbWUiOjAsInNlc3Npb25fc3RhdGUiOiI5NjVmNzM1MS0yZThiLTQ1MjgtOWYzZC1lZTYyODNhOTViMTYiLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImVsb2dib29rLXN1cGVydXNlciIsImVsb2dib29rLW5vcm1hbHVzZXIiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InJlYWxtLW1hbmFnZW1lbnQiOnsicm9sZXMiOlsidmlldy11c2VycyIsInF1ZXJ5LWdyb3VwcyIsInF1ZXJ5LXVzZXJzIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJuYW1lIjoiQWRtaW5pc3RyYXRvciBBZG1pbmlzdHJhdG93aWNoIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiYWRtaW4iLCJnaXZlbl9uYW1lIjoiQWRtaW5pc3RyYXRvciIsImZhbWlseV9uYW1lIjoiQWRtaW5pc3RyYXRvd2ljaCIsImVtYWlsIjoic2VyZ2VqLmtlcm5AcHRhLmRlIiwicm9sZXN0ZXN0IjoiW2Vsb2dib29rLXN1cGVydXNlciwgZWxvZ2Jvb2stbm9ybWFsdXNlciwgdW1hX2F1dGhvcml6YXRpb24sIG9mZmxpbmVfYWNjZXNzLCB1bWFfYXV0aG9yaXphdGlvbiwgZWxvZ2Jvb2stbm9ybWFsdXNlcl0ifQ.o94Bl43oqyLNzZRABvIq9z-XI8JQjqj2FSDdUUEZGZPTN4uwD5fyi0sONbDxmTFvgWPh_8ZhX6tlDGiupVDBY4eRH43Eettm-t4CDauL7FzB3w3dDPFMB5DhP4rrpk_kATwnY2NKLRbequnh8Z6wLXjcmQNLgrgknXB_gogWAqH29dqKexwceMNIbq-kjaeLsmHSXM9TE9q7_Ln9el04OlkpOVspVguedfINcNFg0DmYLJWyD2ORkOHLmYigN6YnyB9P2NFOnKGlLuQ87GjosI00zBniRGi3PhE9NGd51Qggdbcsm0aM8GiMaZ7SO5i8iQWL10TRFRFyTEfy6hSO8g", + "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJodVl0eVByUEVLQ1phY3FfMW5sOGZscENETnFHdmZEZHctYUxGQXNoWHZVIn0.eyJqdGkiOiJlZmNmNzExNS04YzRiLTQzZmQtOGM0ZS0xNjVhYTVmM2ZhZDEiLCJleHAiOjE1MDY2MDE5NTAsIm5iZiI6MCwiaWF0IjoxNTA2NjAwMTUwLCJpc3MiOiJodHRwOi8vZW50amF2YTAwMjo4MDgwL2F1dGgvcmVhbG1zL2Vsb2dib29rIiwiYXVkIjoiZWxvZ2Jvb2stYmFja2VuZCIsInN1YiI6IjM1OWVmOWM5LTc3ZGYtNGEzZC1hOWM5LWY5NmQ4MzdkMmQ1NyIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJlbG9nYm9vay1iYWNrZW5kIiwiYXV0aF90aW1lIjowLCJzZXNzaW9uX3N0YXRlIjoiOTY1ZjczNTEtMmU4Yi00NTI4LTlmM2QtZWU2MjgzYTk1YjE2IiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImVsb2dib29rLXN1cGVydXNlciIsImVsb2dib29rLW5vcm1hbHVzZXIiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InJlYWxtLW1hbmFnZW1lbnQiOnsicm9sZXMiOlsidmlldy11c2VycyIsInF1ZXJ5LWdyb3VwcyIsInF1ZXJ5LXVzZXJzIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19fQ.rN1f4h9t1-sHW2EXpvYs3Spo8Zxe1-qNuLWCgOwD6E3l_zDwdHOlPxJwlPLwweQ2uuHi1-blk80OdgoDueDslE3tCdkyg_5lXOXG_jVwqgIF8qP2KTlz9gjhJBwBJ94YsHYV2wwy8jvTmUk108FVzEYBvAHL7KMzoD-BJ_4QxLhLuUvhO7I2-xP9sNRnUG_4xOrXl22WhQQVNvWBWL076TOSdBsno8-1oh4zWrXsbRa_iA1GyDQ_QM5Cpf11WE6tfvTDJsEHT_6GBQ8qz8FWSh4P_YtVDTOZZhDbbdddFeZPnQdxkLWXBhpD_jw8JuuE1qR_rAUytWdJpSjz2V90mQ", + "token_type": "bearer", + "session_state": "965f7351-2e8b-4528-9f3d-ee6283a95b16", + "expires_in": 300, + "refresh_expires_in": 1800 +}
diff --git a/src/test/resources/VersionInfo.json b/src/test/resources/VersionInfo.json new file mode 100644 index 0000000..35510d9 --- /dev/null +++ b/src/test/resources/VersionInfo.json
@@ -0,0 +1,3 @@ +{ + "backendVersion": "0x.0x.xx" +} \ No newline at end of file
diff --git a/src/test/resources/testErrorReturn.json b/src/test/resources/testErrorReturn.json new file mode 100644 index 0000000..f5540af --- /dev/null +++ b/src/test/resources/testErrorReturn.json
@@ -0,0 +1,4 @@ +{ + "errorText": "TESTAT", + "errorCode": 999 +}
diff --git a/src/test/resources/testGeneralReturnItem.json b/src/test/resources/testGeneralReturnItem.json new file mode 100644 index 0000000..34f9d39 --- /dev/null +++ b/src/test/resources/testGeneralReturnItem.json
@@ -0,0 +1,3 @@ +{ + "ret" : "It works!" +} \ No newline at end of file
diff --git a/src/test/resources/testKeyCloakRoles.json b/src/test/resources/testKeyCloakRoles.json new file mode 100644 index 0000000..04088f1 --- /dev/null +++ b/src/test/resources/testKeyCloakRoles.json
@@ -0,0 +1,70 @@ +[ + { + "id": "e423626e-4616-45b7-9c3d-10a7f0acab8c", + "name": "elogbook-superuser", + "description": "Darf sehr sehr viel", + "scopeParamRequired": false, + "composite": true, + "clientRole": false, + "containerId": "elogbook" + }, + { + "id": "7a145be5-20ba-4992-ad54-17c28d0bc0f9", + "name": "feedin-management-access", + "scopeParamRequired": false, + "composite": false, + "clientRole": false, + "containerId": "elogbook" + }, + { + "id": "b1cf034b-bce3-4d29-9e9d-692bf420ce83", + "name": "planned-policies-access", + "scopeParamRequired": false, + "composite": false, + "clientRole": false, + "containerId": "elogbook" + }, + { + "id": "baf44fc2-7888-4888-beaa-79288e9268a0", + "name": "planning-access", + "scopeParamRequired": false, + "composite": false, + "clientRole": false, + "containerId": "elogbook" + }, + { + "id": "b20abd6d-f202-41d5-91e2-f3e8266bd1fb", + "name": "offline_access", + "description": "${role_offline-access}", + "scopeParamRequired": true, + "composite": false, + "clientRole": false, + "containerId": "elogbook" + }, + { + "id": "173ed3dd-7c83-4202-bec8-c2f2ab9919fc", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "scopeParamRequired": false, + "composite": false, + "clientRole": false, + "containerId": "elogbook" + }, + { + "id": "384e7a68-8e70-41aa-bbbd-1a0ffb293335", + "name": "elogbook-access", + "scopeParamRequired": false, + "composite": false, + "clientRole": false, + "containerId": "elogbook" + }, + { + "id": "6b8d2da8-220c-4f83-8e15-889004e66359", + "name": "elogbook-normaluser", + "description": "Darf vieles, aber nicht alles", + "scopeParamRequired": false, + "composite": false, + "clientRole": false, + "containerId": "elogbook" + } +]
diff --git a/src/test/resources/testKeyCloakUsers.json b/src/test/resources/testKeyCloakUsers.json new file mode 100644 index 0000000..c590535 --- /dev/null +++ b/src/test/resources/testKeyCloakUsers.json
@@ -0,0 +1,90 @@ +[ + { + "id": "359ef9c9-77df-4a3d-a9c9-f96d837d2d57", + "createdTimestamp": 1501594173784, + "username": "admin", + "enabled": true, + "totp": false, + "emailVerified": false, + "firstName": "Administrator", + "lastName": "Administratowich", + "realmRoles": [ + "elogbook-superuser", + "elogbook_access", + "feedin_management_access", + "planned_policies_access", + "offline_access", + "uma_authorization", + "planning_access", + "elogbook-normaluser" + ], + "disableableCredentialTypes": [ + "password" + ], + "requiredActions": [], + "access": { + "manageGroupMembership": false, + "view": true, + "mapRoles": false, + "impersonate": false, + "manage": false + } + }, + { + "id": "c4b78aa7-91d2-45d7-8ca3-163156d9ee40", + "createdTimestamp": 1501594239066, + "username": "hugo", + "enabled": true, + "totp": false, + "emailVerified": false, + "firstName": "Hugo", + "lastName": "Boss", + "realmRoles": [ + "elogbook_access", + "feedin_management_access", + "planned_policies_access", + "offline_access", + "uma_authorization", + "planning_access", + "elogbook-normaluser" + ], + "disableableCredentialTypes": [ + "password" + ], + "requiredActions": [], + "access": { + "manageGroupMembership": false, + "view": true, + "mapRoles": false, + "impersonate": false, + "manage": false + } + }, + { + "id": "c2e9d7ae-2bfa-4578-b09e-f5dc5f09a879", + "createdTimestamp": 1501594273661, + "username": "otto", + "enabled": true, + "totp": false, + "emailVerified": false, + "firstName": "Otto", + "lastName": "Normalverbraucher", + "realmRoles": [ + "elogbook_access", + "offline_access", + "uma_authorization", + "elogbook-normaluser" + ], + "disableableCredentialTypes": [ + "password" + ], + "requiredActions": [], + "access": { + "manageGroupMembership": false, + "view": true, + "mapRoles": false, + "impersonate": false, + "manage": false + } + } +] \ No newline at end of file
diff --git a/src/test/resources/testLoginCredentials.json b/src/test/resources/testLoginCredentials.json new file mode 100644 index 0000000..88974c6 --- /dev/null +++ b/src/test/resources/testLoginCredentials.json
@@ -0,0 +1,4 @@ +{ + "userName": "Carlo", + "password": "Cottura" +} \ No newline at end of file
diff --git a/src/test/resources/testUserAuthentication.json b/src/test/resources/testUserAuthentication.json new file mode 100644 index 0000000..2cdef21 --- /dev/null +++ b/src/test/resources/testUserAuthentication.json
@@ -0,0 +1,8 @@ +{ + "id": 1, + "selected": true, + "username": "Pedro", + "password": "pwd", + "name": "Pedro Pepito Sanchez", + "specialUser": false +}