TSK-1651: Add XSRF Support (#1602)

* TSK-1651: Add XSRF Support

* TSK-1651: now sending XRSF Header for requests with absolute path

* TSK-1651: created configuration to enable XSRF for spring-boot example

Co-authored-by: Mustapha Zorgati <15628173+mustaphazorgati@users.noreply.github.com>
This commit is contained in:
Chi Nguyen 2021-06-10 11:28:30 +02:00 committed by GitHub
parent dd5bccc62c
commit 9b98b56ce4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 19 deletions

View File

@ -8,6 +8,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@ -26,15 +27,18 @@ public class BootWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
private final String ldapUserDnPatterns;
private final boolean devMode;
private final boolean enableCsrf;
public BootWebSecurityConfigurer(
@Value("${taskana.ldap.serverUrl:ldap://localhost:10389}") String ldapServerUrl,
@Value("${taskana.ldap.baseDn:OU=Test,O=TASKANA}") String ldapBaseDn,
@Value("${taskana.ldap.groupSearchBase:cn=groups}") String ldapGroupSearchBase,
@Value("${taskana.ldap.userDnPatterns:uid={0},cn=users}") String ldapUserDnPatterns,
@Value("${enableCsrf:false}") boolean enableCsrf,
LdapAuthoritiesPopulator ldapAuthoritiesPopulator,
GrantedAuthoritiesMapper grantedAuthoritiesMapper,
@Value("${devMode:false}") boolean devMode) {
this.enableCsrf = enableCsrf;
this.ldapAuthoritiesPopulator = ldapAuthoritiesPopulator;
this.grantedAuthoritiesMapper = grantedAuthoritiesMapper;
this.ldapServerUrl = ldapServerUrl;
@ -60,21 +64,25 @@ public class BootWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
HttpSecurity httpSecurity =
http.authorizeRequests()
.antMatchers("/css/**", "/img/**")
.permitAll()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/docs/**")
.permitAll()
.and()
.addFilter(jaasApiIntegrationFilter())
.addFilterAfter(new SpringSecurityToJaasFilter(), JaasApiIntegrationFilter.class);
http.authorizeRequests()
.antMatchers("/css/**", "/img/**")
.permitAll()
.and()
.csrf()
.disable()
.httpBasic()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/docs/**")
.permitAll()
.and()
.addFilter(jaasApiIntegrationFilter())
.addFilterAfter(new SpringSecurityToJaasFilter(), JaasApiIntegrationFilter.class);
if (enableCsrf) {
CookieCsrfTokenRepository csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
csrfTokenRepository.setCookiePath("/");
httpSecurity.csrf().csrfTokenRepository(csrfTokenRepository);
} else {
httpSecurity.csrf().disable().httpBasic();
}
if (devMode) {
http.headers()

View File

@ -31,6 +31,9 @@ taskana.schemaName=TASKANA
####### property that control rest api security deploy use true for no security.
devMode=false
# This property enables the support of XSRF tokens. This will not work together with devMode.
enableCsrf=true
####### property that control if the database is cleaned and sample data is generated
generateSampleData=true

View File

@ -4,7 +4,7 @@
import { BrowserModule } from '@angular/platform-browser';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientModule, HttpClientXsrfModule, HttpXsrfTokenExtractor } from '@angular/common/http';
import { NgxsModule } from '@ngxs/store';
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
import { AlertModule } from 'ngx-bootstrap';
@ -82,7 +82,8 @@ const MODULES = [
MatIconModule,
MatSelectModule,
NgxsModule.forRoot(STATES, { developmentMode: !environment.production }),
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 })
NgxsReduxDevtoolsPluginModule.forRoot({ disabled: environment.production, maxAge: 25 }),
HttpClientXsrfModule
];
const DECLARATIONS = [AppComponent, NavBarComponent, UserInformationComponent, NoAccessComponent, SidenavListComponent];

View File

@ -1,5 +1,12 @@
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
import {
HttpErrorResponse,
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
HttpXsrfTokenExtractor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service';
import { environment } from 'environments/environment';
@ -9,10 +16,18 @@ import { NOTIFICATION_TYPES } from '../../models/notifications';
@Injectable()
export class HttpClientInterceptor implements HttpInterceptor {
constructor(private requestInProgressService: RequestInProgressService, private errorsService: NotificationService) {}
constructor(
private requestInProgressService: RequestInProgressService,
private errorsService: NotificationService,
private tokenExtractor: HttpXsrfTokenExtractor
) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let req = request.clone({ headers: request.headers.set('Content-Type', 'application/hal+json') });
let req = request.clone({ setHeaders: { 'Content-Type': 'application/hal+json' } });
let token = this.tokenExtractor.getToken() as string;
if (token !== null) {
req = req.clone({ setHeaders: { 'X-XSRF-TOKEN': token } });
}
if (!environment.production) {
req = req.clone({ headers: req.headers.set('Authorization', 'Basic YWRtaW46YWRtaW4=') });
}