Skip to content

Commit 59fad7e

Browse files
authored
Handled NPE in the AuthenticationActivity (#759)
2 parents dc844e3 + 9af9473 commit 59fad7e

File tree

6 files changed

+134
-24
lines changed

6 files changed

+134
-24
lines changed

auth0/src/main/java/com/auth0/android/Auth0.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public open class Auth0 private constructor(
7272
* @return Url to call to perform the web flow of OAuth
7373
*/
7474
public open val authorizeUrl: String
75-
get() = domainUrl!!.newBuilder()
75+
get() = domainUrl.newBuilder()
7676
.addEncodedPathSegment("authorize")
7777
.build()
7878
.toString()
@@ -83,7 +83,7 @@ public open class Auth0 private constructor(
8383
* @return Url to call to perform the web logout
8484
*/
8585
public open val logoutUrl: String
86-
get() = domainUrl!!.newBuilder()
86+
get() = domainUrl.newBuilder()
8787
.addEncodedPathSegment("v2")
8888
.addEncodedPathSegment("logout")
8989
.build()
@@ -134,7 +134,7 @@ public open class Auth0 private constructor(
134134
): Auth0 {
135135
val domainUrl = ensureValidUrl(domain)
136136
requireNotNull(domainUrl) { String.format("Invalid domain url: '%s'", domain) }
137-
if (instance == null || instance!!.clientId != clientId || instance!!.domainUrl.host != domainUrl.host || instance!!.configurationDomain != configurationDomain) {
137+
if (instance == null || instance?.clientId != clientId || instance?.domainUrl?.host != domainUrl.host || instance?.configurationDomain != configurationDomain) {
138138
instance = Auth0(clientId, domainUrl, configurationDomain)
139139
}
140140
return instance!!

auth0/src/main/java/com/auth0/android/authentication/AuthenticationException.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ public class AuthenticationException : Auth0Exception {
2626

2727
public constructor(message: String, cause: Exception? = null) : super(message, cause)
2828

29-
public constructor(code: String, description: String, cause: Exception) : this(DEFAULT_MESSAGE, cause) {
29+
public constructor(code: String, description: String, cause: Exception) : this(
30+
DEFAULT_MESSAGE,
31+
cause
32+
) {
3033
this.code = code
3134
this.description = description
3235
}
@@ -126,7 +129,10 @@ public class AuthenticationException : Auth0Exception {
126129
get() = "a0.invalid_configuration" == code
127130

128131
// When a user closes the browser app and in turn, cancels the authentication
129-
@Deprecated("This property can refer to both log in and log out actions.", replaceWith = ReplaceWith("isCanceled"))
132+
@Deprecated(
133+
"This property can refer to both log in and log out actions.",
134+
replaceWith = ReplaceWith("isCanceled")
135+
)
130136
public val isAuthenticationCanceled: Boolean
131137
get() = isCanceled
132138

@@ -183,7 +189,7 @@ public class AuthenticationException : Auth0Exception {
183189
/// When authenticating with web-based authentication using prompt=none and the auth0 session had expired
184190
public val isLoginRequired: Boolean
185191
get() = "login_required" == code
186-
192+
187193
/// User is deleted
188194
public val isRefreshTokenDeleted: Boolean
189195
get() = "invalid_grant" == code
@@ -205,6 +211,12 @@ public class AuthenticationException : Auth0Exception {
205211

206212
internal companion object {
207213
internal const val ERROR_VALUE_AUTHENTICATION_CANCELED = "a0.authentication_canceled"
214+
internal const val ERROR_KEY_URI_NULL = "a0.auth.authorize_uri"
215+
internal const val ERROR_VALUE_AUTHORIZE_URI_INVALID =
216+
"Authorization URI is received as null from the intent"
217+
internal const val ERROR_KEY_CT_OPTIONS_NULL = "a0.auth.ct_options"
218+
internal const val ERROR_VALUE_CT_OPTIONS_INVALID =
219+
"Custom tab options are received as null from the intent"
208220
private const val ERROR_KEY = "error"
209221
private const val CODE_KEY = "code"
210222
private const val DESCRIPTION_KEY = "description"

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

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import android.net.Uri
77
import android.os.Bundle
88
import androidx.annotation.VisibleForTesting
99
import com.auth0.android.authentication.AuthenticationException
10+
import com.auth0.android.authentication.AuthenticationException.Companion.ERROR_KEY_CT_OPTIONS_NULL
11+
import com.auth0.android.authentication.AuthenticationException.Companion.ERROR_KEY_URI_NULL
12+
import com.auth0.android.authentication.AuthenticationException.Companion.ERROR_VALUE_AUTHORIZE_URI_INVALID
13+
import com.auth0.android.authentication.AuthenticationException.Companion.ERROR_VALUE_CT_OPTIONS_INVALID
1014
import com.auth0.android.callback.RunnableTask
1115
import com.auth0.android.provider.WebAuthProvider.failure
1216
import com.auth0.android.provider.WebAuthProvider.resume
@@ -68,23 +72,44 @@ public open class AuthenticationActivity : Activity() {
6872
}
6973

7074
private fun launchAuthenticationIntent() {
71-
val extras = intent.extras
72-
val authorizeUri = extras!!.getParcelable<Uri>(EXTRA_AUTHORIZE_URI)
73-
val customTabsOptions: CustomTabsOptions = extras.getParcelable(EXTRA_CT_OPTIONS)!!
75+
val extras: Bundle? = intent.extras
76+
77+
val authorizeUri = extras?.getParcelable<Uri>(EXTRA_AUTHORIZE_URI)
78+
authorizeUri ?: run {
79+
deliverAuthenticationFailure(
80+
AuthenticationException(
81+
ERROR_KEY_URI_NULL, ERROR_VALUE_AUTHORIZE_URI_INVALID
82+
)
83+
)
84+
return
85+
}
86+
87+
val customTabsOptions: CustomTabsOptions? = extras.getParcelable(EXTRA_CT_OPTIONS)
88+
customTabsOptions ?: run {
89+
deliverAuthenticationFailure(
90+
AuthenticationException(
91+
ERROR_KEY_CT_OPTIONS_NULL, ERROR_VALUE_CT_OPTIONS_INVALID
92+
)
93+
)
94+
return
95+
}
96+
7497
val launchAsTwa: Boolean = extras.getBoolean(EXTRA_LAUNCH_AS_TWA, false)
7598
customTabsController = createCustomTabsController(this, customTabsOptions)
7699
customTabsController!!.bindService()
77-
customTabsController!!.launchUri(authorizeUri!!, launchAsTwa, getInstance(), object : RunnableTask<AuthenticationException> {
78-
override fun apply(error: AuthenticationException) {
79-
deliverAuthenticationFailure(error)
80-
}
81-
})
100+
customTabsController!!.launchUri(authorizeUri,
101+
launchAsTwa,
102+
getInstance(),
103+
object : RunnableTask<AuthenticationException> {
104+
override fun apply(error: AuthenticationException) {
105+
deliverAuthenticationFailure(error)
106+
}
107+
})
82108
}
83109

84110
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
85111
internal open fun createCustomTabsController(
86-
context: Context,
87-
options: CustomTabsOptions
112+
context: Context, options: CustomTabsOptions
88113
): CustomTabsController {
89114
return CustomTabsController(context, options, TwaLauncher(context))
90115
}
@@ -107,10 +132,7 @@ public open class AuthenticationActivity : Activity() {
107132

108133
@JvmStatic
109134
internal fun authenticateUsingBrowser(
110-
context: Context,
111-
authorizeUri: Uri,
112-
launchAsTwa: Boolean,
113-
options: CustomTabsOptions
135+
context: Context, authorizeUri: Uri, launchAsTwa: Boolean, options: CustomTabsOptions
114136
) {
115137
val intent = Intent(context, AuthenticationActivity::class.java)
116138
intent.putExtra(EXTRA_AUTHORIZE_URI, authorizeUri)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ public object WebAuthProvider {
8282
}
8383

8484
internal fun failure(exception: AuthenticationException) {
85+
if (managerInstance == null) {
86+
Log.w(TAG, "There is no previous instance of this provider.")
87+
return
88+
}
8589
managerInstance!!.failure(exception)
8690
}
8791

auth0/src/test/java/com/auth0/android/provider/AuthenticationActivityMock.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@ package com.auth0.android.provider
22

33
import android.content.Context
44
import android.content.Intent
5+
import com.auth0.android.authentication.AuthenticationException
56

67
public class AuthenticationActivityMock : AuthenticationActivity() {
78
internal var customTabsController: CustomTabsController? = null
89
public var deliveredIntent: Intent? = null
910
private set
11+
public var deliveredException: AuthenticationException? = null
12+
private set
1013

1114
override fun createCustomTabsController(
1215
context: Context,
@@ -19,4 +22,9 @@ public class AuthenticationActivityMock : AuthenticationActivity() {
1922
deliveredIntent = result
2023
super.deliverAuthenticationResult(result)
2124
}
25+
26+
override fun deliverAuthenticationFailure(ex: AuthenticationException) {
27+
deliveredException = ex
28+
super.deliverAuthenticationFailure(ex)
29+
}
2230
}

auth0/src/test/java/com/auth0/android/provider/AuthenticationActivityTest.kt

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import androidx.test.espresso.intent.matcher.IntentMatchers
99
import com.auth0.android.authentication.AuthenticationException
1010
import com.auth0.android.callback.RunnableTask
1111
import com.auth0.android.provider.AuthenticationActivity
12+
import com.auth0.android.provider.AuthenticationActivity.Companion.EXTRA_AUTHORIZE_URI
13+
import com.auth0.android.provider.AuthenticationActivity.Companion.EXTRA_CT_OPTIONS
14+
import com.auth0.android.provider.AuthenticationActivity.Companion.EXTRA_LAUNCH_AS_TWA
1215
import com.auth0.android.provider.CustomTabsOptions
1316
import com.nhaarman.mockitokotlin2.any
1417
import org.hamcrest.CoreMatchers
@@ -92,7 +95,12 @@ public class AuthenticationActivityTest {
9295
createActivity(intentCaptor.value)
9396
activityController.create().start().resume()
9497
Mockito.verify(customTabsController).bindService()
95-
Mockito.verify(customTabsController).launchUri(uriCaptor.capture(), launchAsTwaCaptor.capture(), any(), failureCallbackCaptor.capture())
98+
Mockito.verify(customTabsController).launchUri(
99+
uriCaptor.capture(),
100+
launchAsTwaCaptor.capture(),
101+
any(),
102+
failureCallbackCaptor.capture()
103+
)
96104
MatcherAssert.assertThat(uriCaptor.value, Is.`is`(Matchers.notNullValue()))
97105
MatcherAssert.assertThat(uriCaptor.value, Is.`is`(uri))
98106
MatcherAssert.assertThat(activity.deliveredIntent, Is.`is`(Matchers.nullValue()))
@@ -123,7 +131,12 @@ public class AuthenticationActivityTest {
123131
createActivity(intentCaptor.value)
124132
activityController.create().start().resume()
125133
Mockito.verify(customTabsController).bindService()
126-
Mockito.verify(customTabsController).launchUri(uriCaptor.capture(), launchAsTwaCaptor.capture(), any(), failureCallbackCaptor.capture())
134+
Mockito.verify(customTabsController).launchUri(
135+
uriCaptor.capture(),
136+
launchAsTwaCaptor.capture(),
137+
any(),
138+
failureCallbackCaptor.capture()
139+
)
127140
MatcherAssert.assertThat(uriCaptor.value, Is.`is`(Matchers.notNullValue()))
128141
MatcherAssert.assertThat(uriCaptor.value, Is.`is`(uri))
129142
MatcherAssert.assertThat(activity.deliveredIntent, Is.`is`(Matchers.nullValue()))
@@ -154,7 +167,12 @@ public class AuthenticationActivityTest {
154167
createActivity(intentCaptor.value)
155168
activityController.create().start().resume()
156169
Mockito.verify(customTabsController).bindService()
157-
Mockito.verify(customTabsController).launchUri(uriCaptor.capture(), launchAsTwaCaptor.capture(), any(), failureCallbackCaptor.capture())
170+
Mockito.verify(customTabsController).launchUri(
171+
uriCaptor.capture(),
172+
launchAsTwaCaptor.capture(),
173+
any(),
174+
failureCallbackCaptor.capture()
175+
)
158176
MatcherAssert.assertThat(uriCaptor.value, Is.`is`(Matchers.notNullValue()))
159177
MatcherAssert.assertThat(uriCaptor.value, Is.`is`(uri))
160178
MatcherAssert.assertThat(launchAsTwaCaptor.value, Is.`is`(Matchers.notNullValue()))
@@ -184,7 +202,12 @@ public class AuthenticationActivityTest {
184202
createActivity(intentCaptor.value)
185203
activityController.create().start().resume()
186204
Mockito.verify(customTabsController).bindService()
187-
Mockito.verify(customTabsController).launchUri(uriCaptor.capture(), launchAsTwaCaptor.capture(), any(), failureCallbackCaptor.capture())
205+
Mockito.verify(customTabsController).launchUri(
206+
uriCaptor.capture(),
207+
launchAsTwaCaptor.capture(),
208+
any(),
209+
failureCallbackCaptor.capture()
210+
)
188211
MatcherAssert.assertThat(uriCaptor.value, Is.`is`(Matchers.notNullValue()))
189212
MatcherAssert.assertThat(uriCaptor.value, Is.`is`(uri))
190213
MatcherAssert.assertThat(launchAsTwaCaptor.value, Is.`is`(Matchers.notNullValue()))
@@ -243,6 +266,47 @@ public class AuthenticationActivityTest {
243266
MatcherAssert.assertThat(controller, Is.`is`(Matchers.notNullValue()))
244267
}
245268

269+
270+
@Test
271+
public fun shouldThrowExceptionIfAuthorizeUriIsNullInIntent() {
272+
AuthenticationActivity.authenticateUsingBrowser(
273+
callerActivity,
274+
uri,
275+
false,
276+
customTabsOptions
277+
)
278+
Mockito.verify(callerActivity).startActivity(intentCaptor.capture())
279+
createActivity(intentCaptor.value)
280+
activity.intent = Intent().apply {
281+
putExtra(EXTRA_LAUNCH_AS_TWA, false)
282+
putExtra(EXTRA_CT_OPTIONS, customTabsOptions)
283+
}
284+
activityController.create().start().resume()
285+
MatcherAssert.assertThat(activity.deliveredException, Is.`is`(Matchers.notNullValue()))
286+
MatcherAssert.assertThat(activity.isFinishing, Is.`is`(true))
287+
activityController.destroy()
288+
}
289+
290+
@Test
291+
public fun shouldThrowExceptionIfCustomTabsIsNullInIntent() {
292+
AuthenticationActivity.authenticateUsingBrowser(
293+
callerActivity,
294+
uri,
295+
false,
296+
customTabsOptions
297+
)
298+
Mockito.verify(callerActivity).startActivity(intentCaptor.capture())
299+
createActivity(intentCaptor.value)
300+
activity.intent = Intent().apply {
301+
putExtra(EXTRA_LAUNCH_AS_TWA, false)
302+
putExtra(EXTRA_AUTHORIZE_URI, uri)
303+
}
304+
activityController.create().start().resume()
305+
MatcherAssert.assertThat(activity.deliveredException, Is.`is`(Matchers.notNullValue()))
306+
MatcherAssert.assertThat(activity.isFinishing, Is.`is`(true))
307+
activityController.destroy()
308+
}
309+
246310
private fun recreateAndCallNewIntent(data: Intent) {
247311
val outState = Bundle()
248312
activityController.saveInstanceState(outState)

0 commit comments

Comments
 (0)