From b8ca257dd91a65104484e501d784122a3464eca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 10 Jun 2022 13:51:49 +0200 Subject: [PATCH] Fix NullPointerException for issuer without scheme in id token Uri.getScheme() may return null if no scheme is contained in the given string. This could cause a crash during id token validation when this was the case for the contained "iss" claim. --- library/java/net/openid/appauth/IdToken.java | 3 +- .../net/openid/appauth/IdTokenTest.java | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/library/java/net/openid/appauth/IdToken.java b/library/java/net/openid/appauth/IdToken.java index 4a4556ef..d914407a 100644 --- a/library/java/net/openid/appauth/IdToken.java +++ b/library/java/net/openid/appauth/IdToken.java @@ -229,7 +229,8 @@ void validate(@NonNull TokenRequest tokenRequest, // components. Uri issuerUri = Uri.parse(this.issuer); - if (!skipIssuerHttpsCheck && !issuerUri.getScheme().equals("https")) { + String issuerScheme = issuerUri.getScheme(); + if (!skipIssuerHttpsCheck && (issuerScheme == null || !issuerScheme.equals("https"))) { throw AuthorizationException.fromTemplate(GeneralErrors.ID_TOKEN_VALIDATION_ERROR, new IdTokenException("Issuer must be an https URL")); } diff --git a/library/javatests/net/openid/appauth/IdTokenTest.java b/library/javatests/net/openid/appauth/IdTokenTest.java index 13944f7c..1daf71f8 100644 --- a/library/javatests/net/openid/appauth/IdTokenTest.java +++ b/library/javatests/net/openid/appauth/IdTokenTest.java @@ -361,6 +361,34 @@ public void testValidate_shouldFailOnIssuerWithFragment() idToken.validate(tokenRequest, clock); } + @Test(expected = AuthorizationException.class) + public void testValidate_shouldFailOnIssuerMissingScheme() + throws AuthorizationException, JSONException, MissingArgumentException { + Long nowInSeconds = SystemClock.INSTANCE.getCurrentTimeMillis() / 1000; + Long tenMinutesInSeconds = (long) (10 * 60); + IdToken idToken = new IdToken( + "some.issuer", + TEST_SUBJECT, + Collections.singletonList(TEST_CLIENT_ID), + nowInSeconds + tenMinutesInSeconds, + nowInSeconds + ); + + String serviceDocJsonWithIssuerMissingHost = getDiscoveryDocJsonWithIssuer("some.issuer"); + AuthorizationServiceDiscovery discoveryDoc = new AuthorizationServiceDiscovery( + new JSONObject(serviceDocJsonWithIssuerMissingHost)); + AuthorizationServiceConfiguration serviceConfiguration = + new AuthorizationServiceConfiguration(discoveryDoc); + TokenRequest tokenRequest = new TokenRequest.Builder(serviceConfiguration, TEST_CLIENT_ID) + .setAuthorizationCode(TEST_AUTH_CODE) + .setCodeVerifier(TEST_CODE_VERIFIER) + .setGrantType(GrantTypeValues.AUTHORIZATION_CODE) + .setRedirectUri(TEST_APP_REDIRECT_URI) + .build(); + Clock clock = SystemClock.INSTANCE; + idToken.validate(tokenRequest, clock); + } + @Test public void testValidate_audienceMatch() throws AuthorizationException { Long nowInSeconds = SystemClock.INSTANCE.getCurrentTimeMillis() / 1000;