From 4ea17b76dc6b774106230773cf755c3b10594bb0 Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Tue, 2 Jul 2019 13:34:38 +0300 Subject: [PATCH] Fix credentials encoding for OIDC token request (#43808) As defined in https://tools.ietf.org/html/rfc6749#section-2.3.1 both client id and client secret need to be encoded with the application/x-www-form-urlencoded encoding algorithm when used as credentials for HTTP Basic Authentication in requests to the OP. Resolves #43709 --- .../oidc/OpenIdConnectAuthenticator.java | 7 +++-- x-pack/qa/oidc-op-tests/build.gradle | 2 +- .../authc/oidc/OpenIdConnectAuthIT.java | 29 ++++++++++++++----- 3 files changed, 28 insertions(+), 10 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 9994e30140e47..a3218fc90552f 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 @@ -95,6 +95,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; + +import java.net.URLEncoder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Path; @@ -465,8 +467,9 @@ private void exchangeCodeForToken(AuthorizationCode code, ActionListener) () -> { diff --git a/x-pack/qa/oidc-op-tests/build.gradle b/x-pack/qa/oidc-op-tests/build.gradle index d31e4c2c00310..f80cb2035206d 100644 --- a/x-pack/qa/oidc-op-tests/build.gradle +++ b/x-pack/qa/oidc-op-tests/build.gradle @@ -42,7 +42,7 @@ testClusters.integTest { setting 'xpack.security.authc.realms.oidc.c2id.op.userinfo_endpoint', { "http://127.0.0.1:${ephemeralPort}/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', 'elasticsearch-rp' + 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' 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 7835b236ed84d..3022b34c4aeec 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 @@ -76,23 +76,38 @@ public void setupUserAndRoles() throws IOException { * C2id server only supports dynamic registration, so we can't pre-seed it's config with our client data. Execute only once */ @BeforeClass - public static void registerClient() throws Exception { + public static void registerClients() throws Exception { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost httpPost = new HttpPost(REGISTRATION_URL); - final BasicHttpContext context = new BasicHttpContext(); - String json = "{" + - "\"grant_types\": [\"implicit\", \"authorization_code\"]," + - "\"response_types\": [\"code\", \"token id_token\"]," + + String codeClient = "{" + + "\"grant_types\": [\"authorization_code\"]," + + "\"response_types\": [\"code\"]," + + "\"preferred_client_id\":\"https://my.elasticsearch.org/rp\"," + + "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]" + + "}"; + String implicitClient = "{" + + "\"grant_types\": [\"implicit\"]," + + "\"response_types\": [\"token id_token\"]," + "\"preferred_client_id\":\"elasticsearch-rp\"," + "\"preferred_client_secret\":\"b07efb7a1cf6ec9462afe7b6d3ab55c6c7880262aa61ac28dded292aca47c9a2\"," + "\"redirect_uris\": [\"https://my.fantastic.rp/cb\"]" + "}"; - httpPost.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON)); + 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)); } }