diff --git a/backend/src/main/java/SecurityInit.java b/backend/src/main/java/SecurityInit.java new file mode 100644 index 00000000..00b8b504 --- /dev/null +++ b/backend/src/main/java/SecurityInit.java @@ -0,0 +1,5 @@ +import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; +import org.springframework.web.WebApplicationInitializer; + +public class SecurityInit extends AbstractSecurityWebApplicationInitializer implements WebApplicationInitializer { +} diff --git a/backend/src/main/java/ru/micord/ervu/security/CsrfTokenAwareLogoutSuccessHandler.java b/backend/src/main/java/ru/micord/ervu/security/CsrfTokenAwareLogoutSuccessHandler.java new file mode 100644 index 00000000..8c9b1895 --- /dev/null +++ b/backend/src/main/java/ru/micord/ervu/security/CsrfTokenAwareLogoutSuccessHandler.java @@ -0,0 +1,34 @@ +package ru.micord.ervu.security; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; +import org.springframework.security.web.csrf.CsrfToken; +import org.springframework.security.web.csrf.CsrfTokenRepository; + +public class CsrfTokenAwareLogoutSuccessHandler implements LogoutSuccessHandler { + + private final CsrfTokenRepository csrfTokenRepository; + + private final LogoutSuccessHandler delegate = new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK); + + public CsrfTokenAwareLogoutSuccessHandler(CsrfTokenRepository csrfTokenRepository) { + this.csrfTokenRepository = csrfTokenRepository; + } + + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, + ServletException { + CsrfToken csrfToken = this.csrfTokenRepository.generateToken(request); + this.csrfTokenRepository.saveToken(csrfToken, request, response); + this.delegate.onLogoutSuccess(request, response, authentication); + } + +} diff --git a/backend/src/main/java/ru/micord/ervu/security/SecurityConfig.java b/backend/src/main/java/ru/micord/ervu/security/SecurityConfig.java index 44a4223b..6df367d7 100644 --- a/backend/src/main/java/ru/micord/ervu/security/SecurityConfig.java +++ b/backend/src/main/java/ru/micord/ervu/security/SecurityConfig.java @@ -10,9 +10,14 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfTokenRequestHandler; +import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler; import ru.micord.ervu.security.webbpm.jwt.filter.JwtAuthenticationFilter; import ru.micord.ervu.security.webbpm.jwt.UnauthorizedEntryPoint; +import static ru.micord.ervu.security.SecurityConstants.ESIA_LOGOUT; + @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @@ -22,19 +27,31 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { - httpConfigure(http); http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } protected void httpConfigure(HttpSecurity httpSecurity) throws Exception { - String[] permitAll = {"/esia/url", "/esia/auth", "esia/refresh"}; - + String[] permitAll = {"/version","/esia/url", "/esia/auth", "esia/refresh"}; + CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse(); + tokenRepository.setCookiePath("/"); + XorCsrfTokenRequestAttributeHandler delegate = new XorCsrfTokenRequestAttributeHandler(); + delegate.setCsrfRequestAttributeName(null); + // Use only the handle() method of XorCsrfTokenRequestAttributeHandler and the + // default implementation of resolveCsrfTokenValue() from CsrfTokenRequestHandler + CsrfTokenRequestHandler requestHandler = delegate::handle; httpSecurity.authorizeRequests() .antMatchers(permitAll).permitAll() .antMatchers("/**").authenticated() .and() - .csrf().disable() + .csrf((csrf) -> csrf + .csrfTokenRepository(tokenRepository) + .csrfTokenRequestHandler(requestHandler) + ) + .logout((logout) -> logout + .logoutUrl(ESIA_LOGOUT) + .logoutSuccessHandler(new CsrfTokenAwareLogoutSuccessHandler(tokenRepository)) + ) .exceptionHandling().authenticationEntryPoint(entryPoint()) .and() .sessionManagement() diff --git a/backend/src/main/java/ru/micord/ervu/security/SecurityConstants.java b/backend/src/main/java/ru/micord/ervu/security/SecurityConstants.java new file mode 100644 index 00000000..1853716d --- /dev/null +++ b/backend/src/main/java/ru/micord/ervu/security/SecurityConstants.java @@ -0,0 +1,5 @@ +package ru.micord.ervu.security; + +public class SecurityConstants { + public static final String ESIA_LOGOUT = "/esia/logout"; +} diff --git a/backend/src/main/java/ru/micord/ervu/security/esia/controller/EsiaController.java b/backend/src/main/java/ru/micord/ervu/security/esia/controller/EsiaController.java index d408ff4d..42aecf09 100644 --- a/backend/src/main/java/ru/micord/ervu/security/esia/controller/EsiaController.java +++ b/backend/src/main/java/ru/micord/ervu/security/esia/controller/EsiaController.java @@ -3,12 +3,13 @@ package ru.micord.ervu.security.esia.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import ru.micord.ervu.security.SecurityConstants; import ru.micord.ervu.security.esia.model.OrgInfoModel; import ru.micord.ervu.security.esia.service.EsiaAuthService; import ru.micord.ervu.security.esia.service.EsiaDataService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -24,37 +25,37 @@ public class EsiaController { @Autowired private EsiaDataService esiaDataService; - @RequestMapping(value = "/esia/url") + @GetMapping(value = "/esia/url") public String getEsiaUrl() { return esiaAuthService.generateAuthCodeUrl(); } - @RequestMapping(value = "/esia/auth", params = "code", method = RequestMethod.GET) + @GetMapping(value = "/esia/auth", params = "code") public boolean esiaAuth(@RequestParam("code") String code, HttpServletRequest request, HttpServletResponse response) { return esiaAuthService.getEsiaTokensByCode(code, request, response); } - @RequestMapping(value = "/esia/refresh") + @PostMapping(value = "/esia/refresh") public void refreshToken(HttpServletRequest request, HttpServletResponse response) { esiaAuthService.getEsiaTokensByRefreshToken(request, response); } - @RequestMapping(value = "/esia/org") + @GetMapping(value = "/esia/org") public OrgInfoModel getOrgInfo(HttpServletRequest request) { return esiaDataService.getOrgInfo(request); } - @RequestMapping(value = "/esia/userfullname") + @GetMapping(value = "/esia/userfullname") public String getUserFullname(HttpServletRequest request) { return esiaDataService.getUserFullname(request); } - @RequestMapping(value = "/esia/orgunitname") + @GetMapping(value = "/esia/orgunitname") public String getOrgUnitName(HttpServletRequest request) { return esiaDataService.getOrgUnitName(request); } - @RequestMapping(value = "/esia/logout") + @PostMapping(SecurityConstants.ESIA_LOGOUT) public String logout(HttpServletRequest request, HttpServletResponse response) { return esiaAuthService.logout(request, response); } diff --git a/backend/src/main/java/ru/micord/ervu/security/esia/service/EsiaAuthService.java b/backend/src/main/java/ru/micord/ervu/security/esia/service/EsiaAuthService.java index a0170d61..e035a42a 100644 --- a/backend/src/main/java/ru/micord/ervu/security/esia/service/EsiaAuthService.java +++ b/backend/src/main/java/ru/micord/ervu/security/esia/service/EsiaAuthService.java @@ -200,11 +200,19 @@ public class EsiaAuthService { .build() .send(postReq, HttpResponse.BodyHandlers.ofString()); String responseString = postResp.body(); - EsiaTokenResponse tokenResponse = objectMapper.readValue(responseString, EsiaTokenResponse.class); - if (tokenResponse != null && tokenResponse.getError() != null) { + EsiaTokenResponse tokenResponse = objectMapper.readValue(responseString, + EsiaTokenResponse.class + ); + + if (tokenResponse == null) { + throw new IllegalStateException("Got empty esia response"); + } + + if (tokenResponse.getError() != null) { throw new RuntimeException(tokenResponse.getError_description()); } String accessToken = tokenResponse.getAccess_token(); + boolean hasRole = ulDataService.checkRole(accessToken); if (!hasRole) { throw new RuntimeException("The user does not have the required role"); diff --git a/frontend/src/resources/template/app/component/log_out.html b/frontend/src/resources/template/app/component/log_out.html index cf7831d2..319b0904 100644 --- a/frontend/src/resources/template/app/component/log_out.html +++ b/frontend/src/resources/template/app/component/log_out.html @@ -1,6 +1,6 @@ - -
+ +
{{getOrgUnitName()}}
Данные организации -
\ No newline at end of file +
diff --git a/frontend/src/ts/ervu/component/fileupload/ErvuFileUpload.ts b/frontend/src/ts/ervu/component/fileupload/ErvuFileUpload.ts index 3e0da6a8..4ed140be 100644 --- a/frontend/src/ts/ervu/component/fileupload/ErvuFileUpload.ts +++ b/frontend/src/ts/ervu/component/fileupload/ErvuFileUpload.ts @@ -11,6 +11,8 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef} from import {FileItem, FileUploader} from "ng2-file-upload"; import {FileLikeObject} from "ng2-file-upload/file-upload/file-like-object.class"; import {EmployeeInfoFileFormType} from "./EmployeeInfoFileFormType"; +import {CookieService} from "ngx-cookie"; +import {TokenConstants} from "../../../modules/security/TokenConstants"; @Component({ moduleId: module.id, @@ -59,6 +61,7 @@ export class ErvuFileUpload extends InputControl { private messagesService: MessagesService; private isUploadErrorOccurred = false; private appConfigService: AppConfigService; + private cookieService: CookieService; constructor(el: ElementRef, cd: ChangeDetectorRef) { super(el, cd); @@ -69,6 +72,7 @@ export class ErvuFileUpload extends InputControl { super.initialize(); this.messagesService = this.injector.get(MessagesService); this.appConfigService = this.injector.get(AppConfigService); + this.cookieService = this.injector.get(CookieService); this.url = `/${this.appConfigService.getParamValue(ErvuFileUpload.BACKEND_URL)}/employee/document`; this.uploader.setOptions({ @@ -99,6 +103,10 @@ export class ErvuFileUpload extends InputControl { { name: "Client-Time-Zone", value: Intl.DateTimeFormat().resolvedOptions().timeZone + }, + { + name: TokenConstants.CSRF_HEADER_NAME, + value: this.cookieService.get(TokenConstants.CSRF_TOKEN_NAME) } ] }); @@ -129,6 +137,24 @@ export class ErvuFileUpload extends InputControl { private setUploaderMethods() { this.uploader.onBeforeUploadItem = (fileItem: FileItem) => { + + //refresh headers + this.uploader.setOptions({ + headers: [ + { + name: "X-Employee-Info-File-Form-Type", + value: EmployeeInfoFileFormType[this.formType] + }, + { + name: "Client-Time-Zone", + value: Intl.DateTimeFormat().resolvedOptions().timeZone + }, + { + name: TokenConstants.CSRF_HEADER_NAME, + value: this.cookieService.get(TokenConstants.CSRF_TOKEN_NAME) + } + ] + }); this.fileUploadStartEvent.trigger(); this.isDropZoneVisible = false; this.isFilesListVisible = false; @@ -239,4 +265,4 @@ export class ErvuFileUpload extends InputControl { this.isUploadErrorOccurred = false; this.cd.markForCheck(); } -} \ No newline at end of file +} diff --git a/frontend/src/ts/esia/OrgDataRoot.ts b/frontend/src/ts/esia/OrgDataRoot.ts index feee9eb9..901362ed 100644 --- a/frontend/src/ts/esia/OrgDataRoot.ts +++ b/frontend/src/ts/esia/OrgDataRoot.ts @@ -2,10 +2,10 @@ import {AnalyticalScope, Behavior, Container, ControlWithValue} from "@webbpm/ba import {HttpClient} from "@angular/common/http"; import {OrgData} from "./OrgData"; import {OrgInfoModel} from "../generated/ru/micord/ervu/security/esia/model/OrgInfoModel"; -import {CookieService} from "ngx-cookie"; +import {AuthenticationService} from "../modules/security/authentication.service"; @AnalyticalScope(Container) -export class OrgDataRoot extends Behavior{ +export class OrgDataRoot extends Behavior { private container: Container; @@ -14,8 +14,9 @@ export class OrgDataRoot extends Behavior{ this.container = this.getScript(Container); let orgScripts: OrgData[] = this.container.getScriptsInThisAndChildren(OrgData); let httpClient = this.injector.get(HttpClient); - let cookieService = this.injector.get(CookieService); - if (cookieService.get("webbpm.ervu-lkrp-ul")) { + let cookieService = this.injector.get(AuthenticationService); + + if (cookieService.isAuthenticated()) { httpClient.get("esia/org") .toPromise() .then(orgInfoModel => { @@ -23,9 +24,9 @@ export class OrgDataRoot extends Behavior{ return; } for (let orgData of orgScripts) { - let control: ControlWithValue = orgData.getScriptInObject(orgData.getObjectId(), - 'component.ControlWithValue'); - control.setValue(orgInfoModel[orgData.dataId]); + let control: ControlWithValue = orgData.getScriptInObject(orgData.getObjectId(), + 'component.ControlWithValue'); + control.setValue(orgInfoModel[orgData.dataId]); } }); } diff --git a/frontend/src/ts/modules/app/app.module.ts b/frontend/src/ts/modules/app/app.module.ts index 092f4970..b752669f 100644 --- a/frontend/src/ts/modules/app/app.module.ts +++ b/frontend/src/ts/modules/app/app.module.ts @@ -1,4 +1,4 @@ -import {forwardRef, NgModule} from "@angular/core"; +import {APP_INITIALIZER, forwardRef, NgModule} from "@angular/core"; import {NgbModule} from "@ng-bootstrap/ng-bootstrap"; import {CommonModule, registerLocaleData} from "@angular/common"; import localeRu from '@angular/common/locales/ru'; @@ -25,6 +25,7 @@ import {FileUploadModule} from "ng2-file-upload"; import {ErvuFileUpload} from "../../ervu/component/fileupload/ErvuFileUpload"; import {InMemoryStaticGrid} from "../../ervu/component/grid/InMemoryStaticGrid"; import {ErvuDownloadFileButton} from "../../ervu/component/button/ErvuDownloadFileButton"; +import {AuthenticationService} from "../security/authentication.service"; registerLocaleData(localeRu); export const DIRECTIVES = [ @@ -39,6 +40,10 @@ export const DIRECTIVES = [ forwardRef(() => InMemoryStaticGrid) ]; +function checkAuthentication(authService: AuthenticationService): () => Promise { + return () => authService.checkAuthentication(); +} + @NgModule({ imports: [ CommonModule, @@ -60,6 +65,13 @@ export const DIRECTIVES = [ DIRECTIVES ], providers: [ + AuthenticationService, + { + provide: APP_INITIALIZER, + useFactory: checkAuthentication, + deps: [AuthenticationService], + multi: true, + }, { provide: ProgressIndicationService, useClass: AppProgressIndicationService } ], bootstrap: [], diff --git a/frontend/src/ts/modules/app/component/logout.component.ts b/frontend/src/ts/modules/app/component/logout.component.ts index e8c3b8be..0ac178ae 100644 --- a/frontend/src/ts/modules/app/component/logout.component.ts +++ b/frontend/src/ts/modules/app/component/logout.component.ts @@ -1,7 +1,7 @@ import {ChangeDetectorRef, Component, OnInit} from "@angular/core"; import {Router} from "@angular/router"; import {HttpClient} from "@angular/common/http"; -import {CookieService} from "ngx-cookie"; +import {AuthenticationService} from "../../security/authentication.service"; @Component({ moduleId: module.id, @@ -13,13 +13,12 @@ export class LogOutComponent implements OnInit{ private userFullname: string; private orgUnitName: string; - constructor(private router: Router, private httpClient: HttpClient, - private cookieService: CookieService, private cd: ChangeDetectorRef) { + private authenticationService: AuthenticationService, private cd: ChangeDetectorRef) { } ngOnInit(): void { - let isAuth = this.getIsAuth(); + let isAuth = this.authenticationService.isAuthenticated(); if (isAuth) { Promise.all([ this.httpClient.get("esia/userfullname").toPromise(), @@ -33,20 +32,18 @@ export class LogOutComponent implements OnInit{ } public logout(): void { - this.httpClient.get("esia/logout").toPromise().then(url => { - window.open(url, "_self"); - }) + this.authenticationService.logout(); } public getUserFullname(): string { return this.userFullname; } - public getIsAuth(): boolean { - return this.cookieService.get("webbpm.ervu-lkrp-ul") != null; + public isAuthenticated(): boolean { + return this.authenticationService.isAuthenticated(); } public getOrgUnitName(): string { return this.orgUnitName; } -} \ No newline at end of file +} diff --git a/frontend/src/ts/modules/security/TokenConstants.ts b/frontend/src/ts/modules/security/TokenConstants.ts new file mode 100644 index 00000000..597fe759 --- /dev/null +++ b/frontend/src/ts/modules/security/TokenConstants.ts @@ -0,0 +1,4 @@ +export class TokenConstants { + public static readonly CSRF_TOKEN_NAME = "XSRF-TOKEN"; + public static readonly CSRF_HEADER_NAME = "X-XSRF-TOKEN"; +} diff --git a/frontend/src/ts/modules/security/authentication.service.ts b/frontend/src/ts/modules/security/authentication.service.ts new file mode 100644 index 00000000..f427b3d1 --- /dev/null +++ b/frontend/src/ts/modules/security/authentication.service.ts @@ -0,0 +1,27 @@ +import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {Observable} from "rxjs"; +import {CookieService} from "ngx-cookie"; +import {tap} from "rxjs/operators"; +import {AppConfigService} from "@webbpm/base-package"; + +@Injectable({providedIn: 'root'}) +export class AuthenticationService { + + constructor(private http: HttpClient, + private cookieService: CookieService, + private appConfigService: AppConfigService) { + } + + checkAuthentication(): Promise{ + return this.appConfigService.load().then(value => this.http.get("version").toPromise()) + } + + logout(): Promise { + return this.http.post('esia/logout', {}).toPromise(); + } + + public isAuthenticated(): boolean { + return this.cookieService.get('webbpm.ervu-lkrp-ul') != null; + } +} diff --git a/frontend/src/ts/modules/security/guard/auth.guard.ts b/frontend/src/ts/modules/security/guard/auth.guard.ts index 95c2271e..b41e5b3a 100644 --- a/frontend/src/ts/modules/security/guard/auth.guard.ts +++ b/frontend/src/ts/modules/security/guard/auth.guard.ts @@ -2,8 +2,8 @@ import {Injectable} from "@angular/core"; import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from "@angular/router"; import {Observable} from "rxjs"; import {HttpClient, HttpParams} from "@angular/common/http"; -import {CookieService} from "ngx-cookie"; import {MessagesService} from "@webbpm/base-package"; +import {AuthenticationService} from "../authentication.service"; @Injectable({providedIn:'root'}) export abstract class AuthGuard implements CanActivate { @@ -11,7 +11,7 @@ export abstract class AuthGuard implements CanActivate { protected constructor( protected router: Router, private httpClient: HttpClient, - private cookieService: CookieService, + private authenticationService: AuthenticationService, private messageService: MessagesService ) { } @@ -55,11 +55,7 @@ export abstract class AuthGuard implements CanActivate { }); } - private checkAccess(): Promise | boolean { - return this.getIsAuth() != null; + private checkAccess(): boolean { + return this.authenticationService.isAuthenticated(); }; - - public getIsAuth(): string { - return this.cookieService.get('webbpm.ervu-lkrp-ul'); - } } diff --git a/frontend/src/ts/modules/webbpm/interceptor/absolute-url-csrf.interceptor.ts b/frontend/src/ts/modules/webbpm/interceptor/absolute-url-csrf.interceptor.ts new file mode 100644 index 00000000..ea231886 --- /dev/null +++ b/frontend/src/ts/modules/webbpm/interceptor/absolute-url-csrf.interceptor.ts @@ -0,0 +1,26 @@ +import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import {CookieService} from "ngx-cookie"; +import {TokenConstants} from "../../security/TokenConstants"; + +@Injectable() +export class AbsoluteUrlCsrfInterceptor implements HttpInterceptor { + + constructor(private cookieService: CookieService) { + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + + let requestToForward = req; + let token = this.cookieService.get(TokenConstants.CSRF_TOKEN_NAME) as string; + + if (token != null) { + let headers = {}; + let headerName = TokenConstants.CSRF_HEADER_NAME; + headers[headerName] = token; + requestToForward = req.clone({setHeaders: headers}); + } + return next.handle(requestToForward); + } +} diff --git a/frontend/src/ts/modules/webbpm/interceptor/default-interceptors.prod.ts b/frontend/src/ts/modules/webbpm/interceptor/default-interceptors.prod.ts index 07735d52..6cd9ffe7 100644 --- a/frontend/src/ts/modules/webbpm/interceptor/default-interceptors.prod.ts +++ b/frontend/src/ts/modules/webbpm/interceptor/default-interceptors.prod.ts @@ -4,9 +4,11 @@ import { HttpSecurityErrorInterceptor, HttpSecurityInterceptor } from "@webbpm/base-package"; +import {AbsoluteUrlCsrfInterceptor} from "./absolute-url-csrf.interceptor"; export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [ {provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true}, {provide: HTTP_INTERCEPTORS, useClass: HttpSecurityErrorInterceptor, multi: true}, - {provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true} + {provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true}, + {provide: HTTP_INTERCEPTORS, useClass: AbsoluteUrlCsrfInterceptor, multi: true} ]; diff --git a/frontend/src/ts/modules/webbpm/interceptor/default-interceptors.ts b/frontend/src/ts/modules/webbpm/interceptor/default-interceptors.ts index ee46e0c2..77b3b401 100644 --- a/frontend/src/ts/modules/webbpm/interceptor/default-interceptors.ts +++ b/frontend/src/ts/modules/webbpm/interceptor/default-interceptors.ts @@ -1,9 +1,11 @@ import {HTTP_INTERCEPTORS} from "@angular/common/http"; import {FormDirtyInterceptor, HttpSecurityInterceptor} from "@webbpm/base-package"; import {DevHttpSecurityErrorInterceptor} from "./http-security-error-interceptor.dev"; +import {AbsoluteUrlCsrfInterceptor} from "./absolute-url-csrf.interceptor"; export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [ {provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true}, {provide: HTTP_INTERCEPTORS, useClass: DevHttpSecurityErrorInterceptor, multi: true}, - {provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true} + {provide: HTTP_INTERCEPTORS, useClass: FormDirtyInterceptor, multi: true}, + {provide: HTTP_INTERCEPTORS, useClass: AbsoluteUrlCsrfInterceptor, multi: true}, ]; diff --git a/frontend/src/ts/modules/webbpm/webbpm.module.ts b/frontend/src/ts/modules/webbpm/webbpm.module.ts index c9ef120c..3326d6e7 100644 --- a/frontend/src/ts/modules/webbpm/webbpm.module.ts +++ b/frontend/src/ts/modules/webbpm/webbpm.module.ts @@ -17,6 +17,8 @@ import { import {AppRoutingModule} from "../app/app-routing.module"; import {GlobalErrorHandler} from "./handler/global-error.handler.prod"; import {DEFAULT_HTTP_INTERCEPTOR_PROVIDERS} from "./interceptor/default-interceptors.prod"; +import {HttpClientModule, HttpClientXsrfModule} from "@angular/common/http"; +import {TokenConstants} from "../security/TokenConstants"; let IMPORTS = [ BrowserAnimationsModule, @@ -30,7 +32,10 @@ let IMPORTS = [ CoreModule, ComponentsModule, AppModule, - WebbpmRoutingModule + WebbpmRoutingModule, + HttpClientModule, + HttpClientXsrfModule.withOptions( + {cookieName: TokenConstants.CSRF_TOKEN_NAME, headerName: TokenConstants.CSRF_HEADER_NAME}) ]; @NgModule({ diff --git a/pom.xml b/pom.xml index 6d975700..c055fd73 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,27 @@ + + org.springframework.security + spring-security-bom + 5.8.14 + import + pom + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-annotations + + + ru.cg.webbpm platform-bom