Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GEOS-11369] Additional authentication options for cascaded WMS|WMTS data stores #7552

Merged
merged 8 commits into from
Apr 30, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ src/release/installer/win/target/
# spotless up to date checks
.spotless-index

# Eclipse stuff
src/web/app/.temp-Start*
Binary file modified doc/en/user/source/data/cascaded/images/wmsconfigure.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/en/user/source/data/cascaded/images/wmtsconfigure.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions doc/en/user/source/data/cascaded/wms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ To connect to an external WMS, it is necessary to load it as a new store. To st
- If the WMS requires authentication, the user name to connect as.
* - :guilabel:`Password`
- If the WMS requires authentication, the password to connect with.
* - :guilabel:`HTTP header name`
- If the WMS requires a custom HTTP header, the header name.
* - :guilabel:`HTTP header value`
- If the WMS requires a custom HTTP header, the header value.
* - :guilabel:`AuthKey/API key`
- If the WMS requires an Authentication key in the querystring, provide a key=value pair.
* - :guilabel:`Max concurrent connections`
- The maximum number of persistent connections to keep for this WMS.

Expand Down
2 changes: 2 additions & 0 deletions doc/en/user/source/data/cascaded/wmts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ To connect to an external WMTS, it is necessary to load it as a new store. To s
- If the WMTS requires a custom HTTP header, the header name.
* - :guilabel:`HTTP header value`
- If the WMTS requires a custom HTTP header, the header value.
* - :guilabel:`AuthKey/API key`
- If the WMTS requires an Authentication key in the querystring, provide a key=value pair.
* - :guilabel:`Max concurrent connections`
- The maximum number of persistent connections to keep for this WMTS.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public interface HTTPStoreInfo extends StoreInfo {

void setPassword(String password);

String getAuthKey();

void setAuthKey(String authKey);

/**
* @return Upper limit on the number of http connections the store should hold in the pool if
* {@link #isUseConnectionPooling()} is {@code true}.
Expand Down
28 changes: 23 additions & 5 deletions src/main/src/main/java/org/geoserver/catalog/ResourcePool.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
public class ResourcePool {

/**
* OGC "cilyndrical earth" model, we'll use it to translate meters to degrees (yes, it's ugly)
* OGC "cylindrical earth" model, we'll use it to translate meters to degrees (yes, it's ugly)
*/
static final double OGC_DEGREE_TO_METERS = 6378137.0 * 2.0 * Math.PI / 360;

Expand Down Expand Up @@ -1970,16 +1970,27 @@ private WebMapServer createWebMapServer(
WMSStoreInfo expandedStore, EntityResolver entityResolver)
throws IOException, org.geotools.ows.ServiceException {
HTTPClient client = getHTTPClient(expandedStore);
String capabilitiesURL = expandedStore.getCapabilitiesURL();
URL serverURL = new URL(capabilitiesURL);
URL serverURL = new URL(expandedStore.getCapabilitiesURL());
Map<String, Object> hints = new HashMap<>();
hints.put(DocumentHandler.DEFAULT_NAMESPACE_HINT_KEY, WMSSchema.getInstance());
hints.put(DocumentFactory.VALIDATION_HINT, Boolean.FALSE);
if (entityResolver != null) {
hints.put(XMLHandlerHints.ENTITY_RESOLVER, entityResolver);
}

return new WebMapServer(serverURL, client, hints);
WebMapServer wms;
if (StringUtils.isNotEmpty(expandedStore.getHeaderName())
&& StringUtils.isNotEmpty(expandedStore.getHeaderValue())) {
wms =
new WebMapServer(
serverURL,
client,
hints,
Collections.singletonMap(
expandedStore.getHeaderName(), expandedStore.getHeaderValue()));
} else {
wms = new WebMapServer(serverURL, client, hints);
}
return wms;
}

/**
Expand Down Expand Up @@ -2084,10 +2095,17 @@ private HTTPClient getHTTPClient(HTTPStoreInfo info) {
}
String username = info.getUsername();
String password = info.getPassword();
String authKey = info.getAuthKey();
int connectTimeout = info.getConnectTimeout();
int readTimeout = info.getReadTimeout();
client.setUser(username);
client.setPassword(password);
if (authKey != null) {
String[] kv = authKey.split("=");
if (kv.length == 2) {
client.setExtraParams(Map.of(kv[0], kv[1]));
}
}
client.setConnectTimeout(connectTimeout);
client.setReadTimeout(readTimeout);

Expand Down
12 changes: 12 additions & 0 deletions src/main/src/main/java/org/geoserver/catalog/WMSStoreInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,16 @@ public interface WMSStoreInfo extends HTTPStoreInfo {
* @throws IOException Any I/O problems.
*/
WebMapServer getWebMapServer(ProgressListener listener) throws IOException;

String getHeaderName();
petersmythe marked this conversation as resolved.
Show resolved Hide resolved

void setHeaderName(String headerName);

String getHeaderValue();

void setHeaderValue(String headerValue);

String getAuthKey();

void setAuthKey(String authKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ public interface WMTSStoreInfo extends HTTPStoreInfo {
String getHeaderValue();

void setHeaderValue(String headerValue);

String getAuthKey();

void setAuthKey(String authKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public class WMSStoreInfoImpl extends StoreInfoImpl implements WMSStoreInfo {
String capabilitiesURL;
private String user;
private String password;
private String headerName;
private String headerValue;
private String authKey;
private int maxConnections;
private int readTimeout;
private int connectTimeout;
Expand Down Expand Up @@ -94,6 +97,36 @@ public void setConnectTimeout(int timeoutSeconds) {
this.connectTimeout = timeoutSeconds;
}

@Override
public String getHeaderName() {
return headerName;
}

@Override
public void setHeaderName(String headerName) {
this.headerName = headerName;
}

@Override
public String getHeaderValue() {
return headerValue;
}

@Override
public void setHeaderValue(String headerValue) {
this.headerValue = headerValue;
}

@Override
public String getAuthKey() {
return authKey;
}

@Override
public void setAuthKey(String authKey) {
this.authKey = authKey;
}

@Override
public void accept(CatalogVisitor visitor) {
visitor.visit(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class WMTSStoreInfoImpl extends StoreInfoImpl implements WMTSStoreInfo {
// Map<String, String> headers;
private String headerName; // todo: replace with Map<String, String>
private String headerValue; // todo: replace with Map<String, String>
petersmythe marked this conversation as resolved.
Show resolved Hide resolved
private String authKey;

protected WMTSStoreInfoImpl() {}

Expand Down Expand Up @@ -118,6 +119,16 @@ public void setHeaderValue(String headerValue) {
this.headerValue = headerValue;
}

@Override
public String getAuthKey() {
return authKey;
}

@Override
public void setAuthKey(String authKey) {
this.authKey = authKey;
}

@Override
public void accept(CatalogVisitor visitor) {
visitor.visit(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,36 @@ public void setPassword(String password) {
delegate.setPassword(password);
}

@Override
public String getHeaderName() {
return delegate.getHeaderName();
}

@Override
public void setHeaderName(String headerName) {
delegate.setHeaderName(headerName);
}

@Override
public String getHeaderValue() {
return delegate.getHeaderValue();
}

@Override
public void setHeaderValue(String headerValue) {
delegate.setHeaderValue(headerValue);
}

@Override
public String getAuthKey() {
return delegate.getAuthKey();
}

@Override
public void setAuthKey(String authKey) {
delegate.setAuthKey(authKey);
}

@Override
public int getMaxConnections() {
return delegate.getMaxConnections();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ public void setHeaderValue(String headerValue) {
delegate.setHeaderValue(headerValue);
}

@Override
public String getAuthKey() {
return delegate.getAuthKey();
}

@Override
public void setAuthKey(String authKey) {
delegate.setAuthKey(authKey);
}

@Override
public Date getDateModified() {
return delegate.getDateModified();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1449,7 +1449,7 @@ public void testWmtsCascadeAutoDisable() throws Exception {
}

@Test
public void testCovergaeStoreInfoAutodisable() throws Exception {
public void testCoverageStoreInfoAutodisable() throws Exception {
GeoServerExtensions.extensions(ResourcePoolInitializer.class)
.get(0)
.initialize(getGeoServer());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*/
package org.geoserver.test.http;

import java.util.Collections;
import java.util.Map;
import org.geotools.http.HTTPClient;

/**
Expand All @@ -18,6 +20,8 @@ public abstract class AbstractHttpClient implements HTTPClient {

protected String password;

protected Map<String, String> extraParams = Collections.emptyMap();

protected int connectTimeout;

protected int readTimeout;
Expand All @@ -44,6 +48,16 @@ public void setPassword(String password) {
this.password = password;
}

@Override
public Map<String, String> getExtraParams() {
return this.extraParams;
}

@Override
public void setExtraParams(Map<String, String> extraParams) {
this.extraParams = extraParams;
}

@Override
public int getConnectTimeout() {
return connectTimeout;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,12 @@ public String toString() {
}
}
}

@Override
public Map<String, String> getExtraParams() {
return null;
}

@Override
public void setExtraParams(Map<String, String> extraParams) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
<div wicket:id="capabilitiesURL"></div>
<div wicket:id="userNamePanel"></div>
<div wicket:id="passwordPanel"></div>
<div wicket:id="headerNamePanel"></div>
<div wicket:id="headerValuePanel"></div>
<div wicket:id="authKeyPanel"></div>
<div wicket:id="useConnectionPoolingPanel"></div>
<div wicket:id="maxConnectionsPanel"></div>
<div wicket:id="connectTimeoutPanel"></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ abstract class AbstractWMSStorePage extends GeoServerSecuredPage {

protected PasswordParamPanel password;

protected TextParamPanel<String> headerNamePanel;
protected TextParamPanel<String> headerValuePanel;
protected TextParamPanel<String> authKeyPanel;

void initUI(final WMSStoreInfo store) {
IModel<WMSStoreInfo> model = new Model<>(store);

Expand Down Expand Up @@ -124,6 +128,30 @@ void initUI(final WMSStoreInfo store) {
new ResourceModel("AbstractWMSStorePage.password"),
false));

headerNamePanel =
new TextParamPanel<>(
"headerNamePanel",
new PropertyModel<>(model, "headerName"),
new ResourceModel("AbstractWMSStorePage.headerName"),
false);
form.add(headerNamePanel);

headerValuePanel =
new TextParamPanel<>(
"headerValuePanel",
new PropertyModel<>(model, "headerValue"),
new ResourceModel("AbstractWMSStorePage.headerValue"),
false);
form.add(headerValuePanel);

authKeyPanel =
new TextParamPanel<>(
"authKeyPanel",
new PropertyModel<>(model, "authKey"),
new ResourceModel("AbstractWMSStorePage.authKey"),
false);
form.add(authKeyPanel);

// max concurrent connections
final PropertyModel<Boolean> useHttpConnectionPoolModel =
new PropertyModel<>(model, "useConnectionPooling");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<div wicket:id="passwordPanel"></div>
<div wicket:id="headerNamePanel"></div>
<div wicket:id="headerValuePanel"></div>
<div wicket:id="authKeyPanel"></div>
<div wicket:id="useConnectionPoolingPanel"></div>
<div wicket:id="maxConnectionsPanel"></div>
<div wicket:id="connectTimeoutPanel"></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ abstract class AbstractWMTSStorePage extends GeoServerSecuredPage {

protected TextParamPanel<String> headerNamePanel;
protected TextParamPanel<String> headerValuePanel;
protected TextParamPanel<String> authKeyPanel;

void initUI(final WMTSStoreInfo store) {
IModel<WMTSStoreInfo> model = new Model<>(store);
Expand Down Expand Up @@ -142,6 +143,14 @@ void initUI(final WMTSStoreInfo store) {
false);
form.add(headerValuePanel);

authKeyPanel =
new TextParamPanel<>(
"authKeyPanel",
new PropertyModel<>(model, "authKey"),
new ResourceModel("AbstractWMSStorePage.authKey"),
false);
form.add(authKeyPanel);

// max concurrent connections
final PropertyModel<Boolean> useHttpConnectionPoolModel =
new PropertyModel<>(model, "useConnectionPooling");
Expand Down