Skip to content

Commit c8808f4

Browse files
krisctlPrabhakar Kumar
authored andcommitted
!! Breaking Change !! The Token Authentication key name is updated from mwi_auth_token to mwi-auth-token.
Underscore separated header names are not recognized by reverse proxies like NGINX, and require additional settings to allow them to pass through. For more information, see: https://nginx.org/en/docs/http/ngx_http_core_module.html#ignore_invalid_headers
1 parent d8b0a88 commit c8808f4

File tree

15 files changed

+120
-74
lines changed

15 files changed

+120
-74
lines changed

SECURITY.md

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,29 +65,30 @@ $ env MWI_ENABLE_SSL=True MWI_SSL_CERT_FILE="/path/to/certificate.pem" MWI_SSL_K
6565

6666
`matlab-proxy` is a web server and that allows one to start and access MATLAB on the machine the server is running on. Anyone with access to the server can access MATLAB and thereby the machine on which its running.
6767

68-
`Token-Based Authentication` is enabled by default and the server will require a token to authenticate access. This token can be provided to the server in a few ways:
68+
`Token-Based Authentication` is enabled by default and the server requires a token to authenticate access. Users can provide this token to the server in the following ways:
6969

70-
1. Through the [URL parameter](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) : `mwi_auth_token`. Example:
70+
1. Use the [URL parameter](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) : `mwi-auth-token`. Example:
7171
```html
72-
https://localhost:8888/?mwi_auth_token=abcdef...
72+
https://localhost:8888/?mwi-auth-token=abcdef...
7373
```
74-
Once provided, this information is cached in the browser and will be used in subsequent interactions
74+
The browser caches the token for subsequent interactions.
7575

76-
2. Through the auth token input field in the Status Information dialogue box that is presented when the user is not already logged in.
76+
2. Use the auth token input field in the Status Information dialogue box that appears when the user is not already logged in.
7777
<p align="center">
7878
<img width="800" src="./img/token_authentication_page.png">
7979
</p>
8080

81-
3. Through a `mwi_auth_token` header. Example:
81+
3. Use a `mwi-auth-token` header. Example:
8282
``` html
83-
mwi_auth_token:abcdef..
83+
mwi-auth-token:abcdef..
8484
```
85+
> :warning: `matlab-proxy` version v0.16.0 and later require you to provide the token name in the URL or header with hyphens instead of underscores, for example `mwi-auth-token` instead of `mwi_auth_token`.
8586

8687
**NOTE** : Its highly recommended to use this feature along with SSL enabled as shown [here](#use-token-authentication-with-ssl-enabled).
8788

88-
### **Use with auto-generated tokens**
89+
### **Use auto-generated tokens**
8990

90-
When enabled, `matlab-proxy` will require the URL to specify the access token using the [query component](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) `mwi_auth_token`.
91+
When enabled, `matlab-proxy` requires the URL to specify the access token using the [query component](https://www.rfc-editor.org/rfc/rfc3986#section-3.4) `mwi-auth-token`.
9192

9293
Example:
9394

@@ -96,13 +97,13 @@ Example:
9697
# Start matlab-proxy with Token-Based Authentication enabled by default
9798
$ matlab-proxy-app
9899

99-
# The access link is presented in the terminal upon startup like follows:
100+
# The access link appears in the terminal:
100101
==================================================================================================
101102
Access MATLAB at:
102-
http://127.0.0.1:37109?mwi_auth_token=SY78vUw5qyf0JTJzGK4mKJlk_exkzL_SMFJyilbGtNI
103+
http://127.0.0.1:37109?mwi-auth-token=SY78vUw5qyf0JTJzGK4mKJlk_exkzL_SMFJyilbGtNI
103104
==================================================================================================
104105
```
105-
In this example `SY78vUw5qyf0JTJzGK4mKJlk_exkzL_SMFJyilbGtNI` is the token that the server would need for all future communication.
106+
In this example `SY78vUw5qyf0JTJzGK4mKJlk_exkzL_SMFJyilbGtNI` is the token that the server needs for future communication.
106107

107108
After initial access, this token is cached by the browser, and all subsequent access from the same browser to the server will not require this token.
108109
You will however need this token to access the server from a new browser session or if you have cleared cookies or have cookies disabled.
@@ -121,10 +122,10 @@ Example:
121122
# Start matlab-proxy with Token-Based Authentication enabled, and with custom token with a value of "MyCustomSecretToken"
122123
$ env MWI_ENABLE_TOKEN_AUTH=True MWI_AUTH_TOKEN=MyCustomSecretToken matlab-proxy-app
123124

124-
# The access link is presented in the terminal upon startup like follows:
125+
# The access link appears in the terminal:
125126
==================================================================================================
126127
Access MATLAB at:
127-
http://127.0.0.1:37109?mwi_auth_token=MyCustomSecretToken
128+
http://127.0.0.1:37109?mwi-auth-token=MyCustomSecretToken
128129
==================================================================================================
129130
```
130131

@@ -137,13 +138,13 @@ For example, the following command starts the server to deliver content on `HTTP
137138
# Start matlab-proxy with Token-Based Authentication & SSL enabled with custom token with a value of "asdf"
138139
$ env MWI_SSL_CERT_FILE="/path/to/certificate.pem" MWI_SSL_KEY_FILE="/path/to/keyfile.key" MWI_ENABLE_TOKEN_AUTH=True MWI_AUTH_TOKEN=asdf matlab-proxy-app
139140

140-
# The access link is presented in the terminal upon startup like follows:
141+
# The access link appears in the terminal:
141142
==================================================================================================
142143
Access MATLAB at:
143-
https://127.0.0.1:37109?mwi_auth_token=asdf
144+
https://127.0.0.1:37109?mwi-auth-token=asdf
144145
==================================================================================================
145146

146-
# NOTE: This server is running HTTP(S) !
147+
# NOTE: This server is running HTTP(S)
147148

148149
```
149150

@@ -173,10 +174,10 @@ $ ssh test-user@usermachine
173174
-------------------------------------------------------------------------------------------------------------------
174175
Your running servers are:
175176
-------------------------------------------------------------------------------------------------------------------
176-
1. https://127.0.0.1:46525/asdf?mwi_auth_token=asdfasdf
177-
2. http://127.0.0.1:39057/test?mwi_auth_token=_qNJIXEbnXwrj9nxZwbJiWno0YqYSh8BMdQOR6K67y0
178-
3. http://127.0.0.1:35647/test?mwi_auth_token=r6djdrcf591PttYlDZcVL78xIa1XgCviM9dQD-BrqDE
179-
4. http://127.0.0.1:36537/test?mwi_auth_token=HdQ-9tooAzA0A0CrpUxP1e5crQBErMQC3tPGTkTtrVo
177+
1. https://127.0.0.1:46525/asdf?mwi-auth-token=asdfasdf
178+
2. http://127.0.0.1:39057/test?mwi-auth-token=_qNJIXEbnXwrj9nxZwbJiWno0YqYSh8BMdQOR6K67y0
179+
3. http://127.0.0.1:35647/test?mwi-auth-token=r6djdrcf591PttYlDZcVL78xIa1XgCviM9dQD-BrqDE
180+
4. http://127.0.0.1:36537/test?mwi-auth-token=HdQ-9tooAzA0A0CrpUxP1e5crQBErMQC3tPGTkTtrVo
180181
5. http://127.0.0.1:35433/test
181182
-------------------------------------------------------------------------------------------------------------------
182183
Thank you.
@@ -209,7 +210,7 @@ Example:
209210
# Start matlab-proxy with Token-Based Authentication disabled
210211
$ env MWI_ENABLE_TOKEN_AUTH="False" matlab-proxy-app
211212

212-
# The access link is presented in the terminal upon startup like follows:
213+
# The access link appears in the terminal:
213214
==================================================================================================
214215
Access MATLAB at:
215216
http://127.0.0.1:37110

gui/src/actionCreators/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
selectIsAuthenticated
3636
} from '../selectors';
3737
import sha256 from 'crypto-js/sha256';
38+
import { MWI_AUTH_TOKEN_NAME_FOR_HTTP } from '../constants';
3839

3940
export function setAuthStatus (authentication) {
4041
return {
@@ -296,7 +297,7 @@ export function updateAuthStatus (token) {
296297
const options = {
297298
method: 'POST',
298299
headers: {
299-
mwi_auth_token: tokenHash
300+
[MWI_AUTH_TOKEN_NAME_FOR_HTTP]: tokenHash
300301
}
301302
};
302303
const response = await fetchWithTimeout(dispatch, './authenticate', options, 15000);

gui/src/components/App/App.spec.js

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import App from './index';
77
import * as actionCreators from '../../actionCreators';
88
import state from '../../test/utils/state';
99
import { MAX_REQUEST_FAIL_COUNT } from '../../constants';
10+
import { MWI_AUTH_TOKEN_NAME_FOR_HTTP } from '../../constants';
1011

1112
const _ = require('lodash');
1213

@@ -47,7 +48,7 @@ describe('App Component', () => {
4748
});
4849

4950
it('should render overlayTrigger (after closing the tutorial)', () => {
50-
// Hide the tutorial before rendering the component.
51+
// Hide the tutorial before rendering the component.
5152
initialState.tutorialHidden = true;
5253
initialState.overlayVisibility = false;
5354

@@ -64,7 +65,7 @@ describe('App Component', () => {
6465
});
6566

6667
it('should render LicensingGatherer component within the App component when no licensing is provided and user is authenticated', () => {
67-
// Set lincensingInfo to empty object.
68+
// Set licensingInfo to empty object.
6869
initialState.overlayVisibility = true;
6970
initialState.serverStatus.licensingInfo = {};
7071
initialState.authentication.enabled = true;
@@ -79,7 +80,7 @@ describe('App Component', () => {
7980
});
8081

8182
it('should render LicensingGatherer component within the App component when no licensing is provided and authentication is disabled', () => {
82-
// Set lincensingInfo to empty object.
83+
// Set licensingInfo to empty object.
8384
initialState.overlayVisibility = true;
8485
initialState.serverStatus.licensingInfo = {};
8586
initialState.authentication.enabled = false;
@@ -93,7 +94,7 @@ describe('App Component', () => {
9394
});
9495

9596
it('should render Information Component within App Component after licensing is provided and user is authenticated', () => {
96-
// Hide the tutorial and make the overlay visible.
97+
// Hide the tutorial and make the overlay visible.
9798
initialState.tutorialHidden = true;
9899
initialState.overlayVisibility = true;
99100

@@ -112,7 +113,7 @@ describe('App Component', () => {
112113
});
113114

114115
it('should render Information Component within App Component after licensing is provided and auth is not enabled', () => {
115-
// Hide the tutorial and make the overlay visible.
116+
// Hide the tutorial and make the overlay visible.
116117
initialState.tutorialHidden = true;
117118
initialState.overlayVisibility = true;
118119

@@ -131,7 +132,7 @@ describe('App Component', () => {
131132
});
132133

133134
it('should display integration terminated error', () => {
134-
// Hide the tutorial, make the overlay visible and set fetchFailCount to MAX_REQUEST_FAIL_COUNT
135+
// Hide the tutorial, make the overlay visible and set fetchFailCount to MAX_REQUEST_FAIL_COUNT
135136
initialState.tutorialHidden = true;
136137
initialState.overlayVisibility = true;
137138
initialState.serverStatus.fetchFailCount = MAX_REQUEST_FAIL_COUNT;
@@ -173,7 +174,7 @@ describe('App Component', () => {
173174
});
174175

175176
it('should display Confirmation component ', () => {
176-
// Hide the tutorial and make the overlay visible
177+
// Hide the tutorial and make the overlay visible
177178
initialState.tutorialHidden = true;
178179
initialState.overlayVisibility = true;
179180

@@ -196,7 +197,7 @@ describe('App Component', () => {
196197
});
197198

198199
it('should display Help Component', () => {
199-
// Hide the tutorial and make the overlay visible
200+
// Hide the tutorial and make the overlay visible
200201
initialState.tutorialHidden = true;
201202
initialState.overlayVisibility = true;
202203

@@ -230,9 +231,9 @@ describe('App Component', () => {
230231

231232
const tokenInQuery = '12345';
232233
it.each([
233-
[`?mwi_auth_token=${tokenInQuery}&test1=1&test2=2`, tokenInQuery],
234-
[`?test1=1&mwi_auth_token=${tokenInQuery}&test2=2`, tokenInQuery],
235-
[`?test1=1&test2=2&mwi_auth_token=${tokenInQuery}`, tokenInQuery]
234+
[`?${MWI_AUTH_TOKEN_NAME_FOR_HTTP}=${tokenInQuery}&test1=1&test2=2`, tokenInQuery],
235+
[`?test1=1&${MWI_AUTH_TOKEN_NAME_FOR_HTTP}=${tokenInQuery}&test2=2`, tokenInQuery],
236+
[`?test1=1&test2=2&${MWI_AUTH_TOKEN_NAME_FOR_HTTP}=${tokenInQuery}`, tokenInQuery]
236237
])("should pick the token correctly when the query parameters are '%s'", (queryParams, expectedToken) => {
237238
const url = 'http://localhost.com:5555';
238239
const mockUpdateAuthStatus = jest.spyOn(actionCreators, 'updateAuthStatus');

gui/src/components/App/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {
4343
} from '../../actionCreators';
4444
import blurredBackground from './MATLAB-env-blur.png';
4545
import EntitlementSelector from '../EntitlementSelector';
46+
import { MWI_AUTH_TOKEN_NAME_FOR_HTTP } from '../../constants';
4647

4748
function App () {
4849
const dispatch = useDispatch();
@@ -165,10 +166,10 @@ function App () {
165166
cancel={endSession}
166167
title='MATLAB is currently open in another window'
167168
cancelButton={wasEverActive ? ('Cancel') : ('Continue in existing window')}
168-
confirmButton = {wasEverActive ? ('Confirm') : ('Continue in this window')}>
169+
confirmButton={wasEverActive ? ('Confirm') : ('Continue in this window')}>
169170
{wasEverActive
170171
? 'You have been disconnected because MATLAB is open in another window. Click on Confirm to continue using MATLAB here.'
171-
: <div>MATLAB is open in another window and cannot be opened in a second window or tab at the same time.<br></br>Would you like to continue in this window?</div> }
172+
: <div>MATLAB is open in another window and cannot be opened in a second window or tab at the same time.<br></br>Would you like to continue in this window?</div>}
172173
</Confirmation>
173174
);
174175
}
@@ -204,7 +205,7 @@ function App () {
204205

205206
useEffect(() => {
206207
const queryParams = parseQueryParams(window.location);
207-
const token = queryParams.get('mwi_auth_token');
208+
const token = queryParams.get(MWI_AUTH_TOKEN_NAME_FOR_HTTP);
208209

209210
if (token) {
210211
dispatch(updateAuthStatus(token));

gui/src/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
export const STATUS_REQUEST_INTERVAL_MS = 1000;
55
// Maximum number of consecutive failed requests allowed before triggering a connection error
66
export const MAX_REQUEST_FAIL_COUNT = 60;
7+
export const MWI_AUTH_TOKEN_NAME_FOR_HTTP = 'mwi-auth-token';

matlab_proxy/app_state.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
from typing import Final, Optional
1212

1313
from matlab_proxy import util
14-
from matlab_proxy.settings import (
15-
get_process_startup_timeout,
16-
)
1714
from matlab_proxy.constants import (
1815
CONNECTOR_SECUREPORT_FILENAME,
1916
MATLAB_LOGS_FILE_NAME,
2017
)
18+
from matlab_proxy.settings import (
19+
get_process_startup_timeout,
20+
)
2121
from matlab_proxy.util import mw, mwi, system, windows
2222
from matlab_proxy.util.mwi import environment_variables as mwi_env
2323
from matlab_proxy.util.mwi import token_auth
@@ -28,12 +28,11 @@
2828
LicensingError,
2929
MatlabError,
3030
OnlineLicensingError,
31-
XvfbError,
3231
UIVisibleFatalError,
32+
XvfbError,
3333
log_error,
3434
)
3535

36-
3736
logger = mwi.logger.get()
3837

3938

@@ -314,7 +313,11 @@ def _get_token_auth_headers(self) -> Optional[dict]:
314313
[Dict | None]: Returns token authentication headers if any.
315314
"""
316315
return (
317-
{self.settings["mwi_auth_token_name"]: self.settings["mwi_auth_token_hash"]}
316+
{
317+
self.settings["mwi_auth_token_name_for_http"]: self.settings[
318+
"mwi_auth_token_hash"
319+
]
320+
}
318321
if self.settings["mwi_is_token_auth_enabled"]
319322
else None
320323
)

matlab_proxy/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@
2626

2727
# This constant when set to True restricts the number of active sessions to one
2828
IS_CONCURRENCY_CHECK_ENABLED: Final[bool] = True
29+
MWI_AUTH_TOKEN_NAME_FOR_HTTP = "mwi-auth-token"

matlab_proxy/settings.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import matlab_proxy
1919
from matlab_proxy import constants
20+
from matlab_proxy.constants import MWI_AUTH_TOKEN_NAME_FOR_HTTP
2021
from matlab_proxy.util import mwi, system
2122
from matlab_proxy.util.mwi import environment_variables as mwi_env
2223
from matlab_proxy.util.mwi import token_auth
@@ -197,11 +198,12 @@ def get_dev_settings(config):
197198
"mwi_logs_root_dir": get_mwi_logs_root_dir(dev=True),
198199
"mw_context_tags": get_mw_context_tags(matlab_proxy.get_default_config_name()),
199200
"mwi_server_url": None,
200-
"mwi_is_token_auth_enabled": mwi_auth_token != None,
201+
"mwi_is_token_auth_enabled": mwi_auth_token is not None,
201202
"mwi_auth_status": False,
202203
"mwi_auth_token": mwi_auth_token,
203204
"mwi_auth_token_hash": mwi_auth_token_hash,
204-
"mwi_auth_token_name": mwi_env.get_env_name_mwi_auth_token().lower(),
205+
"mwi_auth_token_name_for_http": MWI_AUTH_TOKEN_NAME_FOR_HTTP,
206+
"mwi_auth_token_name_for_env": mwi_env.get_env_name_mwi_auth_token().lower(),
205207
"mwi_use_existing_license": mwi.validators.validate_use_existing_licensing(
206208
os.getenv(mwi_env.get_env_name_mwi_use_existing_license(), "")
207209
),
@@ -322,11 +324,12 @@ def get_server_settings(config_name):
322324
"mw_context_tags": get_mw_context_tags(config_name),
323325
# The url where the matlab-proxy server is accessible at
324326
"mwi_server_url": None,
325-
"mwi_is_token_auth_enabled": mwi_auth_token != None,
327+
"mwi_is_token_auth_enabled": mwi_auth_token is not None,
326328
"mwi_auth_status": False,
327329
"mwi_auth_token": mwi_auth_token,
328330
"mwi_auth_token_hash": mwi_auth_token_hash,
329-
"mwi_auth_token_name": mwi_env.get_env_name_mwi_auth_token().lower(),
331+
"mwi_auth_token_name_for_http": MWI_AUTH_TOKEN_NAME_FOR_HTTP,
332+
"mwi_auth_token_name_for_env": mwi_env.get_env_name_mwi_auth_token().lower(),
330333
"mwi_use_existing_license": mwi.validators.validate_use_existing_licensing(
331334
os.getenv(mwi_env.get_env_name_mwi_use_existing_license(), "")
332335
),

matlab_proxy/util/mwi/token_auth.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def generate_mwi_auth_token_and_hash():
5959
def get_mwi_auth_token_access_str(app_settings):
6060
"""Returns formatted string with mwi token for use with server URL"""
6161
if app_settings["mwi_is_token_auth_enabled"]:
62-
mwi_auth_token_name = app_settings["mwi_auth_token_name"]
62+
mwi_auth_token_name = app_settings["mwi_auth_token_name_for_http"]
6363
mwi_auth_token = app_settings["mwi_auth_token"]
6464
return f"?{mwi_auth_token_name}={mwi_auth_token}"
6565

@@ -134,7 +134,20 @@ async def _get_token_name(request):
134134
str : token name
135135
"""
136136
app_settings = request.app["settings"]
137-
return app_settings["mwi_auth_token_name"]
137+
return app_settings["mwi_auth_token_name_for_env"]
138+
139+
140+
def _get_token_name_for_http(request):
141+
"""Gets the name of the token from settings.
142+
143+
Args:
144+
request (HTTPRequest) : Used to get to app settings
145+
146+
Returns:
147+
str : token name
148+
"""
149+
app_settings = request.app["settings"]
150+
return app_settings["mwi_auth_token_name_for_http"]
138151

139152

140153
async def _get_token(request):
@@ -238,11 +251,11 @@ async def _is_valid_token_in_url_query(request):
238251
query_string = request.query_string
239252
logger.debug(f"url query parameters found:{query_string}")
240253
if query_string:
241-
token_name = await _get_token_name(request)
254+
token_name = _get_token_name_for_http(request)
242255
parsed_token = parse_qs(request.query_string).get(token_name)
243256
if parsed_token:
244257
parsed_token = parsed_token[0]
245-
logger.debug(f"parsed_token from url query string.")
258+
logger.debug("parsed_token from url query string.")
246259
return await _is_valid_token(parsed_token, request)
247260

248261
logger.debug("Token not found in url query.")
@@ -262,8 +275,9 @@ async def _is_valid_token_in_headers(request):
262275
"""
263276
logger.debug("Checking for token in request headers...")
264277
headers = request.headers
265-
token_name = await _get_token_name(request)
278+
token_name = _get_token_name_for_http(request)
266279
if token_name in headers:
280+
logger.debug(f"Token found in headers: {token_name}")
267281
is_valid_token = await _is_valid_token(headers[token_name], request)
268282
if is_valid_token:
269283
await _store_token_hash_into_session(request)

0 commit comments

Comments
 (0)