Skip to content

Commit d3d6541

Browse files
#11644: Implement dynamic request configurations (#11648)
--------- Co-authored-by: allyoucanmap <stefano.bovio@geosolutionsgroup.com>
1 parent a3568c8 commit d3d6541

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1331
-394
lines changed

docs/developer-guide/integrations/geoserver.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -158,25 +158,30 @@ The last step is to configure MapStore to use the authkey with the configured in
158158

159159
```javascript
160160
//...
161-
"useAuthenticationRules": true,
162-
"authenticationRules": [{
163-
"urlPattern": ".*geostore.*",
164-
"method": "bearer"
165-
}, {
161+
"requestsConfigurationRules": [
162+
{
163+
"urlPattern": ".*rest/geostore.*",
164+
"headers": {
165+
"Authorization": "Bearer ${securityToken}"
166+
}
167+
},
168+
{
166169
"urlPattern": "\\/geoserver/.*",
167-
"authkeyParamName": "authkey",
168-
"method": "authkey"
169-
}],
170+
"params": {
171+
"authkey": "${securityToken}"
172+
}
173+
}
174+
],
170175
//...
171176
```
172177

173-
- Verify that "useAuthenticationRules" is set to `true`
174-
- `authenticationRules` array should contain 2 rules:
175-
- The first rule should already be present, and defines the authentication method used internally in mapstore
178+
- Note: The new `requestsConfigurationRules` system is always active when rules are present, no flag needed
179+
- `requestsConfigurationRules` array should contain 2 rules:
180+
- The first rule should already be present, and defines the authentication method used internally in mapstore (Bearer token)
176181
- The second rule (the one you need to add) should be added and defines how to authenticate to GeoServer:
177182
- `urlPattern`: is a regular expression that identifies the request url where to apply the rule
178-
- `method`: set it to `authkey` to use the authentication filter you just created in Geoserver.
179-
- `authkeyParamName`: is the name of the authkey parameter defined in GeoServer (set to `authkey` by default)
183+
- `params`: use query parameters for authkey authentication
184+
- `authkey`: the name of the parameter (must match the one in GeoServer configuration, default is `authkey`)
180185

181186
### Advantages of user integration
182187

docs/developer-guide/local-config.md

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,30 @@ This is the main structure:
4545
// path to the translation files directory (if different from default)
4646
"translationsPath",
4747
// if true, every ajax and mapping request will be authenticated with the configurations if match a rule (default: true)
48-
"useAuthenticationRules": true
49-
// the authentication rules to match
50-
"authenticationRules": [
51-
{ // every rule has a `urlPattern` regex to match
52-
"urlPattern": ".*geostore.*",
53-
// and a authentication `method` to use (basic, authkey, browserWithCredentials, header)
54-
"method": "basic"
55-
}, {
56-
"urlPattern": "\\/geoserver.*",
57-
"method": "authkey"
58-
}],
48+
// the request configuration rules to match
49+
"requestsConfigurationRules": [
50+
{ // every rule has a `urlPattern` regex to match
51+
"urlPattern": ".*geostore.*",
52+
// headers to add to matching requests
53+
"headers": {
54+
"Authorization": "Bearer ${securityToken}"
55+
}
56+
}, {
57+
"urlPattern": "\\/geoserver/.*",
58+
// parameters to add to matching requests
59+
"params": {
60+
"authkey": "${securityToken}"
61+
}
62+
}, {
63+
"urlPattern": ".*azure-blob.*",
64+
// expiration timestamp (optional, Unix timestamp in seconds)
65+
"expires": 1735689600,
66+
// parameters can be used for SAS tokens
67+
"params": {
68+
"sv": "2024-11-04",
69+
"sig": "${sasToken}"
70+
}
71+
}],
5972
// flag for postponing mapstore 2 load time after theme
6073
"loadAfterTheme": false,
6174
// if defined, WMS layer styles localization will be added
@@ -150,23 +163,59 @@ For configuring plugins, see the [Configuring Plugins Section](plugins-documenta
150163
- `initialState`: is an object that will initialize the state with some default values and this WILL OVERRIDE the initialState imposed by plugins & reducers.
151164
- `projectionDefs`: is an array of objects that contain definitions for Coordinate Reference Systems
152165
- `gridFiles`: is an object that contains definitions for grid files used in coordinate transformations
153-
- `useAuthenticationRules`: if this flag is set to true, the `authenticationRules` will be used to authenticate every ajax and mapping request. If the flag is set to false, the `authenticationRules` will be ignored.
154-
- `authenticationRules`: is an array of objects that contain rules to match for authentication. Each rule has a `urlPattern` regex to match and a `method` to use (`basic`, `authkey`, `header`, `browserWithCredentials`). If the URL of a request matches the `urlPattern` of a rule, the `method` will be used to authenticate the request. The `method` can be:
155-
- `basic` will use the basic authentication method getting the credentials from the user that logged in (adding the header `Authorization` `Basic <base64(username:password)>` to the request). ***Note**: this method is not implemented for image tile requests (e.g. layers) but only for ajax requests.*
156-
- `authkey` will use the authkey method getting the credentials from the user that logged in. The token of the current MapStore session will be used as the authkey value, so this works only with the geoserver integration.
157-
- `bearer` will use the header `Authorization` `Bearer <token>` getting the credentials from the user that logged in. The token of the current MapStore session will be used as the bearer value, so this works only with the geoserver integration.
158-
- `header` will use the header method getting the credentials from the user that logged in. You can add an `headers` object containing the static headers to this rule to specify witch headers to use. e.g.
159-
- `browserWithCredentials` will add the `withCredentials` parameter to ajax requests, so the browser will send the cookies and the authentication headers to the server. This method is useful when you have a proxy that needs to authenticate the user. ***Note**: this method is not implemented for image tile requests (e.g. layers) but only for ajax requests.*
160-
161-
```json
166+
- `useAuthenticationRules` (deprecated): if this flag is set to true, legacy `authenticationRules` will be used. The new `requestsConfigurationRules` system does not require this flag and is always active when rules are present.
167+
- `requestsConfigurationRules`: is an array of objects that contain rules to match for request configuration. Each rule has a `urlPattern` regex to match and either `headers`, `params`, or `withCredentials` configuration. If the URL of a request matches the `urlPattern` of a rule, the configuration will be applied to the request.
168+
169+
**Available variable for template substitution (ES6 template syntax `${variable}`):**
170+
- `${securityToken}` - The current MapStore session token (automatically replaced)
171+
172+
**Configuration options:**
173+
- `headers` - Object containing HTTP headers to add to matching requests. Example:
174+
175+
```json
162176
{
163-
"urlPattern": ".*geostore.*",
164-
"method": "header",
165-
"headers": {
166-
"X-Auth-Token": "mytoken"
167-
}
177+
"urlPattern": ".*geostore.*",
178+
"headers": {
179+
"Authorization": "Bearer ${securityToken}"
180+
}
168181
}
169182
```
183+
184+
- `params` - Object containing query parameters to add to matching requests. Example:
185+
186+
```json
187+
{
188+
"urlPattern": "\\/geoserver/.*",
189+
"params": {
190+
"authkey": "${securityToken}"
191+
}
192+
}
193+
```
194+
195+
- `withCredentials` - Boolean to enable sending credentials with requests (useful with proxies):
196+
197+
```json
198+
{
199+
"urlPattern": ".*internal-api.*",
200+
"withCredentials": true
201+
}
202+
```
203+
204+
- `expires` - Optional Unix timestamp (in seconds) for automatic rule expiration. Example:
205+
206+
```json
207+
{
208+
"urlPattern": ".*azure-blob.*",
209+
"expires": 1735689600,
210+
"params": {
211+
"sv": "2024-11-04",
212+
"sig": "token"
213+
}
214+
}
215+
```
216+
217+
!!! note "Backward Compatibility"
218+
The old `useAuthenticationRules` and `authenticationRules` configuration still works and will be automatically converted to the new format. However, the new format is recommended for better flexibility and features like expiration support.
170219

171220
### initialState configuration
172221

docs/developer-guide/mapstore-migration-guide.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,65 @@ This is a list of things to check if you want to update from a previous version
2020
- Optionally check also accessory files like `.eslinrc`, if you want to keep aligned with lint standards.
2121
- Follow the instructions below, in order, from your version to the one you want to update to.
2222

23+
## Migration from 2025.02.02 to 2026.01.00
24+
25+
### Replace authenticationRules with requestsConfigurationRules
26+
27+
As part of improving the authentication rules to make dynamic request configurations, we have deprecated the use of `authenticationRules` in favor of the new request rule configuration `requestsConfigurationRules`. The new system provides a more flexible way to configure request authentication and parameters.
28+
29+
### Configuration Changes
30+
31+
#### Old Configuration (authenticationRules)
32+
33+
```json
34+
{
35+
"useAuthenticationRules": true,
36+
"authenticationRules": [
37+
{
38+
"urlPattern": ".*rest/geostore.*",
39+
"method": "bearer"
40+
},
41+
{
42+
"urlPattern": ".*rest/config.*",
43+
"method": "bearer"
44+
}
45+
]
46+
}
47+
```
48+
49+
#### New Configuration (requestsConfigurationRules)
50+
51+
```json
52+
{
53+
"requestsConfigurationRules": [
54+
{
55+
"urlPattern": ".*rest/geostore.*",
56+
"headers": {
57+
"Authorization": "Bearer ${securityToken}"
58+
}
59+
},
60+
{
61+
"urlPattern": ".*rest/config.*",
62+
"headers": {
63+
"Authorization": "Bearer ${securityToken}"
64+
}
65+
}
66+
]
67+
}
68+
```
69+
70+
**Note**: The `${securityToken}` placeholder is automatically replaced at runtime with the actual security token from the security context
71+
72+
#### Method Mapping
73+
74+
| Old Method | New Configuration |
75+
|------------|------------------|
76+
| `bearer` | `headers: { "Authorization": "Bearer ${securityToken}" }` |
77+
| `authkey` | `params: { "authkey": "${securityToken}" }` |
78+
| `basic` | `headers: { "Authorization": "${authHeader}" }` |
79+
| `header` | `headers: { ... }` |
80+
| `browserWithCredentials` | `withCredentials: true` |
81+
2382
## Migration from 2025.01.01 to 2025.02.00
2483

2584
### Update authenticationRules in localConfig.json

web/client/actions/security.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import AuthenticationAPI from '../api/GeoStoreDAO';
1414
import {setCredentials, getToken, getRefreshToken} from '../utils/SecurityUtils';
1515
import {encodeUTF8} from '../utils/EncodeUtils';
1616

17-
1817
export const CHECK_LOGGED_USER = 'CHECK_LOGGED_USER';
1918
export const LOGIN_SUBMIT = 'LOGIN_SUBMIT';
2019
export const LOGIN_PROMPT_CLOSED = "LOGIN:LOGIN_PROMPT_CLOSED";
@@ -34,6 +33,11 @@ export const SET_CREDENTIALS = 'SECURITY:SET_CREDENTIALS';
3433
export const CLEAR_SECURITY = 'SECURITY:CLEAR_SECURITY';
3534
export const SET_PROTECTED_SERVICES = 'SECURITY:SET_PROTECTED_SERVICES';
3635
export const REFRESH_SECURITY_LAYERS = 'SECURITY:REFRESH_SECURITY_LAYERS';
36+
37+
export const UPDATE_REQUESTS_RULES = 'SECURITY:UPDATE_REQUESTS_RULES';
38+
export const LOAD_REQUESTS_RULES = 'SECURITY:LOAD_REQUESTS_RULES';
39+
export const LOAD_REQUESTS_RULES_ERROR = 'SECURITY:LOAD_REQUESTS_RULES_ERROR';
40+
3741
export function loginSuccess(userDetails, username, password, authProvider) {
3842
return {
3943
type: LOGIN_SUCCESS,
@@ -229,3 +233,36 @@ export function refreshSecurityLayers() {
229233
type: REFRESH_SECURITY_LAYERS
230234
};
231235
}
236+
237+
/**
238+
* Updates the request configuration rules
239+
* @param {Array} rules - Array of request configuration rules
240+
* @param {boolean} enabled - Whether request configuration is enabled
241+
*/
242+
export const updateRequestsRules = (rules) => {
243+
return {
244+
type: UPDATE_REQUESTS_RULES,
245+
rules
246+
};
247+
};
248+
249+
/**
250+
* Starts loading request configuration rules
251+
*/
252+
export const loadRequestsRules = (rules) => {
253+
return {
254+
type: LOAD_REQUESTS_RULES,
255+
rules
256+
};
257+
};
258+
259+
/**
260+
* Error loading request configuration rules
261+
* @param {Error} error - The error that occurred
262+
*/
263+
export const loadRequestsRulesError = (error) => {
264+
return {
265+
type: LOAD_REQUESTS_RULES_ERROR,
266+
error
267+
};
268+
};

web/client/api/ArcGIS.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
import { getAuthorizationBasic } from '../utils/SecurityUtils';
109
import axios from '../libs/ajax';
1110
import { reprojectBbox } from '../utils/CoordinatesUtils';
1211
import trimEnd from 'lodash/trimEnd';
@@ -89,14 +88,13 @@ export const searchAndPaginate = (records, params) => {
8988
};
9089
const getData = (url, params = {}) => {
9190
const protectedId = params?.info?.options?.service?.protectedId;
92-
let headers = getAuthorizationBasic(protectedId);
9391
const request = _cache[url]
9492
? () => Promise.resolve(_cache[url])
9593
: () => axios.get(url, {
9694
params: {
9795
f: 'json'
9896
},
99-
headers
97+
_msAuthSourceId: protectedId
10098
}).then(({ data }) => {
10199
_cache[url] = data;
102100
return data;

web/client/api/CSW.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import { extractCrsFromURN, makeBboxFromOWS, makeNumericEPSG, getExtentFromNorma
1616
import WMS from "../api/WMS";
1717
import { THREE_D_TILES, getCapabilities } from './ThreeDTiles';
1818
import { getDefaultUrl } from '../utils/URLUtils';
19-
import { getAuthorizationBasic } from '../utils/SecurityUtils';
2019

2120
export const parseUrl = (url) => {
2221
const parsed = urlUtil.parse(getDefaultUrl(url), true);
@@ -513,12 +512,11 @@ const Api = {
513512
getRecords: function(url, startPosition, maxRecords, text, options) {
514513
const body = constructXMLBody(startPosition, maxRecords, text, options);
515514
const protectedId = options?.options?.service?.protectedId;
516-
let headers = getAuthorizationBasic(protectedId);
517515
return axios.post(parseUrl(url), body, {
518516
headers: {
519-
'Content-Type': 'application/xml',
520-
...headers
521-
}
517+
'Content-Type': 'application/xml'
518+
},
519+
_msAuthSourceId: protectedId
522520
}).then((response) => {
523521
const { error, _dcRef, result } = parseCSWResponse(response) || {};
524522
if (result) {

web/client/api/TMS.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
*/
88
import xml2js from 'xml2js';
99
import axios from '../libs/ajax';
10-
import { getAuthorizationBasic } from '../utils/SecurityUtils';
1110

1211
/**
1312
* Common requests to TMS services.
@@ -21,8 +20,7 @@ import { getAuthorizationBasic } from '../utils/SecurityUtils';
2120
*/
2221
export const getTileMap = (url, options) => {
2322
const protectedId = options?.service?.protectedId;
24-
let headers = getAuthorizationBasic(protectedId);
25-
return axios.get(url, {headers})
23+
return axios.get(url, {_msAuthSourceId: protectedId})
2624
.then(response => {
2725
return new Promise((resolve) => {
2826
xml2js.parseString(response.data, { explicitArray: false }, (ignore, result) => resolve(result));

web/client/api/ThreeDTiles.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import axios from '../libs/ajax';
1010
import { convertRadianToDegrees } from '../utils/CoordinatesUtils';
1111
import { METERS_PER_UNIT } from '../utils/MapUtils';
1212
import { logError } from '../utils/DebugUtils';
13-
import { getAuthorizationBasic } from '../utils/SecurityUtils';
1413

1514
// converts the boundingVolume of the root tileset to a valid layer bbox
1615
function tilesetToBoundingBox(Cesium, tileset) {
@@ -140,8 +139,7 @@ function extractCapabilities(tileset) {
140139
*/
141140
export const getCapabilities = (url, info) => {
142141
const protectedId = info?.options?.service?.protectedId;
143-
let headers = getAuthorizationBasic(protectedId);
144-
return axios.get(url, {headers})
142+
return axios.get(url, {_msAuthSourceId: protectedId})
145143
.then(({ data }) => {
146144
return extractCapabilities(data).then((properties) => ({ tileset: data, ...properties }));
147145
}).catch((e) => {

web/client/api/WFS.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {toOGCFilterParts} from '../utils/FilterUtils';
1414
import { getDefaultUrl } from '../utils/URLUtils';
1515
import { castArray } from 'lodash';
1616
import { isValidGetFeatureInfoFormat } from '../utils/WMSUtils';
17-
import { getAuthorizationBasic } from '../utils/SecurityUtils';
1817

1918
const capabilitiesCache = {};
2019

@@ -140,8 +139,7 @@ export const getCapabilities = function(url, info) {
140139
return Promise.resolve(cached.data);
141140
}
142141
const protectedId = info?.options?.service?.protectedId;
143-
let headers = getAuthorizationBasic(protectedId);
144-
return axios.get(getCapabilitiesURL(url, {headers}))
142+
return axios.get(getCapabilitiesURL(url), {_msAuthSourceId: protectedId})
145143
.then((response) => {
146144
let json;
147145
xml2js.parseString(response.data, { explicitArray: false, stripPrefix: true }, (ignore, result) => {

0 commit comments

Comments
 (0)