From 3360fa13fb529d33c602a170f9753479928dbdd3 Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Thu, 25 Jun 2020 08:52:32 +0300 Subject: [PATCH 1/6] wip --- .../oidc/OpenIdConnectRealmSettings.java | 28 +++++-- .../oidc/OpenIdConnectAuthenticator.java | 35 +++++++-- .../authc/oidc/OpenIdConnectRealm.java | 9 ++- .../authc/oidc/RelyingPartyConfiguration.java | 18 ++++- .../oidc/OpenIdConnectAuthenticatorTests.java | 7 ++ .../oidc/OpenIdConnectRealmSettingsTests.java | 78 ++++++++++++++++++- x-pack/qa/oidc-op-tests/build.gradle | 34 +++++++- .../authc/oidc/OpenIdConnectAuthIT.java | 76 +++++++++++++++--- x-pack/test/idp-fixture/docker-compose.yml | 4 +- 9 files changed, 261 insertions(+), 28 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/oidc/OpenIdConnectRealmSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/oidc/OpenIdConnectRealmSettings.java index 55a7a4f4aaff7..f40613349e056 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/oidc/OpenIdConnectRealmSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/oidc/OpenIdConnectRealmSettings.java @@ -32,9 +32,11 @@ public class OpenIdConnectRealmSettings { private OpenIdConnectRealmSettings() { } - private static final List SUPPORTED_SIGNATURE_ALGORITHMS = - List.of("HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512"); + public static final List SUPPORTED_SIGNATURE_ALGORITHMS = + List.of("HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512", "PS256", "PS384", "PS512"); private static final List RESPONSE_TYPES = List.of("code", "id_token", "id_token token"); + public static final List CLIENT_AUTH_METHODS = List.of("client_secret_basic", "client_secret_post", "client_secret_jwt"); + public static final List SUPPORTED_CLIENT_AUTH_JWT_ALGORITHMS = List.of("HS256", "HS384", "HS512"); public static final String TYPE = "oidc"; public static final Setting.AffixSetting RP_CLIENT_ID @@ -78,7 +80,22 @@ private OpenIdConnectRealmSettings() { public static final Setting.AffixSetting> RP_REQUESTED_SCOPES = Setting.affixKeySetting( RealmSettings.realmSettingPrefix(TYPE), "rp.requested_scopes", key -> Setting.listSetting(key, Collections.singletonList("openid"), Function.identity(), Setting.Property.NodeScope)); - + public static final Setting.AffixSetting RP_CLIENT_AUTH_METHOD + = Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "rp.client_auth_method", + key -> new Setting<>(key, "client_secret_basic", Function.identity(), v -> { + if (CLIENT_AUTH_METHODS.contains(v) == false) { + throw new IllegalArgumentException( + "Invalid value [" + v + "] for [" + key + "]. Allowed values are " + CLIENT_AUTH_METHODS + "}]"); + } + }, Setting.Property.NodeScope)); + public static final Setting.AffixSetting RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM + = Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "rp.client_auth_jwt_signature_algorithm", + key -> new Setting<>(key, "HS384", Function.identity(), v -> { + if (SUPPORTED_CLIENT_AUTH_JWT_ALGORITHMS.contains(v) == false) { + throw new IllegalArgumentException( + "Invalid value [" + v + "] for [" + key + "]. Allowed values are " + SUPPORTED_CLIENT_AUTH_JWT_ALGORITHMS + "}]"); + } + }, Setting.Property.NodeScope)); public static final Setting.AffixSetting OP_AUTHORIZATION_ENDPOINT = Setting.affixKeySetting(RealmSettings.realmSettingPrefix(TYPE), "op.authorization_endpoint", key -> Setting.simpleString(key, v -> { @@ -194,8 +211,9 @@ public Iterator> settings() { public static Set> getSettings() { final Set> set = Sets.newHashSet( RP_CLIENT_ID, RP_REDIRECT_URI, RP_RESPONSE_TYPE, RP_REQUESTED_SCOPES, RP_CLIENT_SECRET, RP_SIGNATURE_ALGORITHM, - RP_POST_LOGOUT_REDIRECT_URI, OP_AUTHORIZATION_ENDPOINT, OP_TOKEN_ENDPOINT, OP_USERINFO_ENDPOINT, - OP_ENDSESSION_ENDPOINT, OP_ISSUER, OP_JWKSET_PATH, POPULATE_USER_METADATA, HTTP_CONNECT_TIMEOUT, HTTP_CONNECTION_READ_TIMEOUT, + RP_POST_LOGOUT_REDIRECT_URI, RP_CLIENT_AUTH_METHOD, RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM, OP_AUTHORIZATION_ENDPOINT, + OP_TOKEN_ENDPOINT, OP_USERINFO_ENDPOINT, OP_ENDSESSION_ENDPOINT, OP_ISSUER, OP_JWKSET_PATH, + POPULATE_USER_METADATA, HTTP_CONNECT_TIMEOUT, HTTP_CONNECTION_READ_TIMEOUT, HTTP_SOCKET_TIMEOUT, HTTP_MAX_CONNECTIONS, HTTP_MAX_ENDPOINT_CONNECTIONS, HTTP_PROXY_HOST, HTTP_PROXY_PORT, HTTP_PROXY_SCHEME, ALLOWED_CLOCK_SKEW); set.addAll(DelegatedAuthorizationSettings.getSettings(TYPE)); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java index 8fe5c595fca4e..81188cc24c624 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java @@ -22,6 +22,8 @@ import com.nimbusds.oauth2.sdk.ErrorObject; import com.nimbusds.oauth2.sdk.ResponseType; import com.nimbusds.oauth2.sdk.TokenErrorResponse; +import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod; +import com.nimbusds.oauth2.sdk.auth.ClientSecretJWT; import com.nimbusds.oauth2.sdk.auth.Secret; import com.nimbusds.oauth2.sdk.id.State; import com.nimbusds.oauth2.sdk.token.AccessToken; @@ -45,8 +47,10 @@ import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; +import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthenticationException; import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; @@ -56,6 +60,7 @@ import org.apache.http.config.RegistryBuilder; import org.apache.http.entity.ContentType; import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; import org.apache.http.impl.nio.client.HttpAsyncClients; @@ -85,6 +90,7 @@ import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.xpack.core.security.authc.RealmConfig; import org.elasticsearch.xpack.core.security.authc.RealmSettings; +import org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings; import org.elasticsearch.xpack.core.ssl.SSLConfiguration; import org.elasticsearch.xpack.core.ssl.SSLService; @@ -463,19 +469,36 @@ private void exchangeCodeForToken(AuthorizationCode code, ActionListener params = new ArrayList<>(); for (Map.Entry> entry : codeGrant.toParameters().entrySet()) { // All parameters of AuthorizationCodeGrant are singleton lists params.add(new BasicNameValuePair(entry.getKey(), entry.getValue().get(0))); } + if (rpConfig.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)) { + UsernamePasswordCredentials creds = + new UsernamePasswordCredentials(URLEncoder.encode(rpConfig.getClientId().getValue(), StandardCharsets.UTF_8), + URLEncoder.encode(rpConfig.getClientSecret().toString(), StandardCharsets.UTF_8)); + httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null)); + } else if (rpConfig.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.CLIENT_SECRET_POST)) { + params.add(new BasicNameValuePair("client_id", rpConfig.getClientId().getValue())); + params.add(new BasicNameValuePair("client_secret", rpConfig.getClientSecret().toString())); + } else if (rpConfig.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.CLIENT_SECRET_JWT)) { + ClientSecretJWT clientSecretJWT = new ClientSecretJWT(rpConfig.getClientId(), opConfig.getTokenEndpoint(), + rpConfig.getClientAuthenticationJwtAlgorithm(), new Secret(rpConfig.getClientSecret().toString())); + for (Map.Entry> entry : clientSecretJWT.toParameters().entrySet()) { + // Both client_assertion and client_assertion_type are singleton lists + params.add(new BasicNameValuePair(entry.getKey(), entry.getValue().get(0))); + } + } else { + tokensListener.onFailure(new ElasticsearchSecurityException("Failed to exchange code for Id Token using Token Endpoint." + + "Expected client authentication method to be one of " + OpenIdConnectRealmSettings.CLIENT_AUTH_METHODS + " but was " + + rpConfig.getClientAuthenticationMethod())); + } httpPost.setEntity(new UrlEncodedFormEntity(params)); - httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); - UsernamePasswordCredentials creds = - new UsernamePasswordCredentials(URLEncoder.encode(rpConfig.getClientId().getValue(), StandardCharsets.UTF_8), - URLEncoder.encode(rpConfig.getClientSecret().toString(), StandardCharsets.UTF_8)); - httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null)); SpecialPermission.check(); AccessController.doPrivileged((PrivilegedAction) () -> { + httpClient.execute(httpPost, new FutureCallback() { @Override public void completed(HttpResponse result) { @@ -496,7 +519,7 @@ public void cancelled() { }); return null; }); - } catch (AuthenticationException | UnsupportedEncodingException e) { + } catch (AuthenticationException | UnsupportedEncodingException | JOSEException e) { tokensListener.onFailure( new ElasticsearchSecurityException("Failed to exchange code for Id Token using the Token Endpoint.", e)); } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealm.java index 2189c629a5059..59a2d078eeec3 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealm.java @@ -12,6 +12,7 @@ import com.nimbusds.oauth2.sdk.ParseException; import com.nimbusds.oauth2.sdk.ResponseType; import com.nimbusds.oauth2.sdk.Scope; +import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod; import com.nimbusds.oauth2.sdk.id.ClientID; import com.nimbusds.oauth2.sdk.id.Issuer; import com.nimbusds.oauth2.sdk.id.State; @@ -71,6 +72,8 @@ import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.OP_USERINFO_ENDPOINT; import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.POPULATE_USER_METADATA; import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.PRINCIPAL_CLAIM; +import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM; +import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD; import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_CLIENT_ID; import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_CLIENT_SECRET; import static org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings.RP_POST_LOGOUT_REDIRECT_URI; @@ -268,9 +271,11 @@ private RelyingPartyConfiguration buildRelyingPartyConfiguration(RealmConfig con requestedScope.add("openid"); } final JWSAlgorithm signatureAlgorithm = JWSAlgorithm.parse(require(config, RP_SIGNATURE_ALGORITHM)); - + final ClientAuthenticationMethod clientAuthenticationMethod = + ClientAuthenticationMethod.parse(require(config, RP_CLIENT_AUTH_METHOD)); + final JWSAlgorithm clientAuthJwtAlgorithm = JWSAlgorithm.parse(require(config, RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM)); return new RelyingPartyConfiguration(clientId, clientSecret, redirectUri, responseType, requestedScope, - signatureAlgorithm, postLogoutRedirectUri); + signatureAlgorithm, clientAuthenticationMethod, clientAuthJwtAlgorithm, postLogoutRedirectUri); } private OpenIdConnectProviderConfiguration buildOpenIdConnectProviderConfiguration(RealmConfig config) { diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/RelyingPartyConfiguration.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/RelyingPartyConfiguration.java index ed67974c0b0d2..deae6fcfff011 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/RelyingPartyConfiguration.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/RelyingPartyConfiguration.java @@ -8,6 +8,7 @@ import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.oauth2.sdk.ResponseType; import com.nimbusds.oauth2.sdk.Scope; +import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod; import com.nimbusds.oauth2.sdk.id.ClientID; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.settings.SecureString; @@ -26,15 +27,22 @@ public class RelyingPartyConfiguration { private final Scope requestedScope; private final JWSAlgorithm signatureAlgorithm; private final URI postLogoutRedirectUri; + private final ClientAuthenticationMethod clientAuthenticationMethod; + private final JWSAlgorithm clientAuthenticationJwtAlgorithm; public RelyingPartyConfiguration(ClientID clientId, SecureString clientSecret, URI redirectUri, ResponseType responseType, - Scope requestedScope, JWSAlgorithm algorithm, @Nullable URI postLogoutRedirectUri) { + Scope requestedScope, JWSAlgorithm algorithm, ClientAuthenticationMethod clientAuthenticationMethod, + JWSAlgorithm clientAuthenticationJwtAlgorithm, @Nullable URI postLogoutRedirectUri) { this.clientId = Objects.requireNonNull(clientId, "clientId must be provided"); this.clientSecret = Objects.requireNonNull(clientSecret, "clientSecret must be provided"); this.redirectUri = Objects.requireNonNull(redirectUri, "redirectUri must be provided"); this.responseType = Objects.requireNonNull(responseType, "responseType must be provided"); this.requestedScope = Objects.requireNonNull(requestedScope, "responseType must be provided"); this.signatureAlgorithm = Objects.requireNonNull(algorithm, "algorithm must be provided"); + this.clientAuthenticationMethod = Objects.requireNonNull(clientAuthenticationMethod, + "clientAuthenticationMethod must be provided"); + this.clientAuthenticationJwtAlgorithm = Objects.requireNonNull(clientAuthenticationJwtAlgorithm, + "clientAuthenticationJwtAlgorithm must be provided"); this.postLogoutRedirectUri = postLogoutRedirectUri; } @@ -65,4 +73,12 @@ public JWSAlgorithm getSignatureAlgorithm() { public URI getPostLogoutRedirectUri() { return postLogoutRedirectUri; } + + public ClientAuthenticationMethod getClientAuthenticationMethod() { + return clientAuthenticationMethod; + } + + public JWSAlgorithm getClientAuthenticationJwtAlgorithm() { + return clientAuthenticationJwtAlgorithm; + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticatorTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticatorTests.java index bf0bdbee13e9c..65247fe0971fa 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticatorTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticatorTests.java @@ -27,6 +27,7 @@ import com.nimbusds.jwt.proc.BadJWTException; import com.nimbusds.oauth2.sdk.ResponseType; import com.nimbusds.oauth2.sdk.Scope; +import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod; import com.nimbusds.oauth2.sdk.auth.Secret; import com.nimbusds.oauth2.sdk.id.ClientID; import com.nimbusds.oauth2.sdk.id.Issuer; @@ -841,6 +842,8 @@ private RelyingPartyConfiguration getDefaultRpConfig() throws URISyntaxException new ResponseType("id_token", "token"), new Scope("openid"), JWSAlgorithm.RS384, + ClientAuthenticationMethod.CLIENT_SECRET_BASIC, + JWSAlgorithm.HS384, new URI("https://rp.elastic.co/successfull_logout")); } private RelyingPartyConfiguration getRpConfig(String alg) throws URISyntaxException { @@ -851,6 +854,8 @@ private RelyingPartyConfiguration getRpConfig(String alg) throws URISyntaxExcept new ResponseType("id_token", "token"), new Scope("openid"), JWSAlgorithm.parse(alg), + ClientAuthenticationMethod.CLIENT_SECRET_BASIC, + JWSAlgorithm.HS384, new URI("https://rp.elastic.co/successfull_logout")); } @@ -862,6 +867,8 @@ private RelyingPartyConfiguration getRpConfigNoAccessToken(String alg) throws UR new ResponseType("id_token"), new Scope("openid"), JWSAlgorithm.parse(alg), + ClientAuthenticationMethod.CLIENT_SECRET_BASIC, + JWSAlgorithm.HS384, new URI("https://rp.elastic.co/successfull_logout")); } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealmSettingsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealmSettingsTests.java index 9827be75a2c88..0b8c236844675 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealmSettingsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectRealmSettingsTests.java @@ -34,6 +34,43 @@ public void setupEnv() { threadContext = new ThreadContext(globalSettings); } + public void testAllSettings() { + final Settings.Builder settingsBuilder = Settings.builder() + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_TOKEN_ENDPOINT), "https://op.example.com/token") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_USERINFO_ENDPOINT), "https://op.example.com/userinfo") + .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.POPULATE_USER_METADATA), randomBoolean()) + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.PRINCIPAL_CLAIM.getClaim()), "sub") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.GROUPS_CLAIM.getClaim()), "group1") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.DN_CLAIM.getClaim()), "uid=sub,ou=people,dc=example,dc=com") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.NAME_CLAIM.getClaim()), "name") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.MAIL_CLAIM.getClaim()), "e@mail.com") + .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") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_REQUESTED_SCOPES), "openid") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_SIGNATURE_ALGORITHM), + randomFrom(OpenIdConnectRealmSettings.SUPPORTED_SIGNATURE_ALGORITHMS)) + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_POST_LOGOUT_REDIRECT_URI), "https://my.rp.com/logout") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD), + randomFrom(OpenIdConnectRealmSettings.CLIENT_AUTH_METHODS)) + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM), + randomFrom(OpenIdConnectRealmSettings.SUPPORTED_CLIENT_AUTH_JWT_ALGORITHMS)) + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_CONNECT_TIMEOUT), "5s") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_CONNECTION_READ_TIMEOUT), "5s") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_SOCKET_TIMEOUT), "5s") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_MAX_CONNECTIONS), "5") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_MAX_ENDPOINT_CONNECTIONS), "5") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_PROXY_HOST), "host") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_PROXY_PORT), "8080") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.HTTP_PROXY_SCHEME), "http") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.ALLOWED_CLOCK_SKEW), "10s"); + settingsBuilder.setSecureSettings(getSecureSettings()); + new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null); + } + public void testIncorrectResponseTypeThrowsError() { final Settings.Builder settingsBuilder = Settings.builder() .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login") @@ -116,10 +153,8 @@ public void testMissingTokenEndpointIsAllowedInImplicitFlow() { settingsBuilder.setSecureSettings(getSecureSettings()); final OpenIdConnectRealm realm = new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null); assertNotNull(realm); - } - public void testInvalidTokenEndpointThrowsError() { final Settings.Builder settingsBuilder = Settings.builder() .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login") @@ -327,6 +362,45 @@ public void testInvalidProxyHostThrowsError() { )); } + public void testInvalidClientAuthenticationMethodThrowsError() { + final Settings.Builder settingsBuilder = Settings.builder() + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login") + .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.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_CLIENT_AUTH_METHOD), "none") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_RESPONSE_TYPE), "code"); + settingsBuilder.setSecureSettings(getSecureSettings()); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> { + new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null); + }); + assertThat(exception.getMessage(), + Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD))); + } + + public void testInvalidClientAuthenticationJwtAlgorithmThrowsError() { + final Settings.Builder settingsBuilder = Settings.builder() + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.OP_AUTHORIZATION_ENDPOINT), "https://op.example.com/login") + .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.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") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_METHOD), "client_secret_jwt") + .put(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM), "AB234"); + settingsBuilder.setSecureSettings(getSecureSettings()); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> { + new OpenIdConnectRealm(buildConfig(settingsBuilder.build()), null, null); + }); + assertThat(exception.getMessage(), + Matchers.containsString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_AUTH_JWT_SIGNATURE_ALGORITHM))); + } + private MockSecureSettings getSecureSettings() { MockSecureSettings secureSettings = new MockSecureSettings(); secureSettings.setString(getFullSettingKey(REALM_NAME, OpenIdConnectRealmSettings.RP_CLIENT_SECRET), diff --git a/x-pack/qa/oidc-op-tests/build.gradle b/x-pack/qa/oidc-op-tests/build.gradle index bd4fa155d8855..e346b69d1c711 100644 --- a/x-pack/qa/oidc-op-tests/build.gradle +++ b/x-pack/qa/oidc-op-tests/build.gradle @@ -83,9 +83,41 @@ testClusters.integTest { setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.groups', 'groups' setting 'xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.host', '127.0.0.1' setting 'xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.port', {"${ephemeralProxyPort}"} + // OpenID Connect Realm 4 configured for client_secret_post authentication + setting 'xpack.security.authc.realms.oidc.c2id-post.order', '5' + setting 'xpack.security.authc.realms.oidc.c2id-post.op.issuer', 'http://localhost:8080' + setting 'xpack.security.authc.realms.oidc.c2id-post.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" } + setting 'xpack.security.authc.realms.oidc.c2id-post.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" } + setting 'xpack.security.authc.realms.oidc.c2id-post.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" } + setting 'xpack.security.authc.realms.oidc.c2id-post.op.jwkset_path', 'op-jwks.json' + setting 'xpack.security.authc.realms.oidc.c2id-post.rp.redirect_uri', 'https://my.fantastic.rp/cb' + setting 'xpack.security.authc.realms.oidc.c2id-post.rp.client_id', 'elasticsearch-post' + setting 'xpack.security.authc.realms.oidc.c2id-post.rp.client_auth_method', 'client_secret_post' + keystore 'xpack.security.authc.realms.oidc.c2id-post.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2' + setting 'xpack.security.authc.realms.oidc.c2id-post.rp.response_type', 'code' + setting 'xpack.security.authc.realms.oidc.c2id-post.claims.principal', 'sub' + setting 'xpack.security.authc.realms.oidc.c2id-post.claims.name', 'name' + setting 'xpack.security.authc.realms.oidc.c2id-post.claims.mail', 'email' + setting 'xpack.security.authc.realms.oidc.c2id-post.claims.groups', 'groups' + // OpenID Connect Realm 5 configured for client_secret_jwt authentication + setting 'xpack.security.authc.realms.oidc.c2id-jwt.order', '6' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.issuer', 'http://localhost:8080' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" } + setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" } + setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" } + setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.jwkset_path', 'op-jwks.json' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.rp.redirect_uri', 'https://my.fantastic.rp/cb' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.rp.client_id', 'elasticsearch-post-jwt' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.rp.client_auth_method', 'client_secret_jwt' + keystore 'xpack.security.authc.realms.oidc.c2id-jwt.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.rp.response_type', 'code' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.claims.principal', 'sub' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.claims.name', 'name' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.claims.mail', 'email' + setting 'xpack.security.authc.realms.oidc.c2id-jwt.claims.groups', 'groups' setting 'xpack.ml.enabled', 'false' extraConfigFile 'op-jwks.json', idpFixtureProject.file("oidc/op-jwks.json") - + setting 'logger.org.elasticsearch.xpack.security.authc.oidc', 'TRACE' user username: "test_admin", password: "x-pack-test-password" } diff --git a/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java b/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java index 6e1dd7c7fdce9..bb844f1ff5080 100644 --- a/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java +++ b/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java @@ -65,6 +65,8 @@ public class OpenIdConnectAuthIT extends ESRestTestCase { private static final String REALM_NAME = "c2id"; private static final String REALM_NAME_IMPLICIT = "c2id-implicit"; private static final String REALM_NAME_PROXY = "c2id-proxy"; + private static final String REALM_NAME_CLIENT_POST_AUTH = "c2id-post"; + private static final String REALM_NAME_CLIENT_JWT_AUTH = "c2id-jwt"; private static final String FACILITATOR_PASSWORD = "f@cilit@t0r"; private static final String REGISTRATION_URL = "http://127.0.0.1:" + getEphemeralPortFromProperty("8080") + "/c2id/clients"; private static final String LOGIN_API = "http://127.0.0.1:" + getEphemeralPortFromProperty("8080") + "/c2id-login/api/"; @@ -86,7 +88,8 @@ public static void registerClients() throws Exception { "\"response_types\": [\"code\"]," + "\"preferred_client_id\":\"https://my.elasticsearch.org/rp\"," + "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + - "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]" + + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," + + "\"token_endpoint_auth_method\":\"client_secret_basic\"" + "}"; String implicitClient = "{" + "\"grant_types\": [\"implicit\"]," + @@ -95,22 +98,61 @@ public static void registerClients() throws Exception { "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]" + "}"; + String postClient = "{" + + "\"grant_types\": [\"authorization_code\"]," + + "\"response_types\": [\"code\"]," + + "\"preferred_client_id\":\"elasticsearch-post\"," + + "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," + + "\"token_endpoint_auth_method\":\"client_secret_post\"" + + "}"; + String jwtClient = "{" + + "\"grant_types\": [\"authorization_code\"]," + + "\"response_types\": [\"code\"]," + + "\"preferred_client_id\":\"elasticsearch-post-jwt\"," + + "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," + + "\"token_endpoint_auth_method\":\"client_secret_jwt\"" + + "}"; HttpPost httpPost = new HttpPost(REGISTRATION_URL); final BasicHttpContext context = new BasicHttpContext(); httpPost.setEntity(new StringEntity(codeClient, ContentType.APPLICATION_JSON)); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Content-type", "application/json"); httpPost.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a"); - CloseableHttpResponse response = SocketAccess.doPrivileged(() -> httpClient.execute(httpPost, context)); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - httpPost.setEntity(new StringEntity(implicitClient, ContentType.APPLICATION_JSON)); + HttpPost httpPost2 = new HttpPost(REGISTRATION_URL); httpPost2.setEntity(new StringEntity(implicitClient, ContentType.APPLICATION_JSON)); httpPost2.setHeader("Accept", "application/json"); httpPost2.setHeader("Content-type", "application/json"); httpPost2.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a"); - CloseableHttpResponse response2 = SocketAccess.doPrivileged(() -> httpClient.execute(httpPost2, context)); - assertThat(response2.getStatusLine().getStatusCode(), equalTo(200)); + + HttpPost httpPost3 = new HttpPost(REGISTRATION_URL); + httpPost3.setEntity(new StringEntity(postClient, ContentType.APPLICATION_JSON)); + httpPost3.setHeader("Accept", "application/json"); + httpPost3.setHeader("Content-type", "application/json"); + httpPost3.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a"); + + HttpPost httpPost4 = new HttpPost(REGISTRATION_URL); + httpPost4.setEntity(new StringEntity(jwtClient, ContentType.APPLICATION_JSON)); + httpPost4.setHeader("Accept", "application/json"); + httpPost4.setHeader("Content-type", "application/json"); + httpPost4.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a"); + + SocketAccess.doPrivileged(() -> { + try (CloseableHttpResponse response = httpClient.execute(httpPost, context)) { + assertThat(response.getStatusLine().getStatusCode(), equalTo(201)); + } + try (CloseableHttpResponse response2 = httpClient.execute(httpPost2, context)) { + assertThat(response2.getStatusLine().getStatusCode(), equalTo(201)); + } + try (CloseableHttpResponse response3 = httpClient.execute(httpPost3, context)) { + assertThat(response3.getStatusLine().getStatusCode(), equalTo(201)); + } + try (CloseableHttpResponse response4 = httpClient.execute(httpPost4, context)) { + assertThat(response4.getStatusLine().getStatusCode(), equalTo(201)); + } + }); } } @@ -250,10 +292,25 @@ public void testAuthenticateWithCodeFlow() throws Exception { verifyElasticsearchAccessTokenForCodeFlow(tokens.v1()); } + public void testAuthenticateWithCodeFlowAndClientPost() throws Exception { + final PrepareAuthResponse prepareAuthResponse = getRedirectedFromFacilitator(REALM_NAME_CLIENT_POST_AUTH); + final String redirectUri = authenticateAtOP(prepareAuthResponse.getAuthUri()); + Tuple tokens = completeAuthentication(redirectUri, prepareAuthResponse.getState(), + prepareAuthResponse.getNonce(), REALM_NAME_CLIENT_POST_AUTH); + verifyElasticsearchAccessTokenForCodeFlow(tokens.v1()); + } + + public void testAuthenticateWithCodeFlowAndClientJwtPost() throws Exception { + final PrepareAuthResponse prepareAuthResponse = getRedirectedFromFacilitator(REALM_NAME_CLIENT_JWT_AUTH); + final String redirectUri = authenticateAtOP(prepareAuthResponse.getAuthUri()); + Tuple tokens = completeAuthentication(redirectUri, prepareAuthResponse.getState(), + prepareAuthResponse.getNonce(), REALM_NAME_CLIENT_JWT_AUTH); + verifyElasticsearchAccessTokenForCodeFlow(tokens.v1()); + } + public void testAuthenticateWithImplicitFlow() throws Exception { final PrepareAuthResponse prepareAuthResponse = getRedirectedFromFacilitator(REALM_NAME_IMPLICIT); final String redirectUri = authenticateAtOP(prepareAuthResponse.getAuthUri()); - Tuple tokens = completeAuthentication(redirectUri, prepareAuthResponse.getState(), prepareAuthResponse.getNonce(), REALM_NAME_IMPLICIT); verifyElasticsearchAccessTokenForImplicitFlow(tokens.v1()); @@ -304,7 +361,6 @@ private void verifyElasticsearchAccessTokenForImplicitFlow(String accessToken) t assertThat(metadata.get("oidc(iss)"), equalTo("http://localhost:8080")); } - private PrepareAuthResponse getRedirectedFromFacilitator(String realmName) throws Exception { final Map body = Collections.singletonMap("realm", realmName); Request request = buildRequest("POST", "/_security/oidc/prepare", body, facilitatorAuth()); @@ -387,7 +443,9 @@ private void setRoleMappings() throws IOException { "\"rules\": {" + " \"any\" : [" + " {\"field\": { \"realm.name\": \"" + REALM_NAME + "\"} }," + - " {\"field\": { \"realm.name\": \"" + REALM_NAME_PROXY + "\"} }" + + " {\"field\": { \"realm.name\": \"" + REALM_NAME_PROXY + "\"} }," + + " {\"field\": { \"realm.name\": \"" + REALM_NAME_CLIENT_POST_AUTH + "\"} }," + + " {\"field\": { \"realm.name\": \"" + REALM_NAME_CLIENT_JWT_AUTH + "\"} }" + " ]" + "}" + "}"); diff --git a/x-pack/test/idp-fixture/docker-compose.yml b/x-pack/test/idp-fixture/docker-compose.yml index 3b46e05552a83..6c65c1b89973d 100644 --- a/x-pack/test/idp-fixture/docker-compose.yml +++ b/x-pack/test/idp-fixture/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.1' services: openldap: command: --copy-service --loglevel debug - image: "osixia/openldap:1.2.3" + image: "osixia/openldap:1.4.0" ports: - "389" - "636" @@ -40,7 +40,7 @@ services: - ./idp/shib-jetty-base/start.d/ssl.ini:/opt/shib-jetty-base/start.d/ssl.ini oidc-provider: - image: "c2id/c2id-server:7.8" + image: "c2id/c2id-server:9.5" depends_on: - http-proxy ports: From 7050759cfb616d9ec60f127868d1ca5382d9eee4 Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Mon, 29 Jun 2020 13:05:58 +0300 Subject: [PATCH 2/6] OIDC: Enable additional client auth types The OpenID Connect specification defines a number of ways for a client (RP) to authenticate itself to the OP when accessing the Token Endpoint. We currently only support `client_secret_basic`. This change introduces support for 2 additional authentication methods, namely `client_secret_post` (where the client credentials are passed in the body of the POST request to the OP) and `client_secret_jwt` where the client constructs a JWT and signs it using the the client secret as a key. Support for the above, and especially `client_secret_jwt` in our integration tests meant that the OP we use ( Connect2id server ) should be able to validate the JWT that we send it from the RP. Since we run the OP in docker and it listens on an ephemeral port we would have no way of knowing the port so that we can configure the ES running via the testcluster to know the "correct" Token Endpoint, and even if we did, this would not be the Token Endpoint URL that the OP would think it listens on. To alleviate this, we run an ES single node cluster in docker, alongside the OP so that we can configured it with the correct hostname and port within the docker network. --- .../oidc/OpenIdConnectAuthenticator.java | 3 - x-pack/qa/oidc-op-tests/build.gradle | 113 +----------- .../authc/oidc/OpenIdConnectAuthIT.java | 172 +++++++++++------- .../src/test/resources/tls/testnode.jks | Bin 0 -> 9903 bytes x-pack/test/idp-fixture/build.gradle | 34 +++- x-pack/test/idp-fixture/docker-compose.yml | 119 +++++++++++- .../idp-fixture/docker-test-entrypoint.sh | 12 ++ .../test/idp-fixture/oidc/override.properties | 6 +- 8 files changed, 270 insertions(+), 189 deletions(-) create mode 100644 x-pack/qa/oidc-op-tests/src/test/resources/tls/testnode.jks create mode 100755 x-pack/test/idp-fixture/docker-test-entrypoint.sh diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java index 81188cc24c624..160f7454b2150 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java @@ -47,10 +47,8 @@ import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; -import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthenticationException; import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; @@ -60,7 +58,6 @@ import org.apache.http.config.RegistryBuilder; import org.apache.http.entity.ContentType; import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; import org.apache.http.impl.nio.client.HttpAsyncClients; diff --git a/x-pack/qa/oidc-op-tests/build.gradle b/x-pack/qa/oidc-op-tests/build.gradle index e346b69d1c711..1a5be2e25e906 100644 --- a/x-pack/qa/oidc-op-tests/build.gradle +++ b/x-pack/qa/oidc-op-tests/build.gradle @@ -1,6 +1,3 @@ -Project idpFixtureProject = xpackProject("test:idp-fixture") - -apply plugin: 'elasticsearch.testclusters' apply plugin: 'elasticsearch.standalone-rest-test' apply plugin: 'elasticsearch.rest-test' apply plugin: 'elasticsearch.test.fixtures' @@ -11,114 +8,6 @@ dependencies { testImplementation project(path: xpackModule('security'), configuration: 'testArtifacts') } testFixtures.useFixture ":x-pack:test:idp-fixture", "oidc-provider" - -String ephemeralOpPort -String ephemeralProxyPort -task setupPorts { - // Don't attempt to get ephemeral ports when Docker is not available - onlyIf { idpFixtureProject.postProcessFixture.state.skipped == false } - dependsOn idpFixtureProject.postProcessFixture - doLast { - ephemeralOpPort = idpFixtureProject.postProcessFixture.ext."test.fixtures.oidc-provider.tcp.8080" - ephemeralProxyPort = idpFixtureProject.postProcessFixture.ext."test.fixtures.http-proxy.tcp.8888" - } -} - -integTest.runner { - dependsOn setupPorts -} - -testClusters.integTest { - testDistribution = 'DEFAULT' - setting 'xpack.license.self_generated.type', 'trial' - setting 'xpack.security.enabled', 'true' - setting 'xpack.security.http.ssl.enabled', 'false' - setting 'xpack.security.authc.token.enabled', 'true' - setting 'xpack.security.authc.realms.file.file.order', '0' - setting 'xpack.security.authc.realms.native.native.order', '1' - // OpenID Connect Realm 1 configured for authorization grant flow - setting 'xpack.security.authc.realms.oidc.c2id.order', '2' - setting 'xpack.security.authc.realms.oidc.c2id.op.issuer', 'http://localhost:8080' - setting 'xpack.security.authc.realms.oidc.c2id.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" } - setting 'xpack.security.authc.realms.oidc.c2id.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" } - setting 'xpack.security.authc.realms.oidc.c2id.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" } - setting 'xpack.security.authc.realms.oidc.c2id.op.jwkset_path', 'op-jwks.json' - setting 'xpack.security.authc.realms.oidc.c2id.rp.redirect_uri', 'https://my.fantastic.rp/cb' - setting 'xpack.security.authc.realms.oidc.c2id.rp.client_id', 'https://my.elasticsearch.org/rp' - keystore 'xpack.security.authc.realms.oidc.c2id.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2' - setting 'xpack.security.authc.realms.oidc.c2id.rp.response_type', 'code' - setting 'xpack.security.authc.realms.oidc.c2id.claims.principal', 'sub' - setting 'xpack.security.authc.realms.oidc.c2id.claims.name', 'name' - setting 'xpack.security.authc.realms.oidc.c2id.claims.mail', 'email' - setting 'xpack.security.authc.realms.oidc.c2id.claims.groups', 'groups' - // OpenID Connect Realm 2 configured for implicit flow - setting 'xpack.security.authc.realms.oidc.c2id-implicit.order', '3' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.issuer', 'http://localhost:8080' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" } - setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" } - setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" } - setting 'xpack.security.authc.realms.oidc.c2id-implicit.op.jwkset_path', 'op-jwks.json' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.rp.redirect_uri', 'https://my.fantastic.rp/cb' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.rp.client_id', 'elasticsearch-rp' - keystore 'xpack.security.authc.realms.oidc.c2id-implicit.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.rp.response_type', 'id_token token' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.claims.principal', 'sub' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.claims.name', 'name' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.claims.mail', 'email' - setting 'xpack.security.authc.realms.oidc.c2id-implicit.claims.groups', 'groups' - // OpenID Connect Realm 3 configured to use a proxy - setting 'xpack.security.authc.realms.oidc.c2id-proxy.order', '4' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.issuer', 'http://localhost:8080' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" } - setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" } - setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" } - setting 'xpack.security.authc.realms.oidc.c2id-proxy.op.jwkset_path', 'op-jwks.json' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.rp.redirect_uri', 'https://my.fantastic.rp/cb' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.rp.client_id', 'https://my.elasticsearch.org/rp' - keystore 'xpack.security.authc.realms.oidc.c2id-proxy.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.rp.response_type', 'code' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.principal', 'sub' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.name', 'name' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.mail', 'email' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.claims.groups', 'groups' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.host', '127.0.0.1' - setting 'xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.port', {"${ephemeralProxyPort}"} - // OpenID Connect Realm 4 configured for client_secret_post authentication - setting 'xpack.security.authc.realms.oidc.c2id-post.order', '5' - setting 'xpack.security.authc.realms.oidc.c2id-post.op.issuer', 'http://localhost:8080' - setting 'xpack.security.authc.realms.oidc.c2id-post.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" } - setting 'xpack.security.authc.realms.oidc.c2id-post.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" } - setting 'xpack.security.authc.realms.oidc.c2id-post.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" } - setting 'xpack.security.authc.realms.oidc.c2id-post.op.jwkset_path', 'op-jwks.json' - setting 'xpack.security.authc.realms.oidc.c2id-post.rp.redirect_uri', 'https://my.fantastic.rp/cb' - setting 'xpack.security.authc.realms.oidc.c2id-post.rp.client_id', 'elasticsearch-post' - setting 'xpack.security.authc.realms.oidc.c2id-post.rp.client_auth_method', 'client_secret_post' - keystore 'xpack.security.authc.realms.oidc.c2id-post.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2' - setting 'xpack.security.authc.realms.oidc.c2id-post.rp.response_type', 'code' - setting 'xpack.security.authc.realms.oidc.c2id-post.claims.principal', 'sub' - setting 'xpack.security.authc.realms.oidc.c2id-post.claims.name', 'name' - setting 'xpack.security.authc.realms.oidc.c2id-post.claims.mail', 'email' - setting 'xpack.security.authc.realms.oidc.c2id-post.claims.groups', 'groups' - // OpenID Connect Realm 5 configured for client_secret_jwt authentication - setting 'xpack.security.authc.realms.oidc.c2id-jwt.order', '6' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.issuer', 'http://localhost:8080' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.authorization_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id-login" } - setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.token_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/token" } - setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralOpPort}/c2id/userinfo" } - setting 'xpack.security.authc.realms.oidc.c2id-jwt.op.jwkset_path', 'op-jwks.json' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.rp.redirect_uri', 'https://my.fantastic.rp/cb' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.rp.client_id', 'elasticsearch-post-jwt' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.rp.client_auth_method', 'client_secret_jwt' - keystore 'xpack.security.authc.realms.oidc.c2id-jwt.rp.client_secret', 'b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.rp.response_type', 'code' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.claims.principal', 'sub' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.claims.name', 'name' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.claims.mail', 'email' - setting 'xpack.security.authc.realms.oidc.c2id-jwt.claims.groups', 'groups' - setting 'xpack.ml.enabled', 'false' - extraConfigFile 'op-jwks.json', idpFixtureProject.file("oidc/op-jwks.json") - setting 'logger.org.elasticsearch.xpack.security.authc.oidc', 'TRACE' - user username: "test_admin", password: "x-pack-test-password" -} +testFixtures.useFixture ":x-pack:test:idp-fixture", "elasticsearch-node" thirdPartyAudit.enabled = false diff --git a/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java b/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java index bb844f1ff5080..a932d1db8e5ff 100644 --- a/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java +++ b/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java @@ -9,6 +9,7 @@ import net.minidev.json.parser.JSONParser; import org.apache.http.Header; import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.config.RequestConfig; @@ -29,10 +30,12 @@ import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; +import org.elasticsearch.client.RestClient; import org.elasticsearch.common.CheckedFunction; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.collect.Tuple; +import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; @@ -47,8 +50,11 @@ import org.junit.Before; import org.junit.BeforeClass; +import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; +import java.net.URL; +import java.nio.file.Path; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -68,15 +74,28 @@ public class OpenIdConnectAuthIT extends ESRestTestCase { private static final String REALM_NAME_CLIENT_POST_AUTH = "c2id-post"; private static final String REALM_NAME_CLIENT_JWT_AUTH = "c2id-jwt"; private static final String FACILITATOR_PASSWORD = "f@cilit@t0r"; - private static final String REGISTRATION_URL = "http://127.0.0.1:" + getEphemeralPortFromProperty("8080") + "/c2id/clients"; - private static final String LOGIN_API = "http://127.0.0.1:" + getEphemeralPortFromProperty("8080") + "/c2id-login/api/"; + private static final String REGISTRATION_URL = "http://127.0.0.1:" + getEphemeralTcpPortFromProperty("oidc-provider", "8080") + + "/c2id/clients"; + private static final String LOGIN_API = "http://127.0.0.1:" + getEphemeralTcpPortFromProperty("oidc-provider", "8080") + + "/c2id-login/api/"; + private static final String ES_PORT = getEphemeralTcpPortFromProperty("elasticsearch-node", "9200"); + private static Path HTTP_TRUSTSTORE; @Before - public void setupUserAndRoles() throws IOException { + public void setupUserAndRoles() throws Exception { setFacilitatorUser(); setRoleMappings(); } + @BeforeClass + public static void readTrustStore() throws Exception { + final URL resource = OpenIdConnectAuthIT.class.getResource("/tls/testnode.jks"); + if (resource == null) { + throw new FileNotFoundException("Cannot find classpath resource /tls/testnode.jks"); + } + HTTP_TRUSTSTORE = PathUtils.get(resource.toURI()); + } + /** * C2id server only supports dynamic registration, so we can't pre-seed it's config with our client data. Execute only once */ @@ -158,9 +177,11 @@ public static void registerClients() throws Exception { @Override protected Settings restAdminSettings() { - String token = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray())); + String token = basicAuthHeaderValue("x_pack_rest_user", new SecureString("x-pack-test-password".toCharArray())); return Settings.builder() .put(ThreadContext.PREFIX + ".Authorization", token) + .put(TRUSTSTORE_PATH, HTTP_TRUSTSTORE) + .put(TRUSTSTORE_PASSWORD, "testnode") .build(); } @@ -235,19 +256,21 @@ private String authenticateAtOP(URI opAuthUri) throws Exception { } } - private static String getEphemeralPortFromProperty(String port) { - String key = "test.fixtures.oidc-provider.tcp." + port; + private static String getEphemeralTcpPortFromProperty(String service, String port) { + String key = "test.fixtures." + service + ".tcp." + port; final String value = System.getProperty(key); assertNotNull("Expected the actual value for port " + port + " to be in system property " + key, value); return value; } - private Map callAuthenticateApiUsingAccessToken(String accessToken) throws IOException { + private Map callAuthenticateApiUsingAccessToken(String accessToken) throws Exception { Request request = new Request("GET", "/_security/_authenticate"); RequestOptions.Builder options = request.getOptions().toBuilder(); options.addHeader("Authorization", "Bearer " + accessToken); request.setOptions(options); - return entityAsMap(client().performRequest(request)); + try (RestClient restClient = getClient()) { + return entityAsMap(restClient.performRequest(request)); + } } private T execute(CloseableHttpClient client, HttpEntityEnclosingRequestBase request, @@ -337,7 +360,7 @@ public void testAuthenticateWithCodeFlowFailsForWrongRealm() throws Exception { assertThat(401, equalTo(e.getResponse().getStatusLine().getStatusCode())); } - private void verifyElasticsearchAccessTokenForCodeFlow(String accessToken) throws IOException { + private void verifyElasticsearchAccessTokenForCodeFlow(String accessToken) throws Exception { final Map map = callAuthenticateApiUsingAccessToken(accessToken); logger.info("Authentication with token Response: " + map); assertThat(map.get("username"), equalTo("alice")); @@ -346,10 +369,10 @@ private void verifyElasticsearchAccessTokenForCodeFlow(String accessToken) throw assertThat(map.get("metadata"), instanceOf(Map.class)); final Map metadata = (Map) map.get("metadata"); assertThat(metadata.get("oidc(sub)"), equalTo("alice")); - assertThat(metadata.get("oidc(iss)"), equalTo("http://localhost:8080")); + assertThat(metadata.get("oidc(iss)"), equalTo("http://oidc-provider:8080/c2id")); } - private void verifyElasticsearchAccessTokenForImplicitFlow(String accessToken) throws IOException { + private void verifyElasticsearchAccessTokenForImplicitFlow(String accessToken) throws Exception { final Map map = callAuthenticateApiUsingAccessToken(accessToken); logger.info("Authentication with token Response: " + map); assertThat(map.get("username"), equalTo("alice")); @@ -358,21 +381,23 @@ private void verifyElasticsearchAccessTokenForImplicitFlow(String accessToken) t assertThat(map.get("metadata"), instanceOf(Map.class)); final Map metadata = (Map) map.get("metadata"); assertThat(metadata.get("oidc(sub)"), equalTo("alice")); - assertThat(metadata.get("oidc(iss)"), equalTo("http://localhost:8080")); + assertThat(metadata.get("oidc(iss)"), equalTo("http://oidc-provider:8080/c2id")); } private PrepareAuthResponse getRedirectedFromFacilitator(String realmName) throws Exception { final Map body = Collections.singletonMap("realm", realmName); - Request request = buildRequest("POST", "/_security/oidc/prepare", body, facilitatorAuth()); - final Response prepare = client().performRequest(request); - assertOK(prepare); - final Map responseBody = parseResponseAsMap(prepare.getEntity()); - logger.info("Created OpenIDConnect authentication request {}", responseBody); - final String state = (String) responseBody.get("state"); - final String nonce = (String) responseBody.get("nonce"); - final String authUri = (String) responseBody.get("redirect"); - final String realm = (String) responseBody.get("realm"); - return new PrepareAuthResponse(new URI(authUri), state, nonce, realm); + Request request = buildRequest("POST", "/_security/oidc/prepare?error_trace=true", body, facilitatorAuth()); + try (RestClient restClient = getClient()) { + final Response prepare = restClient.performRequest(request); + assertOK(prepare); + final Map responseBody = parseResponseAsMap(prepare.getEntity()); + logger.info("Created OpenIDConnect authentication request {}", responseBody); + final String state = (String) responseBody.get("state"); + final String nonce = (String) responseBody.get("nonce"); + final String authUri = (String) responseBody.get("redirect"); + final String realm = (String) responseBody.get("realm"); + return new PrepareAuthResponse(new URI(authUri), state, nonce, realm); + } } private Tuple completeAuthentication(String redirectUri, String state, String nonce, @Nullable String realm) @@ -381,17 +406,19 @@ private Tuple completeAuthentication(String redirectUri, String body.put("redirect_uri", redirectUri); body.put("state", state); body.put("nonce", nonce); - if (realm != null){ + if (realm != null) { body.put("realm", realm); } Request request = buildRequest("POST", "/_security/oidc/authenticate", body, facilitatorAuth()); - final Response authenticate = client().performRequest(request); - assertOK(authenticate); - final Map responseBody = parseResponseAsMap(authenticate.getEntity()); - logger.info(" OpenIDConnect authentication response {}", responseBody); - assertNotNull(responseBody.get("access_token")); - assertNotNull(responseBody.get("refresh_token")); - return Tuple.tuple(responseBody.get("access_token").toString(), responseBody.get("refresh_token").toString()); + try (RestClient restClient = getClient()) { + final Response authenticate = restClient.performRequest(request); + assertOK(authenticate); + final Map responseBody = parseResponseAsMap(authenticate.getEntity()); + logger.info(" OpenIDConnect authentication response {}", responseBody); + assertNotNull(responseBody.get("access_token")); + assertNotNull(responseBody.get("refresh_token")); + return Tuple.tuple(responseBody.get("access_token").toString(), responseBody.get("refresh_token").toString()); + } } private Request buildRequest(String method, String endpoint, Map body, Header... headers) throws IOException { @@ -427,49 +454,56 @@ private void assertHttpOk(StatusLine status) { * We create a user named `facilitator` with the appropriate privileges ( `manage_oidc` ). A facilitator web app * would need to create one also, in order to access the OIDC related APIs on behalf of the user. */ - private void setFacilitatorUser() throws IOException { - Request createRoleRequest = new Request("PUT", "/_security/role/facilitator"); - createRoleRequest.setJsonEntity("{ \"cluster\" : [\"manage_oidc\", \"manage_token\"] }"); - adminClient().performRequest(createRoleRequest); - Request createUserRequest = new Request("PUT", "/_security/user/facilitator"); - createUserRequest.setJsonEntity("{ \"password\" : \"" + FACILITATOR_PASSWORD + "\", \"roles\" : [\"facilitator\"] }"); - adminClient().performRequest(createUserRequest); + private void setFacilitatorUser() throws Exception { + try (RestClient restClient = getClient()) { + Request createRoleRequest = new Request("PUT", "/_security/role/facilitator"); + createRoleRequest.setJsonEntity("{ \"cluster\" : [\"manage_oidc\", \"manage_token\"] }"); + restClient.performRequest(createRoleRequest); + Request createUserRequest = new Request("PUT", "/_security/user/facilitator"); + createUserRequest.setJsonEntity("{ \"password\" : \"" + FACILITATOR_PASSWORD + "\", \"roles\" : [\"facilitator\"] }"); + restClient.performRequest(createUserRequest); + } } - private void setRoleMappings() throws IOException { - Request createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_kibana"); - createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"kibana_admin\"]," + - "\"enabled\": true," + - "\"rules\": {" + - " \"any\" : [" + - " {\"field\": { \"realm.name\": \"" + REALM_NAME + "\"} }," + - " {\"field\": { \"realm.name\": \"" + REALM_NAME_PROXY + "\"} }," + - " {\"field\": { \"realm.name\": \"" + REALM_NAME_CLIENT_POST_AUTH + "\"} }," + - " {\"field\": { \"realm.name\": \"" + REALM_NAME_CLIENT_JWT_AUTH + "\"} }" + - " ]" + - "}" + - "}"); - adminClient().performRequest(createRoleMappingRequest); - - createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_limited"); - createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"limited_user\"]," + - "\"enabled\": true," + - "\"rules\": {" + - "\"field\": { \"realm.name\": \"" + REALM_NAME_IMPLICIT + "\"}" + - "}" + - "}"); - adminClient().performRequest(createRoleMappingRequest); - - createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_auditor"); - createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"auditor\"]," + - "\"enabled\": true," + - "\"rules\": {" + - "\"field\": { \"groups\": \"audit\"}" + - "}" + - "}"); - adminClient().performRequest(createRoleMappingRequest); + private void setRoleMappings() throws Exception { + try (RestClient restClient = getClient()) { + Request createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_kibana"); + createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"kibana_admin\"]," + + "\"enabled\": true," + + "\"rules\": {" + + " \"any\" : [" + + " {\"field\": { \"realm.name\": \"" + REALM_NAME + "\"} }," + + " {\"field\": { \"realm.name\": \"" + REALM_NAME_PROXY + "\"} }," + + " {\"field\": { \"realm.name\": \"" + REALM_NAME_CLIENT_POST_AUTH + "\"} }," + + " {\"field\": { \"realm.name\": \"" + REALM_NAME_CLIENT_JWT_AUTH + "\"} }" + + " ]" + + "}" + + "}"); + restClient.performRequest(createRoleMappingRequest); + + createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_limited"); + createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"limited_user\"]," + + "\"enabled\": true," + + "\"rules\": {" + + "\"field\": { \"realm.name\": \"" + REALM_NAME_IMPLICIT + "\"}" + + "}" + + "}"); + restClient.performRequest(createRoleMappingRequest); + + createRoleMappingRequest = new Request("PUT", "/_security/role_mapping/oidc_auditor"); + createRoleMappingRequest.setJsonEntity("{ \"roles\" : [\"auditor\"]," + + "\"enabled\": true," + + "\"rules\": {" + + "\"field\": { \"groups\": \"audit\"}" + + "}" + + "}"); + restClient.performRequest(createRoleMappingRequest); + } } + private RestClient getClient() throws Exception { + return buildClient(restAdminSettings(), new HttpHost[]{new HttpHost("localhost", Integer.parseInt(ES_PORT), "https")}); + } /** * Simple POJO encapsulating a response to calling /_security/oidc/prepare diff --git a/x-pack/qa/oidc-op-tests/src/test/resources/tls/testnode.jks b/x-pack/qa/oidc-op-tests/src/test/resources/tls/testnode.jks new file mode 100644 index 0000000000000000000000000000000000000000..7c0c4f1aae7fb00ae4f1323d9a51367b615e3e3c GIT binary patch literal 9903 zcmeI22UJtry6=+^=}0fqiy)nZj`S)Zy*H^z04b3UQWKi=s&tVK(nL_I^p1d3MY^CO zARsCT2)v-~z44rP-ag}wJMO!8yvGIY~tU0sh_xs9!a`N%yBLDyZVLo`64-i1$ z3HR`HMZ(}#a661`=i<428*?ET5(v47jn9J(1OvH2q(I;W0NAPg;_(y1?gX-W6n{o< z#;7b15TdCuH$!a+Xm(2qGTvvq==;KVHU8z@(d}@m&ZgH%6}ofX>JicR6*Z$`lOqw6 zp4`{;{a(W$_%zx_{rVw&$oFC(Y zfWIby1;oKp0D!mPmyBtH$0WL%`}Ne`tL%-%EE#*rP^G$!2LumtQYBQ_l601sKAp@S z=HRrVpR?&rNtcrFc<)?&yGf?9u-&f!RR=-UKo~GTg5e^V3QVC1uxs9ev(ObLwuHaX zY_g!nvzmdR63(uZf>DtWR2Ul18EI$Z?11#}L{t8G$p7OAhIFxUbVcL;d0H4v{nzpN zdxX#3Bzo>9(epQnMuLMeD-lV8S()>Hz~9#aOBDc71~J>a3wR?Wc#X|_!}V$(8onO) zJJ1%J<8+;P=OGh+#9|0y0gUzO8b(jKKBv9eNpbHW)2SYIUB*=5%?J<|U*#eb>ojH% z5CG4{&ePEw4s&$JjBUt0d8i8b!zr+4A!w|Z5HzUmr&Exa5H(clHB&{)g)A?UamyM( zh_LZ63l*_X1OyUbJR}H84k5+H$4lmjO4;Rw0WVQu*&$t^3=q2CP7=Y-dk>TXLiXEb z@EI>qG6>0UXF)bFC?kaar~gsf!1$Ck-_ zEQs+wL5ZKH(3$yveST;l>-krPAs!12BnDux!v~>(KtQb~qJ7}d#F_k1fmIP+Uft72 zurI9{`%N=g?MXTBbt{)=a$0`JJ5td2#DWP8vax3Gjg!w+q=N%N*PZB-XKP45Juc&8 zYbfh6dM-$kqYs<$>8K2AyGq<7BQVtUy{P`E`{)CX30mGGv?*p?8;32nfLr53ga5SB zYGL(7jl-pN-r1$YvcSG|+%8e8a zEG>tt>_({r29D~g156=uC6jkEs*?KnD_t2GS5I4b22A#{G&JZZ9tl4oBUeA2uhFT0 z;SBr!GQxX5T6qqvL6R#i_U=APpfyFN^Pw24y;T-g9taBv02b&%v>^m%2oi%afd?1? zAwDz6fxuJn1qc@A>m0x+d^&|3HGNoi2_ZsdBK4u9SQi_{aqxabRkRo-@azeI^DiCa zro_8u zjGh|JU$%xUu&qr*w`sE%!rC2qy>VxE?u;21iRr%)pm^P1;gH)9DH}zlxWr|1Kl|41 ziwe}>T$ZeY{-e0J^y&ucrt2|H2`JZsnbti5^Qim#YZO1t%c8YX*UQGl<9)+}rAGrF_z4|UK z$N9|r2mH9mTX0urn9VH=`!~WrUEu$deehKX8Z3(8pYbRAcz}s;0-j5EE3MAI%nKOk zkx&8%-WitIVb0@|Xayl<>HO$8ZNLn`obwxAM%^NxzS76m;7+XFyp2R zt4Y!|K9o3J>?5JfJlR#^ao^zsP|88+P_@gLCE}PAHeo)0kw4q3^9#^lU?MTY)---% z@k8PRvAa2ilCOu<8VNdhpr;Kj<1n-g@fN zNW5cKS$_e6&B`2hbco z+Yy+LTiPHua@`nN|74)iQhHM2dw2{{pA6LxoVixZ{*j?+pq0;G3lVjj+?t&Lk4$1p zTJ@-1B*FWw!R~QP!Oze_?&|FZM{&9V~+ApFxUU>-J@ z>|^KR@1u+PPQVmHG5^#Tp@BY2cmOTy$u}8`hfP4GAj)_PQV-@Klc>GDrw{YzIBq+dN`qXbc&bOPruF6JZ$^_t_xME3R3IcIVL-6HS zm&hvRar3Mmu#Qj#!m<8CZKALcRQz0<_{03S+C((49^)&#KU+m{Fc4!fflw&Gaj-s$ z!HbMbZ&5v)e{=Qy9%;Rv)V30!i%~Y@sV;}3@(npw-6K=!IFrM+p07=iy`d~a=a(qS z5C&o7F2cIrDMP2IFgJG%>`%hlsoh-m@}$0(?wh3X``*%GN@DO)=-xyRV;4xofZU8K zNpR2Wa}|%xOYZGmR;)`oW2(SD5G5eZS|@>$jo|s?V16F=@>iPhpV4WW_IMf}}^Vete@Ng=Z)J?gb{sX1I;-34DxMw?Q5o7=WT)@JV+o%5=_rM$X z=4{P&U)iZ`^aGe4-cbqq*yZPh?MnNu58Lh-aIL21c7WbEb3DR(g_4zb5gxUyDB0Hf zeN1R=$pcX!%HoRrw&{I&Yp4CyoV~Uv-K^HiU`j(NjkC)K(!H1gh@_R)ePWm?Of05o zpw3$*s(&=YU%!dAxpZR8%V4U)G$f)=v&p-78=nw|Tt^h((bx99-jxB4bjn*bMz=8S z8%{U3Qtor8!ql3-;UU0vyGE<>WlS6HcZnwZ!NA=_|6Mt7^ro0v@+z_slrCH@6TzsT z{aPTbY-g*-fzu`6lo=W%C81+tWm6nn^L-FVOb5OMubEGKNG-2J<9czfhF>~!WWfPf zX3Dw<6#}@F(ae+8Yq^6EAkFEg*fIOaGPoxouL9KSG=Z@WFHhv?u!@{I)hRwuzfAZ+ zXZGd%-fr9U(#VeFZj~v1U%5+_%4Nq)l9EoE^~uYtF;D3zaIK?jd0J$yR?m*y!5eX% zdj9_2&1aF^y``Niv;QZw?a2Z0J2`?%J17fM7ix(VkUJqT_sj4GBO?rK^2BvGM#>Pa|-m2|gDQIg+Qu5|~vFvT~qB`!Y0 zUtFmf6BH_p5WnnPhLBogo#-^R&uFHfXY0=C@&h}gH*E(zCK{V%>E91pH7hys9`N-N zvMbwU8OegQyQq$x@WSC`Df{a9v9!9~we4EXqQjZW4RHYnJK?S=SiaqrHVm*2hP8K> z59_7%jfrv7)W&fwBBOXRCwDguJox$gHipOac@fI}9_=sahxpCktm;a&;;hZ;FjNa6 z2Q+2qc`B8}-m+Zef@KBB+l6>#45^Oij|>|g9ST$p?RSQLSYgdtygvaWRsyCRd~0s67gjI;9i3Ygq?AM7m}adNd~9iZp7{DVeF4 z9_hS7Vv<%)O8JtHR;yvY#HmlPT`nsYj}aSRxo7T5kxbO})9_L2er7fav|MfSP+hT0 z4rBewRe|~Ce&vkI6__1~gpc-fp0u`G9&9dw$v9tiou+|rVUpo>p#jT_z` zp&t$_tG1fyeSWg$RNm<8jEu<)TUpE2rm^NtxYt87317cei$l*M&s(8zo$9NfaD8Cm zqlOdhyxhrqkly9q_m_v>h#%m}zk5U^9c{m>!^6N#OYXs2z6}p%ZUc&R(l+qg-yFCj zI4b^X)^#R{g|Igz(9mmoUF8Z))v`3nFh7e$)>gE>XlBzkqV97eed^7*E4k>$4jKMI z5h6a_>dypejAO!wT6Ylr9A5RWr)5WC=)NGW0zz(e?=x?DKbgI@=bZz&>k(n*x009= zP*Y^HC~-)G&4d<_ z2vc6CabL5t6-|e?GQlM9I#O-(E53)FQPlXFYA41;ueVE94VClq^zoX6|u* zJ0?QCO5RJjlt{{PuxnF|_2gH4&Pgx9%1WpOTO5iUs6A$@ zD}_F1tad=IJ}X;*muLqGPII;IPslP2i*0I2~Ce7@bi{Ldh)A!reU`5sr2? zo^WOZB+{8#-pdnd4|j#TW6r>sf9(~BLj<9iy((b|DD+H4gkntLUnYbUN{kuk$5XLA zY+P(@gfR`q|5?7Tq@kzH-5L;c+VNxOwPh5NaR^Y_1s}Rm##X}n4%><3Og<{x1&V^c z^{8`SsfBMXS+nVHrl>m!eL(3+`+F<%5Ks0-#gx%iwFa4MF+Hgp5_8;>_-0cZ(?p!E z(jn=?7%Km!VlsuO(kZCvQVtdV?i)t6d)W%NsP@(2EP|31BrbbbTg|77oQ=8$>bpW_ zPX+`!s|9)U4jL+J6z17TZ4M{a{C6(WjASD4;r)$$&Ca<>CkvDL*W!U)xm{>Bzofu- zCu)HYi7fNNv+y*Yc$OvJZ6!j+#Cg#6H-S19#XFL|Y1k`9=I=*G9;g8?Pe*IRdWfA! zBRL@#A6MFD^C#k@3x_iR8? zFgt|p+>YMA+;BV7vwwx0bNb#NTL<#%+J=!y9RU|t9`uK}ZG*CP4J4S%(rxv;daN6#Q4etISEVB%8)~I)u*pL>zbA;*F0@r z1W(Zs?u0W*JZo|-=)a%3GW6*diNrxWg;G>BzjFY)xIJj;$fr6Taf9od!Fp3-T|;pQ zvNvm?T0CQ6NTp3Pb-Hqg7Sn|$F8AHI91^A=p*Gd1ZX`E2<_kh_Q|;w;Q9t=M7v8ax zG^G5NDUJ$d&V3{+Ufd&N&X$Dq?6b;T!ilKb^N+Py59cIsVrP|Yz_)jcetok@bhinG ziVU!9whJqW>DsD}et_RR;D0>ygJ9}E1ROp)XGgfJC*Li1B*M`dj$vB+C=R;+7t=8q zrXw*-BmYR`?du9uYp2Ao{t@K!8_fUW=|9B(zf!d5?^J4$Up?dRI9~p0nEXyb zQtjABSEhOx5&e5V%)9^znPY&(M{kwsEwOETg^~y-F!7=Veb`+L%J{oJA7vZxl2sn9LkoP@p&yM+4(zJuyrW55%imCcM2V!MPznMUz z!aCiquA?4ZJMH*EJ}r>TB5a9%x%evwv2&LC^XO9|du#YDV-}_R8*tWMs@mx3&gNHn zfx$Q<_gW@^PH%g#{j^?q`VEN5W+e|M&R$x`LDTFHOL3H@DBikWkI&k3Cxj|IHG$x*6o-g*LN%TdAvP) zH+0pS%&VMpFW%%8erONro3Np=b`=yqrQsyyhwDS9Bz2L-oyC7PA<92TCOe?;TP=lLIN`tIXEN7PPBOQho5(c>1 z_V}Rgsw)K?`dPIs)~~Fe)0DtLn%bZ=MqxX6bmD4N$O~T}CvNU{j@}Zw{=8YPTq*ZU z4Rh(t>r=Pohi65ux_a4v{@m%8T5!G8uP0W9!_xY>t!(bHA6{+>BkFtM2p8@B8fA+Q zcLKf9pGfI&$(Tjvb5E<_=_hY=C39_vl-Vj*OD@tN1FI|lmi}Za5@XT(?GCT|yiGvH zYG`sv|C|3a=qGByWANJjl$+3j7f)b!tfcMZ55IIH)?hatI%b{IX-zq8SgP?@;S)=T zrdu^lY{|>KV2)eWadOr3z?w+QGRX}#_TabE2)BRqN*%Y-ROyAooj z^?c(TT04GMfp+wwynbdX^~}&z%Vo;jd!%VJl>NLGId{>UcazBOmA}m=mNTXKpc96+ zxTViN%aARhebjU#KRSnhX|&t6gXZ?9mwIw(VT}BiZ=xoNpN` literal 0 HcmV?d00001 diff --git a/x-pack/test/idp-fixture/build.gradle b/x-pack/test/idp-fixture/build.gradle index c55123e08d0f1..826288808a801 100644 --- a/x-pack/test/idp-fixture/build.gradle +++ b/x-pack/test/idp-fixture/build.gradle @@ -1,4 +1,36 @@ +import org.elasticsearch.gradle.VersionProperties +import org.elasticsearch.gradle.Architecture + apply plugin: 'elasticsearch.build' apply plugin: 'elasticsearch.test.fixtures' +apply plugin: 'elasticsearch.distribution-download' + +test.enabled = false + +task copyKeystore(type: Sync) { + from project(':x-pack:plugin:core') + .file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks') + into "${buildDir}/certs" + doLast { + file("${buildDir}/certs").setReadable(true, false) + file("${buildDir}/certs/testnode.jks").setReadable(true, false) + } +} -test.enabled = false \ No newline at end of file +elasticsearch_distributions { + docker { + type = 'docker' + architecture = Architecture.current() + flavor = System.getProperty('tests.distribution', 'default') + version = VersionProperties.getElasticsearch() + failIfUnavailable = false // This ensures we skip this testing if Docker is unavailable + } +} +preProcessFixture { + dependsOn copyKeystore, elasticsearch_distributions.docker + doLast { + File file = file("${buildDir}/logs/node1") + file.mkdirs() + file.setWritable(true, false) + } +} diff --git a/x-pack/test/idp-fixture/docker-compose.yml b/x-pack/test/idp-fixture/docker-compose.yml index 6c65c1b89973d..0386644c40373 100644 --- a/x-pack/test/idp-fixture/docker-compose.yml +++ b/x-pack/test/idp-fixture/docker-compose.yml @@ -1,5 +1,118 @@ -version: '3.1' +version: '3.7' services: + elasticsearch-node: + image: elasticsearch:test + environment: + - node.name=elasticsearch-node + - cluster.initial_master_nodes=elasticsearch-node + - cluster.name=elasticsearch-node + - bootstrap.memory_lock=true + - network.publish_host=127.0.0.1 + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + - path.repo=/tmp/es-repo + - node.attr.testattr=test + - cluster.routing.allocation.disk.watermark.low=1b + - cluster.routing.allocation.disk.watermark.high=1b + - cluster.routing.allocation.disk.watermark.flood_stage=1b + - node.store.allow_mmap=false + - xpack.license.self_generated.type=trial + - xpack.security.enabled=true + - xpack.security.http.ssl.enabled=true + - xpack.security.http.ssl.keystore.path=testnode.jks + - xpack.security.authc.token.enabled=true + - xpack.security.authc.realms.file.file.order=0 + - xpack.security.authc.realms.native.native.order=1 + - xpack.security.authc.realms.oidc.c2id.order=2 + - xpack.security.authc.realms.oidc.c2id.op.issuer=http://oidc-provider:8080/c2id + - xpack.security.authc.realms.oidc.c2id.op.authorization_endpoint=http://oidc-provider:8080/c2id-login + - xpack.security.authc.realms.oidc.c2id.op.token_endpoint=http://oidc-provider:8080/c2id/token + - xpack.security.authc.realms.oidc.c2id.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo + - xpack.security.authc.realms.oidc.c2id.op.jwkset_path=op-jwks.json + - xpack.security.authc.realms.oidc.c2id.rp.redirect_uri=https://my.fantastic.rp/cb + - xpack.security.authc.realms.oidc.c2id.rp.client_id=https://my.elasticsearch.org/rp + - xpack.security.authc.realms.oidc.c2id.rp.response_type=code + - xpack.security.authc.realms.oidc.c2id.claims.principal=sub + - xpack.security.authc.realms.oidc.c2id.claims.name=name + - xpack.security.authc.realms.oidc.c2id.claims.mail=email + - xpack.security.authc.realms.oidc.c2id.claims.groups=groups + - xpack.security.authc.realms.oidc.c2id-implicit.order=3 + - xpack.security.authc.realms.oidc.c2id-implicit.op.issuer=http://oidc-provider:8080/c2id + - xpack.security.authc.realms.oidc.c2id-implicit.op.authorization_endpoint=http://oidc-provider:8080/c2id-login + - xpack.security.authc.realms.oidc.c2id-implicit.op.token_endpoint=http://oidc-provider:8080/c2id/token + - xpack.security.authc.realms.oidc.c2id-implicit.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo + - xpack.security.authc.realms.oidc.c2id-implicit.op.jwkset_path=op-jwks.json + - xpack.security.authc.realms.oidc.c2id-implicit.rp.redirect_uri=https://my.fantastic.rp/cb + - xpack.security.authc.realms.oidc.c2id-implicit.rp.client_id=elasticsearch-rp + - xpack.security.authc.realms.oidc.c2id-implicit.rp.response_type=id_token token + - xpack.security.authc.realms.oidc.c2id-implicit.claims.principal=sub + - xpack.security.authc.realms.oidc.c2id-implicit.claims.name=name + - xpack.security.authc.realms.oidc.c2id-implicit.claims.mail=email + - xpack.security.authc.realms.oidc.c2id-implicit.claims.groups=groups + - xpack.security.authc.realms.oidc.c2id-proxy.order=4 + - xpack.security.authc.realms.oidc.c2id-proxy.op.issuer=http://oidc-provider:8080/c2id + - xpack.security.authc.realms.oidc.c2id-proxy.op.authorization_endpoint=http://oidc-provider:8080/c2id-login + - xpack.security.authc.realms.oidc.c2id-proxy.op.token_endpoint=http://oidc-provider:8080/c2id/token + - xpack.security.authc.realms.oidc.c2id-proxy.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo + - xpack.security.authc.realms.oidc.c2id-proxy.op.jwkset_path=op-jwks.json + - xpack.security.authc.realms.oidc.c2id-proxy.rp.redirect_uri=https://my.fantastic.rp/cb + - xpack.security.authc.realms.oidc.c2id-proxy.rp.client_id=https://my.elasticsearch.org/rp + - xpack.security.authc.realms.oidc.c2id-proxy.rp.response_type=code + - xpack.security.authc.realms.oidc.c2id-proxy.claims.principal=sub + - xpack.security.authc.realms.oidc.c2id-proxy.claims.name=name + - xpack.security.authc.realms.oidc.c2id-proxy.claims.mail=email + - xpack.security.authc.realms.oidc.c2id-proxy.claims.groups=groups + - xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.host=http-proxy + - xpack.security.authc.realms.oidc.c2id-proxy.http.proxy.port=8888 + - xpack.security.authc.realms.oidc.c2id-post.order=5 + - xpack.security.authc.realms.oidc.c2id-post.op.issuer=http://oidc-provider:8080/c2id + - xpack.security.authc.realms.oidc.c2id-post.op.authorization_endpoint=http://oidc-provider:8080/c2id-login + - xpack.security.authc.realms.oidc.c2id-post.op.token_endpoint=http://oidc-provider:8080/c2id/token + - xpack.security.authc.realms.oidc.c2id-post.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo + - xpack.security.authc.realms.oidc.c2id-post.op.jwkset_path=op-jwks.json + - xpack.security.authc.realms.oidc.c2id-post.rp.redirect_uri=https://my.fantastic.rp/cb + - xpack.security.authc.realms.oidc.c2id-post.rp.client_id=elasticsearch-post + - xpack.security.authc.realms.oidc.c2id-post.rp.client_auth_method=client_secret_post + - xpack.security.authc.realms.oidc.c2id-post.rp.response_type=code + - xpack.security.authc.realms.oidc.c2id-post.claims.principal=sub + - xpack.security.authc.realms.oidc.c2id-post.claims.name=name + - xpack.security.authc.realms.oidc.c2id-post.claims.mail=email + - xpack.security.authc.realms.oidc.c2id-post.claims.groups=groups + - xpack.security.authc.realms.oidc.c2id-jwt.order=6 + - xpack.security.authc.realms.oidc.c2id-jwt.op.issuer=http://oidc-provider:8080/c2idaggre + - xpack.security.authc.realms.oidc.c2id-jwt.op.authorization_endpoint=http://oidc-provider:8080/c2id-login + - xpack.security.authc.realms.oidc.c2id-jwt.op.token_endpoint=http://oidc-provider:8080/c2id/token + - xpack.security.authc.realms.oidc.c2id-jwt.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo + - xpack.security.authc.realms.oidc.c2id-jwt.op.jwkset_path=op-jwks.json + - xpack.security.authc.realms.oidc.c2id-jwt.rp.redirect_uri=https://my.fantastic.rp/cb + - xpack.security.authc.realms.oidc.c2id-jwt.rp.client_id=elasticsearch-post-jwt + - xpack.security.authc.realms.oidc.c2id-jwt.rp.client_auth_method=client_secret_jwt + - xpack.security.authc.realms.oidc.c2id-jwt.rp.response_type=code + - xpack.security.authc.realms.oidc.c2id-jwt.claims.principal=sub + - xpack.security.authc.realms.oidc.c2id-jwt.claims.name=name + - xpack.security.authc.realms.oidc.c2id-jwt.claims.mail=email + - xpack.security.authc.realms.oidc.c2id-jwt.claims.groups=groups + volumes: + - ./build/logs/node1:/usr/share/elasticsearch/logs + - ./build/certs/testnode.jks:/usr/share/elasticsearch/config/testnode.jks + - ./docker-test-entrypoint.sh:/docker-test-entrypoint.sh + - ./oidc/op-jwks.json:/usr/share/elasticsearch/config/op-jwks.json + ports: + - "9200" + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 + hard: 65536 + entrypoint: /docker-test-entrypoint.sh + healthcheck: + start_period: 15s + test: ["CMD", "curl", "-f", "-u", "x_pack_rest_user:x-pack-test-password", "-k", "https://localhost:9200"] + interval: 10s + timeout: 2s + retries: 5 + openldap: command: --copy-service --loglevel debug image: "osixia/openldap:1.4.0" @@ -45,6 +158,8 @@ services: - http-proxy ports: - "8080" + expose: + - "8080" volumes: - ./oidc/override.properties:/etc/c2id/override.properties @@ -54,3 +169,5 @@ services: - ./oidc/nginx.conf:/etc/nginx/nginx.conf ports: - "8888" + expose: + - "8888" diff --git a/x-pack/test/idp-fixture/docker-test-entrypoint.sh b/x-pack/test/idp-fixture/docker-test-entrypoint.sh new file mode 100755 index 0000000000000..b0309360e89c5 --- /dev/null +++ b/x-pack/test/idp-fixture/docker-test-entrypoint.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd /usr/share/elasticsearch/bin/ +./elasticsearch-users useradd x_pack_rest_user -p x-pack-test-password -r superuser || true +echo "testnode" >/tmp/password +echo "b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2" >/tmp/client_secret +cat /tmp/password | ./elasticsearch-keystore add -x -f -v 'xpack.security.http.ssl.keystore.secure_password' +cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id.rp.client_secret' +cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id-implicit.rp.client_secret' +cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id-proxy.rp.client_secret' +cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id-post.rp.client_secret' +cat /tmp/client_secret | ./elasticsearch-keystore add -x -f -v 'xpack.security.authc.realms.oidc.c2id-jwt.rp.client_secret' +/usr/local/bin/docker-entrypoint.sh | tee >/usr/share/elasticsearch/logs/console.log diff --git a/x-pack/test/idp-fixture/oidc/override.properties b/x-pack/test/idp-fixture/oidc/override.properties index 888bde9acb48e..fe4ba4a6e894f 100644 --- a/x-pack/test/idp-fixture/oidc/override.properties +++ b/x-pack/test/idp-fixture/oidc/override.properties @@ -1,4 +1,4 @@ -op.issuer=http://localhost:8080 -op.authz.endpoint=http://localhost:8080/c2id-login/ +op.issuer=http://oidc-provider:8080/c2id +op.authz.endpoint=http://oidc-provider:8080/c2id-login/ op.reg.apiAccessTokenSHA256=d1c4fa70d9ee708d13cfa01daa0e060a05a2075a53c5cc1ad79e460e96ab5363 -jose.jwkSer=RnVsbCBrZXk6CnsKICAia2V5cyI6IFsKICAgIHsKICAgICAgInAiOiAiLXhhN2d2aW5tY3N3QXU3Vm1mV2loZ2o3U3gzUzhmd2dFSTdMZEVveW5FU1RzcElaeUY5aHc0NVhQZmI5VHlpbzZsOHZTS0F5RmU4T2lOalpkNE1Ra0ttYlJzTmxxR1Y5VlBoWF84UG1JSm5mcGVhb3E5YnZfU0k1blZHUl9zYUUzZE9sTEE2VWpaS0lsRVBNb0ZuRlZCMUFaUU9qQlhRRzZPTDg2eDZ2NHMwIiwKICAgICAgImt0eSI6ICJSU0EiLAogICAgICAicSI6ICJ2Q3pDQUlpdHV0MGx1V0djQloyLUFabURLc1RxNkkxcUp0RmlEYkIyZFBNQVlBNldOWTdaWEZoVWxsSjJrT2ZELWdlYjlkYkN2ODBxNEwyajVZSjZoOTBUc1NRWWVHRlljN1lZMGdCMU5VR3l5cXctb29QN0EtYlJmMGI3b3I4ajZJb0hzQTZKa2JranN6c3otbkJ2U2RmUURlZkRNSVc3Ni1ZWjN0c2hsY2MiLAogICAgICAiZCI6ICJtbFBOcm1zVVM5UmJtX1I5SElyeHdmeFYzZnJ2QzlaQktFZzRzc1ZZaThfY09lSjV2U1hyQV9laEtwa2g4QVhYaUdWUGpQbVlyd29xQzFVUksxUkZmLVg0dG10emV2OUVHaU12Z0JCaEF5RkdTSUd0VUNla2x4Q2dhb3BpMXdZSU1Bd0M0STZwMUtaZURxTVNCWVZGeHA5ZWlJZ2pwb05JbV9lR3hXUUs5VHNnYmk5T3lyc1VqaE9KLVczN2JVMEJWUU56UXpxODhCcGxmNzM3VmV1dy1FeDZaMk1iWXR3SWdfZ0JVb0JEZ0NrZkhoOVE4MElYcEZRV0x1RzgwenFrdkVwTHZ0RWxLbDRvQ3BHVnBjcmFUOFNsOGpYc3FDT1k0dnVRT19LRVUzS2VPNUNJbHd4eEhJYXZjQTE5cHFpSWJ5cm1LbThxS0ZEWHluUFJMSGFNZ1EiLAogICAgICAiZSI6ICJBUUFCIiwKICAgICAgImtpZCI6ICJyc2EzODRfMjA0OCIsCiAgICAgICJxaSI6ICJzMldTamVrVDl3S2JPbk9neGNoaDJPY3VubzE2Y20wS281Z3hoUWJTdVMyMldfUjJBR2ZVdkRieGF0cTRLakQ3THo3X1k2TjdTUkwzUVpudVhoZ1djeXgyNGhrUGppQUZLNmlkYVZKQzJqQmgycEZTUDVTNXZxZ0lsME12eWY4NjlwdkN4S0NzaGRKMGdlRWhveE93VkRPYXJqdTl2Zm9IQV90LWJoRlZrUnciLAogICAgICAiZHAiOiAiQlJhQTFqYVRydG9mTHZBSUJBYW1OSEVhSm51RU9zTVJJMFRCZXFuR1BNUm0tY2RjSG1OUVo5WUtqb2JpdXlmbnhGZ0piVDlSeElBRG0ySkpoZEp5RTN4Y1dTSzhmSjBSM1Jick1aT1dwako0QmJTVzFtU1VtRnlKTGxib3puRFhZR2RaZ1hzS0o1UkFrRUNQZFBCY3YwZVlkbk9NYWhfZndfaFZoNjRuZ2tFIiwKICAgICAgImFsZyI6ICJSU0EzODQiLAogICAgICAiZHEiOiAiUFJoVERKVlR3cDNXaDZfWFZrTjIwMUlpTWhxcElrUDN1UTYyUlRlTDNrQ2ZXSkNqMkZPLTRxcVRIQk0tQjZJWUVPLXpoVWZyQnhiMzJ1djNjS2JDWGFZN3BJSFJxQlFEQWQ2WGhHYzlwc0xqNThXd3VGY2RncERJYUFpRjNyc3NUMjJ4UFVvYkJFTVdBalV3bFJrNEtNTjItMnpLQk5FR3lIcDIzOUpKdnpVIiwKICAgICAgIm4iOiAidUpDWDVDbEZpM0JnTXBvOWhRSVZ2SDh0Vi1jLTVFdG5OeUZxVm91R3NlNWwyUG92MWJGb0tsRllsU25YTzNWUE9KRWR3azNDdl9VT0UtQzlqZERYRHpvS3Z4RURaTVM1TDZWMFpIVEJoNndIOV9iN3JHSlBxLV9RdlNkejczSzZxbHpGaUtQamRvdTF6VlFYTmZfblBZbnRnQkdNRUtBc1pRNGp0cWJCdE5lV0h0MF9UM001cEktTV9KNGVlRWpCTW95TkZuU2ExTEZDVmZRNl9YVnpjelp1TlRGMlh6UmdRWkFmcmJGRXZ6eXR1TzVMZTNTTXFrUUFJeDhFQmkwYXVlRUNqNEQ4cDNVNXFVRG92NEF2VnRJbUZlbFJvb1pBMHJtVW1KRHJ4WExrVkhuVUpzaUF6ZW9TLTNBSnV1bHJkMGpuNjJ5VjZHV2dFWklZMVNlZVd3IgogICAgfQogIF0KfQo \ No newline at end of file +jose.jwkSer=RnVsbCBrZXk6CnsKICAia2V5cyI6IFsKICAgIHsKICAgICAgInAiOiAiLXhhN2d2aW5tY3N3QXU3Vm1mV2loZ2o3U3gzUzhmd2dFSTdMZEVveW5FU1RzcElaeUY5aHc0NVhQZmI5VHlpbzZsOHZTS0F5RmU4T2lOalpkNE1Ra0ttYlJzTmxxR1Y5VlBoWF84UG1JSm5mcGVhb3E5YnZfU0k1blZHUl9zYUUzZE9sTEE2VWpaS0lsRVBNb0ZuRlZCMUFaUU9qQlhRRzZPTDg2eDZ2NHMwIiwKICAgICAgImt0eSI6ICJSU0EiLAogICAgICAicSI6ICJ2Q3pDQUlpdHV0MGx1V0djQloyLUFabURLc1RxNkkxcUp0RmlEYkIyZFBNQVlBNldOWTdaWEZoVWxsSjJrT2ZELWdlYjlkYkN2ODBxNEwyajVZSjZoOTBUc1NRWWVHRlljN1lZMGdCMU5VR3l5cXctb29QN0EtYlJmMGI3b3I4ajZJb0hzQTZKa2JranN6c3otbkJ2U2RmUURlZkRNSVc3Ni1ZWjN0c2hsY2MiLAogICAgICAiZCI6ICJtbFBOcm1zVVM5UmJtX1I5SElyeHdmeFYzZnJ2QzlaQktFZzRzc1ZZaThfY09lSjV2U1hyQV9laEtwa2g4QVhYaUdWUGpQbVlyd29xQzFVUksxUkZmLVg0dG10emV2OUVHaU12Z0JCaEF5RkdTSUd0VUNla2x4Q2dhb3BpMXdZSU1Bd0M0STZwMUtaZURxTVNCWVZGeHA5ZWlJZ2pwb05JbV9lR3hXUUs5VHNnYmk5T3lyc1VqaE9KLVczN2JVMEJWUU56UXpxODhCcGxmNzM3VmV1dy1FeDZaMk1iWXR3SWdfZ0JVb0JEZ0NrZkhoOVE4MElYcEZRV0x1RzgwenFrdkVwTHZ0RWxLbDRvQ3BHVnBjcmFUOFNsOGpYc3FDT1k0dnVRT19LRVUzS2VPNUNJbHd4eEhJYXZjQTE5cHFpSWJ5cm1LbThxS0ZEWHluUFJMSGFNZ1EiLAogICAgICAiZSI6ICJBUUFCIiwKICAgICAgImtpZCI6ICJyc2EzODRfMjA0OCIsCiAgICAgICJxaSI6ICJzMldTamVrVDl3S2JPbk9neGNoaDJPY3VubzE2Y20wS281Z3hoUWJTdVMyMldfUjJBR2ZVdkRieGF0cTRLakQ3THo3X1k2TjdTUkwzUVpudVhoZ1djeXgyNGhrUGppQUZLNmlkYVZKQzJqQmgycEZTUDVTNXZxZ0lsME12eWY4NjlwdkN4S0NzaGRKMGdlRWhveE93VkRPYXJqdTl2Zm9IQV90LWJoRlZrUnciLAogICAgICAiZHAiOiAiQlJhQTFqYVRydG9mTHZBSUJBYW1OSEVhSm51RU9zTVJJMFRCZXFuR1BNUm0tY2RjSG1OUVo5WUtqb2JpdXlmbnhGZ0piVDlSeElBRG0ySkpoZEp5RTN4Y1dTSzhmSjBSM1Jick1aT1dwako0QmJTVzFtU1VtRnlKTGxib3puRFhZR2RaZ1hzS0o1UkFrRUNQZFBCY3YwZVlkbk9NYWhfZndfaFZoNjRuZ2tFIiwKICAgICAgImFsZyI6ICJSU0EzODQiLAogICAgICAiZHEiOiAiUFJoVERKVlR3cDNXaDZfWFZrTjIwMUlpTWhxcElrUDN1UTYyUlRlTDNrQ2ZXSkNqMkZPLTRxcVRIQk0tQjZJWUVPLXpoVWZyQnhiMzJ1djNjS2JDWGFZN3BJSFJxQlFEQWQ2WGhHYzlwc0xqNThXd3VGY2RncERJYUFpRjNyc3NUMjJ4UFVvYkJFTVdBalV3bFJrNEtNTjItMnpLQk5FR3lIcDIzOUpKdnpVIiwKICAgICAgIm4iOiAidUpDWDVDbEZpM0JnTXBvOWhRSVZ2SDh0Vi1jLTVFdG5OeUZxVm91R3NlNWwyUG92MWJGb0tsRllsU25YTzNWUE9KRWR3azNDdl9VT0UtQzlqZERYRHpvS3Z4RURaTVM1TDZWMFpIVEJoNndIOV9iN3JHSlBxLV9RdlNkejczSzZxbHpGaUtQamRvdTF6VlFYTmZfblBZbnRnQkdNRUtBc1pRNGp0cWJCdE5lV0h0MF9UM001cEktTV9KNGVlRWpCTW95TkZuU2ExTEZDVmZRNl9YVnpjelp1TlRGMlh6UmdRWkFmcmJGRXZ6eXR1TzVMZTNTTXFrUUFJeDhFQmkwYXVlRUNqNEQ4cDNVNXFVRG92NEF2VnRJbUZlbFJvb1pBMHJtVW1KRHJ4WExrVkhuVUpzaUF6ZW9TLTNBSnV1bHJkMGpuNjJ5VjZHV2dFWklZMVNlZVd3IgogICAgfQogIF0KfQo From 0467b14986b3f5b7596a4681b0e7b6bce5a4cffb Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Tue, 30 Jun 2020 07:54:25 +0300 Subject: [PATCH 3/6] remove random characters from config --- x-pack/test/idp-fixture/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/idp-fixture/docker-compose.yml b/x-pack/test/idp-fixture/docker-compose.yml index 0386644c40373..be8ea6b27672c 100644 --- a/x-pack/test/idp-fixture/docker-compose.yml +++ b/x-pack/test/idp-fixture/docker-compose.yml @@ -78,7 +78,7 @@ services: - xpack.security.authc.realms.oidc.c2id-post.claims.mail=email - xpack.security.authc.realms.oidc.c2id-post.claims.groups=groups - xpack.security.authc.realms.oidc.c2id-jwt.order=6 - - xpack.security.authc.realms.oidc.c2id-jwt.op.issuer=http://oidc-provider:8080/c2idaggre + - xpack.security.authc.realms.oidc.c2id-jwt.op.issuer=http://oidc-provider:8080/c2id - xpack.security.authc.realms.oidc.c2id-jwt.op.authorization_endpoint=http://oidc-provider:8080/c2id-login - xpack.security.authc.realms.oidc.c2id-jwt.op.token_endpoint=http://oidc-provider:8080/c2id/token - xpack.security.authc.realms.oidc.c2id-jwt.op.userinfo_endpoint=http://oidc-provider:8080/c2id/userinfo From e1e553724b454b64043e80a74a10c57b7c5c7ceb Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Tue, 30 Jun 2020 17:39:52 +0300 Subject: [PATCH 4/6] address feedback --- .../xpack/security/authc/oidc/OpenIdConnectAuthenticator.java | 4 ++-- .../security/authc/oidc/OpenIdConnectAuthenticatorTests.java | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java index 160f7454b2150..4d2e05dbe4bb0 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthenticator.java @@ -489,8 +489,8 @@ private void exchangeCodeForToken(AuthorizationCode code, ActionListener Date: Wed, 19 Aug 2020 12:01:06 +0300 Subject: [PATCH 5/6] address feedback --- .../authc/oidc/OpenIdConnectAuthIT.java | 19 +++++++++++-------- x-pack/test/idp-fixture/build.gradle | 3 --- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java b/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java index a932d1db8e5ff..b2fd3907dbd00 100644 --- a/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java +++ b/x-pack/qa/oidc-op-tests/src/test/java/org/elasticsearch/xpack/security/authc/oidc/OpenIdConnectAuthIT.java @@ -78,6 +78,9 @@ public class OpenIdConnectAuthIT extends ESRestTestCase { + "/c2id/clients"; private static final String LOGIN_API = "http://127.0.0.1:" + getEphemeralTcpPortFromProperty("oidc-provider", "8080") + "/c2id-login/api/"; + private static final String CLIENT_SECRET = "b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2"; + // SHA256 of this is defined in x-pack/test/idp-fixture/oidc/override.properties + private static final String OP_API_BEARER_TOKEN = "811fa888f3e0fdc9e01d4201bfeee46a"; private static final String ES_PORT = getEphemeralTcpPortFromProperty("elasticsearch-node", "9200"); private static Path HTTP_TRUSTSTORE; @@ -106,7 +109,7 @@ public static void registerClients() throws Exception { "\"grant_types\": [\"authorization_code\"]," + "\"response_types\": [\"code\"]," + "\"preferred_client_id\":\"https://my.elasticsearch.org/rp\"," + - "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + + "\"preferred_client_secret\":\"" + CLIENT_SECRET + "\"," + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," + "\"token_endpoint_auth_method\":\"client_secret_basic\"" + "}"; @@ -114,14 +117,14 @@ public static void registerClients() throws Exception { "\"grant_types\": [\"implicit\"]," + "\"response_types\": [\"token id_token\"]," + "\"preferred_client_id\":\"elasticsearch-rp\"," + - "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + + "\"preferred_client_secret\":\"" + CLIENT_SECRET + "\"," + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]" + "}"; String postClient = "{" + "\"grant_types\": [\"authorization_code\"]," + "\"response_types\": [\"code\"]," + "\"preferred_client_id\":\"elasticsearch-post\"," + - "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + + "\"preferred_client_secret\":\"" + CLIENT_SECRET + "\"," + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," + "\"token_endpoint_auth_method\":\"client_secret_post\"" + "}"; @@ -129,7 +132,7 @@ public static void registerClients() throws Exception { "\"grant_types\": [\"authorization_code\"]," + "\"response_types\": [\"code\"]," + "\"preferred_client_id\":\"elasticsearch-post-jwt\"," + - "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + + "\"preferred_client_secret\":\"" + CLIENT_SECRET + "\"," + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]," + "\"token_endpoint_auth_method\":\"client_secret_jwt\"" + "}"; @@ -138,25 +141,25 @@ public static void registerClients() throws Exception { httpPost.setEntity(new StringEntity(codeClient, ContentType.APPLICATION_JSON)); httpPost.setHeader("Accept", "application/json"); httpPost.setHeader("Content-type", "application/json"); - httpPost.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a"); + httpPost.setHeader("Authorization", "Bearer " + OP_API_BEARER_TOKEN); HttpPost httpPost2 = new HttpPost(REGISTRATION_URL); httpPost2.setEntity(new StringEntity(implicitClient, ContentType.APPLICATION_JSON)); httpPost2.setHeader("Accept", "application/json"); httpPost2.setHeader("Content-type", "application/json"); - httpPost2.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a"); + httpPost2.setHeader("Authorization", "Bearer " + OP_API_BEARER_TOKEN); HttpPost httpPost3 = new HttpPost(REGISTRATION_URL); httpPost3.setEntity(new StringEntity(postClient, ContentType.APPLICATION_JSON)); httpPost3.setHeader("Accept", "application/json"); httpPost3.setHeader("Content-type", "application/json"); - httpPost3.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a"); + httpPost3.setHeader("Authorization", "Bearer " + OP_API_BEARER_TOKEN); HttpPost httpPost4 = new HttpPost(REGISTRATION_URL); httpPost4.setEntity(new StringEntity(jwtClient, ContentType.APPLICATION_JSON)); httpPost4.setHeader("Accept", "application/json"); httpPost4.setHeader("Content-type", "application/json"); - httpPost4.setHeader("Authorization", "Bearer 811fa888f3e0fdc9e01d4201bfeee46a"); + httpPost4.setHeader("Authorization", "Bearer " + OP_API_BEARER_TOKEN); SocketAccess.doPrivileged(() -> { try (CloseableHttpResponse response = httpClient.execute(httpPost, context)) { diff --git a/x-pack/test/idp-fixture/build.gradle b/x-pack/test/idp-fixture/build.gradle index 826288808a801..d9992ca92964b 100644 --- a/x-pack/test/idp-fixture/build.gradle +++ b/x-pack/test/idp-fixture/build.gradle @@ -1,12 +1,9 @@ import org.elasticsearch.gradle.VersionProperties import org.elasticsearch.gradle.Architecture -apply plugin: 'elasticsearch.build' apply plugin: 'elasticsearch.test.fixtures' apply plugin: 'elasticsearch.distribution-download' -test.enabled = false - task copyKeystore(type: Sync) { from project(':x-pack:plugin:core') .file('src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks') From 1dcd6f31090b51a94f0c0947ff402afdbdd8408e Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Wed, 9 Sep 2020 18:55:27 +1000 Subject: [PATCH 6/6] Apply Rene's fix for test fixture From https://github.com/breskeby/elasticsearch/commit/de079d6dde022c5122a0c7b41ae9248abed4ad58 --- x-pack/test/idp-fixture/build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/test/idp-fixture/build.gradle b/x-pack/test/idp-fixture/build.gradle index d9992ca92964b..cb9e49d7d693e 100644 --- a/x-pack/test/idp-fixture/build.gradle +++ b/x-pack/test/idp-fixture/build.gradle @@ -2,7 +2,7 @@ import org.elasticsearch.gradle.VersionProperties import org.elasticsearch.gradle.Architecture apply plugin: 'elasticsearch.test.fixtures' -apply plugin: 'elasticsearch.distribution-download' +apply plugin: 'elasticsearch.internal-distribution-download' task copyKeystore(type: Sync) { from project(':x-pack:plugin:core') @@ -31,3 +31,7 @@ preProcessFixture { file.setWritable(true, false) } } + +tasks.named('composeUp').configure { + dependsOn "preProcessFixture" +}