Add CSRF code to demographics modal (#24998)
* Add CSRF tokens to demographics modal PATCH We have temporarilly copied over the CSRF code from frontend-platform to use with the demographics modal. This code is most likely temporary and is not maintained like frontend-platform.
This commit is contained in:
@@ -7,6 +7,7 @@ import { SelectWithInput } from './SelectWithInput'
|
||||
import { MultiselectDropdown } from './MultiselectDropdown';
|
||||
import AxiosJwtTokenService from '../jwt_auth/AxiosJwtTokenService';
|
||||
import StringUtils from 'edx-ui-toolkit/js/utils/string-utils';
|
||||
import AxiosCsrfTokenService from '../jwt_auth/AxiosCsrfTokenService';
|
||||
|
||||
const FIELD_NAMES = {
|
||||
CURRENT_WORK: "current_work_sector",
|
||||
@@ -51,6 +52,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
accessToken,
|
||||
refreshUrl,
|
||||
);
|
||||
this.csrfTokenService = new AxiosCsrfTokenService(this.props.csrfTokenPath)
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
@@ -59,7 +61,6 @@ class DemographicsCollectionModal extends React.Component {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFTOKEN': Cookies.get('demographics_csrftoken'),
|
||||
'USE-JWT-COOKIE': true
|
||||
},
|
||||
};
|
||||
@@ -135,6 +136,7 @@ class DemographicsCollectionModal extends React.Component {
|
||||
}
|
||||
|
||||
async handleSelectChange(e) {
|
||||
const url = `${this.props.demographicsBaseUrl}/demographics/api/v1/demographics/${this.props.user}/`;
|
||||
const name = e.target.name;
|
||||
const value = e.target.value;
|
||||
const options = {
|
||||
@@ -142,7 +144,6 @@ class DemographicsCollectionModal extends React.Component {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFTOKEN': Cookies.get('demographics_csrftoken'),
|
||||
'USE-JWT-COOKIE': true
|
||||
},
|
||||
body: JSON.stringify({
|
||||
@@ -152,7 +153,8 @@ class DemographicsCollectionModal extends React.Component {
|
||||
|
||||
try {
|
||||
await this.jwtTokenService.getJwtToken();
|
||||
await fetch(`${this.props.demographicsBaseUrl}/demographics/api/v1/demographics/${this.props.user}/`, options)
|
||||
options.headers['X-CSRFToken'] = await this.csrfTokenService.getCsrfToken(url);
|
||||
await fetch(url, options)
|
||||
} catch (error) {
|
||||
this.setState({ loading: false, fieldError: true, errorMessage: error });
|
||||
}
|
||||
|
||||
64
lms/static/js/jwt_auth/AxiosCsrfTokenService.js
Normal file
64
lms/static/js/jwt_auth/AxiosCsrfTokenService.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Service class to support CSRF.
|
||||
*
|
||||
* Temporarily copied from the edx/frontend-platform
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import { getUrlParts, processAxiosErrorAndThrow } from './utils';
|
||||
|
||||
export default class AxiosCsrfTokenService {
|
||||
constructor(csrfTokenApiPath) {
|
||||
this.csrfTokenApiPath = csrfTokenApiPath;
|
||||
this.httpClient = axios.create();
|
||||
// Set withCredentials to true. Enables cross-site Access-Control requests
|
||||
// to be made using cookies, authorization headers or TLS client
|
||||
// certificates. More on MDN:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
|
||||
this.httpClient.defaults.withCredentials = true;
|
||||
this.httpClient.defaults.headers.common['USE-JWT-COOKIE'] = true;
|
||||
|
||||
this.csrfTokenCache = {};
|
||||
this.csrfTokenRequestPromises = {};
|
||||
}
|
||||
|
||||
async getCsrfToken(url) {
|
||||
let urlParts;
|
||||
try {
|
||||
urlParts = getUrlParts(url);
|
||||
} catch (e) {
|
||||
// If the url is not parsable it's likely because a relative
|
||||
// path was supplied as the url. This is acceptable and in
|
||||
// this case we should use the current origin of the page.
|
||||
urlParts = getUrlParts(global.location.origin);
|
||||
}
|
||||
const { protocol, domain } = urlParts;
|
||||
const csrfToken = this.csrfTokenCache[domain];
|
||||
|
||||
if (csrfToken) {
|
||||
return csrfToken;
|
||||
}
|
||||
|
||||
if (!this.csrfTokenRequestPromises[domain]) {
|
||||
this.csrfTokenRequestPromises[domain] = this.httpClient
|
||||
.get(`${protocol}://${domain}${this.csrfTokenApiPath}`)
|
||||
.then((response) => {
|
||||
this.csrfTokenCache[domain] = response.data.csrfToken;
|
||||
return this.csrfTokenCache[domain];
|
||||
})
|
||||
.catch(processAxiosErrorAndThrow)
|
||||
.finally(() => {
|
||||
delete this.csrfTokenRequestPromises[domain];
|
||||
});
|
||||
}
|
||||
|
||||
return this.csrfTokenRequestPromises[domain];
|
||||
}
|
||||
|
||||
clearCsrfTokenCache() {
|
||||
this.csrfTokenCache = {};
|
||||
}
|
||||
|
||||
getHttpClient() {
|
||||
return this.httpClient;
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,7 @@ from student.models import CourseEnrollment
|
||||
"demographicsBaseUrl": getattr(settings, 'DEMOGRAPHICS_BASE_URL', ''),
|
||||
"marketingSiteBaseUrl": getattr(settings, 'MKTG_URLS', {}).get('ROOT', ''),
|
||||
"jwtAuthToken": getattr(settings, 'JWT_AUTH', {}).get('JWT_AUTH_COOKIE_HEADER_PAYLOAD', ''),
|
||||
"csrfTokenPath": getattr(settings, 'DEMOGRAPHICS_CSRF_TOKEN_API_PATH', ''),
|
||||
"bannerLogo": bannerLogoPath
|
||||
},
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user