Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ vNext
- [MINOR] Add Child Spans for Interactive Span (#2516)
- [MINOR] For MSAL CPP flows, match exact claims when deleting AT with intersecting scopes (#2548)
- [MINOR] Replace Deprecated Keystore API for Android 28+ (#2558)
- [PATCH] Make userHandle response field optional (#2560)

Version 18.2.2
----------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,18 @@ import com.microsoft.identity.common.java.constants.FidoConstants.Companion.WEBA
import com.microsoft.identity.common.java.constants.FidoConstants.Companion.WEBAUTHN_RESPONSE_ID_JSON_KEY
import com.microsoft.identity.common.java.constants.FidoConstants.Companion.WEBAUTHN_RESPONSE_SIGNATURE_JSON_KEY
import com.microsoft.identity.common.java.constants.FidoConstants.Companion.WEBAUTHN_RESPONSE_USER_HANDLE_JSON_KEY
import com.microsoft.identity.common.logging.Logger
import org.json.JSONException
import org.json.JSONObject

/**
* A utility class to help convert to and from strings in WebAuthn json format.
*/
class WebAuthnJsonUtil {
companion object {
companion object {

private val TAG = WebAuthnJsonUtil::class.simpleName.toString()

/**
* Takes applicable parameters and creates a string representation of
* PublicKeyCredentialRequestOptionsJSON (https://w3c.github.io/webauthn/#dictdef-publickeycredentialrequestoptionsjson)
Expand Down Expand Up @@ -74,6 +79,7 @@ class WebAuthnJsonUtil {
* @throws JSONException if a value is not present that should be.
*/
fun extractAuthenticatorAssertionResponseJson(fullResponseJson : String): String {
val methodTag = "$TAG:extractAuthenticatorAssertionResponseJson"
val fullResponseJsonObject = JSONObject(fullResponseJson);
val authResponseJsonObject = fullResponseJsonObject
.getJSONObject(FidoConstants.WEBAUTHN_AUTHENTICATION_ASSERTION_RESPONSE_JSON_KEY)
Expand All @@ -87,8 +93,16 @@ class WebAuthnJsonUtil {
WEBAUTHN_RESPONSE_CLIENT_DATA_JSON_KEY))
assertionResult.put(WEBAUTHN_RESPONSE_SIGNATURE_JSON_KEY, authResponseJsonObject.get(
WEBAUTHN_RESPONSE_SIGNATURE_JSON_KEY))
assertionResult.put(WEBAUTHN_RESPONSE_USER_HANDLE_JSON_KEY, authResponseJsonObject.get(
WEBAUTHN_RESPONSE_USER_HANDLE_JSON_KEY))
// UserHandle is optional if allowCredentials was provided in the request (username flow).
if (authResponseJsonObject.isNull(WEBAUTHN_RESPONSE_USER_HANDLE_JSON_KEY)) {
Logger.info(methodTag, "UserHandle not found in assertion response.")
} else {
assertionResult.put(
WEBAUTHN_RESPONSE_USER_HANDLE_JSON_KEY, authResponseJsonObject.get(
WEBAUTHN_RESPONSE_USER_HANDLE_JSON_KEY
)
)
}
return assertionResult.toString()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ class WebAuthnJsonUtilTest {
val attestationObject = "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUj5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGRdAAAAAAAAAAAAAAAAAAAAAAAAAAAAEChA3rcWXFH4p4VYumWuZ2WlAQIDJiABIVgg4RqZaJyaC24Pf4tT-8ONIZ5_Elddf3dNotGOx81jj3siWCAWXS6Lz70hvC2g8hwoLllOwlsbYatNkO2uYFO-eJID6A"

val expectedAuthenticationAssertionResponseJsonAllFieldsFilled = """{"authenticatorData":"$authenticatorData","clientDataJSON":"$clientDataJSON","id":"$idAssertionResponse","signature":"$signature","userHandle":"$userHandle"}"""
val expectedAuthenticationAssertionResponseOnlyRequiredFields = """{"authenticatorData":"$authenticatorData","clientDataJSON":"$clientDataJSON","id":"$idAssertionResponse","signature":"$signature","userHandle":"$userHandle"}"""
val expectedAuthenticationAssertionResponseOnlyRequiredFields = """{"authenticatorData":"$authenticatorData","clientDataJSON":"$clientDataJSON","id":"$idAssertionResponse","signature":"$signature"}"""

val demoAuthenticationResponseJsonAllFieldsFilled = """{"authenticatorAttachment":"$authenticatorAttachment","clientExtensionResults":{},"id":"KEDetxZcUfinhVi6Za5nZQ","rawId":"KEDetxZcUfinhVi6Za5nZQ","response":{"attestationObject":"$attestationObject","authenticatorData":"$authenticatorData","clientDataJSON":"$clientDataJSON","id":"$idAssertionResponse","signature":"$signature","userHandle":"$userHandle"},"type":"public-key"}"""
val demoAuthenticationResponseJsonOnlyRequiredFields = """{"clientExtensionResults":{},"id":"KEDetxZcUfinhVi6Za5nZQ","rawId":"KEDetxZcUfinhVi6Za5nZQ","response":{"attestationObject":null,"authenticatorData":"$authenticatorData","clientDataJSON":"$clientDataJSON","id":"$idAssertionResponse","signature":"$signature","userHandle":"$userHandle"},"type":"public-key"}"""
val demoAuthenticationResponseJsonOnlyRequiredFields = """{"clientExtensionResults":{},"id":"KEDetxZcUfinhVi6Za5nZQ","rawId":"KEDetxZcUfinhVi6Za5nZQ","response":{"attestationObject":null,"authenticatorData":"$authenticatorData","clientDataJSON":"$clientDataJSON","id":"$idAssertionResponse","signature":"$signature"},"type":"public-key"}"""
val demoAuthenticationResponseJsonMissingSignature = """{"clientExtensionResults":{},"id":"KEDetxZcUfinhVi6Za5nZQ","rawId":"KEDetxZcUfinhVi6Za5nZQ","response":{"attestationObject":null,"authenticatorData":"$authenticatorData","clientDataJSON":"$clientDataJSON","id":"$idAssertionResponse","userHandle":"$userHandle"},"type":"public-key"}"""

// Demo JWT from https://jwt.io/
Expand Down
Loading