From 1a444a42dda2c3aae4851e7d05131997999d4433 Mon Sep 17 00:00:00 2001 From: ruben poveda Date: Fri, 16 Feb 2024 11:57:06 +0000 Subject: [PATCH] Fix Android crash NullPointerException --- .../java/com/rnappauth/RNAppAuthModule.java | 230 +++++++++--------- index.d.ts | 3 +- 2 files changed, 119 insertions(+), 114 deletions(-) diff --git a/android/src/main/java/com/rnappauth/RNAppAuthModule.java b/android/src/main/java/com/rnappauth/RNAppAuthModule.java index c14fe538..e68389a4 100644 --- a/android/src/main/java/com/rnappauth/RNAppAuthModule.java +++ b/android/src/main/java/com/rnappauth/RNAppAuthModule.java @@ -102,17 +102,17 @@ public void prefetchConfiguration( final boolean dangerouslyAllowInsecureHttpRequests, final ReadableMap customHeaders, final Double connectionTimeoutMillis, - final Promise promise - ) { + final Promise promise) { if (warmAndPrefetchChrome) { warmChromeCustomTab(reactContext, issuer); } this.parseHeaderMap(customHeaders); - final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, this.authorizationRequestHeaders, connectionTimeoutMillis); + final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, + this.authorizationRequestHeaders, connectionTimeoutMillis); final CountDownLatch fetchConfigurationLatch = new CountDownLatch(1); - if(!isPrefetched) { + if (!isPrefetched) { if (serviceConfiguration != null && !this.hasServiceConfiguration(issuer)) { try { setServiceConfiguration(issuer, createAuthorizationServiceConfiguration(serviceConfiguration)); @@ -130,7 +130,8 @@ public void onFetchConfigurationCompleted( @Nullable AuthorizationServiceConfiguration fetchedConfiguration, @Nullable AuthorizationException ex) { if (ex != null) { - promise.reject("service_configuration_fetch_error", "Failed to fetch configuration", ex); + promise.reject("service_configuration_fetch_error", "Failed to fetch configuration", + ex); return; } setServiceConfiguration(issuer, fetchedConfiguration); @@ -138,8 +139,7 @@ public void onFetchConfigurationCompleted( fetchConfigurationLatch.countDown(); } }, - builder - ); + builder); } } else { fetchConfigurationLatch.countDown(); @@ -166,17 +166,21 @@ public void register( final Double connectionTimeoutMillis, final boolean dangerouslyAllowInsecureHttpRequests, final ReadableMap customHeaders, - final Promise promise - ) { + final Promise promise) { this.parseHeaderMap(customHeaders); - final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, this.registrationRequestHeaders, connectionTimeoutMillis); - final AppAuthConfiguration appAuthConfiguration = this.createAppAuthConfiguration(builder, dangerouslyAllowInsecureHttpRequests, null); + final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, + this.registrationRequestHeaders, connectionTimeoutMillis); + final AppAuthConfiguration appAuthConfiguration = this.createAppAuthConfiguration(builder, + dangerouslyAllowInsecureHttpRequests, null); final HashMap additionalParametersMap = MapUtil.readableMapToHashMap(additionalParameters); - // when serviceConfiguration is provided, we don't need to hit up the OpenID well-known id endpoint + // when serviceConfiguration is provided, we don't need to hit up the OpenID + // well-known id endpoint if (serviceConfiguration != null || hasServiceConfiguration(issuer)) { try { - final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer)? getServiceConfiguration(issuer) : createAuthorizationServiceConfiguration(serviceConfiguration); + final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer) + ? getServiceConfiguration(issuer) + : createAuthorizationServiceConfiguration(serviceConfiguration); registerWithConfiguration( serviceConfig, appAuthConfiguration, @@ -186,8 +190,7 @@ public void register( subjectType, tokenEndpointAuthMethod, additionalParametersMap, - promise - ); + promise); } catch (Exception e) { promise.reject("registration_failed", e.getMessage()); } @@ -215,8 +218,7 @@ public void onFetchConfigurationCompleted( subjectType, tokenEndpointAuthMethod, additionalParametersMap, - promise - ); + promise); } }, builder); @@ -241,11 +243,12 @@ public void authorize( final ReadableMap customHeaders, final ReadableArray androidAllowCustomBrowsers, final boolean androidTrustedWebActivity, - final Promise promise - ) { + final Promise promise) { this.parseHeaderMap(customHeaders); - final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, this.authorizationRequestHeaders, connectionTimeoutMillis); - final AppAuthConfiguration appAuthConfiguration = this.createAppAuthConfiguration(builder, dangerouslyAllowInsecureHttpRequests, androidAllowCustomBrowsers); + final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, + this.authorizationRequestHeaders, connectionTimeoutMillis); + final AppAuthConfiguration appAuthConfiguration = this.createAppAuthConfiguration(builder, + dangerouslyAllowInsecureHttpRequests, androidAllowCustomBrowsers); final HashMap additionalParametersMap = MapUtil.readableMapToHashMap(additionalParameters); // store args in private fields for later use in onActivityResult handler @@ -258,10 +261,13 @@ public void authorize( this.useNonce = useNonce; this.usePKCE = usePKCE; - // when serviceConfiguration is provided, we don't need to hit up the OpenID well-known id endpoint + // when serviceConfiguration is provided, we don't need to hit up the OpenID + // well-known id endpoint if (serviceConfiguration != null || hasServiceConfiguration(issuer)) { try { - final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer) ? getServiceConfiguration(issuer) : createAuthorizationServiceConfiguration(serviceConfiguration); + final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer) + ? getServiceConfiguration(issuer) + : createAuthorizationServiceConfiguration(serviceConfiguration); authorizeWithConfiguration( serviceConfig, appAuthConfiguration, @@ -271,8 +277,7 @@ public void authorize( useNonce, usePKCE, additionalParametersMap, - androidTrustedWebActivity - ); + androidTrustedWebActivity); } catch (ActivityNotFoundException e) { promise.reject("browser_not_found", e.getMessage()); } catch (Exception e) { @@ -303,8 +308,7 @@ public void onFetchConfigurationCompleted( useNonce, usePKCE, additionalParametersMap, - androidTrustedWebActivity - ); + androidTrustedWebActivity); } catch (ActivityNotFoundException e) { promise.reject("browser_not_found", e.getMessage()); } catch (Exception e) { @@ -312,13 +316,9 @@ public void onFetchConfigurationCompleted( } } }, - builder - ); + builder); } - - - } @ReactMethod @@ -336,11 +336,12 @@ public void refresh( final boolean dangerouslyAllowInsecureHttpRequests, final ReadableMap customHeaders, final ReadableArray androidAllowCustomBrowsers, - final Promise promise - ) { + final Promise promise) { this.parseHeaderMap(customHeaders); - final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, this.tokenRequestHeaders, connectionTimeoutMillis); - final AppAuthConfiguration appAuthConfiguration = createAppAuthConfiguration(builder, dangerouslyAllowInsecureHttpRequests, androidAllowCustomBrowsers); + final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, + this.tokenRequestHeaders, connectionTimeoutMillis); + final AppAuthConfiguration appAuthConfiguration = createAppAuthConfiguration(builder, + dangerouslyAllowInsecureHttpRequests, androidAllowCustomBrowsers); final HashMap additionalParametersMap = MapUtil.readableMapToHashMap(additionalParameters); if (clientSecret != null) { @@ -351,10 +352,13 @@ public void refresh( this.dangerouslyAllowInsecureHttpRequests = dangerouslyAllowInsecureHttpRequests; this.additionalParametersMap = additionalParametersMap; - // when serviceConfiguration is provided, we don't need to hit up the OpenID well-known id endpoint + // when serviceConfiguration is provided, we don't need to hit up the OpenID + // well-known id endpoint if (serviceConfiguration != null || hasServiceConfiguration(issuer)) { try { - final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer) ? getServiceConfiguration(issuer) : createAuthorizationServiceConfiguration(serviceConfiguration); + final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer) + ? getServiceConfiguration(issuer) + : createAuthorizationServiceConfiguration(serviceConfiguration); refreshWithConfiguration( serviceConfig, appAuthConfiguration, @@ -365,8 +369,7 @@ public void refresh( additionalParametersMap, clientAuthMethod, clientSecret, - promise - ); + promise); } catch (ActivityNotFoundException e) { promise.reject("browser_not_found", e.getMessage()); } catch (Exception e) { @@ -398,8 +401,7 @@ public void onFetchConfigurationCompleted( additionalParametersMap, clientAuthMethod, clientSecret, - promise - ); + promise); } catch (ActivityNotFoundException e) { promise.reject("browser_not_found", e.getMessage()); } catch (Exception e) { @@ -421,24 +423,25 @@ public void logout( final ReadableMap additionalParameters, final boolean dangerouslyAllowInsecureHttpRequests, final ReadableArray androidAllowCustomBrowsers, - final Promise promise - ) { + final Promise promise) { final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, null); - final AppAuthConfiguration appAuthConfiguration = this.createAppAuthConfiguration(builder, dangerouslyAllowInsecureHttpRequests, androidAllowCustomBrowsers); + final AppAuthConfiguration appAuthConfiguration = this.createAppAuthConfiguration(builder, + dangerouslyAllowInsecureHttpRequests, androidAllowCustomBrowsers); final HashMap additionalParametersMap = MapUtil.readableMapToHashMap(additionalParameters); this.promise = promise; if (serviceConfiguration != null || hasServiceConfiguration(issuer)) { try { - final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer) ? getServiceConfiguration(issuer) : createAuthorizationServiceConfiguration(serviceConfiguration); + final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer) + ? getServiceConfiguration(issuer) + : createAuthorizationServiceConfiguration(serviceConfiguration); endSessionWithConfiguration( serviceConfig, appAuthConfiguration, idTokenHint, postLogoutRedirectUri, - additionalParametersMap - ); + additionalParametersMap); } catch (ActivityNotFoundException e) { promise.reject("browser_not_found", e.getMessage()); } catch (Exception e) { @@ -465,8 +468,7 @@ public void onFetchConfigurationCompleted( appAuthConfiguration, idTokenHint, postLogoutRedirectUri, - additionalParametersMap - ); + additionalParametersMap); } catch (ActivityNotFoundException e) { promise.reject("browser_not_found", e.getMessage()); } catch (Exception e) { @@ -474,8 +476,7 @@ public void onFetchConfigurationCompleted( } } }, - builder - ); + builder); } } @@ -484,6 +485,7 @@ public void onFetchConfigurationCompleted( */ @Override public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { + try { if (requestCode == 52) { if (data == null) { if (promise != null) { @@ -501,9 +503,9 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode, return; } - if (this.skipCodeExchange) { + if (this.skipCodeExchange != null && this.skipCodeExchange) { WritableMap map; - if (this.usePKCE && this.codeVerifier != null) { + if (this.usePKCE != null && this.usePKCE && this.codeVerifier != null) { map = TokenResponseFactory.authorizationCodeResponseToMap(response, this.codeVerifier); } else { map = TokenResponseFactory.authorizationResponseToMap(response); @@ -525,7 +527,12 @@ public void onActivityResult(Activity activity, int requestCode, int resultCode, AuthorizationService authService = new AuthorizationService(this.reactContext, configuration); - TokenRequest tokenRequest = response.createTokenExchangeRequest(this.additionalParametersMap); + TokenRequest tokenRequest; + if(this.additionalParametersMap == null) { + tokenRequest = response.createTokenExchangeRequest(); + } else { + tokenRequest = response.createTokenExchangeRequest(this.additionalParametersMap); + } AuthorizationService.TokenResponseCallback tokenResponseCallback = new AuthorizationService.TokenResponseCallback() { @@ -553,7 +560,7 @@ public void onTokenRequestCompleted( authService.performTokenRequest(tokenRequest, tokenResponseCallback); } - } + } // close if if (requestCode == 53) { if (data == null) { @@ -574,6 +581,13 @@ public void onTokenRequestCompleted( WritableMap map = EndSessionResponseFactory.endSessionResponseToMap(response); endSessionPromise.resolve(map); } + } catch (Exception e) { + if(promise != null) { + promise.reject("run_time_exception", e.getMessage()); + } else { + throw e; + } + } } /* @@ -588,18 +602,15 @@ private void registerWithConfiguration( final String subjectType, final String tokenEndpointAuthMethod, final Map additionalParametersMap, - final Promise promise - ) { + final Promise promise) { final Context context = this.reactContext; AuthorizationService authService = new AuthorizationService(context, appAuthConfiguration); - RegistrationRequest.Builder registrationRequestBuilder = - new RegistrationRequest.Builder( - serviceConfiguration, - arrayToUriList(redirectUris) - ) - .setAdditionalParameters(additionalParametersMap); + RegistrationRequest.Builder registrationRequestBuilder = new RegistrationRequest.Builder( + serviceConfiguration, + arrayToUriList(redirectUris)) + .setAdditionalParameters(additionalParametersMap); if (responseTypes != null) { registrationRequestBuilder.setResponseTypeValues(arrayToList(responseTypes)); @@ -621,7 +632,8 @@ private void registerWithConfiguration( AuthorizationService.RegistrationResponseCallback registrationResponseCallback = new AuthorizationService.RegistrationResponseCallback() { @Override - public void onRegistrationRequestCompleted(@Nullable RegistrationResponse response, @Nullable AuthorizationException ex) { + public void onRegistrationRequestCompleted(@Nullable RegistrationResponse response, + @Nullable AuthorizationException ex) { if (response != null) { WritableMap map = RegistrationResponseFactory.registrationResponseToMap(response); promise.resolve(map); @@ -646,8 +658,7 @@ private void authorizeWithConfiguration( final Boolean useNonce, final Boolean usePKCE, final Map additionalParametersMap, - final Boolean androidTrustedWebActivity - ) { + final Boolean androidTrustedWebActivity) { String scopesString = null; @@ -658,13 +669,11 @@ private void authorizeWithConfiguration( final Context context = this.reactContext; final Activity currentActivity = getCurrentActivity(); - AuthorizationRequest.Builder authRequestBuilder = - new AuthorizationRequest.Builder( - serviceConfiguration, - clientId, - ResponseTypeValues.CODE, - Uri.parse(redirectUrl) - ); + AuthorizationRequest.Builder authRequestBuilder = new AuthorizationRequest.Builder( + serviceConfiguration, + clientId, + ResponseTypeValues.CODE, + Uri.parse(redirectUrl)); if (scopesString != null) { authRequestBuilder.setScope(scopesString); @@ -692,8 +701,8 @@ private void authorizeWithConfiguration( if (additionalParametersMap.containsKey("nonce")) { authRequestBuilder.setNonce(additionalParametersMap.get("nonce")); additionalParametersMap.remove("nonce"); - - } + + } if (additionalParametersMap.containsKey("ui_locales")) { authRequestBuilder.setUiLocales(additionalParametersMap.get("ui_locales")); additionalParametersMap.remove("ui_locales"); @@ -710,7 +719,7 @@ private void authorizeWithConfiguration( authRequestBuilder.setCodeVerifier(this.codeVerifier); } - if(!useNonce) { + if (!useNonce) { authRequestBuilder.setNonce(null); } @@ -750,8 +759,7 @@ private void refreshWithConfiguration( final Map additionalParametersMap, final String clientAuthMethod, final String clientSecret, - final Promise promise - ) { + final Promise promise) { String scopesString = null; @@ -761,13 +769,11 @@ private void refreshWithConfiguration( final Context context = this.reactContext; - TokenRequest.Builder tokenRequestBuilder = - new TokenRequest.Builder( - serviceConfiguration, - clientId - ) - .setRefreshToken(refreshToken) - .setRedirectUri(Uri.parse(redirectUrl)); + TokenRequest.Builder tokenRequestBuilder = new TokenRequest.Builder( + serviceConfiguration, + clientId) + .setRefreshToken(refreshToken) + .setRedirectUri(Uri.parse(redirectUrl)); if (scopesString != null) { tokenRequestBuilder.setScope(scopesString); @@ -793,7 +799,6 @@ public void onTokenRequestCompleted(@Nullable TokenResponse response, @Nullable } }; - if (clientSecret != null) { ClientAuthentication clientAuth = this.getClientAuthentication(clientSecret, clientAuthMethod); authService.performTokenRequest(tokenRequest, clientAuth, tokenResponseCallback); @@ -811,15 +816,13 @@ private void endSessionWithConfiguration( final AppAuthConfiguration appAuthConfiguration, final String idTokenHint, final String postLogoutRedirectUri, - final Map additionalParametersMap - ) { + final Map additionalParametersMap) { final Context context = this.reactContext; final Activity currentActivity = getCurrentActivity(); - EndSessionRequest.Builder endSessionRequestBuilder = - new EndSessionRequest.Builder(serviceConfiguration) - .setIdTokenHint(idTokenHint) - .setPostLogoutRedirectUri(Uri.parse(postLogoutRedirectUri)); + EndSessionRequest.Builder endSessionRequestBuilder = new EndSessionRequest.Builder(serviceConfiguration) + .setIdTokenHint(idTokenHint) + .setPostLogoutRedirectUri(Uri.parse(postLogoutRedirectUri)); if (additionalParametersMap != null) { if (additionalParametersMap.containsKey("state")) { @@ -844,7 +847,7 @@ private void endSessionWithConfiguration( } } - private void parseHeaderMap (ReadableMap headerMap) { + private void parseHeaderMap(ReadableMap headerMap) { if (headerMap == null) { return; } @@ -910,10 +913,8 @@ private List arrayToUriList(ReadableArray array) { private AppAuthConfiguration createAppAuthConfiguration( ConnectionBuilder connectionBuilder, Boolean skipIssuerHttpsCheck, - ReadableArray androidAllowCustomBrowsers - ) { - return new AppAuthConfiguration - .Builder() + ReadableArray androidAllowCustomBrowsers) { + return new AppAuthConfiguration.Builder() .setBrowserMatcher(getBrowserAllowList(androidAllowCustomBrowsers)) .setConnectionBuilder(connectionBuilder) .setSkipIssuerHttpsCheck(skipIssuerHttpsCheck) @@ -921,19 +922,20 @@ private AppAuthConfiguration createAppAuthConfiguration( } /* - * Create appropriate connection builder based on provided settings + * Create appropriate connection builder based on provided settings */ - private ConnectionBuilder createConnectionBuilder(boolean allowInsecureConnections, Map headers, Double connectionTimeoutMillis) { + private ConnectionBuilder createConnectionBuilder(boolean allowInsecureConnections, Map headers, + Double connectionTimeoutMillis) { ConnectionBuilder proxiedBuilder; if (allowInsecureConnections) { - proxiedBuilder =UnsafeConnectionBuilder.INSTANCE; + proxiedBuilder = UnsafeConnectionBuilder.INSTANCE; } else { proxiedBuilder = DefaultConnectionBuilder.INSTANCE; } CustomConnectionBuilder customConnection = new CustomConnectionBuilder(proxiedBuilder); - + if (headers != null) { customConnection.setHeaders(headers); } @@ -953,7 +955,7 @@ private ConnectionBuilder createConnectionBuilder(boolean allowInsecureConnectio } CustomConnectionBuilder customConnection = new CustomConnectionBuilder(proxiedBuilder); - + if (headers != null) { customConnection.setHeaders(headers); } @@ -962,7 +964,7 @@ private ConnectionBuilder createConnectionBuilder(boolean allowInsecureConnectio } /* - * Replicated private method from AuthorizationServiceConfiguration + * Replicated private method from AuthorizationServiceConfiguration */ private Uri buildConfigurationUriFromIssuer(Uri openIdConnectIssuerUri) { return openIdConnectIssuerUri.buildUpon() @@ -971,7 +973,8 @@ private Uri buildConfigurationUriFromIssuer(Uri openIdConnectIssuerUri) { .build(); } - private AuthorizationServiceConfiguration createAuthorizationServiceConfiguration(ReadableMap serviceConfiguration) throws Exception { + private AuthorizationServiceConfiguration createAuthorizationServiceConfiguration(ReadableMap serviceConfiguration) + throws Exception { if (!serviceConfiguration.hasKey("authorizationEndpoint")) { throw new Exception("serviceConfiguration passed without an authorizationEndpoint"); } @@ -995,8 +998,7 @@ private AuthorizationServiceConfiguration createAuthorizationServiceConfiguratio authorizationEndpoint, tokenEndpoint, registrationEndpoint, - endSessionEndpoint - ); + endSessionEndpoint); } private void warmChromeCustomTab(Context context, final String issuer) { @@ -1031,31 +1033,33 @@ private AuthorizationServiceConfiguration getServiceConfiguration(@Nullable Stri } } - private void handleAuthorizationException(final String fallbackErrorCode, final AuthorizationException ex, final Promise promise) { + private void handleAuthorizationException(final String fallbackErrorCode, final AuthorizationException ex, + final Promise promise) { if (ex.getLocalizedMessage() == null) { promise.reject(fallbackErrorCode, ex.error, ex); } else { - promise.reject(ex.error != null ? ex.error: fallbackErrorCode, ex.getLocalizedMessage(), ex); + promise.reject(ex.error != null ? ex.error : fallbackErrorCode, ex.getLocalizedMessage(), ex); } } - private void setServiceConfiguration(@Nullable String issuer, AuthorizationServiceConfiguration serviceConfiguration) { + private void setServiceConfiguration(@Nullable String issuer, + AuthorizationServiceConfiguration serviceConfiguration) { if (issuer != null) { mServiceConfigurations.put(issuer, serviceConfiguration); } } private BrowserMatcher getBrowserAllowList(ReadableArray androidAllowCustomBrowsers) { - if(androidAllowCustomBrowsers == null || androidAllowCustomBrowsers.size() == 0) { + if (androidAllowCustomBrowsers == null || androidAllowCustomBrowsers.size() == 0) { return AnyBrowserMatcher.INSTANCE; } MutableBrowserAllowList browserMatchers = new MutableBrowserAllowList(); - for(int i = 0; i < androidAllowCustomBrowsers.size(); i++) { + for (int i = 0; i < androidAllowCustomBrowsers.size(); i++) { String browser = androidAllowCustomBrowsers.getString(i); - if(browser == null) { + if (browser == null) { continue; } diff --git a/index.d.ts b/index.d.ts index 67e96730..0c59626f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -188,7 +188,8 @@ type AppAuthErrorCode = | 'registration_failed' | 'browser_not_found' | 'end_session_failed' - | 'authentication_error'; + | 'authentication_error' + | 'run_time_exception'; type ErrorCode = | OAuthAuthorizationErrorCode