diff --git a/docs/changelog/126191.yaml b/docs/changelog/126191.yaml new file mode 100644 index 0000000000000..b5ab684e057a6 --- /dev/null +++ b/docs/changelog/126191.yaml @@ -0,0 +1,5 @@ +pr: 126191 +summary: Fix NPE for missing Content Type header in OIDC Authenticator +area: Authentication +type: bug +issues: [] 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 65d2492e3b6b8..af82b9361dd3d 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 @@ -629,18 +629,20 @@ public void cancelled() { /** * Handle the Token Response from the OpenID Connect Provider. If successful, extract the (yet not validated) Id Token * and access token and call the provided listener. + * (Package private for testing purposes) */ - private static void handleTokenResponse(HttpResponse httpResponse, ActionListener> tokensListener) { + static void handleTokenResponse(HttpResponse httpResponse, ActionListener> tokensListener) { try { final HttpEntity entity = httpResponse.getEntity(); final Header encodingHeader = entity.getContentEncoding(); final Header contentHeader = entity.getContentType(); - if (ContentType.parse(contentHeader.getValue()).getMimeType().equals("application/json") == false) { + final String contentHeaderValue = contentHeader == null ? null : ContentType.parse(contentHeader.getValue()).getMimeType(); + if (contentHeaderValue == null || contentHeaderValue.equals("application/json") == false) { tokensListener.onFailure( new IllegalStateException( "Unable to parse Token Response. Content type was expected to be " + "[application/json] but was [" - + contentHeader.getValue() + + contentHeaderValue + "]" ) ); @@ -688,7 +690,7 @@ private static void handleTokenResponse(HttpResponse httpResponse, ActionListene } catch (Exception e) { tokensListener.onFailure( new ElasticsearchSecurityException( - "Failed to exchange code for Id Token using the Token Endpoint. " + "Unable to parse Token Response", + "Failed to exchange code for Id Token using the Token Endpoint. Unable to parse Token Response", e ) ); 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 f839e5e7c1dcb..76069ce500ad9 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 @@ -968,6 +968,23 @@ public void testHandleUserinfoResponseFailure() throws Exception { ); } + public void testHandleTokenResponseNullContentType() { + final HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, RestStatus.OK.getStatus(), ""); + final StringEntity entity = new StringEntity("", (ContentType) null); + response.setEntity(entity); + + final PlainActionFuture> future = new PlainActionFuture<>(); + OpenIdConnectAuthenticator.handleTokenResponse(response, future); + final IllegalStateException exception = expectThrows(IllegalStateException.class, future::actionGet); + + assertThat( + exception, + TestMatchers.throwableWithMessage( + "Unable to parse Token Response. Content type was expected to be [application/json] but was [null]" + ) + ); + } + public void testLogIdTokenAndNonce() throws URISyntaxException, BadJOSEException, JOSEException, IllegalAccessException { final Logger logger = LogManager.getLogger(OpenIdConnectAuthenticator.class); Loggers.setLevel(logger, Level.DEBUG);