Retrieve the XSRF token first, and set it as both the XSRF header and cookie

This commit is contained in:
Art Lowel
2023-02-07 14:49:22 +01:00
parent 6d99f51d78
commit 06de559974
6 changed files with 69 additions and 26 deletions

View File

@@ -4,8 +4,19 @@ import { PostRequest } from '../data/request.models';
import { HALEndpointService } from '../shared/hal-endpoint.service';
import { RequestService } from '../data/request.service';
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
import { HttpHeaders, HttpXsrfTokenExtractor } from '@angular/common/http';
import { XSRF_REQUEST_HEADER } from '../xsrf/xsrf.interceptor';
import {
HttpHeaders,
HttpXsrfTokenExtractor,
HttpClient,
HttpResponse
} from '@angular/common/http';
import {
XSRF_REQUEST_HEADER,
XSRF_RESPONSE_HEADER,
DSPACE_XSRF_COOKIE
} from '../xsrf/xsrf.interceptor';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
/**
* Server side version of the service to send authentication requests
@@ -17,29 +28,40 @@ export class ServerAuthRequestService extends AuthRequestService {
halService: HALEndpointService,
requestService: RequestService,
rdbService: RemoteDataBuildService,
protected tokenExtractor: HttpXsrfTokenExtractor,
protected httpClient: HttpClient,
) {
super(halService, requestService, rdbService);
}
/**
* Factory function to create the request object to send. This needs to be a POST client side and
* a GET server side. Due to CSRF validation, the server isn't allowed to send a POST, so we allow
* only the server IP to send a GET to this endpoint.
* Factory function to create the request object to send.
*
* @param href The href to send the request to
* @protected
*/
protected createShortLivedTokenRequest(href: string): PostRequest {
let options = new HttpHeaders();
options = options.set('Content-Type', 'application/json; charset=utf-8');
options = options.set(XSRF_REQUEST_HEADER, this.tokenExtractor.getToken());
let requestOptions = {
headers: options,
};
return Object.assign(new PostRequest(this.requestService.generateRequestId(), href, {}, requestOptions), {
responseMsToLive: 2 * 1000 // A short lived token is only valid for 2 seconds.
});
protected createShortLivedTokenRequest(href: string): Observable<PostRequest> {
// First do a call to the root endpoint in order to get an XSRF token
return this.httpClient.get(this.halService.getRootHref(), { observe: 'response' }).pipe(
// retrieve the XSRF token from the response header
map((response: HttpResponse<any>) => response.headers.get(XSRF_RESPONSE_HEADER)),
// Use that token to create an HttpHeaders object
map((xsrfToken: string) => new HttpHeaders()
.set('Content-Type', 'application/json; charset=utf-8')
// set the token as the XSRF header
.set(XSRF_REQUEST_HEADER, xsrfToken)
// and as the DSPACE-XSRF-COOKIE
.set('Cookie', `${DSPACE_XSRF_COOKIE}=${xsrfToken}`)),
map((headers: HttpHeaders) =>
// Create a new PostRequest using those headers and the given href
new PostRequest(
this.requestService.generateRequestId(),
href,
{},
{
headers: headers,
}
))
)
}
}