Fail early when rp.client_secret is missing in OIDC realm (#42256)

rp.client_secret is a required secure setting. Make sure we fail with
a SettingsException and a clear, actionable message when building
the realm, if the setting is missing.
This commit is contained in:
Ioannis Kakavas 2019-05-22 13:20:18 +03:00
parent ccdc0e6b3e
commit aab97f1311
5 changed files with 70 additions and 7 deletions

View File

@ -247,6 +247,10 @@ public class OpenIdConnectRealm extends Realm implements Releasable {
}
final ClientID clientId = new ClientID(require(config, RP_CLIENT_ID));
final SecureString clientSecret = config.getSetting(RP_CLIENT_SECRET);
if (clientSecret.length() == 0) {
throw new SettingsException("The configuration setting [" + RealmSettings.getFullSettingKey(config, RP_CLIENT_SECRET)
+ "] is required");
}
final ResponseType responseType;
try {
// This should never happen as it's already validated in the settings

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.security.authc;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.xpack.core.security.action.user.AuthenticateAction;
@ -52,8 +53,12 @@ public class SecurityRealmSettingsTests extends SecurityIntegTestCase {
final Path jwkSet = createTempFile("jwkset", "json");
OpenIdConnectTestCase.writeJwkSetToFile(jwkSet);
final Settings existingSettings = super.nodeSettings(nodeOrdinal);
MockSecureSettings mockSecureSettings =
(MockSecureSettings) Settings.builder().put(existingSettings).getSecureSettings();
mockSecureSettings.setString("xpack.security.authc.realms.oidc.oidc1.rp.client_secret", randomAlphaOfLength(12));
settings = Settings.builder()
.put(super.nodeSettings(nodeOrdinal).filter(s -> s.startsWith("xpack.security.authc.realms.") == false))
.put(existingSettings.filter(s -> s.startsWith("xpack.security.authc.realms.") == false), false)
.put("xpack.security.authc.token.enabled", true)
.put("xpack.security.authc.realms.file.file1.order", 1)
.put("xpack.security.authc.realms.native.native1.order", 2)
@ -80,6 +85,7 @@ public class SecurityRealmSettingsTests extends SecurityIntegTestCase {
.put("xpack.security.authc.realms.oidc.oidc1.rp.client_id", "my_client")
.put("xpack.security.authc.realms.oidc.oidc1.rp.response_type", "code")
.put("xpack.security.authc.realms.oidc.oidc1.claims.principal", "sub")
.setSecureSettings(mockSecureSettings)
.build();
} catch (IOException e) {
throw new RuntimeException(e);

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.security.authc.oidc;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -42,6 +43,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "hybrid");
settingsBuilder.setSecureSettings(getSecureSettings());
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -58,6 +60,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
settingsBuilder.setSecureSettings(getSecureSettings());
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -75,6 +78,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
settingsBuilder.setSecureSettings(getSecureSettings());
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -91,6 +95,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
settingsBuilder.setSecureSettings(getSecureSettings());
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -108,6 +113,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
settingsBuilder.setSecureSettings(getSecureSettings());
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -123,6 +129,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
settingsBuilder.setSecureSettings(getSecureSettings());
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -139,6 +146,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
settingsBuilder.setSecureSettings(getSecureSettings());
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -155,6 +163,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
settingsBuilder.setSecureSettings(getSecureSettings());
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -171,6 +180,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
settingsBuilder.setSecureSettings(getSecureSettings());
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -189,6 +199,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
.putList(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REQUESTED_SCOPES),
Arrays.asList("openid", "scope1", "scope2"));
settingsBuilder.setSecureSettings(getSecureSettings());
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -209,6 +220,7 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
.putList(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REQUESTED_SCOPES),
Arrays.asList("openid", "scope1", "scope2"));
settingsBuilder.setSecureSettings(getSecureSettings());
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
@ -218,6 +230,30 @@ public class OpenIdConnectRealmSettingsTests extends ESTestCase {
Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.NAME_CLAIM.getPattern())));
}
public void testMissingClientSecretThrowsError() {
final Settings.Builder settingsBuilder = Settings.builder()
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_ISSUER), "https://op.example.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_JWKSET_PATH), "https://op.example.com/jwks.json")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_TOKEN_ENDPOINT), "https://op.example.com/token")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
SettingsException exception = expectThrows(SettingsException.class, () -> {
new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null);
});
assertThat(exception.getMessage(),
Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_SECRET)));
}
private MockSecureSettings getSecureSettings() {
MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_SECRET),
randomAlphaOfLengthBetween(12, 18));
return secureSettings;
}
private RealmConfig buildConfig(Settings realmSettings) {
final Settings settings = Settings.builder()
.put("path.home", createTempDir())

View File

@ -165,7 +165,8 @@ public class OpenIdConnectRealmTests extends OpenIdConnectTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
.putList(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REQUESTED_SCOPES),
Arrays.asList("scope1", "scope2"));
Arrays.asList("scope1", "scope2"))
.setSecureSettings(getSecureSettings());
final OpenIdConnectRealm realm = new OpenIdConnectRealm(buildConfig(settingsBuilder.build(), threadContext), null,
null);
final OpenIdConnectPrepareAuthenticationResponse response = realm.buildAuthenticationRequestUri(null, null, null);
@ -187,7 +188,8 @@ public class OpenIdConnectRealmTests extends OpenIdConnectTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
.putList(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REQUESTED_SCOPES),
Arrays.asList("openid", "scope1", "scope2"));
Arrays.asList("openid", "scope1", "scope2"))
.setSecureSettings(getSecureSettings());
final OpenIdConnectRealm realm = new OpenIdConnectRealm(buildConfig(settingsBuilder.build(), threadContext), null,
null);
final OpenIdConnectPrepareAuthenticationResponse response = realm.buildAuthenticationRequestUri(null, null, null);
@ -207,7 +209,9 @@ public class OpenIdConnectRealmTests extends OpenIdConnectTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com/cb")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
.setSecureSettings(getSecureSettings());
;
final OpenIdConnectRealm realm = new OpenIdConnectRealm(buildConfig(settingsBuilder.build(), threadContext), null,
null);
final OpenIdConnectPrepareAuthenticationResponse response = realm.buildAuthenticationRequestUri(null, null, null);
@ -237,7 +241,9 @@ public class OpenIdConnectRealmTests extends OpenIdConnectTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com/cb")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
.setSecureSettings(getSecureSettings());
;
final OpenIdConnectRealm realm = new OpenIdConnectRealm(buildConfig(settingsBuilder.build(), threadContext), null,
null);
final String state = new State().getValue();
@ -257,7 +263,9 @@ public class OpenIdConnectRealmTests extends OpenIdConnectTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REDIRECT_URI), "https://rp.my.com/cb")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_ID), "rp-my")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code");
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code")
.setSecureSettings(getSecureSettings());
;
final OpenIdConnectRealm realm = new OpenIdConnectRealm(buildConfig(settingsBuilder.build(), threadContext), null,
null);
final String state = new State().getValue();

View File

@ -12,6 +12,7 @@ import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.openid.connect.sdk.Nonce;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
@ -50,7 +51,15 @@ public abstract class OpenIdConnectTestCase extends ESTestCase {
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.GROUPS_CLAIM.getClaim()), "groups")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.MAIL_CLAIM.getClaim()), "mail")
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.NAME_CLAIM.getClaim()), "name");
.put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.NAME_CLAIM.getClaim()), "name")
.setSecureSettings(getSecureSettings());
}
protected static MockSecureSettings getSecureSettings() {
MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_SECRET),
randomAlphaOfLengthBetween(12, 18));
return secureSettings;
}
protected JWT generateIdToken(String subject, String audience, String issuer) throws Exception {