Skip to content

Commit

Permalink
Reland "[Autofill Auth] Creating implementation of InternalAuthentica…
Browse files Browse the repository at this point in the history
…tor for Clank."

This is a reland of 55d7119

Original change's description:
> [Autofill Auth] Creating implementation of InternalAuthenticator for Clank.
>
> Using a JNI bridge to create an implementation of InternalAuthenticator
> for Android.
>
> Bug: 949269
> Change-Id: I9cf9c33ffba04b5814ed9fc6f98f2481b23293d1
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2155531
> Reviewed-by: Nina Satragno <nsatragno@chromium.org>
> Reviewed-by: Tommy Martino <tmartino@chromium.org>
> Reviewed-by: Ken Buchanan <kenrb@chromium.org>
> Reviewed-by: Bo <boliu@chromium.org>
> Reviewed-by: Andrew Grieve <agrieve@chromium.org>
> Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
> Reviewed-by: Evan Stade <estade@chromium.org>
> Reviewed-by: Jared Saul <jsaul@google.com>
> Reviewed-by: Kinuko Yasuda <kinuko@chromium.org>
> Commit-Queue: Manas Verma <manasverma@google.com>
> Cr-Commit-Position: refs/heads/master@{#763442}

Bug: 949269
Change-Id: I26095959c78e0ca8b6e5b685ca12b27a20d91a39
Tbr: tmartino@chromium.org,kenrb@chromium.org,boliu@chromium.org,agrieve@chromium.org,arthursonzogni@chromium.org,estade@chromium.org,jsaul@google.com,kinuko@chromium.org
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2173427
Commit-Queue: Manas Verma <manasverma@google.com>
Reviewed-by: Nina Satragno <nsatragno@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Cr-Commit-Position: refs/heads/master@{#764332}
  • Loading branch information
Manas Verma authored and Commit Bot committed Apr 30, 2020
1 parent bbe03a7 commit 6f50f14
Show file tree
Hide file tree
Showing 20 changed files with 496 additions and 84 deletions.
1 change: 1 addition & 0 deletions chrome/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -2962,6 +2962,7 @@ generate_jni("chrome_jni_headers") {
"java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java",
"java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenInstaller.java",
"java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediator.java",
"java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java",
]

# Used for testing only, should not be shipped to end users.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import android.os.Build;

import org.chromium.base.PackageUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.blink.mojom.Authenticator;
import org.chromium.blink.mojom.AuthenticatorStatus;
import org.chromium.blink.mojom.GetAssertionAuthenticatorResponse;
Expand All @@ -21,12 +23,18 @@
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsStatics;
import org.chromium.mojo.system.MojoException;
import org.chromium.url.Origin;

import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.Optional;
import java.util.Queue;

/**
* Android implementation of the authenticator.mojom interface.
* Android implementation of the authenticator.mojom interface. This also acts as the bridge for
* InternalAuthenticator declared in
* //chrome/browser/autofill/android/internal_authenticator_android.h, which is meant for requests
* that originate in the browser process.
*/
public class AuthenticatorImpl extends HandlerResponseCallback implements Authenticator {
private final RenderFrameHost mRenderFrameHost;
Expand All @@ -37,6 +45,13 @@ public class AuthenticatorImpl extends HandlerResponseCallback implements Authen
/** Ensures only one request is processed at a time. */
private boolean mIsOperationPending;

/**
* The origin of the request. This may be overridden by an internal request from the browser
* process.
*/
private Origin mOrigin;
private Optional<Long> mNativeInternalAuthenticatorAndroid = Optional.empty();

private org.chromium.mojo.bindings.Callbacks
.Callback2<Integer, MakeCredentialAuthenticatorResponse> mMakeCredentialCallback;
private org.chromium.mojo.bindings.Callbacks
Expand All @@ -56,9 +71,32 @@ public class AuthenticatorImpl extends HandlerResponseCallback implements Authen
public AuthenticatorImpl(RenderFrameHost renderFrameHost) {
assert renderFrameHost != null;
mRenderFrameHost = renderFrameHost;
mOrigin = mRenderFrameHost.getLastCommittedOrigin();
mWebContents = WebContentsStatics.fromRenderFrameHost(renderFrameHost);
}

private AuthenticatorImpl(
long nativeInternalAuthenticatorAndroid, RenderFrameHost renderFrameHost) {
this(renderFrameHost);
mNativeInternalAuthenticatorAndroid = Optional.of(nativeInternalAuthenticatorAndroid);
}

@CalledByNative
public static AuthenticatorImpl create(
long nativeInternalAuthenticatorAndroid, RenderFrameHost renderFrameHost) {
return new AuthenticatorImpl(nativeInternalAuthenticatorAndroid, renderFrameHost);
}

/**
* Called by InternalAuthenticator, which facilitates WebAuthn for processes that originate from
* the browser process. Since the request is from the browser process, the Relying Party ID may
* not correspond with the origin of the renderer.
*/
@CalledByNative
public void setEffectiveOrigin(Origin origin) {
mOrigin = origin;
}

@Override
public void makeCredential(
PublicKeyCredentialCreationOptions options, MakeCredentialResponse callback) {
Expand All @@ -76,7 +114,22 @@ public void makeCredential(
}

mIsOperationPending = true;
Fido2ApiHandler.getInstance().makeCredential(options, mRenderFrameHost, this);
Fido2ApiHandler.getInstance().makeCredential(options, mRenderFrameHost, mOrigin, this);
}

/**
* Called by InternalAuthenticator, which facilitates WebAuthn for processes that originate from
* the browser process. The origin may be overridden through |setEffectiveOrigin()|. The
* response will be passed through |invokeMakeCredentialResponse()|.
*/
@CalledByNative
public void makeCredentialBridge(ByteBuffer optionsByteBuffer) {
assert mNativeInternalAuthenticatorAndroid.isPresent();
makeCredential(PublicKeyCredentialCreationOptions.deserialize(optionsByteBuffer),
(status, response)
-> AuthenticatorImplJni.get().invokeMakeCredentialResponse(
mNativeInternalAuthenticatorAndroid.get(), status.intValue(),
response.serialize()));
}

@Override
Expand All @@ -96,7 +149,22 @@ public void getAssertion(
}

mIsOperationPending = true;
Fido2ApiHandler.getInstance().getAssertion(options, mRenderFrameHost, this);
Fido2ApiHandler.getInstance().getAssertion(options, mRenderFrameHost, mOrigin, this);
}

/**
* Called by InternalAuthenticator, which facilitates WebAuthn for processes that originate from
* the browser process. The origin may be overridden through |setEffectiveOrigin()|. The
* response will be passed through |invokeGetAssertionResponse()|.
*/
@CalledByNative
public void getAssertionBridge(ByteBuffer optionsByteBuffer) {
assert mNativeInternalAuthenticatorAndroid.isPresent();
getAssertion(PublicKeyCredentialRequestOptions.deserialize(optionsByteBuffer),
(status, response)
-> AuthenticatorImplJni.get().invokeGetAssertionResponse(
mNativeInternalAuthenticatorAndroid.get(), status.intValue(),
response.serialize()));
}

@Override
Expand Down Expand Up @@ -126,6 +194,23 @@ public void isUserVerifyingPlatformAuthenticatorAvailable(
mRenderFrameHost, this);
}

/**
* Called by InternalAuthenticator, which facilitates WebAuthn for processes that originate from
* the browser process. The origin may be overridden through |setEffectiveOrigin()|. The
* response will be passed through
* |invokeIsUserVerifyingPlatformAuthenticatorAvailableResponse()|.
*/
@CalledByNative
public void isUserVerifyingPlatformAuthenticatorAvailableBridge() {
assert mNativeInternalAuthenticatorAndroid.isPresent();
isUserVerifyingPlatformAuthenticatorAvailable(
(isUVPAA)
-> AuthenticatorImplJni.get()
.invokeIsUserVerifyingPlatformAuthenticatorAvailableResponse(
mNativeInternalAuthenticatorAndroid.get(), isUVPAA));
}

@CalledByNative
@Override
public void cancel() {
// Not implemented, ignored because request sent to gmscore fido cannot be cancelled.
Expand Down Expand Up @@ -172,10 +257,21 @@ public void close() {
mIsOperationPending = false;
mMakeCredentialCallback = null;
mGetAssertionCallback = null;
mNativeInternalAuthenticatorAndroid = Optional.empty();
}

@Override
public void onConnectionError(MojoException e) {
close();
}

@NativeMethods
interface Natives {
void invokeMakeCredentialResponse(
long nativeInternalAuthenticatorAndroid, int status, ByteBuffer byteBuffer);
void invokeGetAssertionResponse(
long nativeInternalAuthenticatorAndroid, int status, ByteBuffer byteBuffer);
void invokeIsUserVerifyingPlatformAuthenticatorAvailableResponse(
long nativeInternalAuthenticatorAndroid, boolean isUVPAA);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.chromium.blink.mojom.PublicKeyCredentialCreationOptions;
import org.chromium.blink.mojom.PublicKeyCredentialRequestOptions;
import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.url.Origin;

/**
* Android implementation of the Authenticator service defined in
Expand Down Expand Up @@ -46,13 +47,15 @@ public static Fido2ApiHandler getInstance() {
}

protected void makeCredential(PublicKeyCredentialCreationOptions options,
RenderFrameHost frameHost, HandlerResponseCallback callback) {
new Fido2CredentialRequest().handleMakeCredentialRequest(options, frameHost, callback);
RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
new Fido2CredentialRequest().handleMakeCredentialRequest(
options, frameHost, origin, callback);
}

protected void getAssertion(PublicKeyCredentialRequestOptions options,
RenderFrameHost frameHost, HandlerResponseCallback callback) {
new Fido2CredentialRequest().handleGetAssertionRequest(options, frameHost, callback);
RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
new Fido2CredentialRequest().handleGetAssertionRequest(
options, frameHost, origin, callback);
}

protected void isUserVerifyingPlatformAuthenticatorAvailable(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsStatics;
import org.chromium.net.GURLUtils;
import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.url.Origin;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
Expand Down Expand Up @@ -138,7 +138,7 @@ public void onSuccess(Fido2PendingIntent fido2PendingIntent) {

public void handleMakeCredentialRequest(
org.chromium.blink.mojom.PublicKeyCredentialCreationOptions options,
RenderFrameHost frameHost, HandlerResponseCallback callback) {
RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
assert mCallback == null;
mCallback = callback;
if (mWebContents == null) {
Expand All @@ -153,8 +153,8 @@ public void handleMakeCredentialRequest(
return;
}

int securityCheck =
frameHost.performMakeCredentialWebAuthSecurityChecks(options.relyingParty.id);
int securityCheck = frameHost.performMakeCredentialWebAuthSecurityChecks(
options.relyingParty.id, origin);
if (securityCheck != AuthenticatorStatus.SUCCESS) {
returnErrorAndResetCallback(securityCheck);
return;
Expand All @@ -171,15 +171,15 @@ public void handleMakeCredentialRequest(
BrowserPublicKeyCredentialCreationOptions browserRequestOptions =
new BrowserPublicKeyCredentialCreationOptions.Builder()
.setPublicKeyCredentialCreationOptions(credentialCreationOptions)
.setOrigin(Uri.parse(GURLUtils.getOrigin(frameHost.getLastCommittedURL())))
.setOrigin(Uri.parse(convertOriginToString(origin)))
.build();

Task<Fido2PendingIntent> result = mFido2ApiClient.getRegisterIntent(browserRequestOptions);
result.addOnSuccessListener(mIntentListener);
}

public void handleGetAssertionRequest(PublicKeyCredentialRequestOptions options,
RenderFrameHost frameHost, HandlerResponseCallback callback) {
RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
assert mCallback == null;
mCallback = callback;
if (mWebContents == null) {
Expand All @@ -195,7 +195,7 @@ public void handleGetAssertionRequest(PublicKeyCredentialRequestOptions options,
}

int securityCheck =
frameHost.performGetAssertionWebAuthSecurityChecks(options.relyingPartyId);
frameHost.performGetAssertionWebAuthSecurityChecks(options.relyingPartyId, origin);
if (securityCheck != AuthenticatorStatus.SUCCESS) {
returnErrorAndResetCallback(securityCheck);
return;
Expand All @@ -212,7 +212,7 @@ public void handleGetAssertionRequest(PublicKeyCredentialRequestOptions options,
BrowserPublicKeyCredentialRequestOptions browserRequestOptions =
new BrowserPublicKeyCredentialRequestOptions.Builder()
.setPublicKeyCredentialRequestOptions(getAssertionOptions)
.setOrigin(Uri.parse(GURLUtils.getOrigin(frameHost.getLastCommittedURL())))
.setOrigin(Uri.parse(convertOriginToString(origin)))
.build();

Task<Fido2PendingIntent> result = mFido2ApiClient.getSignIntent(browserRequestOptions);
Expand Down Expand Up @@ -366,4 +366,8 @@ private void processIntentResult(Intent data) {
returnErrorAndResetCallback(AuthenticatorStatus.UNKNOWN_ERROR);
}
}

private String convertOriginToString(Origin origin) {
return origin.getScheme() + "://" + origin.getHost() + ":" + origin.getPort();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.chromium.content_public.common.ContentSwitches;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.net.test.ServerCertificate;
import org.chromium.url.Origin;

/** Test suite for navigator.credentials functionality. */
@RunWith(ChromeJUnit4ClassRunner.class)
Expand All @@ -53,13 +54,13 @@ public class AuthenticatorTest {
private class MockFido2ApiHandler extends Fido2ApiHandler {
@Override
protected void makeCredential(PublicKeyCredentialCreationOptions options,
RenderFrameHost frameHost, HandlerResponseCallback callback) {
RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
callback.onError(AuthenticatorStatus.NOT_IMPLEMENTED);
}

@Override
protected void getAssertion(PublicKeyCredentialRequestOptions options,
RenderFrameHost frameHost, HandlerResponseCallback callback) {
RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
callback.onError(AuthenticatorStatus.NOT_IMPLEMENTED);
}

Expand Down
Loading

0 comments on commit 6f50f14

Please sign in to comment.