Skip to content

Commit f66291d

Browse files
address review comments
1 parent 8696a66 commit f66291d

File tree

7 files changed

+139
-62
lines changed

7 files changed

+139
-62
lines changed

.idea/inspectionProfiles/Project_Default.xml

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/jwt/JwtRealmSettings.java

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
1717
import org.elasticsearch.xpack.core.security.authc.support.ClaimSetting;
1818
import org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings;
19+
import org.elasticsearch.xpack.core.security.authc.support.SecuritySettingsUtil;
1920
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
2021

2122
import java.util.Collection;
@@ -30,6 +31,7 @@
3031
import java.util.stream.Stream;
3132

3233
import static org.elasticsearch.xpack.core.security.authc.support.SecuritySettingsUtil.verifyNonNullNotEmpty;
34+
import static org.elasticsearch.xpack.core.security.authc.support.SecuritySettingsUtil.verifyProxySettings;
3335

3436
/**
3537
* Settings unique to each JWT realm.
@@ -496,32 +498,7 @@ public void validate(String value) {
496498

497499
@Override
498500
public void validate(String value, Map<Setting<?>, Object> settings) {
499-
final String namespace = HTTP_PROXY_HOST.getNamespace(HTTP_PROXY_HOST.getConcreteSetting(key));
500-
final Setting<Integer> portSetting = HTTP_PROXY_PORT.getConcreteSettingForNamespace(namespace);
501-
final Integer port = (Integer) settings.get(portSetting);
502-
final Setting<String> schemeSetting = HTTP_PROXY_SCHEME.getConcreteSettingForNamespace(namespace);
503-
final String scheme = (String) settings.get(schemeSetting);
504-
try {
505-
new HttpHost(value, port, scheme);
506-
} catch (Exception e) {
507-
throw new IllegalArgumentException(
508-
"HTTP host for hostname ["
509-
+ value
510-
+ "] (from ["
511-
+ key
512-
+ "]),"
513-
+ " port ["
514-
+ port
515-
+ "] (from ["
516-
+ portSetting.getKey()
517-
+ "]) and "
518-
+ "scheme ["
519-
+ scheme
520-
+ "] (from (["
521-
+ schemeSetting.getKey()
522-
+ "]) is invalid"
523-
);
524-
}
501+
verifyProxySettings(key, value, settings, HTTP_PROXY_HOST, HTTP_PROXY_SCHEME, HTTP_PROXY_PORT);
525502
}
526503

527504
@Override
@@ -544,11 +521,13 @@ public Iterator<Setting<?>> settings() {
544521
public static final Setting.AffixSetting<String> HTTP_PROXY_SCHEME = Setting.affixKeySetting(
545522
RealmSettings.realmSettingPrefix(TYPE),
546523
"http.proxy.scheme",
547-
key -> Setting.simpleString(key, "http", value -> {
548-
if (value.equals("http") == false && value.equals("https") == false) {
549-
throw new IllegalArgumentException("Invalid value [" + value + "] for [" + key + "]. Only `http` or `https` are allowed.");
550-
}
551-
}, Setting.Property.NodeScope)
524+
key -> Setting.simpleString(
525+
key,
526+
"http",
527+
// TODO allow HTTPS once https://github.com/elastic/elasticsearch/issues/100264 is fixed
528+
value -> verifyNonNullNotEmpty(key, value, List.of("http")),
529+
Setting.Property.NodeScope
530+
)
552531
);
553532

554533
// SSL Configuration settings

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/oidc/OpenIdConnectRealmSettings.java

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
1515
import org.elasticsearch.xpack.core.security.authc.support.ClaimSetting;
1616
import org.elasticsearch.xpack.core.security.authc.support.DelegatedAuthorizationSettings;
17+
import org.elasticsearch.xpack.core.security.authc.support.SecuritySettingsUtil;
1718
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
1819

1920
import java.net.URI;
@@ -234,32 +235,7 @@ public void validate(String value) {
234235

235236
@Override
236237
public void validate(String value, Map<Setting<?>, Object> settings) {
237-
final String namespace = HTTP_PROXY_HOST.getNamespace(HTTP_PROXY_HOST.getConcreteSetting(key));
238-
final Setting<Integer> portSetting = HTTP_PROXY_PORT.getConcreteSettingForNamespace(namespace);
239-
final Integer port = (Integer) settings.get(portSetting);
240-
final Setting<String> schemeSetting = HTTP_PROXY_SCHEME.getConcreteSettingForNamespace(namespace);
241-
final String scheme = (String) settings.get(schemeSetting);
242-
try {
243-
new HttpHost(value, port, scheme);
244-
} catch (Exception e) {
245-
throw new IllegalArgumentException(
246-
"HTTP host for hostname ["
247-
+ value
248-
+ "] (from ["
249-
+ key
250-
+ "]),"
251-
+ " port ["
252-
+ port
253-
+ "] (from ["
254-
+ portSetting.getKey()
255-
+ "]) and "
256-
+ "scheme ["
257-
+ scheme
258-
+ "] (from (["
259-
+ schemeSetting.getKey()
260-
+ "]) is invalid"
261-
);
262-
}
238+
SecuritySettingsUtil.verifyProxySettings(key, value, settings, HTTP_PROXY_HOST, HTTP_PROXY_SCHEME, HTTP_PROXY_PORT);
263239
}
264240

265241
@Override

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/support/SecuritySettingsUtil.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77

88
package org.elasticsearch.xpack.core.security.authc.support;
99

10+
import org.apache.http.HttpHost;
11+
import org.elasticsearch.common.settings.Setting;
12+
1013
import java.util.Collection;
1114
import java.util.List;
15+
import java.util.Map;
1216

1317
/**
1418
* Utilities for validating security settings.
@@ -85,6 +89,45 @@ public static void verifyNonNullNotEmpty(
8589
}
8690
}
8791

92+
public static void verifyProxySettings(
93+
String key,
94+
String hostValue,
95+
Map<Setting<?>, Object> settings,
96+
Setting.AffixSetting<String> hostKey,
97+
Setting.AffixSetting<String> schemeKey,
98+
Setting.AffixSetting<Integer> portKey
99+
) {
100+
final String namespace = hostKey.getNamespace(hostKey.getConcreteSetting(key));
101+
102+
final Setting<Integer> portSetting = portKey.getConcreteSettingForNamespace(namespace);
103+
final Integer port = (Integer) settings.get(portSetting);
104+
105+
final Setting<String> schemeSetting = schemeKey.getConcreteSettingForNamespace(namespace);
106+
final String scheme = (String) settings.get(schemeSetting);
107+
108+
try {
109+
new HttpHost(hostValue, port, scheme);
110+
} catch (Exception e) {
111+
throw new IllegalArgumentException(
112+
"HTTP host for hostname ["
113+
+ hostValue
114+
+ "] (from ["
115+
+ key
116+
+ "]),"
117+
+ " port ["
118+
+ port
119+
+ "] (from ["
120+
+ portSetting.getKey()
121+
+ "]) and "
122+
+ "scheme ["
123+
+ scheme
124+
+ "] (from (["
125+
+ schemeSetting.getKey()
126+
+ "]) is invalid"
127+
);
128+
}
129+
}
130+
88131
private SecuritySettingsUtil() {
89132
throw new IllegalAccessError("not allowed!");
90133
}

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/jwt/JwtRealmSettingsTests.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@
2323
import java.util.Locale;
2424

2525
import static org.elasticsearch.common.Strings.capitalize;
26+
import static org.hamcrest.Matchers.allOf;
2627
import static org.hamcrest.Matchers.containsInAnyOrder;
2728
import static org.hamcrest.Matchers.containsString;
2829
import static org.hamcrest.Matchers.emptyIterable;
30+
import static org.hamcrest.Matchers.endsWith;
2931
import static org.hamcrest.Matchers.equalTo;
3032
import static org.hamcrest.Matchers.is;
33+
import static org.hamcrest.Matchers.startsWith;
3134

3235
/**
3336
* JWT realm settings unit tests. These are low-level tests against ES settings parsers.
@@ -588,4 +591,59 @@ public void testRequiredClaimsCannotBeEmpty() {
588591

589592
assertThat(e.getMessage(), containsString("required claim [" + fullSettingKey + "] cannot be empty"));
590593
}
594+
595+
public void testInvalidProxySchemeThrowsError() {
596+
final String scheme = randomBoolean() ? "https" : randomAlphaOfLengthBetween(3, 8);
597+
final String realmName = randomAlphaOfLengthBetween(3, 8);
598+
final String proxySchemeSettingKey = RealmSettings.getFullSettingKey(realmName, JwtRealmSettings.HTTP_PROXY_SCHEME);
599+
final Settings settings = Settings.builder().put(proxySchemeSettingKey, scheme).build();
600+
601+
final RealmConfig realmConfig = buildRealmConfig(JwtRealmSettings.TYPE, realmName, settings, randomInt());
602+
final IllegalArgumentException e = expectThrows(
603+
IllegalArgumentException.class,
604+
() -> realmConfig.getSetting(JwtRealmSettings.HTTP_PROXY_SCHEME)
605+
);
606+
607+
assertThat(
608+
e.getMessage(),
609+
equalTo(Strings.format("Invalid value [https] for [%s]. Allowed values are [http].", proxySchemeSettingKey))
610+
);
611+
}
612+
613+
public void testInvalidProxyHostThrowsError() {
614+
final int proxyPort = randomIntBetween(1, 65535);
615+
final String realmName = randomAlphaOfLengthBetween(3, 8);
616+
final String proxyPortSettingKey = RealmSettings.getFullSettingKey(realmName, JwtRealmSettings.HTTP_PROXY_PORT);
617+
final String proxyHostSettingKey = RealmSettings.getFullSettingKey(realmName, JwtRealmSettings.HTTP_PROXY_HOST);
618+
final Settings settings = Settings.builder().put(proxyHostSettingKey, "not a url").put(proxyPortSettingKey, proxyPort).build();
619+
620+
final RealmConfig realmConfig = buildRealmConfig(JwtRealmSettings.TYPE, realmName, settings, randomInt());
621+
final IllegalArgumentException e = expectThrows(
622+
IllegalArgumentException.class,
623+
() -> realmConfig.getSetting(JwtRealmSettings.HTTP_PROXY_HOST)
624+
);
625+
626+
assertThat(
627+
e.getMessage(),
628+
allOf(startsWith(Strings.format("HTTP host for hostname [not a url] (from [%s])", proxyHostSettingKey)), endsWith("is invalid"))
629+
);
630+
}
631+
632+
public void testInvalidProxyPortThrowsError() {
633+
final int proxyPort = randomFrom(randomIntBetween(Integer.MIN_VALUE, -1), randomIntBetween(65536, Integer.MAX_VALUE));
634+
final String realmName = randomAlphaOfLengthBetween(3, 8);
635+
final String proxyPortSettingKey = RealmSettings.getFullSettingKey(realmName, JwtRealmSettings.HTTP_PROXY_PORT);
636+
final Settings settings = Settings.builder().put(proxyPortSettingKey, proxyPort).build();
637+
638+
final RealmConfig realmConfig = buildRealmConfig(JwtRealmSettings.TYPE, realmName, settings, randomInt());
639+
final IllegalArgumentException e = expectThrows(
640+
IllegalArgumentException.class,
641+
() -> realmConfig.getSetting(JwtRealmSettings.HTTP_PROXY_PORT)
642+
);
643+
644+
assertThat(
645+
e.getMessage(),
646+
startsWith(Strings.format("Failed to parse value [%d] for setting [%s]", proxyPort, proxyPortSettingKey))
647+
);
648+
}
591649
}

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/jwt/JwtTestCase.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,14 @@ protected Settings.Builder generateRandomRealmSettings(final String name) throws
9898
final boolean includePublicKey = includeRsa || includeEc;
9999
final boolean includeHmac = randomBoolean() || (includePublicKey == false); // one of HMAC/RSA/EC must be true
100100
final boolean populateUserMetadata = randomBoolean();
101+
final boolean useJwksEndpoint = randomBoolean();
102+
final boolean useProxy = useJwksEndpoint && randomBoolean();
101103
final Path jwtSetPathObj = PathUtils.get(pathHome);
102-
final String jwkSetPath = randomBoolean()
104+
final String jwkSetPath = useJwksEndpoint
103105
? "https://op.example.com/jwkset.json"
104106
: Files.createTempFile(jwtSetPathObj, "jwkset.", ".json").toString();
105107

106-
if (jwkSetPath.equals("https://op.example.com/jwkset.json") == false) {
108+
if (useJwksEndpoint == false) {
107109
Files.writeString(PathUtils.get(jwkSetPath), "Non-empty JWK Set Path contents");
108110
}
109111
final ClientAuthenticationType clientAuthenticationType = randomFrom(ClientAuthenticationType.values());
@@ -195,6 +197,17 @@ protected Settings.Builder generateRandomRealmSettings(final String name) throws
195197
.put(RealmSettings.getFullSettingKey(name, SSLConfigurationSettings.TRUSTSTORE_ALGORITHM.realm(JwtRealmSettings.TYPE)), "PKIX")
196198
.put(RealmSettings.getFullSettingKey(name, SSLConfigurationSettings.CERT_AUTH_PATH.realm(JwtRealmSettings.TYPE)), "ca2.pem");
197199

200+
if (useProxy) {
201+
if (randomBoolean()) {
202+
// Scheme is optional, and defaults to HTTP
203+
settingsBuilder.put(RealmSettings.getFullSettingKey(name, JwtRealmSettings.HTTP_PROXY_SCHEME), "http");
204+
}
205+
206+
settingsBuilder
207+
.put(RealmSettings.getFullSettingKey(name, JwtRealmSettings.HTTP_PROXY_HOST), "localhost/proxy")
208+
.put(RealmSettings.getFullSettingKey(name, JwtRealmSettings.HTTP_PROXY_PORT), randomIntBetween(1, 65535));
209+
}
210+
198211
final MockSecureSettings secureSettings = new MockSecureSettings();
199212
if (includeHmac) {
200213
if (randomBoolean()) {

x-pack/test/idp-fixture/src/main/resources/nginx/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# We need to do SSL tunnelling, but NGINX doesn't support this out of the box - there's a module for this, but the only
22
# way to install it is to compile NGINX from source, so here we go
33

4-
FROM nginx:latest
4+
FROM nginx:1.27.1
55

66
RUN set -x \
77
&& apt-get update \
88
# libs and tools that we'll need to build NGINX
99
&& apt-get install --no-install-recommends --no-install-suggests -y \
1010
zlib1g-dev libpcre2-dev libssl-dev wget git gcc patch make \
1111
&& wget http://nginx.org/download/nginx-1.27.1.tar.gz \
12-
&& git clone https://github.com/chobits/ngx_http_proxy_connect_module.git \
12+
&& git clone --depth 1 --branch v0.0.7 --single-branch https://github.com/chobits/ngx_http_proxy_connect_module.git \
1313
&& tar -xzvf nginx-1.27.1.tar.gz \
1414
&& cd nginx-1.27.1 \
1515
# patch the CONNECT module in

0 commit comments

Comments
 (0)