Skip to content

Commit 7b1e9b4

Browse files
authored
Fix geosolutions-it#10506 Adding possibility to fetch legends images using Bearer token (geosolutions-it#10507)
1 parent b3c783e commit 7b1e9b4

File tree

3 files changed

+119
-35
lines changed

3 files changed

+119
-35
lines changed
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* Copyright 2024, GeoSolutions Sas.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
import React, { useEffect, useState } from 'react';
10+
import axios from 'axios';
11+
12+
import { getAuthenticationMethod } from '../../utils/SecurityUtils';
13+
14+
15+
const SecureImage = ({
16+
alt,
17+
src,
18+
...props
19+
}) => {
20+
const [imageSrc, setImageSrc] = useState('');
21+
22+
// Function to validate the image once it loads
23+
const validateImg = (imgElement) => {
24+
// Implement your validation logic here
25+
// For example, check image dimensions, aspect ratio, etc.
26+
if (imgElement.naturalWidth === 0 || imgElement.naturalHeight === 0) {
27+
console.error('Image validation failed: Image is not valid.');
28+
}
29+
};
30+
31+
useEffect(() => {
32+
const authMethod = getAuthenticationMethod(src);
33+
34+
if (authMethod === "bearer") {
35+
axios.get(src, {
36+
responseType: 'blob'
37+
})
38+
.then((response) => {
39+
const imageUrl = URL.createObjectURL(response.data);
40+
setImageSrc(imageUrl);
41+
})
42+
.catch((error) => {
43+
console.error('Error fetching image:', error);
44+
});
45+
} else {
46+
setImageSrc(src);
47+
}
48+
49+
// Clean up the URL object when the component unmounts
50+
return () => {
51+
if (imageSrc) {
52+
URL.revokeObjectURL(imageSrc);
53+
}
54+
};
55+
}, [src]);
56+
57+
return (
58+
<img
59+
alt={alt}
60+
onError={props.onImgError}
61+
onLoad={(e) => validateImg(e.target)}
62+
src={imageSrc}
63+
style={props.style}
64+
{...props}
65+
/>
66+
);
67+
};
68+
69+
export default SecureImage;

web/client/plugins/TOC/components/Legend.jsx

+31-19
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ import PropTypes from 'prop-types';
1414
import React from 'react';
1515

1616
import {
17-
addAuthenticationParameter,
1817
addAuthenticationToSLD,
1918
clearNilValuesForParams
2019
} from '../../../utils/SecurityUtils';
2120
import Message from '../../../components/I18N/Message';
21+
import SecureImage from '../../../components/misc/SecureImage';
22+
2223
import { randomInt } from '../../../utils/RandomUtils';
2324

2425
/**
@@ -85,23 +86,26 @@ class Legend extends React.Component {
8586

8687
const cleanParams = clearNilValuesForParams(layer.params);
8788
const scale = this.getScale(props);
88-
let query = assign({}, {
89-
service: "WMS",
90-
request: "GetLegendGraphic",
91-
format: "image/png",
92-
height: props.legendHeight,
93-
width: props.legendWidth,
94-
layer: layer.name,
95-
style: layer.style || null,
96-
version: layer.version || "1.3.0",
97-
SLD_VERSION: "1.1.0",
98-
LEGEND_OPTIONS: props.legendOptions
99-
}, layer.legendParams || {},
100-
props.language && layer.localizedLayerStyles ? {LANGUAGE: props.language} : {},
101-
addAuthenticationToSLD(cleanParams || {}, props.layer),
102-
cleanParams && cleanParams.SLD_BODY ? {SLD_BODY: cleanParams.SLD_BODY} : {},
103-
scale !== null ? { SCALE: scale } : {});
104-
addAuthenticationParameter(url, query);
89+
let query = assign(
90+
{},
91+
{
92+
service: "WMS",
93+
request: "GetLegendGraphic",
94+
format: "image/png",
95+
height: props.legendHeight,
96+
width: props.legendWidth,
97+
layer: layer.name,
98+
style: layer.style || null,
99+
version: layer.version || "1.3.0",
100+
SLD_VERSION: "1.1.0",
101+
LEGEND_OPTIONS: props.legendOptions
102+
},
103+
layer.legendParams || {},
104+
props.language && layer.localizedLayerStyles ? {LANGUAGE: props.language} : {},
105+
addAuthenticationToSLD(cleanParams || {}, props.layer),
106+
cleanParams && cleanParams.SLD_BODY ? {SLD_BODY: cleanParams.SLD_BODY} : {},
107+
scale !== null ? { SCALE: scale } : {}
108+
);
105109

106110
return urlUtil.format({
107111
host: urlObj.host,
@@ -114,7 +118,15 @@ class Legend extends React.Component {
114118
}
115119
render() {
116120
if (!this.state.error && this.props.layer && this.props.layer.type === "wms" && this.props.layer.url) {
117-
return <img onError={this.onImgError} onLoad={(e) => this.validateImg(e.target)} src={this.getUrl(this.props)} style={this.props.style}/>;
121+
const url = this.getUrl(this.props);
122+
return (
123+
<SecureImage
124+
onError={this.onImgError}
125+
onLoad={(e) => this.validateImg(e.target)}
126+
src={url}
127+
style={this.props.style}
128+
/>
129+
);
118130
}
119131
return <Message msgId="layerProperties.legenderror" />;
120132
}

web/client/plugins/TOC/components/__tests__/Legend-test.jsx

+19-16
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ import React from 'react';
1111
import ReactDOM from 'react-dom';
1212
import Rx from 'rxjs';
1313
import url from 'url';
14+
import * as TestUtils from 'react-dom/test-utils';
1415

1516
import Legend from '../Legend';
1617

17-
import * as TestUtils from 'react-dom/test-utils';
18-
1918
describe("test the Layer legend", () => {
2019
beforeEach((done) => {
2120
document.body.innerHTML = '<div id="container"></div>';
@@ -176,13 +175,15 @@ describe("test the Layer legend", () => {
176175
"name": "layer3",
177176
"format": "image/png"
178177
};
179-
ReactDOM.render(
180-
<Legend
181-
layer={layer}
182-
currentZoomLvl={2.3456}
183-
scales={[10000, 5000, 2000, 1000]}
184-
/>,
185-
document.getElementById("container"));
178+
TestUtils.act(() => {
179+
ReactDOM.render(
180+
<Legend
181+
layer={layer}
182+
currentZoomLvl={2.3456}
183+
scales={[10000, 5000, 2000, 1000]}
184+
/>,
185+
document.getElementById("container"));
186+
});
186187
const legendImage = document.querySelector("img");
187188
expect(legendImage).toBeTruthy();
188189
const { query } = url.parse(legendImage.getAttribute('src'), true);
@@ -197,13 +198,15 @@ describe("test the Layer legend", () => {
197198
"name": "layer3",
198199
"format": "image/png"
199200
};
200-
ReactDOM.render(
201-
<Legend
202-
layer={layer}
203-
currentZoomLvl={10}
204-
scales={[10000, 5000, 2000, 1000]}
205-
/>,
206-
document.getElementById("container"));
201+
TestUtils.act(() => {
202+
ReactDOM.render(
203+
<Legend
204+
layer={layer}
205+
currentZoomLvl={10}
206+
scales={[10000, 5000, 2000, 1000]}
207+
/>,
208+
document.getElementById("container"));
209+
});
207210
const legendImage = document.querySelector("img");
208211
expect(legendImage).toBeTruthy();
209212
const { query } = url.parse(legendImage.getAttribute('src'), true);

0 commit comments

Comments
 (0)