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
This commit is contained in:
Ioannis Kakavas 2019-07-02 13:34:38 +03:00
parent 4cdb24bceb
commit 4ea17b76dc
3 changed files with 28 additions and 10 deletions

View File

@ -95,6 +95,8 @@ import java.io.UnsupportedEncodingException;
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 @@ public class OpenIdConnectAuthenticator {
}
httpPost.setEntity(new UrlEncodedFormEntity(params));
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(rpConfig.getClientId().getValue(),
rpConfig.getClientSecret().toString());
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<Void>) () -> {

View File

@ -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'

View File

@ -76,23 +76,38 @@ public class OpenIdConnectAuthIT extends ESRestTestCase {
* 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));
}
}