Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -51,6 +52,7 @@ class DemographicsCollectionModal extends React.Component {
accessToken,
refreshUrl,
);
this.csrfTokenService = new AxiosCsrfTokenService(this.props.csrfTokenPath)
}

async componentDidMount() {
Expand All @@ -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
},
};
Expand Down Expand Up @@ -135,14 +136,14 @@ 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 = {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'X-CSRFTOKEN': Cookies.get('demographics_csrftoken'),
'USE-JWT-COOKIE': true
},
body: JSON.stringify({
Expand All @@ -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 });
}
Expand Down
64 changes: 64 additions & 0 deletions lms/static/js/jwt_auth/AxiosCsrfTokenService.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
1 change: 1 addition & 0 deletions themes/edx.org/lms/templates/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@
"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
},
)}
Expand Down