mirror of
https://github.com/fabioformosa/quartz-manager.git
synced 2025-12-28 21:23:14 +09:00
Merge pull request #31 from fabioformosa/develop
Refactored project structure for pluggability
This commit is contained in:
30
README.md
30
README.md
@@ -16,24 +16,30 @@ Through this webapp you can launch and control your scheduled job. The UI Consol
|
||||
Open the [Project Roadmap](https://github.com/fabioformosa/quartz-manager/projects) to take a look at the plan of Quartz Manager.
|
||||
Currently this project might be useful to look how to import Quartz Library in a spring boot application. For this purpose, browse the folder `quartz-manager-parent/quartz-manager-api`.
|
||||
We're just working to create a library, from project `quartz-manager-parent/quartz-manager-api`, to be imported in your spring boot where you have your job to be scheduled.
|
||||
The project `quartz-manager-parent/quartz-manager-web` is an example of how-to:
|
||||
* import the library
|
||||
* set the application.yml
|
||||
* add secure layer
|
||||
|
||||
Take a loot to the project [Quartz-Manager Demo](https://github.com/fabioformosa/quartz-manager-demo), it is an example of how-to:
|
||||
* import the quartz-manager-api library in your webapp
|
||||
* include the quartz-manager frontend (angular based) through a webjar
|
||||
* set properties into the application.yml
|
||||
* add a secure layer to allow the API only to logged users
|
||||
* schedule a custom job (a dummy `hello world`)
|
||||
|
||||
**NB: In few days, we'll release the library jar of quartz-manager into the maven central repo.**
|
||||
|
||||
Next steps in the roadmap are:
|
||||
* to add a persistent layer to save all job setup.
|
||||
* to add a complete setup UI panel for quartz, in term of cronjobs and multiple jobs.
|
||||
* to add CI/CD pipeline to ease the deploy pulling a docker container.
|
||||
* Enabling adapters for integrations: kafka, etc.
|
||||
|
||||
## PROJECT STRUCTURE
|
||||
* **quartz-parent/quartz-manager-api** is the library that can be imported in webapp to have the quartz-manager API.
|
||||
* **quartz-parent/quartz-manager-web** is an example of webapp that imports quartz-manager-api. It adds a secure layer and a custom job to be scheduled.
|
||||
* **quartz-parent/quartz-manager-webjar** is a maven module to build and package the angular frontend in a webjar.
|
||||
* **quartz-parent/quartz-manager-security** is ther library that can be imported in a webapp to have a security layer (login) over the quartz-manager API.
|
||||
* **quartz-parent/quartz-manager-web-showcase** is an example of webapp that imports quartz-manager-api. Useful to develop the frontend started locally with the webpack dev server.
|
||||
* **quartz-frontend** is the angular app that interacts with the Quartz Manager API.
|
||||
|
||||
Next steps in the roadmap are:
|
||||
* to simplify the customization of the job through plugins
|
||||
* to add CI/CD pipeline to ease the deploy pulling a docker container
|
||||
* to add a complete setup UI panel for quartz, in term of cronjobs and multiple jobs
|
||||
* to add a persistent layer to save all job logs.
|
||||
|
||||
## QUICK START
|
||||
## HOW-TO CONTRIBUTE
|
||||
**[requirements]** Make sure you have installed
|
||||
* [Java 8](https://java.com/download/) or greater
|
||||
* [Maven](https://maven.apache.org/)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"aot": true,
|
||||
"outputPath": "../server/src/main/resources/static",
|
||||
"outputPath": "dist",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"tsConfig": "src/tsconfig.app.json",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --proxy-config proxy.conf.json",
|
||||
"build": "ng build",
|
||||
"build": "ng build --prod",
|
||||
"test": "jest",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
|
||||
@@ -45,15 +45,19 @@ import {
|
||||
SchedulerService,
|
||||
ConfigService,
|
||||
ProgressWebsocketService,
|
||||
LogsWebsocketService
|
||||
LogsWebsocketService,
|
||||
getHtmlBaseUrl
|
||||
} from './services';
|
||||
import { ChangePasswordComponent } from './views/change-password/change-password.component';
|
||||
import { ForbiddenComponent } from './views/forbidden/forbidden.component';
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
import { environment } from '../environments/environment';
|
||||
|
||||
export function initUserFactory(userService: UserService) {
|
||||
return () => userService.jsessionInitUser();
|
||||
}
|
||||
|
||||
|
||||
// const stompConfig: StompConfig = {
|
||||
// // Which server?
|
||||
// url: 'ws://localhost:8080/quartz-manager/progress',
|
||||
@@ -131,6 +135,16 @@ export function jwtOptionsFactory(apiService: ApiService) {
|
||||
FlexLayoutModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_BASE_HREF,
|
||||
useValue: getHtmlBaseUrl()
|
||||
},
|
||||
{
|
||||
'provide': APP_INITIALIZER,
|
||||
'useFactory': initUserFactory,
|
||||
'deps': [UserService],
|
||||
'multi': true
|
||||
},
|
||||
LoginGuard,
|
||||
GuestGuard,
|
||||
AdminGuard,
|
||||
@@ -141,13 +155,7 @@ export function jwtOptionsFactory(apiService: ApiService) {
|
||||
ApiService,
|
||||
UserService,
|
||||
ConfigService,
|
||||
MatIconRegistry,
|
||||
{
|
||||
'provide': APP_INITIALIZER,
|
||||
'useFactory': initUserFactory,
|
||||
'deps': [UserService],
|
||||
'multi': true
|
||||
}
|
||||
MatIconRegistry
|
||||
// StompService,
|
||||
// ServerSocket
|
||||
// {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from '../../environments/environment';
|
||||
|
||||
|
||||
const WEBJAR_PATH = '/quartz-manager-ui/';
|
||||
|
||||
export function getHtmlBaseUrl(){
|
||||
const baseUrl = getBaseUrl() || '/';
|
||||
return environment.production ? getBaseUrl() + WEBJAR_PATH: '/';
|
||||
}
|
||||
|
||||
export function getBaseUrl(){
|
||||
if(environment.production){
|
||||
let contextPath: string = window.location.pathname.split('/')[1] || '';
|
||||
if(contextPath && ('/' + contextPath + '/') === WEBJAR_PATH)
|
||||
return '';
|
||||
if(contextPath)
|
||||
contextPath = '/' + contextPath;
|
||||
return contextPath;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ConfigService {
|
||||
|
||||
private _api_url = '/quartz-manager/api'
|
||||
private _api_url = getBaseUrl() + '/quartz-manager/api'
|
||||
|
||||
private _refresh_token_url = this._api_url + '/refresh';
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Injectable, OnInit } from '@angular/core';
|
||||
import { WebsocketService, ApiService } from '.';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { WebsocketService, ApiService, getBaseUrl } from '.';
|
||||
import { SocketOption } from '../model/SocketOption.model';
|
||||
|
||||
@Injectable()
|
||||
export class LogsWebsocketService extends WebsocketService {
|
||||
|
||||
constructor(private apiService: ApiService){
|
||||
super(new SocketOption('/quartz-manager/logs', '/topic/logs', apiService.getToken))
|
||||
super(new SocketOption( getBaseUrl() +'/quartz-manager/logs', '/topic/logs', apiService.getToken))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Injectable, OnInit } from '@angular/core';
|
||||
import { WebsocketService, ApiService } from '.';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { WebsocketService, ApiService, getBaseUrl } from '.';
|
||||
import { SocketOption } from '../model/SocketOption.model';
|
||||
|
||||
@Injectable()
|
||||
export class ProgressWebsocketService extends WebsocketService {
|
||||
|
||||
constructor(private apiService: ApiService){
|
||||
super(new SocketOption('/quartz-manager/progress', '/topic/progress', apiService.getToken))
|
||||
super(new SocketOption(getBaseUrl() + '/quartz-manager/progress', '/topic/progress', apiService.getToken))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { getBaseUrl } from '.';
|
||||
import { ApiService } from './api.service';
|
||||
|
||||
@Injectable()
|
||||
@@ -9,30 +10,30 @@ export class SchedulerService {
|
||||
) { }
|
||||
|
||||
startScheduler = () => {
|
||||
return this.apiService.get('/quartz-manager/scheduler/run')
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/run')
|
||||
}
|
||||
|
||||
stopScheduler = () => {
|
||||
return this.apiService.get('/quartz-manager/scheduler/stop')
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/stop')
|
||||
}
|
||||
|
||||
pauseScheduler = () => {
|
||||
return this.apiService.get('/quartz-manager/scheduler/pause')
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/pause')
|
||||
}
|
||||
|
||||
resumeScheduler = () => {
|
||||
return this.apiService.get('/quartz-manager/scheduler/resume')
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/resume')
|
||||
}
|
||||
|
||||
getStatus = () => {
|
||||
return this.apiService.get('/quartz-manager/scheduler')
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler')
|
||||
}
|
||||
|
||||
getConfig = () => {
|
||||
return this.apiService.get('/quartz-manager/scheduler/config')
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/config')
|
||||
}
|
||||
|
||||
updateConfig = (config: Object) => {
|
||||
return this.apiService.post('/quartz-manager/scheduler/config', config)
|
||||
return this.apiService.post(getBaseUrl() + '/quartz-manager/scheduler/config', config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Quartz Manager</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
|
||||
|
||||
5
quartz-manager-parent/.gitignore
vendored
5
quartz-manager-parent/.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
/.settings/
|
||||
/**/.settings/
|
||||
/.project
|
||||
/**/target
|
||||
.classpath
|
||||
.project
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
|
||||
<modules>
|
||||
<module>quartz-manager-api</module>
|
||||
<module>quartz-manager-web</module>
|
||||
<module>quartz-manager-ui-webjar</module>
|
||||
<module>quartz-manager-security</module>
|
||||
<module>quartz-manager-web-showcase</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -27,6 +29,16 @@
|
||||
<artifactId>quartz-manager-api</artifactId>
|
||||
<version>2.2.2-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.fabioformosa.quartz-manager</groupId>
|
||||
<artifactId>quartz-manager-security</artifactId>
|
||||
<version>2.2.2-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.fabioformosa.quartz-manager</groupId>
|
||||
<artifactId>quartz-manager-ui-webjar</artifactId>
|
||||
<version>2.2.2-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
package it.fabioformosa.quartzmanager.controllers;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/quartz-manager/api", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public class UserController {
|
||||
|
||||
|
||||
@GetMapping("/whoami")
|
||||
public @ResponseBody Object user() {
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
if(context != null && context.getAuthentication() != null)
|
||||
return context.getAuthentication().getPrincipal();
|
||||
return "\"NO_AUTH\"";
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT Temporary disabled
|
||||
*
|
||||
@@ -54,20 +64,4 @@ public class UserController {
|
||||
// return ResponseEntity.accepted().body(result);
|
||||
// }
|
||||
|
||||
/*
|
||||
* We are not using userService.findByUsername here(we could), so it is good that we are making
|
||||
* sure that the user has role "ROLE_USER" to access this endpoint.
|
||||
*/
|
||||
// @RequestMapping("/whoami")
|
||||
// // @PreAuthorize("hasRole('USER')")
|
||||
// public User user() {
|
||||
// return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
// }
|
||||
|
||||
@GetMapping("/whoami")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
public Object user() {
|
||||
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
}
|
||||
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>
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.configuration;
|
||||
package it.fabioformosa.quartzmanager.security.configuration;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -27,8 +27,8 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import it.fabioformosa.quartzmanager.configuration.properties.InMemoryAccountProperties;
|
||||
import it.fabioformosa.quartzmanager.configuration.properties.JwtSecurityProperties;
|
||||
import it.fabioformosa.quartzmanager.security.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;
|
||||
@@ -56,10 +56,12 @@ public class WebSecurityConfigJWT extends WebSecurityConfigurerAdapter {
|
||||
private static final String LOGIN_PATH = "/quartz-manager/api/login";
|
||||
private static final String LOGOUT_PATH = "/quartz-manager/api/logout";
|
||||
|
||||
@Value("${server.servlet.context-path}")
|
||||
private static final String WEBJAR_PATH = "/quartz-manager-ui";
|
||||
|
||||
@Value("${server.servlet.context-path:/}")
|
||||
private String contextPath;
|
||||
|
||||
@Value("${app.name}")
|
||||
@Value("${app.name:quartz-manager}")
|
||||
private String APP_NAME;
|
||||
|
||||
@Value("${quartz-manager.security.login-model.form-login-enabled}")
|
||||
@@ -105,7 +107,7 @@ public class WebSecurityConfigJWT extends WebSecurityConfigurerAdapter {
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web.ignoring()//
|
||||
.antMatchers(HttpMethod.GET, PATTERNS_SWAGGER_UI) //
|
||||
.antMatchers(HttpMethod.GET,"/css/**", "/js/**", "/img/**", "/lib/**");
|
||||
.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 {
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.configuration.properties;
|
||||
package it.fabioformosa.quartzmanager.security.configuration.properties;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.configuration.properties;
|
||||
package it.fabioformosa.quartzmanager.security.configuration.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
@@ -0,0 +1,82 @@
|
||||
package it.fabioformosa.quartzmanager.security.controllers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import it.fabioformosa.quartzmanager.security.helpers.impl.JwtTokenHelper;
|
||||
import it.fabioformosa.quartzmanager.security.models.UserTokenState;
|
||||
import it.fabioformosa.quartzmanager.security.services.impl.CustomUserDetailsService;
|
||||
|
||||
/**
|
||||
* JWT Temporary disabled
|
||||
*
|
||||
* @author Fabio.Formosa
|
||||
*
|
||||
*/
|
||||
|
||||
//@RestController
|
||||
//@RequestMapping( value = "/api", produces = MediaType.APPLICATION_JSON_VALUE )
|
||||
public class AuthenticationController {
|
||||
|
||||
static class PasswordChanger {
|
||||
public String oldPassword;
|
||||
public String newPassword;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private CustomUserDetailsService userDetailsService;
|
||||
|
||||
@Autowired
|
||||
JwtTokenHelper tokenHelper;
|
||||
|
||||
@Value("${quartz-manager.security.jwt.expiration-in-sec}")
|
||||
private int EXPIRES_IN_SEC;
|
||||
|
||||
@Value("${quartz-manager.security.jwt.cookie-strategy-cookie}")
|
||||
private String TOKEN_COOKIE;
|
||||
|
||||
@RequestMapping(value = "/changePassword", method = RequestMethod.POST)
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
public ResponseEntity<?> changePassword(@RequestBody PasswordChanger passwordChanger) {
|
||||
userDetailsService.changePassword(passwordChanger.oldPassword, passwordChanger.newPassword);
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put( "result", "success" );
|
||||
return ResponseEntity.accepted().body(result);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/refresh", method = RequestMethod.GET)
|
||||
public ResponseEntity<?> refreshAuthenticationToken(HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
String authToken = tokenHelper.retrieveToken( request );
|
||||
if (authToken != null && tokenHelper.canTokenBeRefreshed(authToken)) {
|
||||
// TODO check user password last update
|
||||
String refreshedToken = tokenHelper.refreshToken(authToken);
|
||||
|
||||
Cookie authCookie = new Cookie( TOKEN_COOKIE, refreshedToken );
|
||||
authCookie.setPath( "/quartz-manager" );
|
||||
authCookie.setHttpOnly( true );
|
||||
authCookie.setMaxAge( EXPIRES_IN_SEC );
|
||||
// Add cookie to response
|
||||
response.addCookie( authCookie );
|
||||
|
||||
UserTokenState userTokenState = new UserTokenState(refreshedToken, EXPIRES_IN_SEC);
|
||||
return ResponseEntity.ok(userTokenState);
|
||||
} else {
|
||||
UserTokenState userTokenState = new UserTokenState();
|
||||
return ResponseEntity.accepted().body(userTokenState);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import org.slf4j.LoggerFactory;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import it.fabioformosa.quartzmanager.configuration.properties.JwtSecurityProperties;
|
||||
import it.fabioformosa.quartzmanager.security.configuration.properties.JwtSecurityProperties;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.security.model;
|
||||
package it.fabioformosa.quartzmanager.security.models;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.GeneratedValue;
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.security.model;
|
||||
package it.fabioformosa.quartzmanager.security.models;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.security.model;
|
||||
package it.fabioformosa.quartzmanager.security.models;
|
||||
|
||||
|
||||
public class UserRequest {
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.security.model;
|
||||
package it.fabioformosa.quartzmanager.security.models;
|
||||
|
||||
public class UserTokenState {
|
||||
private String access_token;
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.security.repository;
|
||||
package it.fabioformosa.quartzmanager.security.repositories;
|
||||
|
||||
/**
|
||||
* Temporary disabled
|
||||
@@ -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 );
|
||||
//}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package it.fabioformosa.quartzmanager.security.service;
|
||||
package it.fabioformosa.quartzmanager.security.services;
|
||||
|
||||
/**
|
||||
* temporary disabled
|
||||
@@ -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
|
||||
139
quartz-manager-parent/quartz-manager-ui-webjar/pom.xml
Normal file
139
quartz-manager-parent/quartz-manager-ui-webjar/pom.xml
Normal file
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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 http://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-ui-webjar</artifactId>
|
||||
|
||||
<name>Quartz Manager UI webjar</name>
|
||||
<description>webjar builder for quartz-manager frontend</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>
|
||||
<frontend.folderName>quartz-manager-frontend</frontend.folderName>
|
||||
<node.version>v10.16.3</node.version>
|
||||
<npm.version>6.9.0</npm.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
|
||||
<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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<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>
|
||||
|
||||
<!-- 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>
|
||||
@@ -9,12 +9,12 @@
|
||||
<version>2.2.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>quartz-manager-web</artifactId>
|
||||
<artifactId>quartz-manager-web-showcase</artifactId>
|
||||
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>Quartz Manager Web</name>
|
||||
<description>A webapp that imports Quartz Manager API lib</description>
|
||||
<name>Quartz Manager Web Showcase</name>
|
||||
<description>A webapp that imports Quartz Manager API lib and the frontend webjar</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
@@ -28,6 +28,14 @@
|
||||
<groupId>it.fabioformosa.quartz-manager</groupId>
|
||||
<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-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SPRING -->
|
||||
<dependency>
|
||||
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
@@ -1,82 +0,0 @@
|
||||
package it.fabioformosa.quartzmanager.controllers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import it.fabioformosa.quartzmanager.security.helpers.impl.JwtTokenHelper;
|
||||
import it.fabioformosa.quartzmanager.security.model.UserTokenState;
|
||||
import it.fabioformosa.quartzmanager.security.service.impl.CustomUserDetailsService;
|
||||
|
||||
/**
|
||||
* JWT Temporary disabled
|
||||
*
|
||||
* @author Fabio.Formosa
|
||||
*
|
||||
*/
|
||||
|
||||
//@RestController
|
||||
//@RequestMapping( value = "/api", produces = MediaType.APPLICATION_JSON_VALUE )
|
||||
public class AuthenticationController {
|
||||
|
||||
static class PasswordChanger {
|
||||
public String oldPassword;
|
||||
public String newPassword;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private CustomUserDetailsService userDetailsService;
|
||||
|
||||
@Autowired
|
||||
JwtTokenHelper tokenHelper;
|
||||
|
||||
@Value("${quartz-manager.security.jwt.expiration-in-sec}")
|
||||
private int EXPIRES_IN_SEC;
|
||||
|
||||
@Value("${quartz-manager.security.jwt.cookie-strategy-cookie}")
|
||||
private String TOKEN_COOKIE;
|
||||
|
||||
@RequestMapping(value = "/changePassword", method = RequestMethod.POST)
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
public ResponseEntity<?> changePassword(@RequestBody PasswordChanger passwordChanger) {
|
||||
userDetailsService.changePassword(passwordChanger.oldPassword, passwordChanger.newPassword);
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put( "result", "success" );
|
||||
return ResponseEntity.accepted().body(result);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/refresh", method = RequestMethod.GET)
|
||||
public ResponseEntity<?> refreshAuthenticationToken(HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
String authToken = tokenHelper.retrieveToken( request );
|
||||
if (authToken != null && tokenHelper.canTokenBeRefreshed(authToken)) {
|
||||
// TODO check user password last update
|
||||
String refreshedToken = tokenHelper.refreshToken(authToken);
|
||||
|
||||
Cookie authCookie = new Cookie( TOKEN_COOKIE, refreshedToken );
|
||||
authCookie.setPath( "/quartz-manager" );
|
||||
authCookie.setHttpOnly( true );
|
||||
authCookie.setMaxAge( EXPIRES_IN_SEC );
|
||||
// Add cookie to response
|
||||
response.addCookie( authCookie );
|
||||
|
||||
UserTokenState userTokenState = new UserTokenState(refreshedToken, EXPIRES_IN_SEC);
|
||||
return ResponseEntity.ok(userTokenState);
|
||||
} else {
|
||||
UserTokenState userTokenState = new UserTokenState();
|
||||
return ResponseEntity.accepted().body(userTokenState);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
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.configuration.properties.JwtSecurityProperties;
|
||||
import it.fabioformosa.quartzmanager.security.model.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);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package it.fabioformosa.quartzmanager.security.repository;
|
||||
|
||||
import it.fabioformosa.quartzmanager.security.model.User;
|
||||
|
||||
public interface UserRepository {
|
||||
User findByUsername( String username );
|
||||
}
|
||||
//public interface UserRepository extends JpaRepository<User, Long> {
|
||||
// User findByUsername( String username );
|
||||
//}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package it.fabioformosa.quartzmanager.security.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import it.fabioformosa.quartzmanager.security.model.User;
|
||||
import it.fabioformosa.quartzmanager.security.model.UserRequest;
|
||||
|
||||
public interface UserService {
|
||||
List<User> findAll();
|
||||
|
||||
User findById(Long id);
|
||||
|
||||
User findByUsername(String username);
|
||||
|
||||
void resetCredentials();
|
||||
|
||||
User save(UserRequest user);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package it.fabioformosa.quartzmanager.security.service.impl;
|
||||
|
||||
import it.fabioformosa.quartzmanager.security.service.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;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package it.fabioformosa.quartzmanager.security.service.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.model.User;
|
||||
import it.fabioformosa.quartzmanager.security.repository.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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package it.fabioformosa.quartzmanager.security.service.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.model.User;
|
||||
import it.fabioformosa.quartzmanager.security.model.UserRequest;
|
||||
import it.fabioformosa.quartzmanager.security.repository.UserRepository;
|
||||
import it.fabioformosa.quartzmanager.security.service.AuthorityService;
|
||||
import it.fabioformosa.quartzmanager.security.service.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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user