diff --git a/quartz-manager-parent/pom.xml b/quartz-manager-parent/pom.xml
index a6213f7..57c3d5f 100644
--- a/quartz-manager-parent/pom.xml
+++ b/quartz-manager-parent/pom.xml
@@ -18,8 +18,9 @@
quartz-manager-api
quartz-manager-ui-webjar
+ quartz-manager-security
quartz-manager-web-showcase
- quartz-manager-security
+
@@ -28,6 +29,16 @@
quartz-manager-api
2.2.2-SNAPSHOT
+
+ it.fabioformosa.quartz-manager
+ quartz-manager-security
+ 2.2.2-SNAPSHOT
+
+
+ it.fabioformosa.quartz-manager
+ quartz-manager-ui-webjar
+ 2.2.2-SNAPSHOT
+
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/controllers/AuthenticationController.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/controllers/AuthenticationController.java
new file mode 100644
index 0000000..ca02749
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/controllers/AuthenticationController.java
@@ -0,0 +1,82 @@
+package it.fabioformosa.quartzmanager.security.controllers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import it.fabioformosa.quartzmanager.security.helpers.impl.JwtTokenHelper;
+import it.fabioformosa.quartzmanager.security.models.UserTokenState;
+import it.fabioformosa.quartzmanager.security.services.impl.CustomUserDetailsService;
+
+/**
+ * JWT Temporary disabled
+ *
+ * @author Fabio.Formosa
+ *
+ */
+
+//@RestController
+//@RequestMapping( value = "/api", produces = MediaType.APPLICATION_JSON_VALUE )
+public class AuthenticationController {
+
+ static class PasswordChanger {
+ public String oldPassword;
+ public String newPassword;
+ }
+
+ @Autowired
+ private CustomUserDetailsService userDetailsService;
+
+ @Autowired
+ JwtTokenHelper tokenHelper;
+
+ @Value("${quartz-manager.security.jwt.expiration-in-sec}")
+ private int EXPIRES_IN_SEC;
+
+ @Value("${quartz-manager.security.jwt.cookie-strategy-cookie}")
+ private String TOKEN_COOKIE;
+
+ @RequestMapping(value = "/changePassword", method = RequestMethod.POST)
+ @PreAuthorize("hasRole('USER')")
+ public ResponseEntity> changePassword(@RequestBody PasswordChanger passwordChanger) {
+ userDetailsService.changePassword(passwordChanger.oldPassword, passwordChanger.newPassword);
+ Map result = new HashMap<>();
+ result.put( "result", "success" );
+ return ResponseEntity.accepted().body(result);
+ }
+
+ @RequestMapping(value = "/refresh", method = RequestMethod.GET)
+ public ResponseEntity> refreshAuthenticationToken(HttpServletRequest request, HttpServletResponse response) {
+
+ String authToken = tokenHelper.retrieveToken( request );
+ if (authToken != null && tokenHelper.canTokenBeRefreshed(authToken)) {
+ // TODO check user password last update
+ String refreshedToken = tokenHelper.refreshToken(authToken);
+
+ Cookie authCookie = new Cookie( TOKEN_COOKIE, refreshedToken );
+ authCookie.setPath( "/quartz-manager" );
+ authCookie.setHttpOnly( true );
+ authCookie.setMaxAge( EXPIRES_IN_SEC );
+ // Add cookie to response
+ response.addCookie( authCookie );
+
+ UserTokenState userTokenState = new UserTokenState(refreshedToken, EXPIRES_IN_SEC);
+ return ResponseEntity.ok(userTokenState);
+ } else {
+ UserTokenState userTokenState = new UserTokenState();
+ return ResponseEntity.accepted().body(userTokenState);
+ }
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/pom.xml b/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
index 1c353c1..654e9e4 100644
--- a/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
+++ b/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
@@ -28,11 +28,14 @@
it.fabioformosa.quartz-manager
quartz-manager-api
-
-
-
-
-
+
+ it.fabioformosa.quartz-manager
+ quartz-manager-ui-webjar
+
+
+ it.fabioformosa.quartz-manager
+ quartz-manager-security
+
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/WebSecurityConfigJWT.java b/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/WebSecurityConfigJWT.java
deleted file mode 100644
index c3e2d8c..0000000
--- a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/WebSecurityConfigJWT.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package it.fabioformosa.quartzmanager.configuration;
-
-import org.apache.commons.lang3.BooleanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
-import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.crypto.factory.PasswordEncoderFactories;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.security.web.authentication.HttpStatusEntryPoint;
-import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.CorsConfigurationSource;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import it.fabioformosa.quartzmanager.configuration.properties.InMemoryAccountProperties;
-import it.fabioformosa.quartzmanager.configuration.properties.JwtSecurityProperties;
-import it.fabioformosa.quartzmanager.security.helpers.LoginConfigurer;
-import it.fabioformosa.quartzmanager.security.helpers.impl.AuthenticationFailureHandler;
-import it.fabioformosa.quartzmanager.security.helpers.impl.AuthenticationSuccessHandler;
-import it.fabioformosa.quartzmanager.security.helpers.impl.FormLoginConfig;
-import it.fabioformosa.quartzmanager.security.helpers.impl.JwtAuthenticationSuccessHandler;
-import it.fabioformosa.quartzmanager.security.helpers.impl.JwtAuthenticationSuccessHandlerImpl;
-import it.fabioformosa.quartzmanager.security.helpers.impl.JwtTokenAuthenticationFilter;
-import it.fabioformosa.quartzmanager.security.helpers.impl.JwtTokenHelper;
-import it.fabioformosa.quartzmanager.security.helpers.impl.JwtUsernamePasswordFiterLoginConfig;
-import it.fabioformosa.quartzmanager.security.helpers.impl.LogoutSuccess;
-import it.fabioformosa.quartzmanager.security.helpers.impl.QuartzManagerHttpSecurity;
-
-/**
- *
- * @author Fabio.Formosa
- *
- */
-@Configuration
-@EnableWebSecurity
-@EnableGlobalMethodSecurity(prePostEnabled = true)
-public class WebSecurityConfigJWT extends WebSecurityConfigurerAdapter {
-
- private static final String[] PATTERNS_SWAGGER_UI = {"/swagger-ui.html", "/v2/api-docs", "/swagger-resources/**", "/webjars/**"};
-
- private static final String LOGIN_PATH = "/quartz-manager/api/login";
- private static final String LOGOUT_PATH = "/quartz-manager/api/logout";
-
- @Value("${server.servlet.context-path}")
- private String contextPath;
-
- @Value("${app.name}")
- private String APP_NAME;
-
- @Value("${quartz-manager.security.login-model.form-login-enabled}")
- private Boolean formLoginEnabled;
- @Value("${quartz-manager.security.login-model.userpwd-filter-enabled}")
- private Boolean userpwdFilterEnabled;
-
- @Autowired
- private JwtSecurityProperties jwtSecurityProps;
-
- @Autowired
- private ObjectMapper objectMapper;
-
- @Autowired
- private UserDetailsService userDetailsService;
-
- @Autowired
- private InMemoryAccountProperties inMemoryAccountProps;
-
-
- @Override
- public void configure(AuthenticationManagerBuilder authenticationManagerBuilder)throws Exception {
- configureInMemoryAuthentication(authenticationManagerBuilder);
- }
-
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.csrf().disable() //
- .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() //
- .exceptionHandling().authenticationEntryPoint(restAuthEntryPoint()).and() //
- .addFilterBefore(jwtAuthenticationTokenFilter(), BasicAuthenticationFilter.class) //
- .authorizeRequests().anyRequest().authenticated();
-
- QuartzManagerHttpSecurity.from(http).withLoginConfigurer(loginConfigurer(), logoutConfigurer()) //
- .login(LOGIN_PATH, authenticationManager()).logout(LOGOUT_PATH);
-
- // temporary disabled csfr
- // http.csrf().ignoringAntMatchers("/api/login", "/api/signup") //
- // .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) //
- }
-
- @Override
- public void configure(WebSecurity web) throws Exception {
- web.ignoring()//
- .antMatchers(HttpMethod.GET, PATTERNS_SWAGGER_UI) //
- .antMatchers(HttpMethod.GET,"/css/**", "/js/**", "/img/**", "/lib/**");
- }
-
- private void configureInMemoryAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
- PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
- if(inMemoryAccountProps.isEnabled() && inMemoryAccountProps.getUsers() != null && !inMemoryAccountProps.getUsers().isEmpty()) {
- InMemoryUserDetailsManagerConfigurer inMemoryAuth = authenticationManagerBuilder.inMemoryAuthentication();
- inMemoryAccountProps.getUsers()
- .forEach(u -> inMemoryAuth
- .withUser(u.getName())
- .password(encoder.encode(u.getPassword()))
- .roles(u.getRoles().toArray(new String[0])));
- }
- }
-
- @Bean
- CorsConfigurationSource corsConfigurationSource() {
- UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
- source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
- return source;
- }
-
- @Bean
- public LoginConfigurer formLoginConfigurer() {
- JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler = jwtAuthenticationSuccessHandler();
- AuthenticationSuccessHandler authenticationSuccessHandler = new AuthenticationSuccessHandler(jwtAuthenticationSuccessHandler);
- AuthenticationFailureHandler authenticationFailureHandler = new AuthenticationFailureHandler();
- LoginConfigurer loginConfigurer = new FormLoginConfig(authenticationSuccessHandler, authenticationFailureHandler);
- return loginConfigurer;
- }
-
- @Bean
- public JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler() {
- JwtTokenHelper jwtTokenHelper = jwtTokenHelper();
- JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler = new JwtAuthenticationSuccessHandlerImpl(contextPath, jwtSecurityProps, jwtTokenHelper, objectMapper);
- return jwtAuthenticationSuccessHandler;
- }
-
- @Bean
- public JwtTokenAuthenticationFilter jwtAuthenticationTokenFilter() throws Exception {
- return new JwtTokenAuthenticationFilter(jwtTokenHelper(), userDetailsService);
- }
-
- @Bean
- public JwtTokenHelper jwtTokenHelper() {
- return new JwtTokenHelper(APP_NAME, jwtSecurityProps);
- }
-
- @Bean
- public LoginConfigurer loginConfigurer() {
- if(BooleanUtils.isTrue(userpwdFilterEnabled))
- return userpwdFilterLoginConfigurer();
- if(BooleanUtils.isNotFalse(formLoginEnabled))
- return formLoginConfigurer();
- throw new RuntimeException("No login configurer enabled!");
- }
-
- @Bean
- public LogoutSuccess logoutConfigurer() {
- return new LogoutSuccess(objectMapper);
- }
-
- @Bean
- public AuthenticationEntryPoint restAuthEntryPoint() {
- return new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED);
- }
-
- @Bean
- @Override
- public UserDetailsService userDetailsServiceBean() throws Exception {
- return super.userDetailsServiceBean();
- }
-
- @Bean
- public LoginConfigurer userpwdFilterLoginConfigurer() {
- LoginConfigurer loginConfigurer = new JwtUsernamePasswordFiterLoginConfig(jwtAuthenticationSuccessHandler());
- return loginConfigurer;
- }
-
- // @Bean
- // public PasswordEncoder passwordEncoder() {
- // return new BCryptPasswordEncoder();
- // }
-
-}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/properties/InMemoryAccountProperties.java b/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/properties/InMemoryAccountProperties.java
deleted file mode 100644
index a6905ba..0000000
--- a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/properties/InMemoryAccountProperties.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package it.fabioformosa.quartzmanager.configuration.properties;
-
-import lombok.Getter;
-import lombok.Setter;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Configuration
-@ConfigurationProperties(prefix = "quartz-manager.accounts.in-memory")
-@Getter @Setter
-public class InMemoryAccountProperties {
- private boolean enabled;
- private List users;
-
- @Getter @Setter
- public static class User {
- private String name;
- private String password;
- private List roles = new ArrayList<>();
- }
-}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/properties/JwtSecurityProperties.java b/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/properties/JwtSecurityProperties.java
deleted file mode 100644
index e33baba..0000000
--- a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/configuration/properties/JwtSecurityProperties.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package it.fabioformosa.quartzmanager.configuration.properties;
-
-import lombok.Data;
-import lombok.Getter;
-import lombok.Setter;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-
-@Configuration
-@ConfigurationProperties(prefix = "quartz-manager.security.jwt")
-@Getter @Setter
-public class JwtSecurityProperties {
- private boolean enabled;
- private String secret;
- private long expirationInSec;
-
- private CookieStrategy cookieStrategy;
- private HeaderStrategy headerStrategy;
-
- @Data
- public static class CookieStrategy {
- private boolean enabled;
- private String cookie;
- }
-
- @Data
- public static class HeaderStrategy {
- private boolean enabled;
- private String header;
- }
-
-}
\ No newline at end of file
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/controllers/AuthenticationController.java b/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/controllers/AuthenticationController.java
deleted file mode 100644
index 4b0d704..0000000
--- a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/controllers/AuthenticationController.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package it.fabioformosa.quartzmanager.controllers;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-
-import it.fabioformosa.quartzmanager.security.helpers.impl.JwtTokenHelper;
-import it.fabioformosa.quartzmanager.security.model.UserTokenState;
-import it.fabioformosa.quartzmanager.security.service.impl.CustomUserDetailsService;
-
-/**
- * JWT Temporary disabled
- *
- * @author Fabio.Formosa
- *
- */
-
-//@RestController
-//@RequestMapping( value = "/api", produces = MediaType.APPLICATION_JSON_VALUE )
-public class AuthenticationController {
-
- static class PasswordChanger {
- public String oldPassword;
- public String newPassword;
- }
-
- @Autowired
- private CustomUserDetailsService userDetailsService;
-
- @Autowired
- JwtTokenHelper tokenHelper;
-
- @Value("${quartz-manager.security.jwt.expiration-in-sec}")
- private int EXPIRES_IN_SEC;
-
- @Value("${quartz-manager.security.jwt.cookie-strategy-cookie}")
- private String TOKEN_COOKIE;
-
- @RequestMapping(value = "/changePassword", method = RequestMethod.POST)
- @PreAuthorize("hasRole('USER')")
- public ResponseEntity> changePassword(@RequestBody PasswordChanger passwordChanger) {
- userDetailsService.changePassword(passwordChanger.oldPassword, passwordChanger.newPassword);
- Map result = new HashMap<>();
- result.put( "result", "success" );
- return ResponseEntity.accepted().body(result);
- }
-
- @RequestMapping(value = "/refresh", method = RequestMethod.GET)
- public ResponseEntity> refreshAuthenticationToken(HttpServletRequest request, HttpServletResponse response) {
-
- String authToken = tokenHelper.retrieveToken( request );
- if (authToken != null && tokenHelper.canTokenBeRefreshed(authToken)) {
- // TODO check user password last update
- String refreshedToken = tokenHelper.refreshToken(authToken);
-
- Cookie authCookie = new Cookie( TOKEN_COOKIE, refreshedToken );
- authCookie.setPath( "/quartz-manager" );
- authCookie.setHttpOnly( true );
- authCookie.setMaxAge( EXPIRES_IN_SEC );
- // Add cookie to response
- response.addCookie( authCookie );
-
- UserTokenState userTokenState = new UserTokenState(refreshedToken, EXPIRES_IN_SEC);
- return ResponseEntity.ok(userTokenState);
- } else {
- UserTokenState userTokenState = new UserTokenState();
- return ResponseEntity.accepted().body(userTokenState);
- }
- }
-
-}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/controllers/UserController.java b/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/controllers/UserController.java
deleted file mode 100644
index 5df6496..0000000
--- a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/quartzmanager/controllers/UserController.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package it.fabioformosa.quartzmanager.controllers;
-
-import org.springframework.http.MediaType;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping(value = "/quartz-manager/api", produces = MediaType.APPLICATION_JSON_VALUE)
-public class UserController {
-
- /**
- * JWT Temporary disabled
- *
- * @author Fabio.Formosa
- *
- */
-
- // @Autowired
- // private UserService userService;
-
-
- // @RequestMapping(method = POST, value = "/signup")
- // public ResponseEntity> addUser(@RequestBody UserRequest userRequest,
- // UriComponentsBuilder ucBuilder) {
- //
- // User existUser = this.userService.findByUsername(userRequest.getUsername());
- // if (existUser != null)
- // throw new ResourceConflictException(userRequest.getId(), "Username already exists");
- // User user = this.userService.save(userRequest);
- // HttpHeaders headers = new HttpHeaders();
- // headers.setLocation(ucBuilder.path("/api/user/{userId}").buildAndExpand(user.getId()).toUri());
- // return new ResponseEntity<>(user, HttpStatus.CREATED);
- // }
- //
- // @RequestMapping(method = GET, value = "/user/all")
- // public List loadAll() {
- // return this.userService.findAll();
- // }
- //
- // @RequestMapping(method = GET, value = "/user/{userId}")
- // public User loadById(@PathVariable Long userId) {
- // return this.userService.findById(userId);
- // }
- //
- //
- // @RequestMapping(method = GET, value = "/user/reset-credentials")
- // public ResponseEntity