Skip to content

Commit cb618e2

Browse files
committed
Added test cases for the authentication api class changes
1 parent 025d6fa commit cb618e2

File tree

7 files changed

+184
-18
lines changed

7 files changed

+184
-18
lines changed

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
8989
.set(USERNAME_KEY, usernameOrEmail)
9090
.set(PASSWORD_KEY, password)
9191
.setGrantType(ParameterBuilder.GRANT_TYPE_PASSWORD_REALM)
92-
.setRealm(realmOrConnection).asDictionary()
92+
.setRealm(realmOrConnection)
93+
.asDictionary()
9394
return loginWithToken(parameters)
9495
}
9596

@@ -175,7 +176,10 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
175176
}.asDictionary()
176177

177178
return loginWithToken(params)
178-
.addParameter(AUTH_RESPONSE_KEY, Gson().toJsonTree(authResponse)) as AuthenticationRequest
179+
.addParameter(
180+
AUTH_RESPONSE_KEY,
181+
Gson().toJsonTree(authResponse)
182+
) as AuthenticationRequest
179183
}
180184

181185

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package com.auth0.android.provider
33
import android.content.Context
44
import android.os.Build
55
import android.util.Log
6+
import androidx.credentials.CredentialManager
67
import com.auth0.android.Auth0
8+
import com.auth0.android.authentication.AuthenticationAPIClient
79
import com.auth0.android.authentication.AuthenticationException
810
import com.auth0.android.authentication.ParameterBuilder
911
import com.auth0.android.callback.Callback
@@ -96,7 +98,11 @@ public object PasskeyAuthProvider {
9698
callback.onFailure(ex)
9799
return
98100
}
99-
val passkeyManager = PasskeyManager(auth0)
101+
val passkeyManager =
102+
PasskeyManager(
103+
AuthenticationAPIClient(auth0),
104+
CredentialManager.create(context)
105+
)
100106
passkeyManager.signin(context, parameters, callback, executor)
101107
}
102108
}
@@ -204,7 +210,11 @@ public object PasskeyAuthProvider {
204210
callback.onFailure(ex)
205211
return
206212
}
207-
val passkeyManager = PasskeyManager(auth0)
213+
val passkeyManager =
214+
PasskeyManager(
215+
AuthenticationAPIClient(auth0),
216+
CredentialManager.create(context)
217+
)
208218
val userMetadata = UserMetadataRequest(email, phoneNumber, username, name)
209219
passkeyManager.signup(
210220
context, userMetadata, parameters, callback, executor

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

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,8 @@ import androidx.credentials.exceptions.CreateCredentialProviderConfigurationExce
2222
import androidx.credentials.exceptions.GetCredentialCancellationException
2323
import androidx.credentials.exceptions.GetCredentialException
2424
import androidx.credentials.exceptions.GetCredentialInterruptedException
25-
import androidx.credentials.exceptions.GetCredentialProviderConfigurationException
26-
import androidx.credentials.exceptions.GetCredentialUnknownException
2725
import androidx.credentials.exceptions.GetCredentialUnsupportedException
2826
import androidx.credentials.exceptions.NoCredentialException
29-
import androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialDomException
30-
import androidx.credentials.exceptions.publickeycredential.GetPublicKeyCredentialDomException
31-
import androidx.credentials.exceptions.publickeycredential.GetPublicKeyCredentialException
32-
import com.auth0.android.Auth0
3327
import com.auth0.android.authentication.AuthenticationAPIClient
3428
import com.auth0.android.authentication.AuthenticationException
3529
import com.auth0.android.authentication.ParameterBuilder
@@ -44,9 +38,12 @@ import java.util.concurrent.Executor
4438
import java.util.concurrent.Executors
4539

4640

47-
internal class PasskeyManager(auth0: Auth0) {
41+
internal class PasskeyManager(
42+
private val authenticationAPIClient: AuthenticationAPIClient,
43+
private val credentialManager: CredentialManager
44+
) {
45+
4846
private val TAG = PasskeyManager::class.simpleName
49-
private val authenticationAPIClient: AuthenticationAPIClient = AuthenticationAPIClient(auth0)
5047

5148
@RequiresApi(api = Build.VERSION_CODES.P)
5249
@SuppressLint("PublicKeyCredential")
@@ -57,7 +54,6 @@ internal class PasskeyManager(auth0: Auth0) {
5754
callback: Callback<Credentials, AuthenticationException>,
5855
executor: Executor = Executors.newSingleThreadExecutor()
5956
) {
60-
val credentialManager = CredentialManager.create(context)
6157

6258
authenticationAPIClient.signupWithPasskey(userMetadata, parameters)
6359
.start(object : Callback<PasskeyRegistrationResponse, AuthenticationException> {
@@ -91,7 +87,9 @@ internal class PasskeyManager(auth0: Auth0) {
9187
)
9288
authenticationAPIClient.signinWithPasskey(
9389
pasKeyRegistrationResponse.authSession, authRequest, parameters
94-
).start(callback)
90+
)
91+
.validateClaims()
92+
.start(callback)
9593
}
9694
})
9795

@@ -112,7 +110,6 @@ internal class PasskeyManager(auth0: Auth0) {
112110
callback: Callback<Credentials, AuthenticationException>,
113111
executor: Executor = Executors.newSingleThreadExecutor()
114112
) {
115-
val credentialManager = CredentialManager.create(context)
116113
authenticationAPIClient.passkeyChallenge(parameters[ParameterBuilder.REALM_KEY])
117114
.start(object : Callback<PasskeyChallengeResponse, AuthenticationException> {
118115
override fun onSuccess(result: PasskeyChallengeResponse) {

auth0/src/test/java/com/auth0/android/authentication/AuthenticationAPIClientTest.kt

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,31 @@ import com.auth0.android.request.HttpMethod
99
import com.auth0.android.request.NetworkingClient
1010
import com.auth0.android.request.RequestOptions
1111
import com.auth0.android.request.ServerResponse
12+
import com.auth0.android.request.UserMetadataRequest
1213
import com.auth0.android.request.internal.RequestFactory
1314
import com.auth0.android.request.internal.ThreadSwitcherShadow
14-
import com.auth0.android.result.*
15+
import com.auth0.android.result.Authentication
16+
import com.auth0.android.result.Challenge
17+
import com.auth0.android.result.Credentials
18+
import com.auth0.android.result.DatabaseUser
19+
import com.auth0.android.result.PasskeyRegistrationResponse
20+
import com.auth0.android.result.UserProfile
1521
import com.auth0.android.util.Auth0UserAgent
1622
import com.auth0.android.util.AuthenticationAPIMockServer
23+
import com.auth0.android.util.AuthenticationAPIMockServer.Companion.SESSION_ID
1724
import com.auth0.android.util.AuthenticationCallbackMatcher
1825
import com.auth0.android.util.MockAuthenticationCallback
1926
import com.auth0.android.util.SSLTestUtils.testClient
2027
import com.google.gson.Gson
2128
import com.google.gson.GsonBuilder
29+
import com.google.gson.JsonElement
2230
import com.google.gson.reflect.TypeToken
23-
import com.nhaarman.mockitokotlin2.*
31+
import com.nhaarman.mockitokotlin2.any
32+
import com.nhaarman.mockitokotlin2.argumentCaptor
33+
import com.nhaarman.mockitokotlin2.eq
34+
import com.nhaarman.mockitokotlin2.mock
35+
import com.nhaarman.mockitokotlin2.verify
36+
import com.nhaarman.mockitokotlin2.whenever
2437
import kotlinx.coroutines.ExperimentalCoroutinesApi
2538
import kotlinx.coroutines.test.runTest
2639
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
@@ -39,7 +52,7 @@ import java.io.ByteArrayInputStream
3952
import java.io.FileReader
4053
import java.io.InputStream
4154
import java.security.PublicKey
42-
import java.util.*
55+
import java.util.Locale
4356

4457
@RunWith(RobolectricTestRunner::class)
4558
@Config(shadows = [ThreadSwitcherShadow::class])
@@ -175,6 +188,84 @@ public class AuthenticationAPIClientTest {
175188
assertThat(body, Matchers.not(Matchers.hasKey("connection")))
176189
}
177190

191+
@Test
192+
public fun shouldSigninWithPasskey() {
193+
mockAPI.willReturnSuccessfulLogin()
194+
val callback = MockAuthenticationCallback<Credentials>()
195+
val auth0 = auth0
196+
val client = AuthenticationAPIClient(auth0)
197+
client.signinWithPasskey("auth-session", mock(), emptyMap())
198+
.start(callback)
199+
ShadowLooper.idleMainLooper()
200+
assertThat(
201+
callback, AuthenticationCallbackMatcher.hasPayloadOfType(
202+
Credentials::class.java
203+
)
204+
)
205+
val request = mockAPI.takeRequest()
206+
assertThat(
207+
request.getHeader("Accept-Language"), Matchers.`is`(
208+
defaultLocale
209+
)
210+
)
211+
val body = bodyFromRequest<String>(request)
212+
assertThat(request.path, Matchers.equalTo("/oauth/token"))
213+
assertThat(body, Matchers.hasEntry("client_id", CLIENT_ID))
214+
assertThat(
215+
body,
216+
Matchers.hasEntry("grant_type", "urn:okta:params:oauth:grant-type:webauthn")
217+
)
218+
assertThat(body, Matchers.hasKey("authn_response"))
219+
assertThat(body, Matchers.hasEntry("auth_session", "auth-session"))
220+
}
221+
222+
@Test
223+
public fun shouldSignupWithPasskey() {
224+
mockAPI.willReturnSuccessfulPasskeyRegistration()
225+
val auth0 = auth0
226+
val client = AuthenticationAPIClient(auth0)
227+
val registrationResponse = client.signupWithPasskey(
228+
mock(),
229+
mapOf("realm" to MY_CONNECTION)
230+
)
231+
.execute()
232+
val request = mockAPI.takeRequest()
233+
assertThat(
234+
request.getHeader("Accept-Language"), Matchers.`is`(
235+
defaultLocale
236+
)
237+
)
238+
val body = bodyFromRequest<String>(request)
239+
assertThat(request.path, Matchers.equalTo("/passkey/register"))
240+
assertThat(body, Matchers.hasEntry("client_id", CLIENT_ID))
241+
assertThat(body, Matchers.hasEntry("realm", MY_CONNECTION))
242+
assertThat(body, Matchers.hasKey("user_profile"))
243+
assertThat(registrationResponse, Matchers.`is`(Matchers.notNullValue()))
244+
assertThat(registrationResponse.authSession, Matchers.comparesEqualTo(SESSION_ID))
245+
}
246+
247+
@Test
248+
public fun shouldGetPasskeyChallenge() {
249+
mockAPI.willReturnSuccessfulPasskeyChallenge()
250+
val auth0 = auth0
251+
val client = AuthenticationAPIClient(auth0)
252+
val challengeResponse = client.passkeyChallenge(MY_CONNECTION)
253+
.execute()
254+
val request = mockAPI.takeRequest()
255+
assertThat(
256+
request.getHeader("Accept-Language"), Matchers.`is`(
257+
defaultLocale
258+
)
259+
)
260+
val body = bodyFromRequest<String>(request)
261+
assertThat(request.path, Matchers.equalTo("/passkey/challenge"))
262+
assertThat(body, Matchers.hasEntry("client_id", CLIENT_ID))
263+
assertThat(body, Matchers.hasEntry("realm", MY_CONNECTION))
264+
assertThat(challengeResponse, Matchers.`is`(Matchers.notNullValue()))
265+
assertThat(challengeResponse.authSession, Matchers.comparesEqualTo(SESSION_ID))
266+
267+
}
268+
178269
@Test
179270
public fun shouldLoginWithMFARecoveryCode() {
180271
mockAPI.willReturnSuccessfulLoginWithRecoveryCode()

auth0/src/test/java/com/auth0/android/authentication/request/AuthenticationRequestMock.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.auth0.android.authentication.AuthenticationException;
77
import com.auth0.android.callback.Callback;
88
import com.auth0.android.request.AuthenticationRequest;
9+
import com.auth0.android.request.Request;
910
import com.auth0.android.result.Credentials;
1011

1112
import java.util.Map;
@@ -48,6 +49,12 @@ public AuthenticationRequest addParameter(@NonNull String name, @NonNull String
4849
return this;
4950
}
5051

52+
@NonNull
53+
@Override
54+
public Request<Credentials, AuthenticationException> addParameter(@NonNull String name, @NonNull Object value) {
55+
return this;
56+
}
57+
5158
@NonNull
5259
@Override
5360
public AuthenticationRequest addHeader(@NonNull String name, @NonNull String value) {

auth0/src/test/java/com/auth0/android/authentication/request/RequestMock.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,10 @@ public void start(@NonNull Callback<T, U> callback) {
5555
public T execute() throws Auth0Exception {
5656
return null;
5757
}
58+
59+
@NonNull
60+
@Override
61+
public Request<T, U> addParameter(@NonNull String name, @NonNull Object value) {
62+
return this;
63+
}
5864
}

auth0/src/test/java/com/auth0/android/util/AuthenticationAPIMockServer.kt

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,55 @@ internal class AuthenticationAPIMockServer : APIMockServer() {
4747
return this
4848
}
4949

50+
fun willReturnSuccessfulPasskeyRegistration(): AuthenticationAPIMockServer {
51+
val json = """{
52+
"authn_params_public_key":{
53+
"challenge": "$CHALLENGE",
54+
"timeout": 6046456,
55+
"rp": {
56+
"id": "auth0.passkey.com",
57+
"name": "Passkey Test"
58+
},
59+
"pubKeyCredParams": [
60+
{
61+
"type": "public-key",
62+
"alg": -7
63+
},
64+
{
65+
"type": "public-key",
66+
"alg": -257
67+
}
68+
],
69+
"authenticatorSelection": {
70+
"authenticatorAttachment": "platform",
71+
"residentKey": "required"
72+
},
73+
"user": {
74+
"id": "53b995f8bce68d9fc900099c",
75+
"name": "p",
76+
"displayName": "d"
77+
}
78+
},
79+
"auth_session": "$SESSION_ID"
80+
}"""
81+
server.enqueue(responseWithJSON(json, 200))
82+
return this
83+
}
84+
85+
fun willReturnSuccessfulPasskeyChallenge():AuthenticationAPIMockServer{
86+
val json = """{
87+
"authn_params_public_key":{
88+
"challenge": "$CHALLENGE",
89+
"timeout": 604645,
90+
"rpId": "domain",
91+
"userVerification":"preferred"
92+
},
93+
"auth_session": "$SESSION_ID"
94+
}"""
95+
server.enqueue(responseWithJSON(json, 200))
96+
return this
97+
}
98+
5099
fun willReturnSuccessfulLoginWithRecoveryCode(): AuthenticationAPIMockServer {
51100
val json = """{
52101
"refresh_token": "$REFRESH_TOKEN",
@@ -155,6 +204,8 @@ internal class AuthenticationAPIMockServer : APIMockServer() {
155204
const val REFRESH_TOKEN = "REFRESH_TOKEN"
156205
const val ID_TOKEN = "ID_TOKEN"
157206
const val ACCESS_TOKEN = "ACCESS_TOKEN"
207+
const val SESSION_ID = "SESSION_ID"
158208
private const val BEARER = "BEARER"
209+
private const val CHALLENGE = "CHALLENGE"
159210
}
160211
}

0 commit comments

Comments
 (0)