SUPPORT-8609 add csrf cookie protection

This commit is contained in:
kochetkov 2024-10-15 15:14:21 +03:00
parent b6d1c9720c
commit bb92c71194
19 changed files with 237 additions and 48 deletions

View file

@ -0,0 +1,5 @@
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
import org.springframework.web.WebApplicationInitializer;
public class SecurityInit extends AbstractSecurityWebApplicationInitializer implements WebApplicationInitializer {
}

View file

@ -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);
}
}

View file

@ -10,9 +10,14 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; 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.filter.JwtAuthenticationFilter;
import ru.micord.ervu.security.webbpm.jwt.UnauthorizedEntryPoint; import ru.micord.ervu.security.webbpm.jwt.UnauthorizedEntryPoint;
import static ru.micord.ervu.security.SecurityConstants.ESIA_LOGOUT;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
@ -22,19 +27,31 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
httpConfigure(http); httpConfigure(http);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
} }
protected void httpConfigure(HttpSecurity httpSecurity) throws Exception { 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() httpSecurity.authorizeRequests()
.antMatchers(permitAll).permitAll() .antMatchers(permitAll).permitAll()
.antMatchers("/**").authenticated() .antMatchers("/**").authenticated()
.and() .and()
.csrf().disable() .csrf((csrf) -> csrf
.csrfTokenRepository(tokenRepository)
.csrfTokenRequestHandler(requestHandler)
)
.logout((logout) -> logout
.logoutUrl(ESIA_LOGOUT)
.logoutSuccessHandler(new CsrfTokenAwareLogoutSuccessHandler(tokenRepository))
)
.exceptionHandling().authenticationEntryPoint(entryPoint()) .exceptionHandling().authenticationEntryPoint(entryPoint())
.and() .and()
.sessionManagement() .sessionManagement()

View file

@ -0,0 +1,5 @@
package ru.micord.ervu.security;
public class SecurityConstants {
public static final String ESIA_LOGOUT = "/esia/logout";
}

View file

@ -3,12 +3,13 @@ package ru.micord.ervu.security.esia.controller;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; 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.model.OrgInfoModel;
import ru.micord.ervu.security.esia.service.EsiaAuthService; import ru.micord.ervu.security.esia.service.EsiaAuthService;
import ru.micord.ervu.security.esia.service.EsiaDataService; import ru.micord.ervu.security.esia.service.EsiaDataService;
import org.springframework.beans.factory.annotation.Autowired; 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.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -24,37 +25,37 @@ public class EsiaController {
@Autowired @Autowired
private EsiaDataService esiaDataService; private EsiaDataService esiaDataService;
@RequestMapping(value = "/esia/url") @GetMapping(value = "/esia/url")
public String getEsiaUrl() { public String getEsiaUrl() {
return esiaAuthService.generateAuthCodeUrl(); 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) { public boolean esiaAuth(@RequestParam("code") String code, HttpServletRequest request, HttpServletResponse response) {
return esiaAuthService.getEsiaTokensByCode(code, request, response); return esiaAuthService.getEsiaTokensByCode(code, request, response);
} }
@RequestMapping(value = "/esia/refresh") @PostMapping(value = "/esia/refresh")
public void refreshToken(HttpServletRequest request, HttpServletResponse response) { public void refreshToken(HttpServletRequest request, HttpServletResponse response) {
esiaAuthService.getEsiaTokensByRefreshToken(request, response); esiaAuthService.getEsiaTokensByRefreshToken(request, response);
} }
@RequestMapping(value = "/esia/org") @GetMapping(value = "/esia/org")
public OrgInfoModel getOrgInfo(HttpServletRequest request) { public OrgInfoModel getOrgInfo(HttpServletRequest request) {
return esiaDataService.getOrgInfo(request); return esiaDataService.getOrgInfo(request);
} }
@RequestMapping(value = "/esia/userfullname") @GetMapping(value = "/esia/userfullname")
public String getUserFullname(HttpServletRequest request) { public String getUserFullname(HttpServletRequest request) {
return esiaDataService.getUserFullname(request); return esiaDataService.getUserFullname(request);
} }
@RequestMapping(value = "/esia/orgunitname") @GetMapping(value = "/esia/orgunitname")
public String getOrgUnitName(HttpServletRequest request) { public String getOrgUnitName(HttpServletRequest request) {
return esiaDataService.getOrgUnitName(request); return esiaDataService.getOrgUnitName(request);
} }
@RequestMapping(value = "/esia/logout") @PostMapping(SecurityConstants.ESIA_LOGOUT)
public String logout(HttpServletRequest request, HttpServletResponse response) { public String logout(HttpServletRequest request, HttpServletResponse response) {
return esiaAuthService.logout(request, response); return esiaAuthService.logout(request, response);
} }

View file

@ -200,11 +200,19 @@ public class EsiaAuthService {
.build() .build()
.send(postReq, HttpResponse.BodyHandlers.ofString()); .send(postReq, HttpResponse.BodyHandlers.ofString());
String responseString = postResp.body(); String responseString = postResp.body();
EsiaTokenResponse tokenResponse = objectMapper.readValue(responseString, EsiaTokenResponse.class); EsiaTokenResponse tokenResponse = objectMapper.readValue(responseString,
if (tokenResponse != null && tokenResponse.getError() != null) { EsiaTokenResponse.class
);
if (tokenResponse == null) {
throw new IllegalStateException("Got empty esia response");
}
if (tokenResponse.getError() != null) {
throw new RuntimeException(tokenResponse.getError_description()); throw new RuntimeException(tokenResponse.getError_description());
} }
String accessToken = tokenResponse.getAccess_token(); String accessToken = tokenResponse.getAccess_token();
boolean hasRole = ulDataService.checkRole(accessToken); boolean hasRole = ulDataService.checkRole(accessToken);
if (!hasRole) { if (!hasRole) {
throw new RuntimeException("The user does not have the required role"); throw new RuntimeException("The user does not have the required role");

View file

@ -1,6 +1,6 @@
<button class="user-info" ngbDropdownToggle *ngIf="getIsAuth()">{{getUserFullname()}}</button> <button class="user-info" ngbDropdownToggle *ngIf="isAuthenticated()">{{getUserFullname()}}</button>
<div ngbDropdownMenu *ngIf="getIsAuth()"> <div ngbDropdownMenu *ngIf="isAuthenticated()">
<div class="user-department">{{getOrgUnitName()}}</div> <div class="user-department">{{getOrgUnitName()}}</div>
<a routerLink="/mydata" class="data">Данные организации</a> <a routerLink="/mydata" class="data">Данные организации</a>
<button ngbDropdownItem class="exit" (click)="logout()">Выйти</button> <button ngbDropdownItem class="exit" (click)="logout()">Выйти</button>
</div> </div>

View file

@ -11,6 +11,8 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef} from
import {FileItem, FileUploader} from "ng2-file-upload"; import {FileItem, FileUploader} from "ng2-file-upload";
import {FileLikeObject} from "ng2-file-upload/file-upload/file-like-object.class"; import {FileLikeObject} from "ng2-file-upload/file-upload/file-like-object.class";
import {EmployeeInfoFileFormType} from "./EmployeeInfoFileFormType"; import {EmployeeInfoFileFormType} from "./EmployeeInfoFileFormType";
import {CookieService} from "ngx-cookie";
import {TokenConstants} from "../../../modules/security/TokenConstants";
@Component({ @Component({
moduleId: module.id, moduleId: module.id,
@ -59,6 +61,7 @@ export class ErvuFileUpload extends InputControl {
private messagesService: MessagesService; private messagesService: MessagesService;
private isUploadErrorOccurred = false; private isUploadErrorOccurred = false;
private appConfigService: AppConfigService; private appConfigService: AppConfigService;
private cookieService: CookieService;
constructor(el: ElementRef, cd: ChangeDetectorRef) { constructor(el: ElementRef, cd: ChangeDetectorRef) {
super(el, cd); super(el, cd);
@ -69,6 +72,7 @@ export class ErvuFileUpload extends InputControl {
super.initialize(); super.initialize();
this.messagesService = this.injector.get(MessagesService); this.messagesService = this.injector.get(MessagesService);
this.appConfigService = this.injector.get(AppConfigService); this.appConfigService = this.injector.get(AppConfigService);
this.cookieService = this.injector.get(CookieService);
this.url = `/${this.appConfigService.getParamValue(ErvuFileUpload.BACKEND_URL)}/employee/document`; this.url = `/${this.appConfigService.getParamValue(ErvuFileUpload.BACKEND_URL)}/employee/document`;
this.uploader.setOptions({ this.uploader.setOptions({
@ -99,6 +103,10 @@ export class ErvuFileUpload extends InputControl {
{ {
name: "Client-Time-Zone", name: "Client-Time-Zone",
value: Intl.DateTimeFormat().resolvedOptions().timeZone 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() { private setUploaderMethods() {
this.uploader.onBeforeUploadItem = (fileItem: FileItem) => { 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.fileUploadStartEvent.trigger();
this.isDropZoneVisible = false; this.isDropZoneVisible = false;
this.isFilesListVisible = false; this.isFilesListVisible = false;
@ -239,4 +265,4 @@ export class ErvuFileUpload extends InputControl {
this.isUploadErrorOccurred = false; this.isUploadErrorOccurred = false;
this.cd.markForCheck(); this.cd.markForCheck();
} }
} }

View file

@ -2,10 +2,10 @@ import {AnalyticalScope, Behavior, Container, ControlWithValue} from "@webbpm/ba
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {OrgData} from "./OrgData"; import {OrgData} from "./OrgData";
import {OrgInfoModel} from "../generated/ru/micord/ervu/security/esia/model/OrgInfoModel"; 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) @AnalyticalScope(Container)
export class OrgDataRoot extends Behavior{ export class OrgDataRoot extends Behavior {
private container: Container; private container: Container;
@ -14,8 +14,9 @@ export class OrgDataRoot extends Behavior{
this.container = this.getScript(Container); this.container = this.getScript(Container);
let orgScripts: OrgData[] = this.container.getScriptsInThisAndChildren(OrgData); let orgScripts: OrgData[] = this.container.getScriptsInThisAndChildren(OrgData);
let httpClient = this.injector.get(HttpClient); let httpClient = this.injector.get(HttpClient);
let cookieService = this.injector.get(CookieService); let cookieService = this.injector.get(AuthenticationService);
if (cookieService.get("webbpm.ervu-lkrp-ul")) {
if (cookieService.isAuthenticated()) {
httpClient.get<OrgInfoModel>("esia/org") httpClient.get<OrgInfoModel>("esia/org")
.toPromise() .toPromise()
.then(orgInfoModel => { .then(orgInfoModel => {
@ -23,9 +24,9 @@ export class OrgDataRoot extends Behavior{
return; return;
} }
for (let orgData of orgScripts) { for (let orgData of orgScripts) {
let control: ControlWithValue = orgData.getScriptInObject(orgData.getObjectId(), let control: ControlWithValue = orgData.getScriptInObject(orgData.getObjectId(),
'component.ControlWithValue'); 'component.ControlWithValue');
control.setValue(orgInfoModel[orgData.dataId]); control.setValue(orgInfoModel[orgData.dataId]);
} }
}); });
} }

View file

@ -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 {NgbModule} from "@ng-bootstrap/ng-bootstrap";
import {CommonModule, registerLocaleData} from "@angular/common"; import {CommonModule, registerLocaleData} from "@angular/common";
import localeRu from '@angular/common/locales/ru'; 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 {ErvuFileUpload} from "../../ervu/component/fileupload/ErvuFileUpload";
import {InMemoryStaticGrid} from "../../ervu/component/grid/InMemoryStaticGrid"; import {InMemoryStaticGrid} from "../../ervu/component/grid/InMemoryStaticGrid";
import {ErvuDownloadFileButton} from "../../ervu/component/button/ErvuDownloadFileButton"; import {ErvuDownloadFileButton} from "../../ervu/component/button/ErvuDownloadFileButton";
import {AuthenticationService} from "../security/authentication.service";
registerLocaleData(localeRu); registerLocaleData(localeRu);
export const DIRECTIVES = [ export const DIRECTIVES = [
@ -39,6 +40,10 @@ export const DIRECTIVES = [
forwardRef(() => InMemoryStaticGrid) forwardRef(() => InMemoryStaticGrid)
]; ];
function checkAuthentication(authService: AuthenticationService): () => Promise<any> {
return () => authService.checkAuthentication();
}
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, CommonModule,
@ -60,6 +65,13 @@ export const DIRECTIVES = [
DIRECTIVES DIRECTIVES
], ],
providers: [ providers: [
AuthenticationService,
{
provide: APP_INITIALIZER,
useFactory: checkAuthentication,
deps: [AuthenticationService],
multi: true,
},
{ provide: ProgressIndicationService, useClass: AppProgressIndicationService } { provide: ProgressIndicationService, useClass: AppProgressIndicationService }
], ],
bootstrap: [], bootstrap: [],

View file

@ -1,7 +1,7 @@
import {ChangeDetectorRef, Component, OnInit} from "@angular/core"; import {ChangeDetectorRef, Component, OnInit} from "@angular/core";
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {CookieService} from "ngx-cookie"; import {AuthenticationService} from "../../security/authentication.service";
@Component({ @Component({
moduleId: module.id, moduleId: module.id,
@ -13,13 +13,12 @@ export class LogOutComponent implements OnInit{
private userFullname: string; private userFullname: string;
private orgUnitName: string; private orgUnitName: string;
constructor(private router: Router, private httpClient: HttpClient, constructor(private router: Router, private httpClient: HttpClient,
private cookieService: CookieService, private cd: ChangeDetectorRef) { private authenticationService: AuthenticationService, private cd: ChangeDetectorRef) {
} }
ngOnInit(): void { ngOnInit(): void {
let isAuth = this.getIsAuth(); let isAuth = this.authenticationService.isAuthenticated();
if (isAuth) { if (isAuth) {
Promise.all([ Promise.all([
this.httpClient.get<string>("esia/userfullname").toPromise(), this.httpClient.get<string>("esia/userfullname").toPromise(),
@ -33,20 +32,18 @@ export class LogOutComponent implements OnInit{
} }
public logout(): void { public logout(): void {
this.httpClient.get<string>("esia/logout").toPromise().then(url => { this.authenticationService.logout();
window.open(url, "_self");
})
} }
public getUserFullname(): string { public getUserFullname(): string {
return this.userFullname; return this.userFullname;
} }
public getIsAuth(): boolean { public isAuthenticated(): boolean {
return this.cookieService.get("webbpm.ervu-lkrp-ul") != null; return this.authenticationService.isAuthenticated();
} }
public getOrgUnitName(): string { public getOrgUnitName(): string {
return this.orgUnitName; return this.orgUnitName;
} }
} }

View file

@ -0,0 +1,4 @@
export class TokenConstants {
public static readonly CSRF_TOKEN_NAME = "XSRF-TOKEN";
public static readonly CSRF_HEADER_NAME = "X-XSRF-TOKEN";
}

View file

@ -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<any>{
return this.appConfigService.load().then(value => this.http.get<any>("version").toPromise())
}
logout(): Promise<string> {
return this.http.post<string>('esia/logout', {}).toPromise();
}
public isAuthenticated(): boolean {
return this.cookieService.get('webbpm.ervu-lkrp-ul') != null;
}
}

View file

@ -2,8 +2,8 @@ import {Injectable} from "@angular/core";
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from "@angular/router"; import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from "@angular/router";
import {Observable} from "rxjs"; import {Observable} from "rxjs";
import {HttpClient, HttpParams} from "@angular/common/http"; import {HttpClient, HttpParams} from "@angular/common/http";
import {CookieService} from "ngx-cookie";
import {MessagesService} from "@webbpm/base-package"; import {MessagesService} from "@webbpm/base-package";
import {AuthenticationService} from "../authentication.service";
@Injectable({providedIn:'root'}) @Injectable({providedIn:'root'})
export abstract class AuthGuard implements CanActivate { export abstract class AuthGuard implements CanActivate {
@ -11,7 +11,7 @@ export abstract class AuthGuard implements CanActivate {
protected constructor( protected constructor(
protected router: Router, protected router: Router,
private httpClient: HttpClient, private httpClient: HttpClient,
private cookieService: CookieService, private authenticationService: AuthenticationService,
private messageService: MessagesService private messageService: MessagesService
) { ) {
} }
@ -55,11 +55,7 @@ export abstract class AuthGuard implements CanActivate {
}); });
} }
private checkAccess(): Promise<boolean> | boolean { private checkAccess(): boolean {
return this.getIsAuth() != null; return this.authenticationService.isAuthenticated();
}; };
public getIsAuth(): string {
return this.cookieService.get('webbpm.ervu-lkrp-ul');
}
} }

View file

@ -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<any>, next: HttpHandler): Observable<HttpEvent<any>> {
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);
}
}

View file

@ -4,9 +4,11 @@ import {
HttpSecurityErrorInterceptor, HttpSecurityErrorInterceptor,
HttpSecurityInterceptor HttpSecurityInterceptor
} from "@webbpm/base-package"; } from "@webbpm/base-package";
import {AbsoluteUrlCsrfInterceptor} from "./absolute-url-csrf.interceptor";
export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [ export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true}, {provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityErrorInterceptor, 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}
]; ];

View file

@ -1,9 +1,11 @@
import {HTTP_INTERCEPTORS} from "@angular/common/http"; import {HTTP_INTERCEPTORS} from "@angular/common/http";
import {FormDirtyInterceptor, HttpSecurityInterceptor} from "@webbpm/base-package"; import {FormDirtyInterceptor, HttpSecurityInterceptor} from "@webbpm/base-package";
import {DevHttpSecurityErrorInterceptor} from "./http-security-error-interceptor.dev"; import {DevHttpSecurityErrorInterceptor} from "./http-security-error-interceptor.dev";
import {AbsoluteUrlCsrfInterceptor} from "./absolute-url-csrf.interceptor";
export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [ export const DEFAULT_HTTP_INTERCEPTOR_PROVIDERS = [
{provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true}, {provide: HTTP_INTERCEPTORS, useClass: HttpSecurityInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: DevHttpSecurityErrorInterceptor, 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},
]; ];

View file

@ -17,6 +17,8 @@ import {
import {AppRoutingModule} from "../app/app-routing.module"; import {AppRoutingModule} from "../app/app-routing.module";
import {GlobalErrorHandler} from "./handler/global-error.handler.prod"; import {GlobalErrorHandler} from "./handler/global-error.handler.prod";
import {DEFAULT_HTTP_INTERCEPTOR_PROVIDERS} from "./interceptor/default-interceptors.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 = [ let IMPORTS = [
BrowserAnimationsModule, BrowserAnimationsModule,
@ -30,7 +32,10 @@ let IMPORTS = [
CoreModule, CoreModule,
ComponentsModule, ComponentsModule,
AppModule, AppModule,
WebbpmRoutingModule WebbpmRoutingModule,
HttpClientModule,
HttpClientXsrfModule.withOptions(
{cookieName: TokenConstants.CSRF_TOKEN_NAME, headerName: TokenConstants.CSRF_HEADER_NAME})
]; ];
@NgModule({ @NgModule({

21
pom.xml
View file

@ -26,6 +26,27 @@
</properties> </properties>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>5.8.14</version>
<scope>import</scope>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <dependency>
<groupId>ru.cg.webbpm</groupId> <groupId>ru.cg.webbpm</groupId>
<artifactId>platform-bom</artifactId> <artifactId>platform-bom</artifactId>