英文:
Unable to register for authentication using Passkey on Android
问题
I'm trying to follow the official documentation to implement Passkey registration. There is also a codelab demonstrating the topic (note that it works as intended on my Android device.)
I created this minimal test-case available on github, which replicates what's taking place in the codelab, in Java instead of Kotlin.
private void signUp() {
CreatePublicKeyCredentialRequest createPublicKeyCredentialRequest = new CreatePublicKeyCredentialRequest(fetchRegistrationJsonFromServer());
credentialManager.createCredentialAsync(
createPublicKeyCredentialRequest,
this,
new CancellationSignal(),
getMainExecutor(),
new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() {
@Override
public void onResult(CreateCredentialResponse result) {
Log.d(TAG, "Registration success");
}
@Override
public void onError(CreateCredentialException e) {
Log.e(TAG, "Registration failure - " + e.getClass().getName());
if (e instanceof CreatePublicKeyCredentialDomException) {
// Handle the passkey DOM errors thrown according to the
// WebAuthn spec.
Log.e(TAG, String.valueOf(((CreatePublicKeyCredentialDomException)e).getDomError()));
} else if (e instanceof CreateCredentialCancellationException) {
// The user intentionally canceled the operation and chose not
// to register the credential.
} else if (e instanceof CreateCredentialInterruptedException) {
// Retry-able error. Consider retrying the call.
} else if (e instanceof CreateCredentialProviderConfigurationException) {
// Your app is missing the provider configuration dependency.
// Most likely, you're missing the
// "credentials-play-services-auth" module.
} else if (e instanceof CreateCredentialUnknownException) {
} else if (e instanceof CreateCustomCredentialException) {
// You have encountered an error from a 3rd-party SDK. If
// you make the API call with a request object that's a
// subclass of
// CreateCustomCredentialRequest using a 3rd-party SDK,
// then you should check for any custom exception type
// constants within that SDK to match with e.type.
// Otherwise, drop or log the exception.
}
}
}
);
}
private String fetchRegistrationJsonFromServer() {
String response = Utils.readFromAssets(this, "reg.txt");
return response.replace("<userId>", getEncodedUserId())
.replace("<userName>", username)
.replace("<userDisplayName>", username)
.replace("<challenge>", getEncodedChallenge());
}
private String getEncodedUserId() {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[64];
random.nextBytes(bytes);
return Base64.encodeToString(bytes, Base64.NO_WRAP | Base64.URL_SAFE | Base64.NO_PADDING);
}
private String getEncodedChallenge() {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[32];
random.nextBytes(bytes);
return Base64.encodeToString(bytes, Base64.NO_WRAP | Base64.URL_SAFE | Base64.NO_PADDING);
}
Currently, it fails with a CreatePublicKeyCredentialDomException
of type androidx.credentials.exceptions.domerrors.SecurityError
.
Note that my app is handling Digital Asset Links properly, according to this document. Please refer to this SO question for reference.
Currently, the only part which looks problematic to me is the registration template. I tried to replace the "rp.id" value with com.unibeam.passkey1
but it did not work.
英文:
I'm trying to follow the official documentation to implement Passkey registration. There is also a codelab demonstrating the topic (note that it works as intended on my Android device.)
I created this minimal test-case available on github, which replicates what's taking place in the codelab, in Java instead of Kotlin.
private void signUp() {
CreatePublicKeyCredentialRequest createPublicKeyCredentialRequest = new CreatePublicKeyCredentialRequest(fetchRegistrationJsonFromServer());
credentialManager.createCredentialAsync(
createPublicKeyCredentialRequest,
this,
new CancellationSignal(),
getMainExecutor(),
new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() {
@Override
public void onResult(CreateCredentialResponse result) {
Log.d(TAG, "Registration success");
}
@Override
public void onError(CreateCredentialException e) {
Log.e(TAG, "Registration failure - " + e.getClass().getName());
if (e instanceof CreatePublicKeyCredentialDomException) {
// Handle the passkey DOM errors thrown according to the
// WebAuthn spec.
Log.e(TAG, String.valueOf(((CreatePublicKeyCredentialDomException)e).getDomError()));
} else if (e instanceof CreateCredentialCancellationException) {
// The user intentionally canceled the operation and chose not
// to register the credential.
} else if (e instanceof CreateCredentialInterruptedException) {
// Retry-able error. Consider retrying the call.
} else if (e instanceof CreateCredentialProviderConfigurationException) {
// Your app is missing the provider configuration dependency.
// Most likely, you're missing the
// "credentials-play-services-auth" module.
} else if (e instanceof CreateCredentialUnknownException) {
} else if (e instanceof CreateCustomCredentialException) {
// You have encountered an error from a 3rd-party SDK. If
// you make the API call with a request object that's a
// subclass of
// CreateCustomCredentialRequest using a 3rd-party SDK,
// then you should check for any custom exception type
// constants within that SDK to match with e.type.
// Otherwise, drop or log the exception.
}
}
}
);
}
private String fetchRegistrationJsonFromServer() {
String response = Utils.readFromAssets(this, "reg.txt");
return response.replace("<userId>", getEncodedUserId())
.replace("<userName>", username)
.replace("<userDisplayName>", username)
.replace("<challenge>", getEncodedChallenge());
}
private String getEncodedUserId() {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[64];
random.nextBytes(bytes);
return Base64.encodeToString(bytes, Base64.NO_WRAP | Base64.URL_SAFE | Base64.NO_PADDING);
}
private String getEncodedChallenge() {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[32];
random.nextBytes(bytes);
return Base64.encodeToString(bytes, Base64.NO_WRAP | Base64.URL_SAFE | Base64.NO_PADDING);
}
Currently, it fails with a CreatePublicKeyCredentialDomException
of type androidx.credentials.exceptions.domerrors.SecurityError
.
Note that my app is handling Digital Asset Links properly, according to this document. Please refer to this SO question for reference.
Currently, the only part which looks problematic to me is the registration template. I tried to replace the "rp.id" value with com.unibeam.passkey1
but it did not work.
答案1
得分: 0
答案是自问自答... 解决方案相当合理:
在注册模板中将 unibeam.github.io
用作 "rp.id"。只有这种方式,底层系统才能发现 https://unibeam.github.io/.well-known/assetlinks.json
!
请注意,这绝对没有记录,好像 Google 不希望人们实施通行证身份验证。
英文:
Answering my own question... The solution was pretty logical:
Using unibeam.github.io
as "rp.id" in the registration template. Only this way, the underlying system is able to discover https://unibeam.github.io/.well-known/assetlinks.json
!
Note that is absolutely not documented, as if Google doesn't want people to implement passkey authentication.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论