Skip to content

Commit 4f7b045

Browse files
committed
Merge branch 'main' of https://github.com/auth0/Auth0.Android into SDK-5712
2 parents 79d3b7a + 7ca1c59 commit 4f7b045

File tree

6 files changed

+115
-15
lines changed

6 files changed

+115
-15
lines changed

EXAMPLES.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,12 +1347,9 @@ account.networkingClient = netClient
13471347
<summary>Using Java</summary>
13481348

13491349
```java
1350-
DefaultClient netClient = new DefaultClient(
1351-
connectTimeout = 30,
1352-
readTimeout = 30
1353-
);
1350+
DefaultClient netClient = new DefaultClient(30, 30);
13541351
Auth0 account = Auth0.getInstance("client id", "domain");
1355-
account.networkingClient = netClient;
1352+
account.setNetworkingClient(netClient);
13561353
```
13571354
</details>
13581355

@@ -1371,11 +1368,13 @@ account.networkingClient = netClient
13711368
<summary>Using Java</summary>
13721369

13731370
```java
1371+
import java.util.HashMap;
1372+
13741373
DefaultClient netClient = new DefaultClient(
1375-
enableLogging = true
1374+
10, 10, new HashMap<>() ,true
13761375
);
13771376
Auth0 account = Auth0.getInstance("client id", "domain");
1378-
account.networkingClient = netClient;
1377+
account.setNetworkingClient(netClient);
13791378
```
13801379
</details>
13811380

@@ -1398,10 +1397,10 @@ Map<String, String> defaultHeaders = new HashMap<>();
13981397
defaultHeaders.put("{HEADER-NAME}", "{HEADER-VALUE}");
13991398

14001399
DefaultClient netClient = new DefaultClient(
1401-
defaultHeaders = defaultHeaders
1400+
10,10 , defaultHeaders
14021401
);
14031402
Auth0 account = Auth0.getInstance("client id", "domain");
1404-
account.networkingClient = netClient;
1403+
account.setNetworkingClient(netClient);
14051404
```
14061405
</details>
14071406

@@ -1435,7 +1434,7 @@ class CustomNetClient extends NetworkingClient {
14351434
ServerResponse response = // ...
14361435

14371436
// Return a ServerResponse from the received response data
1438-
return ServerResponse(responseCode, responseBody, responseHeaders)
1437+
return new ServerResponse(responseCode, responseBody, responseHeaders);
14391438
}
14401439
};
14411440

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ The callback will get invoked when the user returns to your application. There a
197197
198198
##### A note about App Deep Linking:
199199

200+
> Whenever possible, Auth0 recommends using [Android App Links](https://auth0.com/docs/applications/enable-android-app-links) as a secure way to link directly to content within your app. Custom URL schemes can be subject to [client impersonation attacks](https://datatracker.ietf.org/doc/html/rfc8252#section-8.6).
201+
200202
If you followed the configuration steps documented here, you may have noticed the default scheme used for the Callback URI is `https`. This works best for Android API 23 or newer if you're using [Android App Links](https://auth0.com/docs/applications/enable-android-app-links), but in previous Android versions this _may_ show the intent chooser dialog prompting the user to choose either your application or the browser. You can change this behaviour by using a custom unique scheme so that the OS opens directly the link with your app.
201203

202204
1. Update the `auth0Scheme` Manifest Placeholder on the `app/build.gradle` file or update the intent-filter declaration in the `AndroidManifest.xml` to use the new scheme.

auth0/src/main/java/com/auth0/android/provider/CustomTabsOptions.java

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@
77
import android.net.Uri;
88
import android.os.Parcel;
99
import android.os.Parcelable;
10+
1011
import androidx.annotation.ColorRes;
1112
import androidx.annotation.NonNull;
1213
import androidx.annotation.Nullable;
1314
import androidx.browser.customtabs.CustomTabColorSchemeParams;
1415
import androidx.browser.customtabs.CustomTabsIntent;
1516
import androidx.browser.customtabs.CustomTabsSession;
16-
import androidx.browser.trusted.TrustedWebActivityIntent;
1717
import androidx.browser.trusted.TrustedWebActivityIntentBuilder;
1818
import androidx.core.content.ContextCompat;
1919

2020
import com.auth0.android.authentication.AuthenticationException;
2121

22+
import java.util.List;
23+
2224
/**
2325
* Holder for Custom Tabs customization options. Use {@link CustomTabsOptions#newBuilder()} to begin.
2426
*/
@@ -29,10 +31,14 @@ public class CustomTabsOptions implements Parcelable {
2931
private final int toolbarColor;
3032
private final BrowserPicker browserPicker;
3133

32-
private CustomTabsOptions(boolean showTitle, @ColorRes int toolbarColor, @NonNull BrowserPicker browserPicker) {
34+
@Nullable
35+
private final List<String> disabledCustomTabsPackages;
36+
37+
private CustomTabsOptions(boolean showTitle, @ColorRes int toolbarColor, @NonNull BrowserPicker browserPicker, @Nullable List<String> disabledCustomTabsPackages) {
3338
this.showTitle = showTitle;
3439
this.toolbarColor = toolbarColor;
3540
this.browserPicker = browserPicker;
41+
this.disabledCustomTabsPackages = disabledCustomTabsPackages;
3642
}
3743

3844
@Nullable
@@ -44,6 +50,16 @@ boolean hasCompatibleBrowser(@NonNull PackageManager pm) {
4450
return getPreferredPackage(pm) != null;
4551
}
4652

53+
/**
54+
* Returns whether the browser preferred package has custom tab disabled or not.
55+
*
56+
* @param preferredPackage the preferred browser package name.
57+
* @return whether the browser preferred package has custom tab disabled or not.
58+
*/
59+
boolean isDisabledCustomTabBrowser(@NonNull String preferredPackage) {
60+
return disabledCustomTabsPackages != null && disabledCustomTabsPackages.contains(preferredPackage);
61+
}
62+
4763
/**
4864
* Create a new CustomTabsOptions.Builder instance.
4965
*
@@ -57,6 +73,12 @@ public static Builder newBuilder() {
5773

5874
@SuppressLint("ResourceType")
5975
Intent toIntent(@NonNull Context context, @Nullable CustomTabsSession session) {
76+
String preferredPackage = this.getPreferredPackage(context.getPackageManager());
77+
78+
if (preferredPackage != null && this.isDisabledCustomTabBrowser(preferredPackage)) {
79+
return new Intent(Intent.ACTION_VIEW);
80+
}
81+
6082
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(session)
6183
.setShowTitle(showTitle)
6284
.setShareState(CustomTabsIntent.SHARE_STATE_OFF);
@@ -85,13 +107,15 @@ protected CustomTabsOptions(@NonNull Parcel in) {
85107
showTitle = in.readByte() != 0;
86108
toolbarColor = in.readInt();
87109
browserPicker = in.readParcelable(BrowserPicker.class.getClassLoader());
110+
disabledCustomTabsPackages = in.createStringArrayList();
88111
}
89112

90113
@Override
91114
public void writeToParcel(@NonNull Parcel dest, int flags) {
92115
dest.writeByte((byte) (showTitle ? 1 : 0));
93116
dest.writeInt(toolbarColor);
94117
dest.writeParcelable(browserPicker, flags);
118+
dest.writeStringList(disabledCustomTabsPackages);
95119
}
96120

97121
@Override
@@ -120,10 +144,14 @@ public static class Builder {
120144
@NonNull
121145
private BrowserPicker browserPicker;
122146

147+
@Nullable
148+
private List<String> disabledCustomTabsPackages;
149+
123150
Builder() {
124151
this.showTitle = false;
125152
this.toolbarColor = 0;
126153
this.browserPicker = BrowserPicker.newBuilder().build();
154+
this.disabledCustomTabsPackages = null;
127155
}
128156

129157
/**
@@ -171,14 +199,27 @@ public Builder withBrowserPicker(@NonNull BrowserPicker browserPicker) {
171199
return this;
172200
}
173201

202+
/**
203+
* Define a list of browser packages that disables the launching of authentication on custom tabs.
204+
* The authentication url will launch on the preferred package external browser.
205+
*
206+
* @param disabledCustomTabsPackages list of browser packages.
207+
* @return the current builder instance
208+
*/
209+
@NonNull
210+
public Builder withDisabledCustomTabsPackages(List<String> disabledCustomTabsPackages) {
211+
this.disabledCustomTabsPackages = disabledCustomTabsPackages;
212+
return this;
213+
}
214+
174215
/**
175216
* Create a new CustomTabsOptions instance with the customization settings.
176217
*
177218
* @return an instance of CustomTabsOptions with the customization settings.
178219
*/
179220
@NonNull
180221
public CustomTabsOptions build() {
181-
return new CustomTabsOptions(showTitle, toolbarColor, browserPicker);
222+
return new CustomTabsOptions(showTitle, toolbarColor, browserPicker, disabledCustomTabsPackages);
182223
}
183224
}
184225

auth0/src/main/java/com/auth0/android/provider/WebAuthProvider.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ public object WebAuthProvider {
223223
* An error is raised if there are no browser applications installed in the device or if
224224
* the user closed the browser before completing the logout.
225225
*
226-
* @param context to run the log out
226+
* @param context An activity context to run the log out. Passing any other context can cause a crash while starting the [AuthenticationActivity]
227227
* @param callback to invoke when log out is successful
228228
* @see AuthenticationException.isBrowserAppNotAvailable
229229
* @see AuthenticationException.isAuthenticationCanceled
@@ -524,7 +524,7 @@ public object WebAuthProvider {
524524
* device does not support the necessary algorithms to support Proof of Key Exchange (PKCE)
525525
* (this is not expected), or if the user closed the browser before completing the authentication.
526526
*
527-
* @param context context to run the authentication
527+
* @param context An Activity context to run the authentication. Passing any other context can cause a crash while starting the [AuthenticationActivity]
528528
* @param callback to receive the parsed results
529529
* @see AuthenticationException.isBrowserAppNotAvailable
530530
* @see AuthenticationException.isPKCENotAvailable
@@ -574,6 +574,13 @@ public object WebAuthProvider {
574574
manager.startAuthentication(context, redirectUri!!, 110)
575575
}
576576

577+
/**
578+
* Request user Authentication. An error is thrown if there are no browser applications installed in the device, or if
579+
* device does not support the necessary algorithms to support Proof of Key Exchange (PKCE)
580+
* (this is not expected), or if the user closed the browser before completing the authentication.
581+
*
582+
* @param context An Activity context to run the authentication. Passing any other context can cause a crash while starting the [AuthenticationActivity]
583+
*/
577584
@JvmSynthetic
578585
@Throws(AuthenticationException::class)
579586
public suspend fun await(context: Context): Credentials {

auth0/src/main/java/com/auth0/android/request/DefaultClient.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class DefaultClient @VisibleForTesting(otherwise = VisibleForTesting.PRIV
3737
* @param defaultHeaders any headers that should be sent on all requests. If a specific request specifies a header with the same key as any header in the default headers, the header specified on the request will take precedence. Default is an empty map.
3838
* @param enableLogging whether HTTP request and response info should be logged. This should only be set to `true` for debugging purposes in non-production environments, as sensitive information is included in the logs. Defaults to `false`.
3939
*/
40+
@JvmOverloads
4041
public constructor(
4142
connectTimeout: Int = DEFAULT_TIMEOUT_SECONDS,
4243
readTimeout: Int = DEFAULT_TIMEOUT_SECONDS,

auth0/src/test/java/com/auth0/android/provider/CustomTabsOptionsTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414
import org.robolectric.Robolectric;
1515
import org.robolectric.RobolectricTestRunner;
1616

17+
import java.util.ArrayList;
18+
import java.util.Arrays;
1719
import java.util.Collections;
20+
import java.util.List;
1821

1922
import static org.hamcrest.MatcherAssert.assertThat;
2023
import static org.hamcrest.core.Is.is;
2124
import static org.hamcrest.core.IsNull.notNullValue;
2225
import static org.hamcrest.core.IsNull.nullValue;
26+
import static org.junit.Assert.assertEquals;
2327
import static org.mockito.Matchers.any;
2428
import static org.mockito.Mockito.mock;
2529
import static org.mockito.Mockito.spy;
@@ -174,4 +178,50 @@ public void shouldSetBrowserPicker() {
174178
String preferredPackageNow = parceledOptions.getPreferredPackage(activity.getPackageManager());
175179
assertThat(preferredPackageNow, is("com.auth0.browser"));
176180
}
181+
182+
@Test
183+
public void shouldSetDisabledCustomTabPackages() {
184+
Activity activity = spy(Robolectric.setupActivity(Activity.class));
185+
BrowserPickerTest.setupBrowserContext(activity, Collections.singletonList("com.auth0.browser"), null, null);
186+
BrowserPicker browserPicker = BrowserPicker.newBuilder().build();
187+
188+
CustomTabsOptions options = CustomTabsOptions.newBuilder()
189+
.withBrowserPicker(browserPicker)
190+
.withDisabledCustomTabsPackages(List.of("com.auth0.browser"))
191+
.withToolbarColor(android.R.color.black)
192+
.build();
193+
assertThat(options, is(notNullValue()));
194+
195+
Intent intentNoExtras = options.toIntent(activity, null);
196+
197+
assertThat(intentNoExtras, is(notNullValue()));
198+
assertThat(intentNoExtras.getExtras(), is(nullValue()));
199+
assertEquals(intentNoExtras.getAction(), "android.intent.action.VIEW");
200+
201+
Parcel parcel = Parcel.obtain();
202+
options.writeToParcel(parcel, 0);
203+
parcel.setDataPosition(0);
204+
CustomTabsOptions parceledOptions = CustomTabsOptions.CREATOR.createFromParcel(parcel);
205+
assertThat(parceledOptions, is(notNullValue()));
206+
207+
Intent parceledIntent = parceledOptions.toIntent(activity, null);
208+
assertThat(parceledIntent, is(notNullValue()));
209+
assertThat(parceledIntent.getExtras(), is(nullValue()));
210+
assertEquals(parceledIntent.getAction(), "android.intent.action.VIEW");
211+
212+
BrowserPickerTest.setupBrowserContext(activity, Collections.singletonList("com.another.browser"), null, null);
213+
BrowserPicker browserPicker2 = BrowserPicker.newBuilder().build();
214+
215+
CustomTabsOptions options2 = CustomTabsOptions.newBuilder()
216+
.withBrowserPicker(browserPicker2)
217+
.withDisabledCustomTabsPackages(List.of("com.auth0.browser"))
218+
.withToolbarColor(android.R.color.black)
219+
.build();
220+
221+
Intent intentWithToolbarExtra = options2.toIntent(activity, null);
222+
assertThat(intentWithToolbarExtra, is(notNullValue()));
223+
assertThat(intentWithToolbarExtra.hasExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR), is(true));
224+
int resolvedColor = ContextCompat.getColor(activity, android.R.color.black);
225+
assertThat(intentWithToolbarExtra.getIntExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR, 0), is(resolvedColor));
226+
}
177227
}

0 commit comments

Comments
 (0)