Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade SpringBoot 2 to SpringBoot 3 (javax -> jakarta) #1

Merged
merged 19 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
92ac5c3
Finished test setup description and fixed small bug when users do not…
Snorzze Oct 5, 2023
42e2d84
Major Upgrade Spring 2.x -> 3.x done
Snorzze Oct 10, 2023
e3bbd8f
Adjust frontend to backend upgrade (spring boot 3.x)
Snorzze Oct 10, 2023
9b3161b
Merge branch 'main' into major-upgrade
Snorzze Oct 10, 2023
944c38a
Updated README with local development instructions
Snorzze Oct 10, 2023
fbcc1e9
Changing version to 2.0.0-SNAPSHOT. Improved authority mapping,
Snorzze Oct 10, 2023
138ff00
Deleted keycloakPrincipal as for now on only OidcUser is used
Snorzze Oct 10, 2023
223d03f
Don't scan too much for tests, which do not require database or keycloak
rzo1 Oct 10, 2023
316d4fa
Fix initial Hibernate Schema Generation after SpringBoot 3 Upgrade (F…
rzo1 Oct 10, 2023
7fe4cfa
Adds GitHub actions script to run a Maven build
rzo1 Oct 10, 2023
43492a1
Adds missing license header
rzo1 Oct 10, 2023
5b983cf
Updated patch levels, and vulnerabilities (npm audit fix)
Snorzze Oct 10, 2023
9db8749
Merge remote-tracking branch 'origin/major-upgrade' into major-upgrade
Snorzze Oct 10, 2023
58466d1
Updated dev libraries (major & minor)
Snorzze Oct 10, 2023
a463ef3
Updated libraries (major & minor) which do not have problems
Snorzze Oct 10, 2023
fd76645
Updated libraries (major & minor) which were not found by npm-check p…
Snorzze Oct 10, 2023
315e73f
Updated last library vuetify (fixes #5 - thx @rzo1)
Snorzze Oct 10, 2023
fd78187
Removes Navbar Entry for Hilfe
rzo1 Oct 10, 2023
1ac8f8f
Minor fixes in README.md
rzo1 Oct 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: CI Main

on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v1
with:
java-version: '17'

- name: Cache Maven packages
uses: actions/cache@v2
with:
path: ~/.m2
key: ${{ runner.os }}-main-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-main-m2

- name: Run CI @ Backend
run: cd hhn-helpdesk-backend && mvn clean verify
env:
MAVEN_OPTS: -Xmx2048m
75 changes: 75 additions & 0 deletions hhn-helpdesk-backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Local Development
## Keycloak
### Installation
1. [Install docker](https://docs.docker.com/engine/install/)
2. [Start local keycloak as docker container](https://www.keycloak.org/getting-started/getting-started-docker)
- Version should match the `keycloak.version` inside [pom.xml](pom.xml)
- Be sure **not** to use port 8080
```bash
docker run --name keycloak-local -p 8888:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:22.0.4 start-dev
```

### Configuration
1. Go to http://localhost:8888, login with `admin:admin` and create the following realms
rzo1 marked this conversation as resolved.
Show resolved Hide resolved
- `helpdesk`
- `institution`

#### Institution Realm Configuration
rzo1 marked this conversation as resolved.
Show resolved Hide resolved
1. Create the following users
rzo1 marked this conversation as resolved.
Show resolved Hide resolved
- Required user actions: `None`
- Username: `example_user1`, `example_user2`, `...`
- Email: `[email protected]`, `...`
- Email verified: `True`
- First and Last name: `User1 Example`, `...`

#### Helpdesk Realm Configuration
1. Create a new realm role `HHN_HELPDESK_ADMIN`
2. Create new OpenID Connect client for the helpdesk realm
- Client ID: `helpdesk_user`
- Name: `Helpdesk User Client`
- Client authentication: `True`
- Authorization: `False`
- Authentication Flow: Check only `Standard Flow` and turn everything else off
- Valid redirect URIs: `http://localhost:3000/login/oauth2/code/keycloak`
- Leave everything else blank
3. Go to Credentials and copy client secret into [application.properties](src/main/resources/application.properties) as value for `spring.security.oauth2.client.registration.keycloak.client-secret`
4. Go to client scopes, choose `helpdesk_user-dedicated`, and configure a new predefined mapper from type "realm roles"
- Add to ID token: `False`
- Add to access token: `False`
- Add to userinfo: `True`
5. Create user `example_admin`, assign the role `HHN_HELPDESK_ADMIN` in the Role mapping tab (after the creation), and set the password to `example_admin` by pressing "Set password" in the credentials tab (disable "Temporary password")

#### Master Realm Configuration

1. Create new client in the with the following configuration:
- Client ID: `helpdesk_admin`
- Name: `Helpdesk Admin Client`
- Client authentication: `True`
- Authorization: `False`
- Authentication Flow: Check only `Standard Flow` **and** `Service accounts roles`. Turn everything else off
- Leave Root URL, Home URL, Valid redirect URIs, Web origins, and everything else empty or with the standard values
2. Go to Credentials and copy client secret into [application.properties](src/main/resources/application.properties) as value for `hhn.keycloak.admin.client.secret`
3. Go to Service accounts roles and press "Assign roles". Choose "Filter by clients" and assign the following:
- `(institution-realm) manage-users`
- `(institution-realm) query-users`
- `(institution-realm) view-users`
4. Go to Client scopes, choose `helpdesk_admin-dedicated`, and verify that Client ID, Client Host, and Client IP Address token mappers exist

## PostgreSQL Database
1. [Install postgres](https://www.postgresql.org/download/) (or use the official [docker container](https://hub.docker.com/_/postgres))
2. Create database `helpdesk`
3. If you do not use postgres:postgres as default login for your local PostgreSQL installation, change the parameters inside [application.properties](src/main/resources/application.properties)

## Run backend with maven
rzo1 marked this conversation as resolved.
Show resolved Hide resolved
```bash
mvn clean package
mvn spring-boot:run
```

## Run frontend with npm
To run the frontend please refer to the [frontend README](../hhn-helpdesk-frontend/README.md)


# Troubleshooting
> Q: After authenticating the frontend keeps reloading the page
> A: Be sure that your administrator account (e.g. example_admin) got the HHN_HELPDESK_ADMIN role assigned inside keycloak.
32 changes: 14 additions & 18 deletions hhn-helpdesk-backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.12</version>
<version>3.1.4</version>
</parent>

<artifactId>hhn-helpdesk-backend</artifactId>
<groupId>de.hs-heilbronn.rz</groupId>
<version>1.0.3-SNAPSHOT</version>
<version>2.0.0-SNAPSHOT</version>

<organization>
<name>Hochschule Heilbronn</name>
Expand All @@ -36,18 +36,20 @@
<properties>
<copyright.year>2023</copyright.year>

<keycloak.version>21.0.1</keycloak.version>
<keycloak.version>22.0.4</keycloak.version>

<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<commons-lang3.version>3.12.0</commons-lang3.version>
<commons-lang3.version>3.13.0</commons-lang3.version>
<fop.version>2.9</fop.version>
<qrgen.version>3.0.1</qrgen.version>
<!-- pdfbox needs to be compatible with ${fop.version}. Don't upgrade pdfbox to 3.x without checking fop first -->
<pdfbox.version>2.0.28</pdfbox.version>
<batik.version>1.17</batik.version>
<!-- this is needed for schema generation and needs to be aligned with hibernate used by spring boot -->
<hibernate.version>6.2.9.Final</hibernate.version>
</properties>

<repositories>
Expand All @@ -58,18 +60,6 @@
</repository>
</repositories>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.keycloak.bom</groupId>
<artifactId>keycloak-adapter-bom</artifactId>
<version>${keycloak.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand All @@ -84,8 +74,8 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
Expand Down Expand Up @@ -188,6 +178,12 @@
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-ant</artifactId>
<version>${hibernate.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
package de.hhn.rz.db;

import de.hhn.rz.db.entities.AuditLogEntry;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AuditLogRepository extends PagingAndSortingRepository<AuditLogEntry, Long> {
public interface AuditLogRepository extends PagingAndSortingRepository<AuditLogEntry, Long>, CrudRepository<AuditLogEntry, Long> {
rzo1 marked this conversation as resolved.
Show resolved Hide resolved

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@
*/
package de.hhn.rz.db.entities;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;

import java.time.LocalDateTime;

@Entity
Expand All @@ -33,7 +36,8 @@
})
public class AccountCredential {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hibernate_sequence")
@SequenceGenerator(name="hibernate_sequence", sequenceName = "hibernate_sequence", allocationSize = 1)
private Long id;
@Column(length = 255, nullable = false)
private String password;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,22 @@
*/
package de.hhn.rz.db.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;

import java.time.LocalDateTime;

@Entity
public class AuditLogEntry {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hibernate_sequence")
@SequenceGenerator(name="hibernate_sequence", sequenceName = "hibernate_sequence", allocationSize = 1)
private Long id;
@Column(nullable = false)
private LocalDateTime time = LocalDateTime.now();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@
*/
package de.hhn.rz.db.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;

@Entity
public class Location {
@Id
@GeneratedValue
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hibernate_sequence")
@SequenceGenerator(name="hibernate_sequence", sequenceName = "hibernate_sequence", allocationSize = 1)
private Long id;
@Column(length = 255, nullable = false, unique = true)
private String label;
Expand Down
5 changes: 3 additions & 2 deletions hhn-helpdesk-backend/src/main/java/de/hhn/rz/dto/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,18 @@
import org.keycloak.representations.idm.UserRepresentation;

import java.util.List;
import java.util.Optional;

public record Account(String keycloakId, String id, String username, String firstName, String lastName, String email,
String type) {

public Account(UserRepresentation ua) {
this(ua.getId(),
ua.getAttributes().getOrDefault("employeeID", List.of("N/A")).get(0),
Optional.ofNullable(ua.getAttributes()).map(o -> o.get("employeeID")).orElse(List.of("N/A")).get(0),
ua.getUsername(),
ua.getFirstName(),
ua.getLastName(),
ua.getEmail(),
ua.getAttributes().getOrDefault("type", List.of("N/A")).get(0));
Optional.ofNullable(ua.getAttributes()).map(o -> o.get("type")).orElse(List.of("N/A")).get(0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;

@RestController
@CrossOrigin(origins = {"http://localhost:8080", "http://localhost:3000"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -50,11 +51,9 @@ public UserInfo user() {

final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
final Object principal = authentication.getPrincipal();
if (principal instanceof KeycloakPrincipal<?> kp) {
final String user = kp.getKeycloakSecurityContext().getIdToken().getPreferredUsername();
final Set<String> roles = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.toSet());

if (principal instanceof OidcUser ou) {
final String user = ou.getPreferredUsername();
final Set<String> roles = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
return new UserInfo(user, roles);
} else {
return new UserInfo("N/A", Collections.emptySet());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
package de.hhn.rz.security;

import org.keycloak.OAuth2Constants;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.RealmResource;
Expand All @@ -35,11 +33,6 @@ public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEve
return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
}

@Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}

@Bean
public Keycloak keycloak(
@Value("${hhn.keycloak.admin.url}") String url,
Expand Down
Loading
Loading