diff --git a/quartz-manager-frontend/src/app/services/api.service.ts b/quartz-manager-frontend/src/app/services/api.service.ts
index d89a780..c7fde7c 100644
--- a/quartz-manager-frontend/src/app/services/api.service.ts
+++ b/quartz-manager-frontend/src/app/services/api.service.ts
@@ -53,9 +53,6 @@ export class ApiService {
if (args)
options['params'] = serialize(args);
- // if(this.jwtToken)
- // options.headers = options.headers.set('Authorization', `Bearer ${this.jwtToken}`);
-
return this.http.get(path, options)
.pipe(catchError(this.checkError.bind(this)));
}
@@ -78,9 +75,6 @@ export class ApiService {
withCredentials: true
}
- // if(this.jwtToken)
- // options.headers = options.headers.append('Authorization', `Bearer ${this.jwtToken}`);
-
const req = new HttpRequest(method, path, body, options);
return this.http.request(req)
diff --git a/quartz-manager-parent/pom.xml b/quartz-manager-parent/pom.xml
index 8fe58c4..a6213f7 100644
--- a/quartz-manager-parent/pom.xml
+++ b/quartz-manager-parent/pom.xml
@@ -19,7 +19,7 @@
quartz-manager-api
quartz-manager-ui-webjar
quartz-manager-web-showcase
-
+ quartz-manager-security
diff --git a/quartz-manager-parent/quartz-manager-security/pom.xml b/quartz-manager-parent/quartz-manager-security/pom.xml
new file mode 100644
index 0000000..d8945a3
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/pom.xml
@@ -0,0 +1,57 @@
+
+ 4.0.0
+
+ it.fabioformosa.quartz-manager
+ quartz-manager-parent
+ 2.2.2-SNAPSHOT
+
+
+ quartz-manager-security
+
+ Quartz Manager Security
+ Security Layer for Quartz Manager
+
+ https://github.com/fabioformosa/quartz-manager
+
+ ${basedir}/../..
+ UTF-8
+ UTF-8
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ io.jsonwebtoken
+ jjwt
+ 0.9.0
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+ javax.servlet
+ javax.servlet-api
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/WebSecurityConfigJWT.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/WebSecurityConfigJWT.java
new file mode 100644
index 0000000..c5bcb07
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/WebSecurityConfigJWT.java
@@ -0,0 +1,194 @@
+package it.fabioformosa.quartzmanager.security.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.security.configuration.properties.InMemoryAccountProperties;
+import it.fabioformosa.quartzmanager.security.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";
+
+ private static final String WEBJAR_PATH = "/quartz-manager-ui";
+
+ @Value("${server.servlet.context-path:/}")
+ private String contextPath;
+
+ @Value("${app.name:quartz-manager}")
+ 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, WEBJAR_PATH + "/css/**", WEBJAR_PATH + "/js/**", WEBJAR_PATH + "/img/**", WEBJAR_PATH + "/lib/**", WEBJAR_PATH + "/assets/**");
+ }
+
+ 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-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/properties/InMemoryAccountProperties.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/properties/InMemoryAccountProperties.java
new file mode 100644
index 0000000..279a079
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/properties/InMemoryAccountProperties.java
@@ -0,0 +1,24 @@
+package it.fabioformosa.quartzmanager.security.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-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/properties/JwtSecurityProperties.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/properties/JwtSecurityProperties.java
new file mode 100644
index 0000000..1afec00
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/configuration/properties/JwtSecurityProperties.java
@@ -0,0 +1,33 @@
+package it.fabioformosa.quartzmanager.security.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-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/LoginConfigurer.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/LoginConfigurer.java
new file mode 100644
index 0000000..4446087
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/LoginConfigurer.java
@@ -0,0 +1,21 @@
+package it.fabioformosa.quartzmanager.security.helpers;
+
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+
+/**
+ * It configures filters to authenticate credentials sent by client or to set authenticationSuccessHandler
+ *
+ * Implement this interface for a login strategy
+ *
+ */
+public interface LoginConfigurer {
+
+ /**
+ * If the authentication is based on cookie, it returns the name of cookie to be erased at the logout
+ */
+ String cookieMustBeDeletedAtLogout();
+
+ HttpSecurity login(String loginPath, HttpSecurity http, AuthenticationManager authenticationManager) throws Exception;
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AjaxAuthenticationFilter.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AjaxAuthenticationFilter.java
new file mode 100644
index 0000000..0c4e0b3
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AjaxAuthenticationFilter.java
@@ -0,0 +1,55 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.WebAttributes;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+public class AjaxAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
+
+ public class AjaxLoginAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler
+ implements AuthenticationSuccessHandler {
+
+ @Override
+ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
+ Authentication authentication) throws IOException, ServletException {
+ response.setStatus(HttpServletResponse.SC_OK);
+ clearAuthenticationAttributes(request);
+ return;
+ }
+
+ }
+
+ public AjaxAuthenticationFilter(AuthenticationManager authenticationManager) {
+ setAuthenticationManager(authenticationManager);
+ setUsernameParameter("ajaxUsername");
+ setPasswordParameter("ajaxPassword");
+ setPostOnly(true);
+ setFilterProcessesUrl("/ajaxLogin");
+
+ setAuthenticationSuccessHandler(new AjaxLoginAuthSuccessHandler());
+ }
+
+ /**
+ * Removes temporary authentication-related data which may have been stored
+ * in the session during the authentication process.
+ */
+ protected final void clearAuthenticationAttributes(HttpServletRequest request) {
+ HttpSession session = request.getSession(false);
+
+ if (session == null)
+ return;
+
+ session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AnonAuthentication.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AnonAuthentication.java
new file mode 100644
index 0000000..f1c266f
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AnonAuthentication.java
@@ -0,0 +1,45 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+
+public class AnonAuthentication extends AbstractAuthenticationToken {
+ private static final long serialVersionUID = 1L;
+
+ public AnonAuthentication() {
+ super( null );
+ }
+
+ @Override
+ public boolean equals( Object obj ) {
+ if ( this == obj )
+ return true;
+ if ( obj == null )
+ return false;
+ if ( getClass() != obj.getClass() )
+ return false;
+ return true;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return null;
+ }
+
+ @Override
+ public Object getPrincipal() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ return hash;
+ }
+
+ @Override
+ public boolean isAuthenticated() {
+ return true;
+ }
+
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AuthenticationFailureHandler.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AuthenticationFailureHandler.java
new file mode 100644
index 0000000..08bb8b4
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AuthenticationFailureHandler.java
@@ -0,0 +1,20 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
+
+public class AuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
+
+ @Override
+ public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException exception) throws IOException, ServletException {
+
+ super.onAuthenticationFailure(request, response, exception);
+ }
+}
\ No newline at end of file
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AuthenticationSuccessHandler.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AuthenticationSuccessHandler.java
new file mode 100644
index 0000000..6634870
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/AuthenticationSuccessHandler.java
@@ -0,0 +1,35 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
+
+//@Component
+//@ConditionalOnProperty(prefix = "quartz-manager.security.login-model", name = "form-login-enabled", havingValue = "true", matchIfMissing = true)
+public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
+
+ private final JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler;
+
+ // @Autowired
+ public AuthenticationSuccessHandler(JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler) {
+ super();
+ this.jwtAuthenticationSuccessHandler = jwtAuthenticationSuccessHandler;
+ }
+
+ public String cookieMustBeDeletedAtLogout() {
+ return jwtAuthenticationSuccessHandler.cookieMustBeDeletedAtLogout();
+ }
+
+ @Override
+ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
+ Authentication authentication ) throws IOException, ServletException {
+ clearAuthenticationAttributes(request);
+ jwtAuthenticationSuccessHandler.onLoginSuccess(authentication, response);
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/ComboEntryPoint.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/ComboEntryPoint.java
new file mode 100644
index 0000000..7ab933d
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/ComboEntryPoint.java
@@ -0,0 +1,33 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ComboEntryPoint extends LoginUrlAuthenticationEntryPoint {
+
+ private static final String LOGIN_FORM_URL = "/login";
+
+ public ComboEntryPoint() {
+ super(LOGIN_FORM_URL);
+ }
+
+ @Override
+ public void commence(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException authException) throws IOException, ServletException {
+
+ if (RESTRequestMatcher.isRestRequest(request)
+ || WebsocketRequestMatcher.isWebsocketConnectionRequest(request))
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
+ else
+ super.commence(request, response, authException);
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/FormLoginConfig.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/FormLoginConfig.java
new file mode 100644
index 0000000..206f969
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/FormLoginConfig.java
@@ -0,0 +1,75 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+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;
+
+import it.fabioformosa.quartzmanager.security.helpers.LoginConfigurer;
+
+/**
+ * It delegates form to @FormLoginConfigurer of the httpSecurity.
+ *
+ */
+public class FormLoginConfig implements LoginConfigurer {
+
+ private static final Logger log = LoggerFactory.getLogger(FormLoginConfig.class);
+
+ private final AuthenticationSuccessHandler authenticationSuccessHandler;
+
+ private final AuthenticationFailureHandler authenticationFailureHandler;
+
+
+ public FormLoginConfig() {
+ super();
+ authenticationSuccessHandler = null;
+ authenticationFailureHandler = null;
+ }
+
+ public FormLoginConfig(AuthenticationFailureHandler authenticationFailureHandler) {
+ super();
+ authenticationSuccessHandler = null;
+ this.authenticationFailureHandler = authenticationFailureHandler;
+ }
+
+ public FormLoginConfig(AuthenticationSuccessHandler authenticationSuccessHandler) {
+ super();
+ this.authenticationSuccessHandler = authenticationSuccessHandler;
+ authenticationFailureHandler = null;
+ }
+
+ public FormLoginConfig(AuthenticationSuccessHandler authenticationSuccessHandler,
+ AuthenticationFailureHandler authenticationFailureHandler) {
+ super();
+ this.authenticationSuccessHandler = authenticationSuccessHandler;
+ this.authenticationFailureHandler = authenticationFailureHandler;
+ }
+
+ @Override
+ public String cookieMustBeDeletedAtLogout() {
+ return authenticationSuccessHandler.cookieMustBeDeletedAtLogout();
+ }
+
+ @Override
+ public HttpSecurity login(String loginPath,
+ HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
+ log.debug("Configuring login through FormLoginConfigurer...");
+
+ FormLoginConfigurer 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);
+ }
+
+ HttpSecurity httpSecurity = login.and();
+ return httpSecurity;
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationFilter.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationFilter.java
new file mode 100644
index 0000000..c15c0ac
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationFilter.java
@@ -0,0 +1,34 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import javax.servlet.FilterChain;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+import lombok.SneakyThrows;
+
+/**
+ * It extends the @UsernamePasswordAuthenticationFilter and it overrides the successfulAuthentication method to put jwtToken in the response
+ *
+ */
+public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
+
+ private JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler;
+
+ public JwtAuthenticationFilter(AuthenticationManager authenticationManager, JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler) {
+ this.jwtAuthenticationSuccessHandler = jwtAuthenticationSuccessHandler;
+ setAuthenticationManager(authenticationManager);
+ }
+
+ @SneakyThrows
+ @Override
+ protected void successfulAuthentication(HttpServletRequest req,
+ HttpServletResponse res,
+ FilterChain chain,
+ Authentication auth) {
+ jwtAuthenticationSuccessHandler.onLoginSuccess(auth, res);
+ }
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationSuccessHandler.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationSuccessHandler.java
new file mode 100644
index 0000000..6a956c9
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationSuccessHandler.java
@@ -0,0 +1,14 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.Authentication;
+
+public interface JwtAuthenticationSuccessHandler {
+
+ String cookieMustBeDeletedAtLogout();
+
+ void onLoginSuccess(Authentication authentication, HttpServletResponse response) throws IOException;
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationSuccessHandlerImpl.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationSuccessHandlerImpl.java
new file mode 100644
index 0000000..ca5de80
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtAuthenticationSuccessHandlerImpl.java
@@ -0,0 +1,78 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import java.io.IOException;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.userdetails.User;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import it.fabioformosa.quartzmanager.security.configuration.properties.JwtSecurityProperties;
+import it.fabioformosa.quartzmanager.security.models.UserTokenState;
+
+/**
+ * It depends on @JwtTokenHelper to generate the jwtToken.
+ * On login success, it generates the jwtToken and it returns it to the login according to possible strategies: cookie, response header.
+ * You can choice the strategy through @JwtSecurityProperties
+ *
+ */
+public class JwtAuthenticationSuccessHandlerImpl implements JwtAuthenticationSuccessHandler {
+
+ private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationSuccessHandlerImpl.class);
+
+ private final JwtSecurityProperties jwtSecurityProps;
+
+ private final JwtTokenHelper jwtTokenHelper;
+
+ private final ObjectMapper objectMapper;
+
+ private final String contextPath;
+
+ @Autowired
+ public JwtAuthenticationSuccessHandlerImpl(String contextPath, JwtSecurityProperties jwtSecurityProps, JwtTokenHelper jwtTokenHelper, ObjectMapper objectMapper) {
+ this.contextPath = contextPath;
+ this.jwtSecurityProps = jwtSecurityProps;
+ this.jwtTokenHelper = jwtTokenHelper;
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public String cookieMustBeDeletedAtLogout() {
+ if(!jwtSecurityProps.getCookieStrategy().isEnabled())
+ return null;
+ return jwtSecurityProps.getCookieStrategy().getCookie();
+ }
+
+ @Override
+ public void onLoginSuccess(Authentication authentication, HttpServletResponse response) throws IOException {
+ log.debug("Login successed, generating jwtToken...");
+
+ User user = (User) authentication.getPrincipal();
+ String jwtToken = jwtTokenHelper.generateToken(user.getUsername());
+
+ if(jwtSecurityProps.getCookieStrategy().isEnabled()) {
+ Cookie authCookie = new Cookie(jwtSecurityProps.getCookieStrategy().getCookie(), jwtToken);
+ authCookie.setHttpOnly(true);
+ authCookie.setMaxAge((int) jwtSecurityProps.getExpirationInSec());
+ authCookie.setPath(contextPath);
+ response.addCookie(authCookie);
+ log.debug("Set jwtToken into the cookie {}", jwtSecurityProps.getCookieStrategy().getCookie());
+ }
+
+ if(jwtSecurityProps.getHeaderStrategy().isEnabled()) {
+ jwtTokenHelper.setHeader(response, jwtToken);
+ log.debug("Set jwtToken into the response header {}", jwtSecurityProps.getHeaderStrategy().getHeader());
+ }
+
+ UserTokenState userTokenState = new UserTokenState(jwtToken, jwtSecurityProps.getExpirationInSec());
+ String jwtResponse = objectMapper.writeValueAsString(userTokenState);
+ response.setContentType("application/json");
+ response.getWriter().write(jwtResponse);
+ }
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenAuthenticationFilter.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenAuthenticationFilter.java
new file mode 100644
index 0000000..346bb2f
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenAuthenticationFilter.java
@@ -0,0 +1,105 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+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.web.filter.OncePerRequestFilter;
+
+
+/**
+ * It finds the jwtToken into the request, it validates it and sets an @Authentication into the @SecurityContextHolder.
+ * If the request has a path included into the paths that must be skipped, it sets an anonymous authentication
+ *
+ * It delegates the jwtToken retrieve to the @JwtTokenHelper that applies several strategies.
+ *
+ */
+public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
+
+ private static final Logger log = LoggerFactory.getLogger(JwtTokenAuthenticationFilter.class);
+
+ private static final String ROOT_MATCHER = "/";
+ private static final String FAVICON_MATCHER = "/favicon.ico";
+ private static final String HTML_MATCHER = "/**/*.html";
+ private static final String CSS_MATCHER = "/**/*.css";
+ private static final String JS_MATCHER = "/**/*.js";
+ private static final String IMG_MATCHER = "/images/*";
+ private static final String LOGIN_MATCHER = "/api/login";
+ private static final String LOGOUT_MATCHER = "/api/logout";
+
+ private static List PATH_TO_SKIP = Arrays.asList(
+ ROOT_MATCHER,
+ HTML_MATCHER,
+ FAVICON_MATCHER,
+ CSS_MATCHER,
+ JS_MATCHER,
+ IMG_MATCHER,
+ LOGIN_MATCHER,
+ LOGOUT_MATCHER
+ );
+
+ private final JwtTokenHelper jwtTokenHelper;
+ private final UserDetailsService userDetailsService;
+
+
+ public JwtTokenAuthenticationFilter(JwtTokenHelper jwtTokenHelper, UserDetailsService userDetailsService) {
+ super();
+ this.jwtTokenHelper = jwtTokenHelper;
+ this.userDetailsService = userDetailsService;
+ }
+
+ @Override
+ public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
+
+ String jwtToken = jwtTokenHelper.retrieveToken(request);
+ if (jwtToken != null) {
+ log.debug("Found a jwtToken into the request {}", request.getPathInfo());
+ try {
+ String username = jwtTokenHelper.getUsernameFromToken(jwtToken);
+ UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+
+ JwtTokenBasedAuthentication authentication = new JwtTokenBasedAuthentication(userDetails);
+ authentication.setToken(jwtToken);
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ } catch (Exception e) {
+ log.error("Authentication failed! an expected error occurred authenticating the request {}", request.getRequestURL());
+ // SecurityContextHolder.getContext().setAuthentication(new AnonAuthentication());
+ // log.error("Switched to Anonymous Authentication, "
+ // + "because an error occurred setting authentication in security context holder due to " + e.getMessage(), e);
+ }
+ }
+ else if(skipPathRequest(request, PATH_TO_SKIP)) {
+ log.debug("Detected a path to be skipped from authentication, so activated anonymous auth for {}", request.getRequestURL());
+ SecurityContextHolder.getContext().setAuthentication(new AnonAuthentication());
+ }
+ else
+ log.debug("Not found any jwtToken and the request hasn't a path to be skipped from auth. Path: {}", request.getRequestURL());
+
+ chain.doFilter(request, response);
+ }
+
+ private boolean skipPathRequest(HttpServletRequest request, List pathsToSkip ) {
+ if(pathsToSkip == null)
+ pathsToSkip = new ArrayList();
+ List matchers = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList());
+ OrRequestMatcher compositeMatchers = new OrRequestMatcher(matchers);
+ return compositeMatchers.matches(request);
+ }
+
+}
\ No newline at end of file
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenBasedAuthentication.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenBasedAuthentication.java
new file mode 100644
index 0000000..904ed07
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenBasedAuthentication.java
@@ -0,0 +1,42 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.userdetails.UserDetails;
+
+
+public class JwtTokenBasedAuthentication extends AbstractAuthenticationToken {
+
+ private static final long serialVersionUID = 1L;
+
+ private String token;
+ private final UserDetails principle;
+
+ public JwtTokenBasedAuthentication(UserDetails principle) {
+ super(principle.getAuthorities());
+ this.principle = principle;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return token;
+ }
+
+ @Override
+ public UserDetails getPrincipal() {
+ return principle;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ @Override
+ public boolean isAuthenticated() {
+ return true;
+ }
+
+ public void setToken( String token ) {
+ this.token = token;
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenHelper.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenHelper.java
new file mode 100644
index 0000000..679eb57
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenHelper.java
@@ -0,0 +1,163 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+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;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import it.fabioformosa.quartzmanager.security.configuration.properties.JwtSecurityProperties;
+
+/**
+ *
+ * @author Fabio.Formosa
+ *
+ */
+
+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));
+ }
+
+ // @Value("${app.name}")
+ private final String appName;
+
+ // @Autowired
+ private final JwtSecurityProperties jwtSecurityProps;
+
+ private SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS512;
+
+ // @Autowired
+ public JwtTokenHelper(String appName, JwtSecurityProperties jwtSecurityProps) {
+ super();
+ this.appName = appName;
+ this.jwtSecurityProps = jwtSecurityProps;
+ }
+
+ public Boolean canTokenBeRefreshed(String token) {
+ try {
+ final Date expirationDate = getClaimsFromToken(token).getExpiration();
+ // String username = getUsernameFromToken(token);
+ // UserDetails userDetails = userDetailsService.loadUserByUsername(username);
+ return expirationDate.compareTo(generateCurrentDate()) > 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ private Date generateCurrentDate() {
+ return new Date(getCurrentTimeMillis());
+ }
+
+ private Date generateExpirationDate() {
+ return new Date(getCurrentTimeMillis() + jwtSecurityProps.getExpirationInSec() * 1000);
+ }
+
+ private String generateToken(Map claims) {
+ return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate())
+ .signWith(SIGNATURE_ALGORITHM, base64EncodeSecretKey(jwtSecurityProps.getSecret())).compact();
+ }
+
+ public String generateToken(String username) {
+ return Jwts.builder().setIssuer(appName).setSubject(username).setIssuedAt(generateCurrentDate())
+ .setExpiration(generateExpirationDate())
+ .signWith(SIGNATURE_ALGORITHM, base64EncodeSecretKey(jwtSecurityProps.getSecret())).compact();
+ }
+
+ private Claims getClaimsFromToken(String token) {
+ Claims claims;
+ try {
+ claims = Jwts.parser().setSigningKey(base64EncodeSecretKey(jwtSecurityProps.getSecret()))
+ .parseClaimsJws(token).getBody();
+ } catch (Exception e) {
+ claims = null;
+ log.error("Error getting claims from jwt token due to " + e.getMessage(), e);
+ }
+ return claims;
+ }
+
+ /**
+ * Find a specific HTTP cookie in a request.
+ *
+ * @param request
+ * The HTTP request object.
+ * @param name
+ * The cookie name to look for.
+ * @return The cookie, or null if not found.
+ */
+ public Cookie getCookieValueByName(HttpServletRequest request, String name) {
+ if (request.getCookies() == null)
+ return null;
+ for (int i = 0; i < request.getCookies().length; i++)
+ if (request.getCookies()[i].getName().equals(name))
+ return request.getCookies()[i];
+ return null;
+ }
+
+ private long getCurrentTimeMillis() {
+ return LocalDateTime.now().atZone(ZoneId.of("Europe/Rome")).toInstant().toEpochMilli();
+ }
+
+ public String getUsernameFromToken(String token) {
+ String username;
+ try {
+ final Claims claims = getClaimsFromToken(token);
+ username = claims.getSubject();
+ } catch (Exception e) {
+ username = null;
+ log.error("Error getting claims from jwt token due to " + e.getMessage(), e);
+ throw e;
+ }
+ return username;
+ }
+
+ public String refreshToken(String token) {
+ String refreshedToken;
+ try {
+ final Claims claims = getClaimsFromToken(token);
+ claims.setIssuedAt(generateCurrentDate());
+ refreshedToken = generateToken(claims);
+ } catch (Exception e) {
+ log.error("Error refreshing jwt token due to " + e.getMessage(), e);
+ refreshedToken = null;
+ }
+ return refreshedToken;
+ }
+
+ public String retrieveToken(HttpServletRequest request) {
+ if (jwtSecurityProps.getCookieStrategy().isEnabled() == true) {
+ Cookie authCookie = getCookieValueByName(request, jwtSecurityProps.getCookieStrategy().getCookie());
+ if (authCookie != null)
+ return authCookie.getValue();
+ }
+
+ if (jwtSecurityProps.getHeaderStrategy().isEnabled()) {
+ String authHeader = request.getHeader(jwtSecurityProps.getHeaderStrategy().getHeader());
+ if (authHeader != null && authHeader.startsWith("Bearer "))
+ return authHeader.substring(7);
+ }
+
+ if(request.getParameter("access_token") != null)
+ return request.getParameter("access_token");
+
+ return null;
+ }
+
+ public void setHeader(HttpServletResponse response, String token) {
+ response.addHeader(jwtSecurityProps.getHeaderStrategy().getHeader(), "Bearer " + token);
+ }
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtUsernamePasswordFiterLoginConfig.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtUsernamePasswordFiterLoginConfig.java
new file mode 100644
index 0000000..6f6991c
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtUsernamePasswordFiterLoginConfig.java
@@ -0,0 +1,46 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
+import org.springframework.security.web.util.matcher.RegexRequestMatcher;
+import org.springframework.web.filter.GenericFilterBean;
+
+import it.fabioformosa.quartzmanager.security.helpers.LoginConfigurer;
+
+/**
+ * It adds a new filter @JwtAuthenticationFilter after @AbstractPreAuthenticatedProcessingFilter that match login path
+ *
+ */
+public class JwtUsernamePasswordFiterLoginConfig implements LoginConfigurer {
+
+ private static final Logger log = LoggerFactory.getLogger(JwtUsernamePasswordFiterLoginConfig.class);
+
+ private final JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler;
+
+ public JwtUsernamePasswordFiterLoginConfig(JwtAuthenticationSuccessHandler jwtAuthenticationSuccessHandler) {
+ super();
+ this.jwtAuthenticationSuccessHandler = jwtAuthenticationSuccessHandler;
+ }
+
+ public GenericFilterBean authenticationProcessingFilter(String loginPath, AuthenticationManager authenticationManager) throws Exception {
+ JwtAuthenticationFilter authenticationProcessingFilter = new JwtAuthenticationFilter(authenticationManager, jwtAuthenticationSuccessHandler);
+ authenticationProcessingFilter.setRequiresAuthenticationRequestMatcher(new RegexRequestMatcher(loginPath, HttpMethod.POST.name(), false));
+ return authenticationProcessingFilter;
+ }
+
+ @Override
+ public String cookieMustBeDeletedAtLogout() {
+ return jwtAuthenticationSuccessHandler.cookieMustBeDeletedAtLogout();
+ }
+
+ @Override
+ public HttpSecurity login(String loginPath, HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
+ log.debug("Configuring login through JwtAuthenticationFilter...");
+ return http.addFilterAfter(authenticationProcessingFilter(loginPath, authenticationManager), AbstractPreAuthenticatedProcessingFilter.class);
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/LogoutSuccess.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/LogoutSuccess.java
new file mode 100644
index 0000000..5f0eaa0
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/LogoutSuccess.java
@@ -0,0 +1,36 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+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 org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class LogoutSuccess implements LogoutSuccessHandler {
+
+ private final ObjectMapper objectMapper;
+
+ public LogoutSuccess(ObjectMapper objectMapper) {
+ super();
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse response, Authentication authentication)
+ throws IOException, ServletException {
+ Map result = new HashMap<>();
+ result.put( "result", "success" );
+ response.setContentType("application/json");
+ response.getWriter().write(objectMapper.writeValueAsString(result));
+ response.setStatus(HttpServletResponse.SC_OK);
+
+ }
+
+}
\ No newline at end of file
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/QuartzManagerHttpSecurity.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/QuartzManagerHttpSecurity.java
new file mode 100644
index 0000000..55b9edb
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/QuartzManagerHttpSecurity.java
@@ -0,0 +1,57 @@
+package it.fabioformosa.quartzmanager.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 it.fabioformosa.quartzmanager.security.helpers.LoginConfigurer;
+
+/**
+ * It wraps the httpSecurity to provide new function as login and logout
+ *
+ */
+public class QuartzManagerHttpSecurity extends SecurityConfigurerAdapter {
+
+ public static QuartzManagerHttpSecurity from(HttpSecurity httpSecurity){
+ QuartzManagerHttpSecurity newInstance = new QuartzManagerHttpSecurity(httpSecurity);
+ newInstance.setBuilder(httpSecurity);
+ return newInstance;
+ }
+
+ private HttpSecurity httpSecurity;
+
+ private LoginConfigurer loginConfigurer;
+
+ private LogoutSuccess logoutSuccess;
+
+ public QuartzManagerHttpSecurity(HttpSecurity httpSecurity) {
+ this.httpSecurity = httpSecurity;
+ // applicationContext = httpSecurity.getSharedObject(ApplicationContext.class);
+ }
+
+ public QuartzManagerHttpSecurity login(String loginPath, AuthenticationManager authenticationManager) throws Exception {
+ if(loginConfigurer == null || logoutSuccess == null)
+ throw new IllegalStateException("QuartzManagerHttpSecurity requires to be set loginConfigurer and logoutSuccess!");
+ httpSecurity = loginConfigurer.login(loginPath, httpSecurity, authenticationManager);
+ return this;
+ }
+
+
+ public LogoutConfigurer logout(String logoutPath) throws Exception {
+ LogoutConfigurer logoutConfigurer = httpSecurity.logout().logoutRequestMatcher(new AntPathRequestMatcher(logoutPath))
+ .logoutSuccessHandler(logoutSuccess);
+ String cookie = loginConfigurer.cookieMustBeDeletedAtLogout();
+ if(cookie != null)
+ logoutConfigurer.deleteCookies(cookie);
+ return logoutConfigurer;
+ }
+
+ public QuartzManagerHttpSecurity withLoginConfigurer(LoginConfigurer loginConfigurer, LogoutSuccess logoutSuccess) {
+ this.loginConfigurer = loginConfigurer;
+ this.logoutSuccess = logoutSuccess;
+ return this;
+ }
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/RESTRequestMatcher.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/RESTRequestMatcher.java
new file mode 100644
index 0000000..1fb2d2b
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/RESTRequestMatcher.java
@@ -0,0 +1,26 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.web.util.matcher.ELRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
+public class RESTRequestMatcher {
+
+ static private final Logger log = LoggerFactory.getLogger(RESTRequestMatcher.class);
+
+ static public RequestMatcher matcherRequestedWith = new ELRequestMatcher(
+ "hasHeader('X-Requested-With','XMLHttpRequest')");
+ static public RequestMatcher matcherAccept = new ELRequestMatcher(
+ "hasHeader('accept','application/json, text/plain, */*')");
+
+ static public boolean isRestRequest(HttpServletRequest request) {
+ log.trace("Detecting if it's an AJAX Request: " + request.getRequestURL() + " accept: "
+ + request.getHeader("accept") + " " + " X-Requested-With: "
+ + request.getHeader("X-Requested-With"));
+ return matcherRequestedWith.matches(request) || matcherAccept.matches(request);
+ }
+
+}
\ No newline at end of file
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/RestAuthenticationEntryPoint.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/RestAuthenticationEntryPoint.java
new file mode 100644
index 0000000..3615a2e
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/RestAuthenticationEntryPoint.java
@@ -0,0 +1,23 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
+
+ @Override
+ public void commence(HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationException authException) throws IOException {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
+ }
+}
+
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/WebsocketRequestMatcher.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/WebsocketRequestMatcher.java
new file mode 100644
index 0000000..5b42424
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/WebsocketRequestMatcher.java
@@ -0,0 +1,18 @@
+package it.fabioformosa.quartzmanager.security.helpers.impl;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebsocketRequestMatcher {
+
+ static private final Logger log = LoggerFactory.getLogger(WebsocketRequestMatcher.class);
+
+ static public boolean isWebsocketConnectionRequest(HttpServletRequest request) {
+ log.trace("Detecting if it's a Websocket Connection Request: " + request.getRequestURL());
+ return request.getServletPath().equals("/progress/info")
+ || request.getServletPath().equals("/logs/info");
+ }
+
+}
\ No newline at end of file
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/Authority.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/Authority.java
new file mode 100644
index 0000000..32a6284
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/Authority.java
@@ -0,0 +1,53 @@
+package it.fabioformosa.quartzmanager.security.models;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+import org.springframework.security.core.GrantedAuthority;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Temporary enabled only inMemoryAuthentication
+ *
+ * @author Fabio.Formosa
+ *
+ */
+//@Entity
+//@Table(name="Authority")
+public class Authority implements GrantedAuthority {
+
+ @Id
+ @Column(name="id")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ Long id;
+
+ @Column(name="name")
+ String name;
+
+ @Override
+ public String getAuthority() {
+ return name;
+ }
+
+ @JsonIgnore
+ public Long getId() {
+ return id;
+ }
+
+ @JsonIgnore
+ public String getName() {
+ return name;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/User.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/User.java
new file mode 100644
index 0000000..ba0d58a
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/User.java
@@ -0,0 +1,133 @@
+package it.fabioformosa.quartzmanager.security.models;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Temporary enabled only inMemoryAuthentication
+ *
+ * @author Fabio.Formosa
+ *
+ */
+//@Entity
+//@Table(name = "USER")
+public class User implements UserDetails, Serializable {
+ @Id
+ @Column(name = "id")
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "username")
+ private String username;
+
+ @JsonIgnore
+ @Column(name = "password")
+ private String password;
+
+ @Column(name = "firstname")
+ private String firstname;
+
+ @Column(name = "lastname")
+ private String lastname;
+
+
+ @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
+ @JoinTable(name = "user_authority",
+ joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
+ inverseJoinColumns = @JoinColumn(name = "authority_id", referencedColumnName = "id"))
+ private List authorities;
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ return authorities;
+ }
+
+ public String getFirstname() {
+ return firstname;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getLastname() {
+ return lastname;
+ }
+
+ @Override
+ public String getPassword() {
+ return password;
+ }
+
+ @Override
+ public String getUsername() {
+ return username;
+ }
+
+ // We can add the below fields in the users table.
+ // For now, they are hardcoded.
+ @JsonIgnore
+ @Override
+ public boolean isAccountNonExpired() {
+ return true;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+
+ public void setAuthorities(List authorities) {
+ this.authorities = authorities;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firstname = firstname;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public void setLastname(String lastname) {
+
+ this.lastname = lastname;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/UserRequest.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/UserRequest.java
new file mode 100644
index 0000000..469df73
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/UserRequest.java
@@ -0,0 +1,56 @@
+package it.fabioformosa.quartzmanager.security.models;
+
+
+public class UserRequest {
+
+ private Long id;
+
+ private String username;
+
+ private String password;
+
+ private String firstname;
+
+ private String lastname;
+
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getFirstname() {
+ return firstname;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firstname = firstname;
+ }
+
+ public String getLastname() {
+ return lastname;
+ }
+
+ public void setLastname(String lastname) {
+ this.lastname = lastname;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/UserTokenState.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/UserTokenState.java
new file mode 100644
index 0000000..e39cd6b
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/models/UserTokenState.java
@@ -0,0 +1,32 @@
+package it.fabioformosa.quartzmanager.security.models;
+
+public class UserTokenState {
+ private String access_token;
+ private Long expires_in_sec;
+
+ public UserTokenState() {
+ this.access_token = null;
+ this.expires_in_sec = null;
+ }
+
+ public UserTokenState(String access_token, long expires_in_sec) {
+ this.access_token = access_token;
+ this.expires_in_sec = expires_in_sec;
+ }
+
+ public String getAccess_token() {
+ return access_token;
+ }
+
+ public Long getExpires_in_sec() {
+ return expires_in_sec;
+ }
+
+ public void setAccess_token(String access_token) {
+ this.access_token = access_token;
+ }
+
+ public void setExpires_in_sec(Long expires_in_sec) {
+ this.expires_in_sec = expires_in_sec;
+ }
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/repositories/AuthorityRepository.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/repositories/AuthorityRepository.java
new file mode 100644
index 0000000..5d736c1
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/repositories/AuthorityRepository.java
@@ -0,0 +1,13 @@
+package it.fabioformosa.quartzmanager.security.repositories;
+
+/**
+ * Temporary disabled
+ *
+ * @author Fabio
+ *
+ */
+//public interface AuthorityRepository extends JpaRepository {
+// Authority findByName(String name);
+//}
+public interface AuthorityRepository {
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/repositories/UserRepository.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/repositories/UserRepository.java
new file mode 100644
index 0000000..6ae1804
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/repositories/UserRepository.java
@@ -0,0 +1,11 @@
+package it.fabioformosa.quartzmanager.security.repositories;
+
+import it.fabioformosa.quartzmanager.security.models.User;
+
+public interface UserRepository {
+ User findByUsername( String username );
+}
+//public interface UserRepository extends JpaRepository {
+// User findByUsername( String username );
+//}
+
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/AuthorityService.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/AuthorityService.java
new file mode 100644
index 0000000..5eca666
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/AuthorityService.java
@@ -0,0 +1,13 @@
+package it.fabioformosa.quartzmanager.security.services;
+
+/**
+ * temporary disabled
+ * @author Fabio
+ *
+ */
+public interface AuthorityService {
+ // List findById(Long id);
+ //
+ // List findByname(String name);
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/UserService.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/UserService.java
new file mode 100644
index 0000000..5b66879
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/UserService.java
@@ -0,0 +1,18 @@
+package it.fabioformosa.quartzmanager.security.services;
+
+import java.util.List;
+
+import it.fabioformosa.quartzmanager.security.models.User;
+import it.fabioformosa.quartzmanager.security.models.UserRequest;
+
+public interface UserService {
+ List findAll();
+
+ User findById(Long id);
+
+ User findByUsername(String username);
+
+ void resetCredentials();
+
+ User save(UserRequest user);
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/AuthorityServiceImpl.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/AuthorityServiceImpl.java
new file mode 100644
index 0000000..78ebaf4
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/AuthorityServiceImpl.java
@@ -0,0 +1,33 @@
+package it.fabioformosa.quartzmanager.security.services.impl;
+
+import it.fabioformosa.quartzmanager.security.services.AuthorityService;
+
+/**
+ * Temporary disabled
+ * @author Fabio
+ *
+ */
+
+//@Service
+public class AuthorityServiceImpl implements AuthorityService {
+
+ // @Autowired
+ // private AuthorityRepository authorityRepository;
+ //
+ // @Override
+ // public List findById(Long id) {
+ // Authority auth = this.authorityRepository.getOne(id);
+ // List auths = new ArrayList<>();
+ // auths.add(auth);
+ // return auths;
+ // }
+ //
+ // @Override
+ // public List findByname(String name) {
+ // Authority auth = this.authorityRepository.findByName(name);
+ // List auths = new ArrayList<>();
+ // auths.add(auth);
+ // return auths;
+ // }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/CustomUserDetailsService.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/CustomUserDetailsService.java
new file mode 100644
index 0000000..f4b7adc
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/CustomUserDetailsService.java
@@ -0,0 +1,67 @@
+package it.fabioformosa.quartzmanager.security.services.impl;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import it.fabioformosa.quartzmanager.security.models.User;
+import it.fabioformosa.quartzmanager.security.repositories.UserRepository;
+
+/**
+ * Temporary disabled
+ * @author Fabio
+ *
+ */
+//@Service
+public class CustomUserDetailsService implements UserDetailsService {
+
+ protected final Log LOGGER = LogFactory.getLog(getClass());
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private AuthenticationManager authenticationManager;
+
+ public void changePassword(String oldPassword, String newPassword) {
+
+ // Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
+ // String username = currentUser.getName();
+ //
+ // if (authenticationManager != null) {
+ // LOGGER.debug("Re-authenticating user '"+ username + "' for password change request.");
+ //
+ // authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, oldPassword));
+ // } else {
+ // LOGGER.debug("No authentication manager set. can't change Password!");
+ //
+ // return;
+ // }
+ //
+ // LOGGER.debug("Changing password for user '"+ username + "'");
+ //
+ // User user = (User) loadUserByUsername(username);
+ //
+ // user.setPassword(passwordEncoder.encode(newPassword));
+ // userRepository.save(user);
+
+ }
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ User user = userRepository.findByUsername(username);
+ if (user == null)
+ throw new UsernameNotFoundException(String.format("No user found with username '%s'.", username));
+ else
+ return user;
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/UserServiceImpl.java b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/UserServiceImpl.java
new file mode 100644
index 0000000..9831e6e
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/java/it/fabioformosa/quartzmanager/security/services/impl/UserServiceImpl.java
@@ -0,0 +1,79 @@
+package it.fabioformosa.quartzmanager.security.services.impl;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+import it.fabioformosa.quartzmanager.security.models.User;
+import it.fabioformosa.quartzmanager.security.models.UserRequest;
+import it.fabioformosa.quartzmanager.security.repositories.UserRepository;
+import it.fabioformosa.quartzmanager.security.services.AuthorityService;
+import it.fabioformosa.quartzmanager.security.services.UserService;
+
+/**
+ * Temporary disabled
+ * @author Fabio
+ *
+ */
+//@Service
+public class UserServiceImpl implements UserService {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private AuthorityService authService;
+
+ @Override
+ @PreAuthorize("hasRole('ADMIN')")
+ public List findAll() throws AccessDeniedException {
+ // List result = userRepository.findAll();
+ // return result;
+ return null;
+ }
+
+ @Override
+ @PreAuthorize("hasRole('ADMIN')")
+ public User findById(Long id) throws AccessDeniedException {
+ // User u = userRepository.getOne(id);
+ // return u;
+ return null;
+ }
+
+ @Override
+ // @PreAuthorize("hasRole('USER')")
+ public User findByUsername(String username) throws UsernameNotFoundException {
+ User u = userRepository.findByUsername(username);
+ return u;
+ }
+
+ @Override
+ public void resetCredentials() {
+ // List users = userRepository.findAll();
+ // for (User user : users) {
+ // user.setPassword(passwordEncoder.encode("123"));
+ // userRepository.save(user);
+ // }
+ }
+
+ @Override
+ public User save(UserRequest userRequest) {
+ User user = new User();
+ // user.setUsername(userRequest.getUsername());
+ // user.setPassword(passwordEncoder.encode(userRequest.getPassword()));
+ // user.setFirstname(userRequest.getFirstname());
+ // user.setLastname(userRequest.getLastname());
+ // List auth = authService.findByname("ROLE_USER");
+ // user.setAuthorities(auth);
+ // this.userRepository.save(user);
+ return user;
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-security/src/main/resources/META-INF/spring.factories b/quartz-manager-parent/quartz-manager-security/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..9e6be3c
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-security/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,4 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+it.fabioformosa.quartzmanager.security.configuration.WebSecurityConfigJWT,\
+it.fabioformosa.quartzmanager.security.configuration.properties.JwtSecurityProperties,\
+it.fabioformosa.quartzmanager.security.configuration.properties.InMemoryAccountProperties
\ No newline at end of file
diff --git a/quartz-manager-parent/quartz-manager-ui-webjar/pom.xml b/quartz-manager-parent/quartz-manager-ui-webjar/pom.xml
index fb3f625..68aeee1 100644
--- a/quartz-manager-parent/quartz-manager-ui-webjar/pom.xml
+++ b/quartz-manager-parent/quartz-manager-ui-webjar/pom.xml
@@ -26,110 +26,114 @@
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-resources-plugin
- 2.6
-
-
- copy-resources
- generate-resources
-
- copy-resources
-
-
- ${basedir}/target/tmp
-
-
- ../../${frontend.folderName}
-
- static/**
- dist/**
- node_modules/**
-
-
-
-
-
-
-
-
-
-
- com.github.eirslett
- frontend-maven-plugin
- 1.11.0
-
- target/tmp
-
-
+
+
+ build-webjar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 2.6
+
+
+ copy-resources
+ generate-resources
+
+ copy-resources
+
+
+ ${basedir}/target/tmp
+
+
+ ../../${frontend.folderName}
+
+ static/**
+ dist/**
+ node_modules/**
+
+
+
+
+
+
+
-
- install node and npm
-
- install-node-and-npm
-
- generate-resources
+
+
+ com.github.eirslett
+ frontend-maven-plugin
+ 1.11.0
- ${node.version}
- ${npm.version}
+ target/tmp
-
+
+
+
+ install node and npm
+
+ install-node-and-npm
+
+ generate-resources
+
+ ${node.version}
+ ${npm.version}
+
+
+
+
+ npm install
+
+ npm
+
+ process-resources
+
+ install
+
+
+
+
+ npm run build
+
+ npm
+
+ process-resources
+
+ run build
+
+
+
+
+
-
- npm install
-
- npm
-
- process-resources
-
- install
-
-
-
-
- npm run build
-
- npm
-
- process-resources
-
- run build
-
-
-
-
-
-
-
-
- maven-antrun-plugin
- 1.8
-
-
- clean build files
- process-resources
-
-
-
-
-
-
-
-
-
-
- run
-
-
-
-
-
-
+
+
+ maven-antrun-plugin
+ 1.8
+
+
+ clean build files
+ process-resources
+
+
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+
+
+
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/pom.xml b/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
index 0a83c7e..1c353c1 100644
--- a/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
+++ b/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
@@ -29,10 +29,10 @@
quartz-manager-api
-
- it.fabioformosa.quartz-manager
- quartz-manager-ui-webjar
-
+
+
+
+