Skip to content

Commit

Permalink
add actuator and secure it via ADMIN role, harmonize naming of model,…
Browse files Browse the repository at this point in the history
… fix fragment path in templates to work with the SpringBoot JAR as well
  • Loading branch information
stefanreichert committed Oct 18, 2024
1 parent 1ec9df0 commit f587147
Show file tree
Hide file tree
Showing 18 changed files with 65 additions and 45 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# separate terms of service, privacy policy, and support
# documentation.

name: Java CI with Maven
name: TicketZ Continuous Integration

on:
push:
Expand All @@ -16,9 +16,7 @@ on:

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Set up JDK 22
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use an official OpenJDK runtime as a parent image
FROM openjdk:17-jdk-alpine
FROM azul/zulu-openjdk-alpine:21

# Set the working directory in the container
WORKDIR /app
Expand Down
8 changes: 6 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,19 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,27 @@
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

import java.util.List;

@Configuration
@EnableWebSecurity
public class AuthenticationConfiguration {

@Bean
public SecurityFilterChain actuatorFilterChain(HttpSecurity http) throws Exception {
return http
.securityMatcher("/actuator/**")
.authorizeHttpRequests(authorization -> authorization
.requestMatchers("/actuator/**").hasRole("ADMIN"))
.build();
}

@Bean
public AuthenticationManager authenticationManager(JwtAuthenticationProvider jwtAuthenticationProvider, DaoAuthenticationProvider daoAuthenticationProvider) {
return new ProviderManager(List.of(jwtAuthenticationProvider, daoAuthenticationProvider));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package net.wickedshell.ticketz.adapter.rest.controller;

import lombok.RequiredArgsConstructor;
import net.wickedshell.ticketz.adapter.rest.model.RestLoginRequest;
import net.wickedshell.ticketz.adapter.rest.model.RestSignupRequest;
import net.wickedshell.ticketz.adapter.rest.model.LoginRequest;
import net.wickedshell.ticketz.adapter.rest.model.SignupRequest;
import net.wickedshell.ticketz.adapter.rest.security.jwt.JwtAuthenticationRequestFilter;
import net.wickedshell.ticketz.adapter.rest.security.jwt.JwtService;
import net.wickedshell.ticketz.service.model.Role;
Expand Down Expand Up @@ -34,15 +34,15 @@ public class RestAuthenticationController {

@PostMapping(value = "/logins", produces = MimeTypeUtils.TEXT_PLAIN_VALUE)
@PostAuthorize("hasRole('ROLE_API')")
public ResponseEntity<String> login(@RequestBody RestLoginRequest loginRequest) {
public ResponseEntity<String> login(@RequestBody LoginRequest loginRequest) {
AbstractAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword());
authenticationManager.authenticate(authenticationToken);
return ResponseEntity.ok(JwtAuthenticationRequestFilter.BEARER_TOKEN_PREFIX + jwtService.createTokenFromEmail(loginRequest.getEmail()));
}

@PostMapping(value = "/signups")
public ResponseEntity<Void> signup(@RequestBody RestSignupRequest signupRequest) {
public ResponseEntity<Void> signup(@RequestBody SignupRequest signupRequest) {
User user = mapper.map(signupRequest, User.class);
userService.create(user, signupRequest.getPassword(), Set.of(Role.ROLE_USER, Role.ROLE_API));
return ResponseEntity.ok().build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package net.wickedshell.ticketz.adapter.rest.controller;

import lombok.RequiredArgsConstructor;
import net.wickedshell.ticketz.adapter.rest.model.RestTicket;
import net.wickedshell.ticketz.adapter.rest.model.TicketRest;
import net.wickedshell.ticketz.service.model.Ticket;
import net.wickedshell.ticketz.service.port.access.TicketService;
import org.modelmapper.ModelMapper;
Expand All @@ -22,36 +22,36 @@ public class RestTicketController {

@GetMapping
@PreAuthorize("hasRole('ROLE_API')")
public ResponseEntity<List<RestTicket>> allTickets() {
List<RestTicket> restTickets = ticketService.findAll()
public ResponseEntity<List<TicketRest>> allTickets() {
List<TicketRest> ticketRests = ticketService.findAll()
.stream()
.map(ticket -> mapper.map(ticket, RestTicket.class))
.map(ticket -> mapper.map(ticket, TicketRest.class))
.toList();
return ResponseEntity.ok(restTickets);
return ResponseEntity.ok(ticketRests);
}

@GetMapping(value = "/{ticket-number}")
@PreAuthorize("hasRole('ROLE_API')")
public ResponseEntity<RestTicket> oneTicket(@PathVariable("ticket-number") String ticketNumber) {
RestTicket restTicket = mapper.map(ticketService.loadByTicketNumber(ticketNumber), RestTicket.class);
return ResponseEntity.ok(restTicket);
public ResponseEntity<TicketRest> oneTicket(@PathVariable("ticket-number") String ticketNumber) {
TicketRest ticketRest = mapper.map(ticketService.loadByTicketNumber(ticketNumber), TicketRest.class);
return ResponseEntity.ok(ticketRest);
}

@PostMapping
@PreAuthorize("hasRole('ROLE_API')")
public ResponseEntity<RestTicket> create(@RequestBody RestTicket restTicket) {
Ticket ticket = ticketService.create(mapper.map(restTicket, Ticket.class));
return ResponseEntity.created(URI.create(RestRessource.RESOURCE_TICKETS + "/" + ticket.getTicketNumber())).build();
public ResponseEntity<TicketRest> create(@RequestBody TicketRest ticket) {
Ticket newTicket = ticketService.create(mapper.map(ticket, Ticket.class));
return ResponseEntity.created(URI.create(RestRessource.RESOURCE_TICKETS + "/" + newTicket.getTicketNumber())).build();
}

@PutMapping(value = "/{ticket-number}")
@PreAuthorize("hasRole('ROLE_API')")
public ResponseEntity<Void> update(@PathVariable("ticket-number") String ticketNumber,
@RequestBody RestTicket restTicket) {
if (!ticketNumber.equals(restTicket.getTicketNumber())) {
@RequestBody TicketRest ticket) {
if (!ticketNumber.equals(ticket.getTicketNumber())) {
return ResponseEntity.badRequest().build();
}
ticketService.update(mapper.map(restTicket, Ticket.class));
ticketService.update(mapper.map(ticket, Ticket.class));
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RestLoginRequest {
public class LoginRequest {

@NotNull
private String email;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import lombok.Data;

@Data
public class RestSignupRequest {
public class SignupRequest {

@NotNull
private String lastname;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

@Data
@RequiredArgsConstructor
public class RestTicket {
public class TicketRest {

@NotNull
private String title;
Expand All @@ -17,12 +17,12 @@ public class RestTicket {
private String description;

@NotNull
private RestUser author;
private UserRest author;

private RestUser editor;
private UserRest editor;

@NotNull
private RestTicketState state;
private TicketStateRest state;

@NotNull
private long version;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package net.wickedshell.ticketz.adapter.rest.model;

public enum RestTicketState {
public enum TicketStateRest {

CREATED, IN_PROGRESS, FIXED, REJECTED, REOPENED, CLOSED
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

@RequiredArgsConstructor
@Data
public class RestUser {
public class UserRest {

@NotNull
private String lastname;
Expand Down
8 changes: 7 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# common config
spring.thymeleaf.encoding=UTF-8
spring.messages.encoding=ISO-8859-1

# Thymeleaf config
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.prefix=classpath:/templates

# web config
server.servlet.context-path=/ticketz

Expand All @@ -14,6 +17,9 @@ spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver

# Actuator Config
management.endpoints.web.exposure.include=*

# Hibernate config
spring.jpa.hibernate.ddl-auto=create

Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/import.sql
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
INSERT INTO USER_ENTITY (DATE_CREATED,DATE_UPDATED,EMAIL,FIRSTNAME,LASTNAME,PASSWORD_HASH,VERSION, ID, ROLES) values ('2024-01-12 00:00:00.000','2024-01-12 00:00:00.000','test@us.er','Test','User','$2a$10$TYD3Q9P6iElpp7cuhPk0BuZqlZQP3rzzxgfO10Bf9kNrocdSqQ1Aa',0,-1, (0));
INSERT INTO USER_ENTITY (DATE_CREATED,DATE_UPDATED,EMAIL,FIRSTNAME,LASTNAME,PASSWORD_HASH,VERSION, ID, ROLES) values ('2024-01-12 00:00:00.000','2024-01-12 00:00:00.000','admin@us.er','Admin','User','$2a$10$TYD3Q9P6iElpp7cuhPk0BuZqlZQP3rzzxgfO10Bf9kNrocdSqQ1Aa',0,-2, ARRAY [0, 1]);
INSERT INTO USER_ENTITY (DATE_CREATED,DATE_UPDATED,EMAIL,FIRSTNAME,LASTNAME,PASSWORD_HASH,VERSION, ID, ROLES) values ('2024-01-12 00:00:00.000','2024-01-12 00:00:00.000','test@us.er','Test','User','$2a$10$TYD3Q9P6iElpp7cuhPk0BuZqlZQP3rzzxgfO10Bf9kNrocdSqQ1Aa',0,-1, ARRAY [0]);
INSERT INTO TICKET_ENTITY (STATE, AUTHOR_ID, DATE_CREATED, DATE_UPDATED, EDITOR_ID, ID, VERSION, DESCRIPTION, TICKET_NUMBER, TITLE) VALUES (0, -1, '2024-01-13 00:44:13.000000', '2024-01-13 00:44:16.000000', null, 0, 0, 'Test Description', 'test_ticket', 'Test Title');
4 changes: 2 additions & 2 deletions src/main/resources/templates/error.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</head>
<body>
<div class="container">
<div th:replace="~{fragments/header :: header(pageheader=#{pageheader.error})}"></div>
<div th:replace="~{/fragments/header :: header(pageheader=#{pageheader.error})}"></div>
<div class="mb-1">
<p th:if="${url}" id='url'>
<b th:text="#{label.page}"></b>: <span th:text="${url}">Page URL</span>
Expand All @@ -31,7 +31,7 @@
</ul>
<div th:utext="'--&gt;'" th:remove="tag"></div>
</div>
<div th:replace="~{fragments/footer :: footer}"></div>
<div th:replace="~{/fragments/footer :: footer}"></div>
</div>
</body>
</html>
4 changes: 2 additions & 2 deletions src/main/resources/templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</head>
<body>
<div class="container">
<div th:replace="~{fragments/header :: header(pageheader=#{pageheader.login})}"></div>
<div th:replace="~{/fragments/header :: header(pageheader=#{pageheader.login})}"></div>
<form th:action="@{/login}" th:method="post" th:object="${login}">
<div class="mb-3">
<label for="email" class="form-label" th:text="#{label.email}"/>
Expand All @@ -26,7 +26,7 @@
<a th:href="@{/show_signup}" class="btn btn-outline-secondary" th:text="#{button.go_to_signup}"/>
</div>
</form>
<div th:replace="~{fragments/footer :: footer}"></div>
<div th:replace="~{/fragments/footer :: footer}"></div>
</div>
</body>
</html>
4 changes: 2 additions & 2 deletions src/main/resources/templates/signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</head>
<body>
<div class="container">
<div th:replace="~{fragments/header :: header(pageheader=#{pageheader.signup})}"></div>
<div th:replace="~{/fragments/header :: header(pageheader=#{pageheader.signup})}"></div>
<form th:action="@{/signup}" th:method="post" th:object="${signup}">
<div class="mb-3">
<label for="email" class="form-label" th:text="#{label.email}"/>
Expand Down Expand Up @@ -42,7 +42,7 @@
<a th:href="@{/show_login}" class="btn btn-outline-secondary" th:text="#{button.go_to_login}"/>
</div>
</form>
<div th:replace="~{fragments/footer :: footer}"></div>
<div th:replace="~{/fragments/footer :: footer}"></div>
</div>
</body>
</html>
4 changes: 2 additions & 2 deletions src/main/resources/templates/ticket.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</head>
<body>
<div class="container">
<div th:replace="~{fragments/header :: header(pageheader=#{pageheader.ticket})}"></div>
<div th:replace="~{/fragments/header :: header(pageheader=#{pageheader.ticket})}"></div>
<form th:action="@{/secure/tickets/{ticketNumber}(ticketNumber=*{ticketNumber})}" th:method="post" th:object="${ticketWeb}">
<div class="mb-3">
<span class="form-label" th:text="#{label.ticketNumber}"></span>
Expand Down Expand Up @@ -73,7 +73,7 @@
<input type="hidden" id="canGoIntoReopened" name="canGoIntoReopened" th:field="*{canGoIntoReopened}"/>
<input type="hidden" id="canGoIntoClosed" name="canGoIntoClosed" th:field="*{canGoIntoClosed}"/>
</form>
<div th:replace="~{fragments/footer :: footer}"></div>
<div th:replace="~{/fragments/footer :: footer}"></div>
</div>
</body>
</html>
6 changes: 3 additions & 3 deletions src/main/resources/templates/ticket_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
</head>
<body>
<div class="container-lg">
<div th:replace="~{fragments/header :: header(pageheader=#{pageheader.ticket_list})}"></div>
<div th:replace="~{/fragments/header :: header(pageheader=#{pageheader.ticket_list})}"></div>
<div class="mb-3">
<table class="table table-striped">
<thead>
Expand Down Expand Up @@ -43,14 +43,14 @@
</table>
</div>
<div th:each="ticket : ${tickets}">
<div th:replace="~{fragments/confirm_dialog :: confirm(id=${'confirm_' + ticket.ticketNumber}, title=#{dialog.delete_ticket.title}, message=#{dialog.delete_ticket.message(${ticket.ticketNumber})}, confirm_url=@{/secure/tickets/{ticketNumber}:delete(ticketNumber=${ticket.ticketNumber})})}"></div>
<div th:replace="~{/fragments/confirm_dialog :: confirm(id=${'confirm_' + ticket.ticketNumber}, title=#{dialog.delete_ticket.title}, message=#{dialog.delete_ticket.message(${ticket.ticketNumber})}, confirm_url=@{/secure/tickets/{ticketNumber}:delete(ticketNumber=${ticket.ticketNumber})})}"></div>
</div>
<div class="mb-5">
<a th:href="@{/secure/tickets/new}" class="btn btn-success" th:text="#{button.new_ticket}">
<span class="bi bi-trash"></span>
</a>
</div>
<div th:replace="~{fragments/footer :: footer}"></div>
<div th:replace="~{/fragments/footer :: footer}"></div>
</div>
</body>
</html>

0 comments on commit f587147

Please sign in to comment.