Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR refactors the origin validation flow in the FIDO2 server to support web-origin allowlists for platform passkeys while maintaining backward compatibility. The refactoring extracts origin validation logic from ResponseServiceImpl into a dedicated helper class for better code organization and clarity.
Key changes:
- Introduces a web-origin allowlist mechanism to support HTTPS origins alongside existing app facet validation
- Refactors origin validation logic into a dedicated OriginValidationHelper class
- Adds comprehensive test coverage for the new validation scenarios
Reviewed Changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| OriginValidationHelper.java | New helper class containing extracted origin validation logic with support for app facets and web origins |
| OriginValidationHelperTest.java | Comprehensive test suite covering app facet, web allowlist, and fallback validation scenarios |
| ResponseServiceImpl.java | Refactored checkOrigin method to delegate to the new helper class |
| build.gradle | Added JUnit 5 dependencies and test platform configuration |
| README.md | Updated documentation to explain the new web origin allowlist functionality |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
gibeom-gwon
left a comment
There was a problem hiding this comment.
Thank you for the PR @kj84park nim,
I left some comments.
By this change, VerifyCredential.origin and RegisterCredential.origin fields are ineffective when web origin is set.
| } | ||
| } | ||
|
|
||
| public static void validateWeb(URI client, URI rp, List<String> allowed) { |
There was a problem hiding this comment.
How about change rp to originFromRp and client to originFromClient?
| public static void validateWeb(URI client, URI rp, List<String> allowed) { | |
| public static void validateWeb(URI originFromClient, URI originFromRp, List<String> allowed) { |
| protected void checkOrigin(URI originFromClientData, URI originFromRp) { | ||
| final String ANDROID_FACET_SCHEME = "android"; | ||
| final String IOS_FACET_SCHEME = "ios"; | ||
| List<String> configuredOrigins = appOriginService.getOrigins(originFromRp.toString()); |
There was a problem hiding this comment.
Now AppOriginService can contain web origin also, maybe it is good to change name to OriginService. But it is just minor, not essential in this PR.
There was a problem hiding this comment.
I found that getOrigins parameter name is rpId, but originFromRp is provided. I think rpId is more appropriate for this parameter because origin can be variable.
| if (OriginValidationHelper.isAppFacet(originFromClientData)) { | ||
| OriginValidationHelper.validateAppFacet(originFromClientData, configuredOrigins); | ||
| return; | ||
| } | ||
|
|
||
| OriginValidationHelper.validateWeb(originFromClientData, originFromRp, configuredOrigins); |
There was a problem hiding this comment.
Maybe we can create OriginValidationService and provide this logic as method validate.
In OriginValidationService, we can move OriginValidationHelper logics as private method. How do you think about this direction?
There was a problem hiding this comment.
Thanks for the suggestion! How about we merge AppOriginService and OriginValidationHelper into one OriginValidationService that handles both origin lookups and validation?
There was a problem hiding this comment.
This will add validation logic into OriginValidationService and library user need to implement OriginValidationServiceImpl that provides origin lookup?
I think it would be also good direction!
There was a problem hiding this comment.
I implemented OriginValidationService as you originally suggested.
I think it's better that way.
| private static boolean hasWebAllowlist(List<String> allowed) { | ||
| for (String o : allowed) { | ||
| if (o.startsWith("https://") || o.startsWith("http://")) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } |
There was a problem hiding this comment.
This will be called in every assertion and attestation.
If we can get the web origin list as seperate with app origin list, this can be easily check with webOriginAllowed.size() > 0.
I don't think the current implementation has a significant impact on performance, so we can improve this in the future.
There was a problem hiding this comment.
I agree. I'll update this later.
.gitignore
Outdated
| /.nb-gradle/ | ||
| **/build/ | ||
|
|
||
| .DS_Store No newline at end of file |
There was a problem hiding this comment.
Just a minor thing, how about add new line in the bottom?
@gibeom-gwon nim Also, I applied most of your comments and updated the code. Please review. |
gibeom-gwon
left a comment
There was a problem hiding this comment.
Sorry for the late review.
LGTM! 👍
README.md
Outdated
| - Android native (FIDO2 API/Credential Manager): `clientDataJSON.origin` starts with `android:...` (app facet). See "Verify origin" in Android Credential Manager docs: https://developer.android.com/identity/sign-in/credential-manager#verify-origin | ||
| - iOS native (AuthenticationServices, passkeys): `clientDataJSON.origin` is an `https` web origin (no `ios:` prefix), e.g., `https://example.com`. For iOS/macOS passkeys, configure a web-origin allowlist. |
There was a problem hiding this comment.
@kimdora
I added the details based on your feedback. Could you check it?
What is this PR for?
Resolves #60
Overview or reasons
checkOriginflow for clarity.android:/ios:).clientDataJSON.originfor backward compatibility.Tasks
fido2-core/.../helper/OriginValidationHelper.java(isAppFacet, validateAppFacet, validateWeb)ResponseServiceImpl#checkOrigin→ delegate to helper with early-return branchingfido2-core/build.gradlefido2-core/.../test/.../OriginValidationHelperTest.java(app/web/fallback/multi-origin cases)README.mdwith configuration notesResult
app.originscontains any http(s) entries, enforce allowlist and require exact matchclientDataJSON.origin