Skip to content

Update origin verification flow#68

Merged
kj84park merged 5 commits intoline:mainfrom
kj84park:update-origin
Sep 23, 2025
Merged

Update origin verification flow#68
kj84park merged 5 commits intoline:mainfrom
kj84park:update-origin

Conversation

@kj84park
Copy link
Member

@kj84park kj84park commented Sep 15, 2025

What is this PR for?

Resolves #60

Overview or reasons

  • Introduce a web-origin (https) allowlist to support platform passkeys and refactor the checkOrigin flow for clarity.
  • Preserve existing native app facet validation (android:/ios:).
  • For environments without configured web origins, fall back to strict string equality between request origin and
    clientDataJSON.origin for backward compatibility.

Tasks

  • Code
    • Add: fido2-core/.../helper/OriginValidationHelper.java (isAppFacet, validateAppFacet, validateWeb)
    • Change: ResponseServiceImpl#checkOrigin → delegate to helper with early-return branching
    • Build: add JUnit 5 test setup in fido2-core/build.gradle
  • Tests
    • Add: fido2-core/.../test/.../OriginValidationHelperTest.java (app/web/fallback/multi-origin cases)
  • Docs
    • Update README.md with configuration notes

Result

  • App facets: exact string match against the configured allowlist
  • Web origins: if app.origins contains any http(s) entries, enforce allowlist and require exact match
  • Fallback: if no http(s) entries exist, require strict equality between request origin and clientDataJSON.origin
  • Security: exact matching only (no wildcards/normalization); rpIdHash verification unchanged
  • Compatibility: unchanged behavior when no web origins are configured; no API/schema changes

@kj84park kj84park requested review from Copilot and kimdora September 15, 2025 03:42
@kj84park kj84park self-assigned this Sep 15, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Collaborator

@gibeom-gwon gibeom-gwon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Collaborator

@gibeom-gwon gibeom-gwon Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about change rp to originFromRp and client to originFromClient?

Suggested change
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());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +157 to +162
if (OriginValidationHelper.isAppFacet(originFromClientData)) {
OriginValidationHelper.validateAppFacet(originFromClientData, configuredOrigins);
return;
}

OriginValidationHelper.validateWeb(originFromClientData, originFromRp, configuredOrigins);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Member Author

@kj84park kj84park Sep 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gibeom-gwon

Thanks for the suggestion! How about we merge AppOriginService and OriginValidationHelper into one OriginValidationService that handles both origin lookups and validation?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kj84park

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!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented OriginValidationService as you originally suggested.
I think it's better that way.

Comment on lines +61 to +68
private static boolean hasWebAllowlist(List<String> allowed) {
for (String o : allowed) {
if (o.startsWith("https://") || o.startsWith("http://")) {
return true;
}
}
return false;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I'll update this later.

.gitignore Outdated
/.nb-gradle/
**/build/

.DS_Store No newline at end of file
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor thing, how about add new line in the bottom?

@kj84park
Copy link
Member Author

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.

@gibeom-gwon nim
Yes. With web origins configured, the server validates clientDataJSON.origin against the allowlist and ignores the request origin fields.

Also, I applied most of your comments and updated the code. Please review.

gibeom-gwon
gibeom-gwon previously approved these changes Sep 18, 2025
Copy link
Collaborator

@gibeom-gwon gibeom-gwon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review.
LGTM! 👍

README.md Outdated
Comment on lines +207 to +208
- 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.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kimdora
I added the details based on your feedback. Could you check it?

kimdora
kimdora previously approved these changes Sep 23, 2025
Copy link
Contributor

@kimdora kimdora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kj84park kj84park dismissed stale reviews from kimdora and gibeom-gwon via 7322800 September 23, 2025 08:22
@kj84park kj84park requested a review from kimdora September 23, 2025 08:26
@kj84park kj84park merged commit 34cc4cf into line:main Sep 23, 2025
4 checks passed
@kj84park kj84park deleted the update-origin branch September 23, 2025 09:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make checkOrigin also available under non-android/ios scenario

4 participants