Skip to content
Merged
31 changes: 18 additions & 13 deletions docs/developer-guide/integrations/geoserver.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,25 +158,30 @@ The last step is to configure MapStore to use the authkey with the configured in

```javascript
//...
"useAuthenticationRules": true,
"authenticationRules": [{
"urlPattern": ".*geostore.*",
"method": "bearer"
}, {
"requestsConfigurationRules": [
{
"urlPattern": ".*rest/geostore.*",
"headers": {
"Authorization": "Bearer ${securityToken}"
}
},
{
"urlPattern": "\\/geoserver/.*",
"authkeyParamName": "authkey",
"method": "authkey"
}],
"params": {
"authkey": "${securityToken}"
}
}
],
//...
```

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

### Advantages of user integration

Expand Down
99 changes: 74 additions & 25 deletions docs/developer-guide/local-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,30 @@ This is the main structure:
// path to the translation files directory (if different from default)
"translationsPath",
// if true, every ajax and mapping request will be authenticated with the configurations if match a rule (default: true)
"useAuthenticationRules": true
// the authentication rules to match
"authenticationRules": [
{ // every rule has a `urlPattern` regex to match
"urlPattern": ".*geostore.*",
// and a authentication `method` to use (basic, authkey, browserWithCredentials, header)
"method": "basic"
}, {
"urlPattern": "\\/geoserver.*",
"method": "authkey"
}],
// the request configuration rules to match
"requestsConfigurationRules": [
{ // every rule has a `urlPattern` regex to match
"urlPattern": ".*geostore.*",
// headers to add to matching requests
"headers": {
"Authorization": "Bearer ${securityToken}"
}
}, {
"urlPattern": "\\/geoserver/.*",
// parameters to add to matching requests
"params": {
"authkey": "${securityToken}"
}
}, {
"urlPattern": ".*azure-blob.*",
// expiration timestamp (optional, Unix timestamp in seconds)
"expires": 1735689600,
// parameters can be used for SAS tokens
"params": {
"sv": "2024-11-04",
"sig": "${sasToken}"
}
}],
// flag for postponing mapstore 2 load time after theme
"loadAfterTheme": false,
// if defined, WMS layer styles localization will be added
Expand Down Expand Up @@ -150,23 +163,59 @@ For configuring plugins, see the [Configuring Plugins Section](plugins-documenta
- `initialState`: is an object that will initialize the state with some default values and this WILL OVERRIDE the initialState imposed by plugins & reducers.
- `projectionDefs`: is an array of objects that contain definitions for Coordinate Reference Systems
- `gridFiles`: is an object that contains definitions for grid files used in coordinate transformations
- `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.
- `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:
- `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.*
- `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.
- `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.
- `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.
- `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.*

```json
- `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.
- `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.

**Available variable for template substitution (ES6 template syntax `${variable}`):**
- `${securityToken}` - The current MapStore session token (automatically replaced)

**Configuration options:**
- `headers` - Object containing HTTP headers to add to matching requests. Example:

```json
{
"urlPattern": ".*geostore.*",
"method": "header",
"headers": {
"X-Auth-Token": "mytoken"
}
"urlPattern": ".*geostore.*",
"headers": {
"Authorization": "Bearer ${securityToken}"
}
}
```

- `params` - Object containing query parameters to add to matching requests. Example:

```json
{
"urlPattern": "\\/geoserver/.*",
"params": {
"authkey": "${securityToken}"
}
}
```

- `withCredentials` - Boolean to enable sending credentials with requests (useful with proxies):

```json
{
"urlPattern": ".*internal-api.*",
"withCredentials": true
}
```

- `expires` - Optional Unix timestamp (in seconds) for automatic rule expiration. Example:

```json
{
"urlPattern": ".*azure-blob.*",
"expires": 1735689600,
"params": {
"sv": "2024-11-04",
"sig": "token"
}
}
```

!!! note "Backward Compatibility"
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.

### initialState configuration

Expand Down
59 changes: 59 additions & 0 deletions docs/developer-guide/mapstore-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,65 @@ This is a list of things to check if you want to update from a previous version
- Optionally check also accessory files like `.eslinrc`, if you want to keep aligned with lint standards.
- Follow the instructions below, in order, from your version to the one you want to update to.

## Migration from 2025.02.02 to 2026.01.00

### Replace authenticationRules with requestsConfigurationRules

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.

### Configuration Changes

#### Old Configuration (authenticationRules)

```json
{
"useAuthenticationRules": true,
"authenticationRules": [
{
"urlPattern": ".*rest/geostore.*",
"method": "bearer"
},
{
"urlPattern": ".*rest/config.*",
"method": "bearer"
}
]
}
```

#### New Configuration (requestsConfigurationRules)

```json
{
"requestsConfigurationRules": [
{
"urlPattern": ".*rest/geostore.*",
"headers": {
"Authorization": "Bearer ${securityToken}"
}
},
{
"urlPattern": ".*rest/config.*",
"headers": {
"Authorization": "Bearer ${securityToken}"
}
}
]
}
```

**Note**: The `${securityToken}` placeholder is automatically replaced at runtime with the actual security token from the security context

#### Method Mapping

| Old Method | New Configuration |
|------------|------------------|
| `bearer` | `headers: { "Authorization": "Bearer ${securityToken}" }` |
| `authkey` | `params: { "authkey": "${securityToken}" }` |
| `basic` | `headers: { "Authorization": "${authHeader}" }` |
| `header` | `headers: { ... }` |
| `browserWithCredentials` | `withCredentials: true` |

## Migration from 2025.01.01 to 2025.02.00

### Update authenticationRules in localConfig.json
Expand Down
39 changes: 38 additions & 1 deletion web/client/actions/security.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import AuthenticationAPI from '../api/GeoStoreDAO';
import {setCredentials, getToken, getRefreshToken} from '../utils/SecurityUtils';
import {encodeUTF8} from '../utils/EncodeUtils';


export const CHECK_LOGGED_USER = 'CHECK_LOGGED_USER';
export const LOGIN_SUBMIT = 'LOGIN_SUBMIT';
export const LOGIN_PROMPT_CLOSED = "LOGIN:LOGIN_PROMPT_CLOSED";
Expand All @@ -34,6 +33,11 @@ export const SET_CREDENTIALS = 'SECURITY:SET_CREDENTIALS';
export const CLEAR_SECURITY = 'SECURITY:CLEAR_SECURITY';
export const SET_PROTECTED_SERVICES = 'SECURITY:SET_PROTECTED_SERVICES';
export const REFRESH_SECURITY_LAYERS = 'SECURITY:REFRESH_SECURITY_LAYERS';

export const UPDATE_REQUESTS_RULES = 'SECURITY:UPDATE_REQUESTS_RULES';
export const LOAD_REQUESTS_RULES = 'SECURITY:LOAD_REQUESTS_RULES';
export const LOAD_REQUESTS_RULES_ERROR = 'SECURITY:LOAD_REQUESTS_RULES_ERROR';

export function loginSuccess(userDetails, username, password, authProvider) {
return {
type: LOGIN_SUCCESS,
Expand Down Expand Up @@ -229,3 +233,36 @@ export function refreshSecurityLayers() {
type: REFRESH_SECURITY_LAYERS
};
}

/**
* Updates the request configuration rules
* @param {Array} rules - Array of request configuration rules
* @param {boolean} enabled - Whether request configuration is enabled
*/
export const updateRequestsRules = (rules) => {
return {
type: UPDATE_REQUESTS_RULES,
rules
};
};

/**
* Starts loading request configuration rules
*/
export const loadRequestsRules = (rules) => {
return {
type: LOAD_REQUESTS_RULES,
rules
};
};

/**
* Error loading request configuration rules
* @param {Error} error - The error that occurred
*/
export const loadRequestsRulesError = (error) => {
return {
type: LOAD_REQUESTS_RULES_ERROR,
error
};
};
4 changes: 1 addition & 3 deletions web/client/api/ArcGIS.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* LICENSE file in the root directory of this source tree.
*/

import { getAuthorizationBasic } from '../utils/SecurityUtils';
import axios from '../libs/ajax';
import { reprojectBbox } from '../utils/CoordinatesUtils';
import trimEnd from 'lodash/trimEnd';
Expand Down Expand Up @@ -89,14 +88,13 @@ export const searchAndPaginate = (records, params) => {
};
const getData = (url, params = {}) => {
const protectedId = params?.info?.options?.service?.protectedId;
let headers = getAuthorizationBasic(protectedId);
const request = _cache[url]
? () => Promise.resolve(_cache[url])
: () => axios.get(url, {
params: {
f: 'json'
},
headers
_msAuthSourceId: protectedId
}).then(({ data }) => {
_cache[url] = data;
return data;
Expand Down
8 changes: 3 additions & 5 deletions web/client/api/CSW.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { extractCrsFromURN, makeBboxFromOWS, makeNumericEPSG, getExtentFromNorma
import WMS from "../api/WMS";
import { THREE_D_TILES, getCapabilities } from './ThreeDTiles';
import { getDefaultUrl } from '../utils/URLUtils';
import { getAuthorizationBasic } from '../utils/SecurityUtils';

export const parseUrl = (url) => {
const parsed = urlUtil.parse(getDefaultUrl(url), true);
Expand Down Expand Up @@ -513,12 +512,11 @@ const Api = {
getRecords: function(url, startPosition, maxRecords, text, options) {
const body = constructXMLBody(startPosition, maxRecords, text, options);
const protectedId = options?.options?.service?.protectedId;
let headers = getAuthorizationBasic(protectedId);
return axios.post(parseUrl(url), body, {
headers: {
'Content-Type': 'application/xml',
...headers
}
'Content-Type': 'application/xml'
},
_msAuthSourceId: protectedId
}).then((response) => {
const { error, _dcRef, result } = parseCSWResponse(response) || {};
if (result) {
Expand Down
4 changes: 1 addition & 3 deletions web/client/api/TMS.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/
import xml2js from 'xml2js';
import axios from '../libs/ajax';
import { getAuthorizationBasic } from '../utils/SecurityUtils';

/**
* Common requests to TMS services.
Expand All @@ -21,8 +20,7 @@ import { getAuthorizationBasic } from '../utils/SecurityUtils';
*/
export const getTileMap = (url, options) => {
const protectedId = options?.service?.protectedId;
let headers = getAuthorizationBasic(protectedId);
return axios.get(url, {headers})
return axios.get(url, {_msAuthSourceId: protectedId})
.then(response => {
return new Promise((resolve) => {
xml2js.parseString(response.data, { explicitArray: false }, (ignore, result) => resolve(result));
Expand Down
4 changes: 1 addition & 3 deletions web/client/api/ThreeDTiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import axios from '../libs/ajax';
import { convertRadianToDegrees } from '../utils/CoordinatesUtils';
import { METERS_PER_UNIT } from '../utils/MapUtils';
import { logError } from '../utils/DebugUtils';
import { getAuthorizationBasic } from '../utils/SecurityUtils';

// converts the boundingVolume of the root tileset to a valid layer bbox
function tilesetToBoundingBox(Cesium, tileset) {
Expand Down Expand Up @@ -140,8 +139,7 @@ function extractCapabilities(tileset) {
*/
export const getCapabilities = (url, info) => {
const protectedId = info?.options?.service?.protectedId;
let headers = getAuthorizationBasic(protectedId);
return axios.get(url, {headers})
return axios.get(url, {_msAuthSourceId: protectedId})
.then(({ data }) => {
return extractCapabilities(data).then((properties) => ({ tileset: data, ...properties }));
}).catch((e) => {
Expand Down
4 changes: 1 addition & 3 deletions web/client/api/WFS.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {toOGCFilterParts} from '../utils/FilterUtils';
import { getDefaultUrl } from '../utils/URLUtils';
import { castArray } from 'lodash';
import { isValidGetFeatureInfoFormat } from '../utils/WMSUtils';
import { getAuthorizationBasic } from '../utils/SecurityUtils';

const capabilitiesCache = {};

Expand Down Expand Up @@ -140,8 +139,7 @@ export const getCapabilities = function(url, info) {
return Promise.resolve(cached.data);
}
const protectedId = info?.options?.service?.protectedId;
let headers = getAuthorizationBasic(protectedId);
return axios.get(getCapabilitiesURL(url, {headers}))
return axios.get(getCapabilitiesURL(url), {_msAuthSourceId: protectedId})
.then((response) => {
let json;
xml2js.parseString(response.data, { explicitArray: false, stripPrefix: true }, (ignore, result) => {
Expand Down
Loading