|
28 | 28 | import com.rnappauth.utils.UnsafeConnectionBuilder;
|
29 | 29 | import com.rnappauth.utils.RegistrationResponseFactory;
|
30 | 30 | import com.rnappauth.utils.TokenResponseFactory;
|
| 31 | +import com.rnappauth.utils.EndSessionResponseFactory; |
31 | 32 | import com.rnappauth.utils.CustomConnectionBuilder;
|
32 | 33 |
|
33 | 34 | import net.openid.appauth.AppAuthConfiguration;
|
|
45 | 46 | import net.openid.appauth.ResponseTypeValues;
|
46 | 47 | import net.openid.appauth.TokenResponse;
|
47 | 48 | import net.openid.appauth.TokenRequest;
|
| 49 | +import net.openid.appauth.EndSessionRequest; |
| 50 | +import net.openid.appauth.EndSessionResponse; |
48 | 51 | import net.openid.appauth.connectivity.ConnectionBuilder;
|
49 | 52 | import net.openid.appauth.connectivity.DefaultConnectionBuilder;
|
50 | 53 |
|
@@ -84,15 +87,15 @@ public RNAppAuthModule(ReactApplicationContext reactContext) {
|
84 | 87 |
|
85 | 88 | @ReactMethod
|
86 | 89 | public void prefetchConfiguration(
|
87 |
| - final Boolean warmAndPrefetchChrome, |
88 |
| - final String issuer, |
89 |
| - final String redirectUrl, |
90 |
| - final String clientId, |
91 |
| - final ReadableArray scopes, |
92 |
| - final ReadableMap serviceConfiguration, |
93 |
| - final boolean dangerouslyAllowInsecureHttpRequests, |
94 |
| - final ReadableMap headers, |
95 |
| - final Promise promise |
| 90 | + final Boolean warmAndPrefetchChrome, |
| 91 | + final String issuer, |
| 92 | + final String redirectUrl, |
| 93 | + final String clientId, |
| 94 | + final ReadableArray scopes, |
| 95 | + final ReadableMap serviceConfiguration, |
| 96 | + final boolean dangerouslyAllowInsecureHttpRequests, |
| 97 | + final ReadableMap headers, |
| 98 | + final Promise promise |
96 | 99 | ) {
|
97 | 100 | if (warmAndPrefetchChrome) {
|
98 | 101 | warmChromeCustomTab(reactContext, issuer);
|
@@ -145,17 +148,17 @@ public void onFetchConfigurationCompleted(
|
145 | 148 |
|
146 | 149 | @ReactMethod
|
147 | 150 | public void register(
|
148 |
| - String issuer, |
149 |
| - final ReadableArray redirectUris, |
150 |
| - final ReadableArray responseTypes, |
151 |
| - final ReadableArray grantTypes, |
152 |
| - final String subjectType, |
153 |
| - final String tokenEndpointAuthMethod, |
154 |
| - final ReadableMap additionalParameters, |
155 |
| - final ReadableMap serviceConfiguration, |
156 |
| - final boolean dangerouslyAllowInsecureHttpRequests, |
157 |
| - final ReadableMap headers, |
158 |
| - final Promise promise |
| 151 | + String issuer, |
| 152 | + final ReadableArray redirectUris, |
| 153 | + final ReadableArray responseTypes, |
| 154 | + final ReadableArray grantTypes, |
| 155 | + final String subjectType, |
| 156 | + final String tokenEndpointAuthMethod, |
| 157 | + final ReadableMap additionalParameters, |
| 158 | + final ReadableMap serviceConfiguration, |
| 159 | + final boolean dangerouslyAllowInsecureHttpRequests, |
| 160 | + final ReadableMap headers, |
| 161 | + final Promise promise |
159 | 162 | ) {
|
160 | 163 | this.parseHeaderMap(headers);
|
161 | 164 | final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, this.registrationRequestHeaders);
|
@@ -394,6 +397,72 @@ public void onFetchConfigurationCompleted(
|
394 | 397 |
|
395 | 398 | }
|
396 | 399 |
|
| 400 | + @ReactMethod |
| 401 | + public void logout( |
| 402 | + String issuer, |
| 403 | + final String idTokenHint, |
| 404 | + final String postLogoutRedirectUri, |
| 405 | + final ReadableMap serviceConfiguration, |
| 406 | + final ReadableMap additionalParameters, |
| 407 | + final boolean dangerouslyAllowInsecureHttpRequests, |
| 408 | + final Promise promise |
| 409 | + ) { |
| 410 | + final ConnectionBuilder builder = createConnectionBuilder(dangerouslyAllowInsecureHttpRequests, null); |
| 411 | + final AppAuthConfiguration appAuthConfiguration = this.createAppAuthConfiguration(builder, dangerouslyAllowInsecureHttpRequests); |
| 412 | + final HashMap<String, String> additionalParametersMap = MapUtil.readableMapToHashMap(additionalParameters); |
| 413 | + |
| 414 | + this.promise = promise; |
| 415 | + |
| 416 | + if (serviceConfiguration != null || hasServiceConfiguration(issuer)) { |
| 417 | + try { |
| 418 | + final AuthorizationServiceConfiguration serviceConfig = hasServiceConfiguration(issuer) ? getServiceConfiguration(issuer) : createAuthorizationServiceConfiguration(serviceConfiguration); |
| 419 | + endSessionWithConfiguration( |
| 420 | + serviceConfig, |
| 421 | + appAuthConfiguration, |
| 422 | + idTokenHint, |
| 423 | + postLogoutRedirectUri, |
| 424 | + additionalParametersMap |
| 425 | + ); |
| 426 | + } catch (ActivityNotFoundException e) { |
| 427 | + promise.reject("browser_not_found", e.getMessage()); |
| 428 | + } catch (Exception e) { |
| 429 | + promise.reject("end_session_failed", e.getMessage()); |
| 430 | + } |
| 431 | + } else { |
| 432 | + final Uri issuerUri = Uri.parse(issuer); |
| 433 | + AuthorizationServiceConfiguration.fetchFromUrl( |
| 434 | + buildConfigurationUriFromIssuer(issuerUri), |
| 435 | + new AuthorizationServiceConfiguration.RetrieveConfigurationCallback() { |
| 436 | + public void onFetchConfigurationCompleted( |
| 437 | + @Nullable AuthorizationServiceConfiguration fetchedConfiguration, |
| 438 | + @Nullable AuthorizationException ex) { |
| 439 | + if (ex != null) { |
| 440 | + promise.reject("service_configuration_fetch_error", ex.getLocalizedMessage(), ex); |
| 441 | + return; |
| 442 | + } |
| 443 | + |
| 444 | + setServiceConfiguration(issuer, fetchedConfiguration); |
| 445 | + |
| 446 | + try { |
| 447 | + endSessionWithConfiguration( |
| 448 | + fetchedConfiguration, |
| 449 | + appAuthConfiguration, |
| 450 | + idTokenHint, |
| 451 | + postLogoutRedirectUri, |
| 452 | + additionalParametersMap |
| 453 | + ); |
| 454 | + } catch (ActivityNotFoundException e) { |
| 455 | + promise.reject("browser_not_found", e.getMessage()); |
| 456 | + } catch (Exception e) { |
| 457 | + promise.reject("end_session_failed", e.getMessage()); |
| 458 | + } |
| 459 | + } |
| 460 | + }, |
| 461 | + builder |
| 462 | + ); |
| 463 | + } |
| 464 | + } |
| 465 | + |
397 | 466 | /*
|
398 | 467 | * Called when the OAuth browser activity completes
|
399 | 468 | */
|
@@ -468,32 +537,52 @@ public void onTokenRequestCompleted(
|
468 | 537 | }
|
469 | 538 |
|
470 | 539 | }
|
| 540 | + |
| 541 | + if (requestCode == 53) { |
| 542 | + if (data == null) { |
| 543 | + if (promise != null) { |
| 544 | + promise.reject("end_session_failed", "Data intent is null" ); |
| 545 | + } |
| 546 | + return; |
| 547 | + } |
| 548 | + EndSessionResponse response = EndSessionResponse.fromIntent(data); |
| 549 | + AuthorizationException ex = AuthorizationException.fromIntent(data); |
| 550 | + if (ex != null) { |
| 551 | + if (promise != null) { |
| 552 | + handleAuthorizationException("end_session_failed", ex, promise); |
| 553 | + } |
| 554 | + return; |
| 555 | + } |
| 556 | + final Promise endSessionPromise = this.promise; |
| 557 | + WritableMap map = EndSessionResponseFactory.endSessionResponseToMap(response); |
| 558 | + endSessionPromise.resolve(map); |
| 559 | + } |
471 | 560 | }
|
472 | 561 |
|
473 | 562 | /*
|
474 | 563 | * Perform dynamic client registration with the provided configuration
|
475 | 564 | */
|
476 | 565 | private void registerWithConfiguration(
|
477 |
| - final AuthorizationServiceConfiguration serviceConfiguration, |
478 |
| - final AppAuthConfiguration appAuthConfiguration, |
479 |
| - final ReadableArray redirectUris, |
480 |
| - final ReadableArray responseTypes, |
481 |
| - final ReadableArray grantTypes, |
482 |
| - final String subjectType, |
483 |
| - final String tokenEndpointAuthMethod, |
484 |
| - final Map<String, String> additionalParametersMap, |
485 |
| - final Promise promise |
| 566 | + final AuthorizationServiceConfiguration serviceConfiguration, |
| 567 | + final AppAuthConfiguration appAuthConfiguration, |
| 568 | + final ReadableArray redirectUris, |
| 569 | + final ReadableArray responseTypes, |
| 570 | + final ReadableArray grantTypes, |
| 571 | + final String subjectType, |
| 572 | + final String tokenEndpointAuthMethod, |
| 573 | + final Map<String, String> additionalParametersMap, |
| 574 | + final Promise promise |
486 | 575 | ) {
|
487 | 576 | final Context context = this.reactContext;
|
488 | 577 |
|
489 | 578 | AuthorizationService authService = new AuthorizationService(context, appAuthConfiguration);
|
490 | 579 |
|
491 | 580 | RegistrationRequest.Builder registrationRequestBuilder =
|
492 | 581 | new RegistrationRequest.Builder(
|
493 |
| - serviceConfiguration, |
494 |
| - arrayToUriList(redirectUris) |
| 582 | + serviceConfiguration, |
| 583 | + arrayToUriList(redirectUris) |
495 | 584 | )
|
496 |
| - .setAdditionalParameters(additionalParametersMap); |
| 585 | + .setAdditionalParameters(additionalParametersMap); |
497 | 586 |
|
498 | 587 | if (responseTypes != null) {
|
499 | 588 | registrationRequestBuilder.setResponseTypeValues(arrayToList(responseTypes));
|
@@ -677,6 +766,47 @@ public void onTokenRequestCompleted(@Nullable TokenResponse response, @Nullable
|
677 | 766 | }
|
678 | 767 | }
|
679 | 768 |
|
| 769 | + /* |
| 770 | + * End user session with provided configuration |
| 771 | + */ |
| 772 | + private void endSessionWithConfiguration( |
| 773 | + final AuthorizationServiceConfiguration serviceConfiguration, |
| 774 | + final AppAuthConfiguration appAuthConfiguration, |
| 775 | + final String idTokenHint, |
| 776 | + final String postLogoutRedirectUri, |
| 777 | + final Map<String, String> additionalParametersMap |
| 778 | + ) { |
| 779 | + final Context context = this.reactContext; |
| 780 | + final Activity currentActivity = getCurrentActivity(); |
| 781 | + |
| 782 | + EndSessionRequest.Builder endSessionRequestBuilder = |
| 783 | + new EndSessionRequest.Builder( |
| 784 | + serviceConfiguration, |
| 785 | + idTokenHint, |
| 786 | + Uri.parse(postLogoutRedirectUri) |
| 787 | + ); |
| 788 | + |
| 789 | + if (additionalParametersMap != null) { |
| 790 | + if (additionalParametersMap.containsKey("state")) { |
| 791 | + endSessionRequestBuilder.setState(additionalParametersMap.get("state")); |
| 792 | + } |
| 793 | + } |
| 794 | + |
| 795 | + EndSessionRequest endSessionRequest = endSessionRequestBuilder.build(); |
| 796 | + |
| 797 | + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { |
| 798 | + AuthorizationService authService = new AuthorizationService(context, appAuthConfiguration); |
| 799 | + Intent endSessionIntent = authService.getEndSessionRequestIntent(endSessionRequest); |
| 800 | + |
| 801 | + currentActivity.startActivityForResult(endSessionIntent, 53); |
| 802 | + } else { |
| 803 | + AuthorizationService authService = new AuthorizationService(currentActivity, appAuthConfiguration); |
| 804 | + PendingIntent pendingIntent = currentActivity.createPendingResult(53, new Intent(), 0); |
| 805 | + |
| 806 | + authService.performEndSessionRequest(endSessionRequest, pendingIntent); |
| 807 | + } |
| 808 | + } |
| 809 | + |
680 | 810 | private void parseHeaderMap (ReadableMap headerMap) {
|
681 | 811 | if (headerMap == null) {
|
682 | 812 | return;
|
@@ -793,14 +923,19 @@ private AuthorizationServiceConfiguration createAuthorizationServiceConfiguratio
|
793 | 923 | Uri authorizationEndpoint = Uri.parse(serviceConfiguration.getString("authorizationEndpoint"));
|
794 | 924 | Uri tokenEndpoint = Uri.parse(serviceConfiguration.getString("tokenEndpoint"));
|
795 | 925 | Uri registrationEndpoint = null;
|
| 926 | + Uri endSessionEndpoint = null; |
796 | 927 | if (serviceConfiguration.hasKey("registrationEndpoint")) {
|
797 | 928 | registrationEndpoint = Uri.parse(serviceConfiguration.getString("registrationEndpoint"));
|
798 | 929 | }
|
| 930 | + if (serviceConfiguration.hasKey("endSessionEndpoint")) { |
| 931 | + endSessionEndpoint = Uri.parse(serviceConfiguration.getString("endSessionEndpoint")); |
| 932 | + } |
799 | 933 |
|
800 | 934 | return new AuthorizationServiceConfiguration(
|
801 | 935 | authorizationEndpoint,
|
802 | 936 | tokenEndpoint,
|
803 |
| - registrationEndpoint |
| 937 | + registrationEndpoint, |
| 938 | + endSessionEndpoint |
804 | 939 | );
|
805 | 940 | }
|
806 | 941 |
|
@@ -837,7 +972,7 @@ private AuthorizationServiceConfiguration getServiceConfiguration(@Nullable Stri
|
837 | 972 | }
|
838 | 973 |
|
839 | 974 | private void handleAuthorizationException(final String fallbackErrorCode, final AuthorizationException ex, final Promise promise) {
|
840 |
| - if (ex.getLocalizedMessage() == null) { |
| 975 | + if (ex.getLocalizedMessage() == null) { |
841 | 976 | promise.reject(fallbackErrorCode, ex.error, ex);
|
842 | 977 | } else {
|
843 | 978 | promise.reject(ex.error != null ? ex.error: fallbackErrorCode, ex.getLocalizedMessage(), ex);
|
|
0 commit comments