mirror of
https://github.com/fabioformosa/quartz-manager.git
synced 2026-05-14 22:00:30 +09:00
#130 upgraded Spring Boot to 4.0.6
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.5.6</version>
|
||||
<version>4.0.6</version>
|
||||
</parent>
|
||||
|
||||
<groupId>it.fabioformosa.quartz-manager</groupId>
|
||||
@@ -41,17 +41,17 @@
|
||||
</developers>
|
||||
|
||||
<properties>
|
||||
<java.version>9</java.version>
|
||||
<java.version>17</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<org.projectlombok.version>1.18.30</org.projectlombok.version>
|
||||
<maven-surefire-plugin.version>2.22.0</maven-surefire-plugin.version>
|
||||
<maven-failsafe-plugin.version>2.22.0</maven-failsafe-plugin.version>
|
||||
<jacoco-maven-plugin.version>0.8.8</jacoco-maven-plugin.version>
|
||||
<maven-javadoc-plugin.version>3.4.1</maven-javadoc-plugin.version>
|
||||
<org.projectlombok.version>1.18.42</org.projectlombok.version>
|
||||
<maven-surefire-plugin.version>3.5.4</maven-surefire-plugin.version>
|
||||
<maven-failsafe-plugin.version>3.5.4</maven-failsafe-plugin.version>
|
||||
<jacoco-maven-plugin.version>0.8.14</jacoco-maven-plugin.version>
|
||||
<maven-javadoc-plugin.version>3.12.0</maven-javadoc-plugin.version>
|
||||
<nexus-staging-maven-plugin.version>1.6.7</nexus-staging-maven-plugin.version>
|
||||
<maven-release-plugin.version>2.5.3</maven-release-plugin.version>
|
||||
<maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version>
|
||||
<sonar-maven-plugin.version>3.11.0.3922</sonar-maven-plugin.version>
|
||||
<sonar-maven-plugin.version>5.2.0.4988</sonar-maven-plugin.version>
|
||||
<sonar.organization>fabioformosa</sonar.organization>
|
||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||
<sonar.exclusions>
|
||||
@@ -111,12 +111,11 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -125,9 +124,15 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<release>${java.version}</release>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${org.projectlombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<springdoc-openapi.version>1.5.12</springdoc-openapi.version>
|
||||
<java.version>9</java.version>
|
||||
<springdoc-openapi.version>3.0.3</springdoc-openapi.version>
|
||||
<java.version>17</java.version>
|
||||
<sonar.exclusions>**/QuartManagerApplicationTests.java, **/OpenApiConfig.java</sonar.exclusions>
|
||||
</properties>
|
||||
|
||||
@@ -61,6 +61,11 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-webmvc-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MISC -->
|
||||
<dependency>
|
||||
@@ -86,21 +91,6 @@
|
||||
<artifactId>metamorphosis-core</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>2.0.1.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>6.0.2.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>javax.el</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reflections</groupId>
|
||||
<artifactId>reflections</artifactId>
|
||||
@@ -125,15 +115,10 @@
|
||||
<!-- OAS -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${springdoc-openapi.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-common</artifactId>
|
||||
<version>${springdoc-openapi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- TEST -->
|
||||
<dependency>
|
||||
|
||||
@@ -6,8 +6,8 @@ import io.swagger.v3.oas.models.info.License;
|
||||
import it.fabioformosa.quartzmanager.api.common.config.QuartzManagerPaths;
|
||||
import lombok.Generated;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springdoc.core.GroupedOpenApi;
|
||||
import org.springdoc.core.customizers.OpenApiCustomiser;
|
||||
import org.springdoc.core.customizers.OpenApiCustomizer;
|
||||
import org.springdoc.core.models.GroupedOpenApi;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -39,10 +39,10 @@ public class OpenApiConfig {
|
||||
|
||||
@ConditionalOnProperty(name = "quartz-manager.oas.enabled")
|
||||
@Bean
|
||||
public GroupedOpenApi quartzManagerStoreOpenApi(@Autowired(required = false) @Qualifier("quartzManagerOpenApiCustomiser") Optional<OpenApiCustomiser> openApiCustomiser) {
|
||||
public GroupedOpenApi quartzManagerStoreOpenApi(@Autowired(required = false) @Qualifier("quartzManagerOpenApiCustomizer") Optional<OpenApiCustomizer> openApiCustomizer) {
|
||||
String[] paths = {QuartzManagerPaths.QUARTZ_MANAGER_BASE_CONTEXT_PATH + "/**"};
|
||||
GroupedOpenApi.Builder groupedOpenApiBuilder = GroupedOpenApi.builder().group("quartz-manager").pathsToMatch(paths);
|
||||
openApiCustomiser.ifPresent(groupedOpenApiBuilder::addOpenApiCustomiser);
|
||||
openApiCustomizer.ifPresent(groupedOpenApiBuilder::addOpenApiCustomizer);
|
||||
return groupedOpenApiBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,38 @@
|
||||
package it.fabioformosa.quartzmanager.api.configuration;
|
||||
|
||||
import it.fabioformosa.metamorphosis.core.converters.AbstractBaseConverter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
@ComponentScan(basePackages = {"it.fabioformosa.quartzmanager.api"})
|
||||
@Configuration
|
||||
public class QuartzManagerApiConfig {
|
||||
|
||||
@Bean
|
||||
public ConversionService conversionService(List<Converter<?, ?>> converters) {
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
converters.forEach(conversionService::addConverter);
|
||||
converters.stream()
|
||||
.filter(AbstractBaseConverter.class::isInstance)
|
||||
.map(AbstractBaseConverter.class::cast)
|
||||
.forEach(converter -> setConversionService(converter, conversionService));
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
private void setConversionService(AbstractBaseConverter<?, ?> converter, ConversionService conversionService) {
|
||||
try {
|
||||
Field conversionServiceField = AbstractBaseConverter.class.getDeclaredField("conversionService");
|
||||
conversionServiceField.setAccessible(true);
|
||||
conversionServiceField.set(converter, conversionService);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new IllegalStateException("Unable to initialize Quartz Manager converters", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import it.fabioformosa.quartzmanager.api.common.config.QuartzManagerPaths;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackages = {"it.fabioformosa.quartzmanager.api.websockets"})
|
||||
@EnableWebSocketMessageBroker
|
||||
public class WebsocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry config) {
|
||||
|
||||
@@ -19,7 +19,7 @@ import org.quartz.SchedulerException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
@Slf4j
|
||||
@RequestMapping(SimpleTriggerController.SIMPLE_TRIGGER_CONTROLLER_BASE_URL)
|
||||
|
||||
@@ -8,15 +8,23 @@ import it.fabioformosa.quartzmanager.api.dto.TriggerKeyDTO;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.Trigger;
|
||||
import org.quartz.TriggerKey;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Component
|
||||
public class TriggerToTriggerDTO<S extends Trigger, T extends TriggerDTO> extends AbstractBaseConverter<S, T> {
|
||||
public abstract class TriggerToTriggerDTO<S extends Trigger, T extends TriggerDTO> extends AbstractBaseConverter<S, T> {
|
||||
|
||||
@Autowired
|
||||
private TriggerKeyToTriggerKeyDTO triggerKeyToTriggerKeyDTO;
|
||||
|
||||
@Autowired
|
||||
private JobKeyToJobKeyDTO jobKeyToJobKeyDTO;
|
||||
|
||||
@Autowired
|
||||
private JobKeyToJobDetailDTO jobKeyToJobDetailDTO;
|
||||
|
||||
@Override
|
||||
protected void convert(S source, T target) {
|
||||
TriggerKey triggerKey = source.getKey();
|
||||
TriggerKeyDTO triggerKeyDTO = conversionService.convert(triggerKey, TriggerKeyDTO.class);
|
||||
TriggerKeyDTO triggerKeyDTO = triggerKeyToTriggerKeyDTO.convert(triggerKey);
|
||||
target.setTriggerKeyDTO(triggerKeyDTO);
|
||||
|
||||
target.setStartTime(source.getStartTime());
|
||||
@@ -29,16 +37,15 @@ public class TriggerToTriggerDTO<S extends Trigger, T extends TriggerDTO> extend
|
||||
target.setMayFireAgain(source.mayFireAgain());
|
||||
|
||||
JobKey jobKey = source.getJobKey();
|
||||
JobKeyDTO jobKeyDTO = conversionService.convert(jobKey, JobKeyDTO.class);
|
||||
if (jobKey == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
JobKeyDTO jobKeyDTO = jobKeyToJobKeyDTO.convert(jobKey);
|
||||
target.setJobKeyDTO(jobKeyDTO);
|
||||
|
||||
JobDetailDTO jobDetailDTO = conversionService.convert(jobKey, JobDetailDTO.class);
|
||||
JobDetailDTO jobDetailDTO = jobKeyToJobDetailDTO.convert(jobKey);
|
||||
target.setJobDetailDTO(jobDetailDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T createOrRetrieveTarget(S source) {
|
||||
return (T) new TriggerDTO();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package it.fabioformosa.quartzmanager.api.dto;
|
||||
import it.fabioformosa.quartzmanager.api.validators.ValidTriggerRepetition;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.constraints.Positive;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.validation.constraints.Positive;
|
||||
import java.util.Map;
|
||||
|
||||
@ValidTriggerRepetition
|
||||
|
||||
@@ -5,7 +5,7 @@ import it.fabioformosa.quartzmanager.api.validators.ValidTriggerPeriod;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.util.Date;
|
||||
|
||||
@ValidTriggerPeriod
|
||||
|
||||
@@ -9,7 +9,7 @@ import org.quartz.JobExecutionContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
/**
|
||||
* Extends this class to create a job that produces LogRecord to be displayed
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.reflections.Reflections;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public class SimpleTriggerService extends AbstractSchedulerService {
|
||||
}
|
||||
|
||||
public SimpleTriggerDTO scheduleSimpleTrigger(SimpleTriggerCommandDTO simpleTriggerCommandDTO) throws SchedulerException, ClassNotFoundException {
|
||||
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(simpleTriggerCommandDTO.getSimpleTriggerInputDTO().getJobClass());
|
||||
Class<? extends Job> jobClass = Class.forName(simpleTriggerCommandDTO.getSimpleTriggerInputDTO().getJobClass()).asSubclass(Job.class);
|
||||
JobDetail jobDetail = JobBuilder.newJob()
|
||||
.ofType(jobClass)
|
||||
.storeDurably(false)
|
||||
|
||||
@@ -7,7 +7,6 @@ import org.quartz.TriggerKey;
|
||||
import org.quartz.impl.matchers.GroupMatcher;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
@@ -26,9 +25,9 @@ public class TriggerService {
|
||||
|
||||
public List<TriggerKeyDTO> fetchTriggers() throws SchedulerException {
|
||||
Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(GroupMatcher.anyTriggerGroup());
|
||||
return (List<TriggerKeyDTO>) conversionService.convert(triggerKeys,
|
||||
TypeDescriptor.collection(Set.class, TypeDescriptor.valueOf(TriggerKey.class)),
|
||||
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(TriggerKeyDTO.class)));
|
||||
return triggerKeys.stream()
|
||||
.map(triggerKey -> conversionService.convert(triggerKey, TriggerKeyDTO.class))
|
||||
.toList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package it.fabioformosa.quartzmanager.api.validators;
|
||||
|
||||
import it.fabioformosa.quartzmanager.api.dto.TriggerRepetitionDTO;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
public class ValidRepetitionValidator implements ConstraintValidator<ValidTriggerRepetition, TriggerRepetitionDTO> {
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package it.fabioformosa.quartzmanager.api.validators;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@@ -2,8 +2,8 @@ package it.fabioformosa.quartzmanager.api.validators;
|
||||
|
||||
import it.fabioformosa.quartzmanager.api.dto.TriggerPeriodDTO;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
public class ValidTriggerPeriodValidator implements ConstraintValidator<ValidTriggerPeriod, TriggerPeriodDTO> {
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package it.fabioformosa.quartzmanager.api.validators;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@@ -7,8 +7,8 @@ import it.fabioformosa.quartzmanager.api.services.JobService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@@ -28,7 +28,7 @@ class JobControllerTest {
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private JobService jobService;
|
||||
|
||||
@Test
|
||||
|
||||
@@ -3,7 +3,7 @@ package it.fabioformosa.quartzmanager.api.controllers;
|
||||
import it.fabioformosa.quartzmanager.api.QuartManagerApplicationTests;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
@@ -8,8 +8,8 @@ import it.fabioformosa.quartzmanager.api.services.SchedulerService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@@ -26,7 +26,7 @@ class SchedulerControllerTest {
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private SchedulerService schedulerService;
|
||||
|
||||
@Test
|
||||
|
||||
@@ -13,8 +13,8 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@@ -35,7 +35,7 @@ class SimpleTriggerControllerTest {
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private SimpleTriggerService simpleTriggerService;
|
||||
|
||||
@AfterEach
|
||||
|
||||
@@ -14,8 +14,8 @@ import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ArgumentsSource;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@@ -35,7 +35,7 @@ class SimpleTriggerControllerValidationTest {
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private SimpleTriggerService simpleTriggerService;
|
||||
|
||||
@AfterEach
|
||||
|
||||
@@ -5,8 +5,8 @@ import it.fabioformosa.quartzmanager.api.services.TriggerService;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
@@ -19,7 +19,7 @@ class TriggerControllerTest {
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
@MockitoBean
|
||||
private TriggerService triggerService;
|
||||
|
||||
@AfterEach
|
||||
|
||||
@@ -5,13 +5,14 @@ import it.fabioformosa.quartzmanager.api.dto.SimpleTriggerInputDTO;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.ArgumentsProvider;
|
||||
import org.junit.jupiter.params.support.ParameterDeclarations;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class InvalidSimpleTriggerCommandDTOProvider implements ArgumentsProvider {
|
||||
@Override
|
||||
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) {
|
||||
public Stream<? extends Arguments> provideArguments(ParameterDeclarations parameters, ExtensionContext extensionContext) {
|
||||
return Stream.of(
|
||||
Arguments.of(buildSimpleTriggerWithBlankMandatoryFields()),
|
||||
Arguments.of(buildSimpleTriggerWithRepeatCountAndWithoutRepeatInterval()),
|
||||
@@ -22,20 +23,28 @@ public class InvalidSimpleTriggerCommandDTOProvider implements ArgumentsProvider
|
||||
}
|
||||
|
||||
private SimpleTriggerInputDTO buildSimpleTriggerWithNegativeRepeatInterval() {
|
||||
return minimalSimpleTriggerBuilder().repeatInterval(-2000L).repeatCount(10).build();
|
||||
SimpleTriggerInputDTO simpleTriggerInputDTO = minimalSimpleTrigger();
|
||||
simpleTriggerInputDTO.setRepeatInterval(-2000L);
|
||||
simpleTriggerInputDTO.setRepeatCount(10);
|
||||
return simpleTriggerInputDTO;
|
||||
}
|
||||
|
||||
private static SimpleTriggerInputDTO buildSimpleTriggerWithRepeatIntervalAndWithoutRepeatCount() {
|
||||
return minimalSimpleTriggerBuilder().repeatInterval(1L).build();
|
||||
SimpleTriggerInputDTO simpleTriggerInputDTO = minimalSimpleTrigger();
|
||||
simpleTriggerInputDTO.setRepeatInterval(1L);
|
||||
return simpleTriggerInputDTO;
|
||||
}
|
||||
|
||||
private static SimpleTriggerInputDTO.SimpleTriggerInputDTOBuilder<?, ?> minimalSimpleTriggerBuilder() {
|
||||
return SimpleTriggerInputDTO.builder()
|
||||
.jobClass("it.fabioformosa.quartzmanager.api.jobs.SampleJob");
|
||||
private static SimpleTriggerInputDTO minimalSimpleTrigger() {
|
||||
SimpleTriggerInputDTO simpleTriggerInputDTO = new SimpleTriggerInputDTO();
|
||||
simpleTriggerInputDTO.setJobClass("it.fabioformosa.quartzmanager.api.jobs.SampleJob");
|
||||
return simpleTriggerInputDTO;
|
||||
}
|
||||
|
||||
private static SimpleTriggerInputDTO buildSimpleTriggerWithRepeatCountAndWithoutRepeatInterval() {
|
||||
return minimalSimpleTriggerBuilder().repeatCount(1).build();
|
||||
SimpleTriggerInputDTO simpleTriggerInputDTO = minimalSimpleTrigger();
|
||||
simpleTriggerInputDTO.setRepeatCount(1);
|
||||
return simpleTriggerInputDTO;
|
||||
}
|
||||
|
||||
private static SimpleTriggerInputDTO buildSimpleTriggerWithBlankMandatoryFields() {
|
||||
@@ -43,7 +52,10 @@ public class InvalidSimpleTriggerCommandDTOProvider implements ArgumentsProvider
|
||||
}
|
||||
|
||||
private static SimpleTriggerInputDTO buildSimpleTriggerWithInvalidTriggerPeriod() {
|
||||
return minimalSimpleTriggerBuilder().endDate(new Date()).startDate(DateUtils.addHoursToNow(1)).build();
|
||||
SimpleTriggerInputDTO simpleTriggerInputDTO = minimalSimpleTrigger();
|
||||
simpleTriggerInputDTO.setEndDate(new Date());
|
||||
simpleTriggerInputDTO.setStartDate(DateUtils.addHoursToNow(1));
|
||||
return simpleTriggerInputDTO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package it.fabioformosa.quartzmanager.api.controllers.utils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.util.StdDateFormat;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
public class TestUtils {
|
||||
@@ -10,12 +9,11 @@ public class TestUtils {
|
||||
static public ObjectMapper objectMapper = new ObjectMapper();
|
||||
static{
|
||||
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
objectMapper.setDateFormat(new StdDateFormat().withColonInTimeZone(true)); // StdDateFormat is ISO8601 since jackson 2.9
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
static public String toJson(Object object){
|
||||
return objectMapper.writeValueAsString(object);
|
||||
return objectMapper.writeValueAsString(object).replace("+00:00", "Z");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class SampleJobTest {
|
||||
JobExecutionContext jobExecutionContext = Mockito.mock(JobExecutionContext.class);
|
||||
String triggerName = "test-trigger";
|
||||
|
||||
ScheduleBuilder schedulerBuilder = SimpleScheduleBuilder.simpleSchedule()
|
||||
ScheduleBuilder<?> schedulerBuilder = SimpleScheduleBuilder.simpleSchedule()
|
||||
.withRepeatCount(5)
|
||||
.withIntervalInMilliseconds(1000L);
|
||||
JobDetail jobDetail = JobBuilder
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>9</java.version>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>9</java.version>
|
||||
<springdoc-openapi.version>1.5.12</springdoc-openapi.version>
|
||||
<java.version>17</java.version>
|
||||
<springdoc-openapi.version>3.0.3</springdoc-openapi.version>
|
||||
<sonar.exclusions>**/SpringApplicationTest.java</sonar.exclusions>
|
||||
</properties>
|
||||
|
||||
@@ -44,12 +44,29 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Misc -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.0</version>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.13.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>0.13.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>0.13.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@@ -60,16 +77,11 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- OAS -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${springdoc-openapi.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
@@ -100,6 +112,11 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-webmvc-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
|
||||
@@ -7,6 +7,7 @@ import it.fabioformosa.quartzmanager.api.security.helpers.impl.*;
|
||||
import it.fabioformosa.quartzmanager.api.security.properties.InMemoryAccountProperties;
|
||||
import it.fabioformosa.quartzmanager.api.security.properties.JwtSecurityProperties;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -19,10 +20,11 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
@@ -48,7 +50,7 @@ import static it.fabioformosa.quartzmanager.api.common.config.QuartzManagerPaths
|
||||
@ComponentScan(basePackages = {"it.fabioformosa.quartzmanager.api.security"})
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@EnableMethodSecurity(prePostEnabled = true)
|
||||
public class QuartzManagerSecurityConfig {
|
||||
|
||||
private static final String[] PATTERNS_SWAGGER_UI = {"/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**", "/swagger-resources/**", "/webjars/**"};
|
||||
@@ -72,6 +74,12 @@ public class QuartzManagerSecurityConfig {
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ObjectMapper.class)
|
||||
public static ObjectMapper objectMapper() {
|
||||
return new ObjectMapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
@@ -101,17 +109,17 @@ public class QuartzManagerSecurityConfig {
|
||||
public SecurityFilterChain filterChain(HttpSecurity http,
|
||||
@Qualifier("quartzManagerInMemoryAuthentication") InMemoryUserDetailsManager userDetailsService,
|
||||
AuthenticationManager authenticationManager) throws Exception {
|
||||
http.antMatcher(QUARTZ_MANAGER_API_ANT_MATCHER).csrf().disable() //
|
||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() //
|
||||
.exceptionHandling().authenticationEntryPoint(restAuthEntryPoint()).and() //
|
||||
.addFilterBefore(jwtAuthenticationTokenFilter(userDetailsService), BasicAuthenticationFilter.class) //
|
||||
.authorizeRequests();
|
||||
http.securityMatcher(QUARTZ_MANAGER_API_ANT_MATCHER)
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.exceptionHandling(exception -> exception.authenticationEntryPoint(restAuthEntryPoint()))
|
||||
.addFilterBefore(jwtAuthenticationTokenFilter(userDetailsService), BasicAuthenticationFilter.class);
|
||||
|
||||
QuartzManagerHttpSecurity.from(http).withLoginConfigurer(loginConfigurer(), logoutConfigurer()) //
|
||||
.login(QUARTZ_MANAGER_LOGIN_PATH, authenticationManager).logout(QUARTZ_MANAGER_LOGOUT_PATH);
|
||||
|
||||
http.authorizeRequests()
|
||||
.antMatchers(QUARTZ_MANAGER_API_ANT_MATCHER).authenticated();
|
||||
http.authorizeHttpRequests(authorize -> authorize
|
||||
.requestMatchers(QUARTZ_MANAGER_API_ANT_MATCHER).authenticated());
|
||||
|
||||
return http.build();
|
||||
}
|
||||
@@ -119,11 +127,11 @@ public class QuartzManagerSecurityConfig {
|
||||
@Bean(name = "quartzManagerWebSecurityCustomizer")
|
||||
public WebSecurityCustomizer webSecurityCustomizer(@Value("${quartz-manager.oas.enabled:false}") Boolean oasEnabled) {
|
||||
return web -> {
|
||||
web.ignoring()//
|
||||
.antMatchers(HttpMethod.GET, QUARTZ_MANAGER_UI_ANT_MATCHER);
|
||||
web.ignoring()
|
||||
.requestMatchers(QUARTZ_MANAGER_UI_ANT_MATCHER);
|
||||
if(BooleanUtils.isNotFalse(oasEnabled))
|
||||
web.ignoring()
|
||||
.antMatchers(HttpMethod.GET, PATTERNS_SWAGGER_UI);
|
||||
.requestMatchers(PATTERNS_SWAGGER_UI);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import it.fabioformosa.quartzmanager.api.common.config.QuartzManagerPaths;
|
||||
import it.fabioformosa.quartzmanager.api.security.properties.JwtSecurityProperties;
|
||||
import lombok.Generated;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springdoc.core.customizers.OpenApiCustomiser;
|
||||
import org.springdoc.core.customizers.OpenApiCustomizer;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -29,23 +29,24 @@ import java.util.Arrays;
|
||||
public class SecurityOpenApiConfig {
|
||||
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@Bean("quartzManagerOpenApiCustomiser")
|
||||
public OpenApiCustomiser configureQuartzManagerOpenAPI(JwtSecurityProperties jwtSecurityProps) {
|
||||
@Bean("quartzManagerOpenApiCustomizer")
|
||||
public OpenApiCustomizer configureQuartzManagerOpenAPI(JwtSecurityProperties jwtSecurityProps) {
|
||||
return openAPI -> {
|
||||
if (!jwtSecurityProps.getCookieStrategy().isEnabled())
|
||||
openAPI
|
||||
.components(new Components().addSecuritySchemes(OpenAPIConfigConsts.QUARTZ_MANAGER_SEC_OAS_SCHEMA, buildBasicAuthScheme()));
|
||||
|
||||
ObjectSchema loginRequestSchema = new ObjectSchema();
|
||||
loginRequestSchema.addProperty("username", new StringSchema());
|
||||
loginRequestSchema.addProperty("password", new PasswordSchema());
|
||||
loginRequestSchema.required(Arrays.asList("username", "password"));
|
||||
|
||||
openAPI.path(QuartzManagerPaths.QUARTZ_MANAGER_LOGIN_PATH,
|
||||
new PathItem().post(new Operation()
|
||||
.operationId("login")
|
||||
.tags(Arrays.asList("auth"))
|
||||
.requestBody(new RequestBody().content(
|
||||
new Content().addMediaType("application/x-www-form-urlencoded", new MediaType().schema(new Schema().type("object")
|
||||
.addProperties("username", new StringSchema())
|
||||
.addProperties("password", new PasswordSchema())
|
||||
.required(Arrays.asList("username", "password"))
|
||||
))))
|
||||
new Content().addMediaType("application/x-www-form-urlencoded", new MediaType().schema(loginRequestSchema))))
|
||||
.responses(new ApiResponses().addApiResponse("200", new ApiResponse().description("JWT Token to authenticate the next requests")))
|
||||
.responses(new ApiResponses().addApiResponse("401", new ApiResponse().description("Unauthorized - Username or password are incorrect!")))
|
||||
));
|
||||
|
||||
@@ -3,12 +3,14 @@ package it.fabioformosa.quartzmanager.api.security.helpers.impl;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
|
||||
@EqualsAndHashCode
|
||||
import java.util.Collections;
|
||||
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class AnonAuthentication extends AbstractAuthenticationToken {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public AnonAuthentication() {
|
||||
super( null );
|
||||
super(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,8 +3,8 @@ package it.fabioformosa.quartzmanager.api.security.helpers.impl;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
|
||||
|
||||
/**
|
||||
* It delegates the login to the @FormLoginConfigurer of the httpSecurity.
|
||||
@@ -55,19 +54,17 @@ public class FormLoginConfig implements LoginConfigurer {
|
||||
HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
|
||||
log.debug("Configuring login through FormLoginConfigurer...");
|
||||
|
||||
FormLoginConfigurer<HttpSecurity> login = http.formLogin().loginPage(loginPath);
|
||||
|
||||
if(authenticationSuccessHandler != null) {
|
||||
log.debug("Setting an authenticationSuccessHandler");
|
||||
login = login.successHandler(authenticationSuccessHandler);
|
||||
}
|
||||
|
||||
if(authenticationFailureHandler != null) {
|
||||
log.debug("Setting an authenticationFailureHandler");
|
||||
login = login.failureHandler(authenticationFailureHandler);
|
||||
}
|
||||
|
||||
return login.and();
|
||||
return http.formLogin(login -> {
|
||||
login.loginPage(loginPath);
|
||||
if(authenticationSuccessHandler != null) {
|
||||
log.debug("Setting an authenticationSuccessHandler");
|
||||
login.successHandler(authenticationSuccessHandler);
|
||||
}
|
||||
if(authenticationFailureHandler != null) {
|
||||
log.debug("Setting an authenticationFailureHandler");
|
||||
login.failureHandler(authenticationFailureHandler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package it.fabioformosa.quartzmanager.api.security.helpers.impl;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
@@ -2,7 +2,7 @@ package it.fabioformosa.quartzmanager.api.security.helpers.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,15 +5,15 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -92,7 +92,8 @@ public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
private boolean skipPathRequest(HttpServletRequest request, List<String> pathsToSkip ) {
|
||||
if(pathsToSkip == null)
|
||||
pathsToSkip = new ArrayList<>();
|
||||
List<RequestMatcher> matchers = pathsToSkip.stream().map(AntPathRequestMatcher::new).collect(Collectors.toList());
|
||||
PathPatternRequestMatcher.Builder matcherBuilder = PathPatternRequestMatcher.withDefaults();
|
||||
List<RequestMatcher> matchers = pathsToSkip.stream().map(matcherBuilder::matcher).collect(Collectors.toList());
|
||||
OrRequestMatcher compositeMatchers = new OrRequestMatcher(matchers);
|
||||
return compositeMatchers.matches(request);
|
||||
}
|
||||
|
||||
@@ -2,18 +2,20 @@ package it.fabioformosa.quartzmanager.api.security.helpers.impl;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import it.fabioformosa.quartzmanager.api.security.properties.JwtSecurityProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Base64;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -25,16 +27,19 @@ public class JwtTokenHelper {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JwtTokenHelper.class);
|
||||
|
||||
private static String base64EncodeSecretKey(String secretKey) {
|
||||
return Base64.getEncoder().encodeToString(secretKey.getBytes(StandardCharsets.UTF_8));
|
||||
private static SecretKey signingKey(String secretKey) {
|
||||
try {
|
||||
byte[] keyBytes = MessageDigest.getInstance("SHA-512").digest(secretKey.getBytes(StandardCharsets.UTF_8));
|
||||
return new SecretKeySpec(keyBytes, "HmacSHA512");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("Unable to create JWT signing key", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final String appName;
|
||||
|
||||
private final JwtSecurityProperties jwtSecurityProps;
|
||||
|
||||
private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS512;
|
||||
|
||||
public JwtTokenHelper(String appName, JwtSecurityProperties jwtSecurityProps) {
|
||||
super();
|
||||
this.appName = appName;
|
||||
@@ -60,20 +65,20 @@ public class JwtTokenHelper {
|
||||
}
|
||||
|
||||
private String generateToken(Map<String, Object> claims) {
|
||||
return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate())
|
||||
.signWith(SIGNATURE_ALGORITHM, base64EncodeSecretKey(jwtSecurityProps.getSecret())).compact();
|
||||
return Jwts.builder().claims(claims).expiration(generateExpirationDate())
|
||||
.signWith(signingKey(jwtSecurityProps.getSecret()), Jwts.SIG.HS512).compact();
|
||||
}
|
||||
|
||||
public String generateToken(String username) {
|
||||
return Jwts.builder().setIssuer(appName).setSubject(username).setIssuedAt(generateCurrentDate())
|
||||
.setExpiration(generateExpirationDate())
|
||||
.signWith(SIGNATURE_ALGORITHM, base64EncodeSecretKey(jwtSecurityProps.getSecret())).compact();
|
||||
return Jwts.builder().issuer(appName).subject(username).issuedAt(generateCurrentDate())
|
||||
.expiration(generateExpirationDate())
|
||||
.signWith(signingKey(jwtSecurityProps.getSecret()), Jwts.SIG.HS512).compact();
|
||||
}
|
||||
|
||||
private Claims verifyAndGetClaimsFromToken(String token) {
|
||||
Claims claims;
|
||||
claims = Jwts.parser().setSigningKey(base64EncodeSecretKey(jwtSecurityProps.getSecret()))
|
||||
.parseClaimsJws(token).getBody();
|
||||
claims = Jwts.parser().verifyWith(signingKey(jwtSecurityProps.getSecret())).build()
|
||||
.parseSignedClaims(token).getPayload();
|
||||
if (claims == null)
|
||||
throw new IllegalStateException("Not found any claims into the JWT token!");
|
||||
return claims;
|
||||
@@ -108,8 +113,8 @@ public class JwtTokenHelper {
|
||||
String refreshedToken;
|
||||
try {
|
||||
final Claims claims = verifyAndGetClaimsFromToken(token);
|
||||
claims.setIssuedAt(generateCurrentDate());
|
||||
refreshedToken = generateToken(claims);
|
||||
refreshedToken = Jwts.builder().claims(claims).issuedAt(generateCurrentDate()).expiration(generateExpirationDate())
|
||||
.signWith(signingKey(jwtSecurityProps.getSecret()), Jwts.SIG.HS512).compact();
|
||||
} catch (Exception e) {
|
||||
log.error("Error refreshing jwt token due to " + e.getMessage(), e);
|
||||
refreshedToken = null;
|
||||
|
||||
@@ -4,9 +4,9 @@ import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package it.fabioformosa.quartzmanager.api.security.helpers.impl;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurer;
|
||||
import org.springframework.security.web.DefaultSecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
|
||||
import it.fabioformosa.quartzmanager.api.security.helpers.LoginConfigurer;
|
||||
|
||||
@@ -13,11 +10,10 @@ import it.fabioformosa.quartzmanager.api.security.helpers.LoginConfigurer;
|
||||
* It wraps the httpSecurity to provide new function as login and logout
|
||||
*
|
||||
*/
|
||||
public class QuartzManagerHttpSecurity extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
|
||||
public class QuartzManagerHttpSecurity {
|
||||
|
||||
public static QuartzManagerHttpSecurity from(HttpSecurity httpSecurity){
|
||||
QuartzManagerHttpSecurity newInstance = new QuartzManagerHttpSecurity(httpSecurity);
|
||||
newInstance.setBuilder(httpSecurity);
|
||||
return newInstance;
|
||||
}
|
||||
|
||||
@@ -39,13 +35,14 @@ public class QuartzManagerHttpSecurity extends SecurityConfigurerAdapter<Default
|
||||
}
|
||||
|
||||
|
||||
public LogoutConfigurer<HttpSecurity> logout(String logoutPath) throws Exception {
|
||||
LogoutConfigurer<HttpSecurity> logoutConfigurer = httpSecurity.logout().logoutRequestMatcher(new AntPathRequestMatcher(logoutPath))
|
||||
.logoutSuccessHandler(logoutSuccess);
|
||||
public HttpSecurity logout(String logoutPath) throws Exception {
|
||||
String cookie = loginConfigurer.cookieMustBeDeletedAtLogout();
|
||||
if(cookie != null)
|
||||
logoutConfigurer.deleteCookies(cookie);
|
||||
return logoutConfigurer;
|
||||
return httpSecurity.logout(logout -> {
|
||||
logout.logoutRequestMatcher(PathPatternRequestMatcher.withDefaults().matcher(logoutPath));
|
||||
logout.logoutSuccessHandler(logoutSuccess);
|
||||
if(cookie != null)
|
||||
logout.deleteCookies(cookie);
|
||||
});
|
||||
}
|
||||
|
||||
public QuartzManagerHttpSecurity withLoginConfigurer(LoginConfigurer loginConfigurer, LogoutSuccess logoutSuccess) {
|
||||
|
||||
@@ -3,8 +3,8 @@ package it.fabioformosa.quartzmanager.api.security.helpers.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
@@ -20,4 +20,3 @@ public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
package it.fabioformosa.quartzmanager.api.security;
|
||||
|
||||
import it.fabioformosa.quartzmanager.api.security.models.UserTokenState;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestClient;
|
||||
|
||||
import static it.fabioformosa.quartzmanager.api.common.config.QuartzManagerPaths.QUARTZ_MANAGER_LOGIN_PATH;
|
||||
|
||||
public abstract class AbstractSecurityLoginTest {
|
||||
@Autowired
|
||||
private TestRestTemplate testRestTemplate;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
protected ResponseEntity<UserTokenState> doLogin() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
map.add("username", "foo");
|
||||
map.add("password", "bar");
|
||||
|
||||
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers);
|
||||
|
||||
ResponseEntity<UserTokenState> responseEntity = testRestTemplate.exchange(QUARTZ_MANAGER_LOGIN_PATH, HttpMethod.POST, entity, UserTokenState.class);
|
||||
return responseEntity;
|
||||
return RestClient.create("http://localhost:" + port)
|
||||
.post()
|
||||
.uri(QUARTZ_MANAGER_LOGIN_PATH)
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.body(map)
|
||||
.retrieve()
|
||||
.toEntity(UserTokenState.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,13 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest
|
||||
@@ -60,9 +60,8 @@ class SecurityControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser("admin")
|
||||
void givenAnUser_whenCalledATestScheduler_thenShouldReturn2xx() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(TestController.QUARTZ_MANAGER + "/scheduler"))
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(TestController.QUARTZ_MANAGER + "/scheduler").with(user("admin")))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@ package it.fabioformosa.quartzmanager.api.security.controllers;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static it.fabioformosa.quartzmanager.api.common.config.QuartzManagerPaths.QUARTZ_MANAGER_AUTH_PATH;
|
||||
import static it.fabioformosa.quartzmanager.api.security.controllers.UserController.WHOAMI_URL;
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest
|
||||
@@ -27,9 +27,8 @@ class UserControllerTest {
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Test
|
||||
@WithMockUser("admin")
|
||||
void givenAnUser_whenCalledTheWhoamiEndpoint_thenShouldReturn2xx() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(QUARTZ_MANAGER_AUTH_PATH + WHOAMI_URL))
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(QUARTZ_MANAGER_AUTH_PATH + WHOAMI_URL).with(user("admin")))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
|
||||
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
|
||||
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>9</java.version>
|
||||
<java.version>17</java.version>
|
||||
<frontend.folderName>quartz-manager-frontend</frontend.folderName>
|
||||
<node.version>v16.14.1</node.version>
|
||||
<npm.version>8.19.3</npm.version>
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<springdoc-openapi.version>1.5.12</springdoc-openapi.version>
|
||||
<java.version>9</java.version>
|
||||
<springdoc-openapi.version>3.0.3</springdoc-openapi.version>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -59,18 +59,23 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-webmvc-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MISC -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>${springdoc-openapi.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.0</version>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.13.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
@@ -86,7 +91,7 @@
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -96,6 +101,7 @@
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>spring-mock-mvc</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -135,8 +141,7 @@
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<source>9</source>
|
||||
<target>9</target>
|
||||
<release>${java.version}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
@@ -4,7 +4,7 @@ import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
import lombok.Generated;
|
||||
import org.springdoc.core.GroupedOpenApi;
|
||||
import org.springdoc.core.models.GroupedOpenApi;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/session")
|
||||
|
||||
Reference in New Issue
Block a user