Skip to content

Commit da60801

Browse files
SDKS-5096: Enhance WebAuthn registration by adding optional device name (#519)
* SDKS-5096: Enhance WebAuthn registration by adding optional device name parameter
1 parent bb8c89c commit da60801

5 files changed

Lines changed: 28 additions & 17 deletions

File tree

forgerock-auth/src/main/java/org/forgerock/android/auth/callback/WebAuthnRegistrationCallback.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -61,9 +61,9 @@ open class WebAuthnRegistrationCallback : MetadataCallback, WebAuthnCallback {
6161
webAuthnRegistration.options = webAuthnRegistration.options.cloneWith(
6262
ResidentKeyRequirement.valueOf(it))
6363
}
64-
var result = webAuthnRegistration.register(context)
65-
deviceName?.apply { result += "::$deviceName" }
66-
setHiddenCallbackValue(node, result);
64+
65+
val result = webAuthnRegistration.register(context, deviceName)
66+
setHiddenCallbackValue(node, result)
6767
} catch (e: Exception) {
6868
setErrorRethrow(node, e)
6969
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
/*
2-
* Copyright (c) 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2025 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
66
*/
77

88
package org.forgerock.android.auth.webauthn
99

10+
import android.annotation.SuppressLint
1011
import kotlinx.serialization.Serializable
1112

13+
@SuppressLint("UnsafeOptInUsageError")
1214
@Serializable
1315
data class WebAuthnOutcome(val authenticatorAttachment: String , val legacyData: String)

forgerock-auth/src/main/java/org/forgerock/android/auth/webauthn/WebAuthnRegistration.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -27,8 +27,6 @@ import kotlinx.coroutines.tasks.await
2727
import kotlinx.coroutines.withContext
2828
import kotlinx.serialization.encodeToString
2929
import kotlinx.serialization.json.Json
30-
import kotlinx.serialization.json.buildJsonObject
31-
import kotlinx.serialization.json.put
3230
import org.forgerock.android.auth.WebAuthnDataRepository
3331
import org.json.JSONArray
3432
import org.json.JSONException
@@ -149,7 +147,16 @@ open class WebAuthnRegistration() : WebAuthn() {
149147
return getCredentials(excludeCredentials)
150148
}
151149

152-
suspend fun register(context: Context): String {
150+
/**
151+
* Registers a new WebAuthn credential.
152+
*
153+
* @param context Application context used to launch the registration intent.
154+
* @param deviceName Optional friendly name appended to the response so the server can label the credential.
155+
*
156+
* @return The registration outcome as a `::` delimited string, or a JSON-encoded
157+
* [WebAuthnOutcome] when the server supports JSON responses.
158+
*/
159+
suspend fun register(context: Context, deviceName: String? = null): String {
153160
val publicKeyCredential = getPublicKeyCredential(context)
154161
val response = publicKeyCredential.response as AuthenticatorAttestationResponse
155162
val sb = StringBuilder()
@@ -173,10 +180,11 @@ open class WebAuthnRegistration() : WebAuthn() {
173180
persist(context, source)
174181
}
175182
}
183+
deviceName?.let { sb.append("::$it") }
176184
return if (supportsJsonResponse) {
177185
val outcome = WebAuthnOutcome(publicKeyCredential.authenticatorAttachment ?: "platform",
178186
sb.toString())
179-
return Json.encodeToString(outcome)
187+
Json.encodeToString(outcome)
180188
} else {
181189
sb.toString()
182190
}

forgerock-auth/src/test/java/org/forgerock/android/auth/callback/WebAuthnRegistrationCallbackTest.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -22,6 +22,7 @@ import org.junit.Test
2222
import org.junit.runner.RunWith
2323
import org.mockito.Mockito.*
2424
import org.mockito.kotlin.any
25+
import org.mockito.kotlin.anyOrNull
2526
import org.mockito.kotlin.mock
2627
import org.mockito.kotlin.spy
2728
import org.mockito.kotlin.whenever
@@ -49,7 +50,7 @@ class WebAuthnRegistrationCallbackTest {
4950

5051
val spCallback = spy(callback)
5152
doReturn(webAuthnRegistration).`when`(spCallback).getWebAuthnRegistration()
52-
whenever(webAuthnRegistration.register(any())).thenReturn("SuccessResult")
53+
whenever(webAuthnRegistration.register(any(), anyOrNull())).thenReturn("SuccessResult")
5354
spCallback.register(context, node = node)
5455
val hiddenValueCallback = node.getCallback(HiddenValueCallback::class.java)
5556
assertThat(hiddenValueCallback.contentAsJson.getJSONArray("input").getJSONObject(0)
@@ -89,7 +90,7 @@ class WebAuthnRegistrationCallbackTest {
8990

9091
val spCallback = spy(callback)
9192
doReturn(webAuthnRegistration).`when`(spCallback).getWebAuthnRegistration()
92-
whenever(webAuthnRegistration.register(any())).thenReturn("SuccessResult")
93+
whenever(webAuthnRegistration.register(any(), anyOrNull())).thenReturn("SuccessResult")
9394
val future = FRListenerFuture<Void>()
9495
spCallback.register(context, node = node, listener = future)
9596
future.get()
@@ -106,7 +107,7 @@ class WebAuthnRegistrationCallbackTest {
106107
val callback = node.getCallback(WebAuthnRegistrationCallback::class.java)
107108
val spCallback = spy(callback)
108109
doReturn(webAuthnRegistration).`when`(spCallback).getWebAuthnRegistration()
109-
whenever(webAuthnRegistration.register(any())).thenReturn("SuccessResult")
110+
whenever(webAuthnRegistration.register(any(), anyOrNull())).thenReturn("SuccessResult::MyDeviceName")
110111
spCallback.register(context, "MyDeviceName", node)
111112
val hiddenValueCallback = node.getCallback(HiddenValueCallback::class.java)
112113
assertThat(hiddenValueCallback.contentAsJson.getJSONArray("input").getJSONObject(0)

forgerock-auth/src/test/java/org/forgerock/android/auth/webauthn/WebAuthnRegistrationTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 - 2025 Ping Identity Corporation. All rights reserved.
2+
* Copyright (c) 2022 - 2026 Ping Identity Corporation. All rights reserved.
33
*
44
* This software may be modified and distributed under the terms
55
* of the MIT license. See the LICENSE file for details.
@@ -144,9 +144,9 @@ class WebAuthnRegistrationTest : BaseTest() {
144144
}
145145
assertThat(webAuthnRegistration.supportsJsonResponse).isTrue
146146

147-
val result = webAuthnRegistration.register(context)
147+
val result = webAuthnRegistration.register(context, deviceName = "testDevice")
148148

149-
assertThat(result).isEqualTo("{\"authenticatorAttachment\":\"platform\",\"legacyData\":\"clientDataJson::97,116,116,101,115,116,97,116,105,111,110,79,98,106,101,99,116::cmF3SWQ\"}")
149+
assertThat(result).isEqualTo("{\"authenticatorAttachment\":\"platform\",\"legacyData\":\"clientDataJson::97,116,116,101,115,116,97,116,105,111,110,79,98,106,101,99,116::cmF3SWQ::testDevice\"}")
150150
}
151151

152152

0 commit comments

Comments
 (0)