mirror of
https://github.com/fabioformosa/quartz-manager.git
synced 2026-05-14 22:00:30 +09:00
#30 added new module with all config for a security layer
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
<module>quartz-manager-api</module>
|
||||
<module>quartz-manager-ui-webjar</module>
|
||||
<module>quartz-manager-web-showcase</module>
|
||||
</modules>
|
||||
<module>quartz-manager-security</module></modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
57
quartz-manager-parent/quartz-manager-security/pom.xml
Normal file
57
quartz-manager-parent/quartz-manager-security/pom.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>it.fabioformosa.quartz-manager</groupId>
|
||||
<artifactId>quartz-manager-parent</artifactId>
|
||||
<version>2.2.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>quartz-manager-security</artifactId>
|
||||
|
||||
<name>Quartz Manager Security</name>
|
||||
<description>Security Layer for Quartz Manager</description>
|
||||
|
||||
<url>https://github.com/fabioformosa/quartz-manager</url>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -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<AuthenticationManagerBuilder> 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();
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -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<User> users;
|
||||
|
||||
@Getter @Setter
|
||||
public static class User {
|
||||
private String name;
|
||||
private String password;
|
||||
private List<String> roles = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<HttpSecurity> login = http.formLogin().loginPage(loginPath);
|
||||
|
||||
if(authenticationSuccessHandler != null) {
|
||||
log.debug("Setting an authenticationSuccessHandler");
|
||||
login = login.successHandler(authenticationSuccessHandler);
|
||||
}
|
||||
|
||||
if(authenticationFailureHandler != null) {
|
||||
log.debug("Setting an authenticationFailureHandler");
|
||||
login = login.failureHandler(authenticationFailureHandler);
|
||||
}
|
||||
|
||||
HttpSecurity httpSecurity = login.and();
|
||||
return httpSecurity;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<String> 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<String> pathsToSkip ) {
|
||||
if(pathsToSkip == null)
|
||||
pathsToSkip = new ArrayList<String>();
|
||||
List<RequestMatcher> matchers = pathsToSkip.stream().map(path -> new AntPathRequestMatcher(path)).collect(Collectors.toList());
|
||||
OrRequestMatcher compositeMatchers = new OrRequestMatcher(matchers);
|
||||
return compositeMatchers.matches(request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String, Object> 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 <code>null</code> 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<String, String> result = new HashMap<>();
|
||||
result.put( "result", "success" );
|
||||
response.setContentType("application/json");
|
||||
response.getWriter().write(objectMapper.writeValueAsString(result));
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<DefaultSecurityFilterChain, HttpSecurity> {
|
||||
|
||||
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<HttpSecurity> logout(String logoutPath) throws Exception {
|
||||
LogoutConfigurer<HttpSecurity> 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Authority> 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<Authority> 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package it.fabioformosa.quartzmanager.security.repositories;
|
||||
|
||||
/**
|
||||
* Temporary disabled
|
||||
*
|
||||
* @author Fabio
|
||||
*
|
||||
*/
|
||||
//public interface AuthorityRepository extends JpaRepository<Authority, Long> {
|
||||
// Authority findByName(String name);
|
||||
//}
|
||||
public interface AuthorityRepository {
|
||||
}
|
||||
@@ -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, Long> {
|
||||
// User findByUsername( String username );
|
||||
//}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package it.fabioformosa.quartzmanager.security.services;
|
||||
|
||||
/**
|
||||
* temporary disabled
|
||||
* @author Fabio
|
||||
*
|
||||
*/
|
||||
public interface AuthorityService {
|
||||
// List<Authority> findById(Long id);
|
||||
//
|
||||
// List<Authority> findByname(String name);
|
||||
|
||||
}
|
||||
@@ -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<User> findAll();
|
||||
|
||||
User findById(Long id);
|
||||
|
||||
User findByUsername(String username);
|
||||
|
||||
void resetCredentials();
|
||||
|
||||
User save(UserRequest user);
|
||||
}
|
||||
@@ -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<Authority> findById(Long id) {
|
||||
// Authority auth = this.authorityRepository.getOne(id);
|
||||
// List<Authority> auths = new ArrayList<>();
|
||||
// auths.add(auth);
|
||||
// return auths;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<Authority> findByname(String name) {
|
||||
// Authority auth = this.authorityRepository.findByName(name);
|
||||
// List<Authority> auths = new ArrayList<>();
|
||||
// auths.add(auth);
|
||||
// return auths;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<User> findAll() throws AccessDeniedException {
|
||||
// List<User> 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<User> 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<Authority> auth = authService.findByname("ROLE_USER");
|
||||
// user.setAuthorities(auth);
|
||||
// this.userRepository.save(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -26,110 +26,114 @@
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<!-- STEP1: create a copy of the frontend sources from frontend project to this frontend builder project -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${basedir}/target/tmp</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>../../${frontend.folderName}</directory>
|
||||
<excludes>
|
||||
<exclude>static/**</exclude>
|
||||
<exclude>dist/**</exclude>
|
||||
<exclude>node_modules/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- STEP2: download npm, execute npm install, execute npm run build -->
|
||||
<plugin>
|
||||
<groupId>com.github.eirslett</groupId>
|
||||
<artifactId>frontend-maven-plugin</artifactId>
|
||||
<version>1.11.0</version>
|
||||
<configuration>
|
||||
<workingDirectory>target/tmp</workingDirectory>
|
||||
</configuration>
|
||||
<executions>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>build-webjar</id>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<!-- STEP1: create a copy of the frontend sources from frontend project to this frontend builder project -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${basedir}/target/tmp</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>../../${frontend.folderName}</directory>
|
||||
<excludes>
|
||||
<exclude>static/**</exclude>
|
||||
<exclude>dist/**</exclude>
|
||||
<exclude>node_modules/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<execution>
|
||||
<id>install node and npm</id>
|
||||
<goals>
|
||||
<goal>install-node-and-npm</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<!-- STEP2: download npm, execute npm install, execute npm run build -->
|
||||
<plugin>
|
||||
<groupId>com.github.eirslett</groupId>
|
||||
<artifactId>frontend-maven-plugin</artifactId>
|
||||
<version>1.11.0</version>
|
||||
<configuration>
|
||||
<nodeVersion>${node.version}</nodeVersion>
|
||||
<npmVersion>${npm.version}</npmVersion>
|
||||
<workingDirectory>target/tmp</workingDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<executions>
|
||||
|
||||
<execution>
|
||||
<id>install node and npm</id>
|
||||
<goals>
|
||||
<goal>install-node-and-npm</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<nodeVersion>${node.version}</nodeVersion>
|
||||
<npmVersion>${npm.version}</npmVersion>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>npm install</id>
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<arguments>install</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>npm run build</id>
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<arguments>run build</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<execution>
|
||||
<id>npm install</id>
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<arguments>install</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<execution>
|
||||
<id>npm run build</id>
|
||||
<goals>
|
||||
<goal>npm</goal>
|
||||
</goals>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<arguments>run build</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- STEP3: move built artifacts into the META-INF folder -->
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>clean build files</id>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<delete dir="${project.build.outputDirectory}/META-INF/resources/quartz-manager-ui"/>
|
||||
<move todir="${project.build.outputDirectory}/META-INF/resources/quartz-manager-ui">
|
||||
<fileset dir="${project.build.directory}/tmp/dist"/>
|
||||
</move>
|
||||
<delete dir="${project.build.directory}/tmp"/>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<!-- STEP3: move built artifacts into the META-INF folder -->
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>1.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>clean build files</id>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<target>
|
||||
<delete dir="${project.build.outputDirectory}/META-INF/resources/quartz-manager-ui"/>
|
||||
<move todir="${project.build.outputDirectory}/META-INF/resources/quartz-manager-ui">
|
||||
<fileset dir="${project.build.directory}/tmp/dist"/>
|
||||
</move>
|
||||
<delete dir="${project.build.directory}/tmp"/>
|
||||
</target>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
<artifactId>quartz-manager-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>it.fabioformosa.quartz-manager</groupId>
|
||||
<artifactId>quartz-manager-ui-webjar</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency> -->
|
||||
<!-- <groupId>it.fabioformosa.quartz-manager</groupId> -->
|
||||
<!-- <artifactId>quartz-manager-ui-webjar</artifactId> -->
|
||||
<!-- </dependency> -->
|
||||
|
||||
<!-- SPRING -->
|
||||
<dependency>
|
||||
|
||||
Reference in New Issue
Block a user