2015/06/04

Smart Lock for Passwords on Android

端末間でパスワードを同期する

Google Smart Lock for Passwords を使うと、お気に入りのアプリやウェブサイトで使用するアカウントのセキュリティを簡単に強化できます。ユーザーは、Smart Lock で Google アカウントに保存されたパスワードを、Chrome で表示したウェブサイトや Android 搭載端末のアプリで簡単かつ安全に利用できます。

Smart Lock for Passwords を使用すると、Chrome で保存したパスワードを Android 搭載端末で利用できる場合があります。同様に、Android 搭載端末で保存したパスワードを、Google アカウントでログイン済みの Chrome ブラウザで利用できる場合があります。各パスワードは対応するアプリやサイトでのみ利用可能です。詳しくは、ウェブサイトのパスワードを管理するをご覧ください。

携帯端末でパスワードを保存する

Smart Lock for Passwords がオンの場合は、端末のアプリにログインすると、ログイン情報を保存するかどうかの確認を求められる場合があります。[パスワードを保存] をタップすると、アプリ用のパスワードを安全に保存できます。2 つ以上の Google アカウントで端末にログインしている場合は、パスワードを保存するアカウントを選択できます。

Google アカウントに保存されたパスワードで対応アプリに初めてログインすると、Smart Lock for Passwords を使用していることが通知されます。保存したパスワードは passwords.google.com でいつでも確認できます。

引用元: https://support.google.com/accounts/answer/6197437

保存したパスワードを管理する

Chrome ではさまざまなサイトのパスワードを保存できます。Chrome でウェブサイトにログインすると毎回、そのサイトのパスワードを保存するかどうかを確認するメッセージが表示されます。

Chrome にログインしている場合、パスワードは Google アカウントにも同期されます。そのため、同期されたパスワードを別のデバイスでも使用できます。

Chrome でのパスワードの扱い

Chrome でのパスワードの扱いは、デバイス間でパスワードを同期するかどうかによって異なります。

Chrome にログインしているか、Android で Google Smart Lock for Passwords を使っている場合は、Chrome で保存したパスワードを使って Android 搭載端末で自動ログインできる可能性があります。

同様に、Android 搭載端末で保存したパスワードは、Google アカウントでログインした場合に Chrome でも使用できます。

詳しくは、Chrome と Android 搭載端末の間でのパスワードの同期についての説明をご覧ください。

注: Chrome にログインしている場合、ログインに使用した Google アカウントのパスワードを保存するかどうかを確認するメッセージは表示されません。

引用元: https://support.google.com/chrome/answer/95606

Chrome上でWebサービスがID-パスワード形式でユーザ認証する場合, そこで入力したパスワードを保存するかどうか, Chromeが問合せてくる場合がある. パスワードを保存することで同サービスへログインする場合に再度パスワードを入力する必要がなくなるため, サインインの手間を省くことができる.

Chromeのこの便利な機能をAndroidアプリケーション上でも実現することができる.
Smart Lock for Password機構によりアカウントのパスワード情報はGoogleによって安全に管理される.
AndroidアプリケーションはGoogleApiClientを通すことでSmart Lock for Passwordの恩恵を受けることができる.

Smart Lock for Passwords on Android

http://get.google.com/smartlock/

https://developers.google.com/identity/smartlock-passwords/android/

Programmatically save and retrieve credentials, and automatically sign users in across devices and websites in Chrome.

By integrating Smart Lock for Passwords into your Android app, you can automatically sign users in to your app using the credentials they have saved. Users can save both username-password credentials and federated identity provider credentials.

プログラマブルにクレデンシャルを保存および取得し, 異なるデバイス間でのサインインやクロームで訪れるWebサイトの認可処理を自動化する.

Smart Lock for Passwordをあなたのアプリケーションへ統合することで, Smart Lock for Passwordに保存されているクレデンシャルを使用して認可処理を自動化できる. ユーザはユーザ名-パスワードのクレデンシャルと連携IDプロバイダのクレデンシャルを保存することができる.

Integrate Smart Lock for Passwords into your app by using the Credential API to retrieve saved credentials on sign-in. Use successfully retrieved credentials to sign the user in, or use the Credential API to rapidly on-board new users by partially completing your app’s sign in or sign up form. Prompt users after sign-in or sign-up to store their credentials for future automatic authentication.

Smart Lock for Passwordでは保存されたクレデンシャルを取得するためにCredential APIを使う. ユーザのサインインにクレデンシャルを使用するか, Credential APIを使って新しいユーザのサインイン/サインアップを素早く済ませるために一部の情報を埋めた状態でサインイン/サインアップ用の入力フォームを表示する. 自動認可処理のためにユーザがサインイン/サインアップを終えたらクレデンシャルを保存する.

Add Smart Lock for Passwords to Your Android App

Store user credentials with Auth.CredentialsApi.save():

Auth.CredentialApi.save()を使用してクレデンシャルの保存を行う.

Auth.CredentialsApi.save(mCredentialsClient, credential).setResultCallback(
  new ResultCallback() {
      @Override
      public void onResult(Status status) {
          if (status.isSuccess()) {
              // Credentials were saved
          } else {
              if (status.hasResolution()) {
                  // Try to resolve the save request. This will prompt the user if
                  // the credential is new.
                  try {
                      status.startResolutionForResult(this, RC_SAVE);
                  } catch (IntentSender.SendIntentException e) {
                      // Could not resolve the request
                  }
              }
          }
      }
  });

Retrieve stored credentials with Auth.CredentialsApi.request() :

Auth.CredentialsApi.request()で保存されたクレデンシャルを取得する.

Auth.CredentialsApi.request(mCredentialsClient, mCredentialRequest).setResultCallback(
  new ResultCallback() {
      @Override
      public void onResult(CredentialRequestResult credentialRequestResult) {
          if (credentialRequestResult.getStatus().isSuccess()) {
              // Handle successful credential requests
          } else {
              // Handle unsuccessful and incomplete credential requests
          }
      }
  });

Start integrating Smart Lock for Passwords into your Android app

https://developers.google.com/identity/smartlock-passwords/android/get-started

Before you start integrating Smart Lock for Passwords into your app, configure your Google Developers Console project (or create a new project), then enable the Play Services SDK in your Android Studio project. Next steps describes how to integrate Smart Lock for Passwords into your app.

Smart Lock Passwordを導入する前にGoogle Developers Consoleプロジェクトをセットアップし, Android StudioでPlay Service SDKの準備をしておく.

Prerequisites

Smart Lock Password on Androidの必須要件.

  • Android 2.3 or higher かつ Google Play Store 搭載
  • Android emulator with AVD の場合はGoogle APIs platformが搭載された Android 4.2.2 or higher
  • Android Studio(recommended)

Configure your Google Developers Console project

To use Google services, you must create a Google Developers Console project, create an OAuth 2.0 client ID, and register your digitally signed .apk file’s public certificate:

Googleサービスを使用するにはGoogle Developers Console Projectを作成する必要がある. OAuth2.0のクライアントIDを作成し, 電子署名された.apkファイルの公開証明書を登録する.

〜Google Developers Console Projectの説明は省略〜

Configure your Android Studio project

Google Play Serviceを導入. build.gradleのdependenciesを編集する.

compile 'com.google.android.gms:play-services:7.5.0'

AndroidManifest.xmlにGoogle Play Serviceのバージョンを定義.

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version"/>

Create a GoogleApiClient object

To request stored credentials, you must create an instance of GoogleApiClient configured to access the Credentials API.

保存されたクレデンシャルを得るためにGoogleApiClientをからCredentials APIにアクセスする.

mCredentialsClient = new GoogleApiClient.Builder(this)
    .addConnectionCallbacks(this)
    .addOnConnectionFailedListener(this)
    .addApi(Auth.CREDENTIALS_API)
    .build();

Create a CredentialRequest object

A CredentialRequest object specifies the sign-in systems from which you want to request credentials. Build a CredentialRequest using the setSupportsPasswordLogin() method for password-based sign-in, and the setAccountTypes() method for federated sign-in services such as Google Sign-In.

CredentialRequestオブジェクトはサインインシステムに求めるクレデンシャルのリクエストである. CredentialRequestの構築にはパスワードベースサインインのためのsetSupportsPasswordLogin()と, Google Sing-inのような連携サインインサービスのためのsetAccountTypes()がある.

mCredentialRequest = new CredentialRequest.Builder()
    .setSupportsPasswordLogin(true)
    .setAccountTypes(IdentityProviders.GOOGLE, IdentityProviders.TWITTER)
    .build();

Use the constants defined in IdentityProviders to specify commonly-used sign-in providers. For other sign-in providers, use any string that uniquely identifies the provider. You must use the same provider identifier to store credentials as you use to retrieve the credentials.

IdentityProvidersにある定数を使用すると一般的なサインインプロバイダーを指定できる. 他のサインインプロバイダーはプロバイダーを識別できる他のユニークな文字列IDを使用すること. 保存した時のクレデンシャルと読み込む際のクレデンシャルで使用するプロバイダIDは同じであること.

Request stored credentials

After you have created GoogleApiClient and CredentialRequest objects, pass them to the CredentialsApi.request() method to request credentials stored for your app.

GoogleApiClientCredentialRequestオブジェクトを作成したあとはCredentialsApi.request()メソッドにそれらを渡してアプリに保存されたクレデンシャルをリクエストする.

Auth.CredentialsApi.request(mCredentialsClient, mCredentialRequest).setResultCallback(
    new ResultCallback<CredentialRequestResult>() {
        @Override
        public void onResult(CredentialRequestResult credentialRequestResult) {
            if (credentialRequestResult.getStatus().isSuccess()) {
                // See "Handle successful credential requests"
                onCredentialRetrieved(credentialRequestResult.getCredential());
            } else {
                // See "Handle unsuccessful and incomplete credential requests"
                resolveResult(credentialRequestResult.getStatus(), RC_READ);
            }
        }
    });

Define a callback to handle successful and failed requests using the setResultCallback() method.

コールバックを作成してリクエストの成功と失敗をハンドリングするにはsetResultCallback()メソッドを使用する.

Handle successful credential requests

On a successful credential request, use the resulting Credential object to complete the user’s sign-in to your app. Use the getAccountType() method to determine the type of retrieved credentials, then complete the appropriate sign-in process. For example, for Google Sign-In, create a GoogleApiClient object that includes the user’s ID, then use the object to start the sign-in flow. For password-based sign-in, use the user’s ID and password from the Credential object to complete your app’s sign-in process.

クレデンシャルのリクエストがうまくいくと, サインインの結果としてCredentialオブジェクトを返す. サインインを終えたらgetAccountType()メソッドを使いクレデンシャルの種別を取得する. 例えば, Google Sign-inではユーザIDを含んだGoogleApiClientオブジェクトを作成し, サインインフローを開始する. パスワードベースのサインインではCredentialオブジェクトからユーザIDとパスワードを使用してサインインプロセスを完了させる.

private void onCredentialRetrieved(Credential credential) {
    String accountType = credential.getAccountType();
    if (accountType.equals(IdentityProviders.GOOGLE)) {
        // The user has previously signed in with Google Sign-In. Start the sign-in flow with
        // the same ID.
        // See https://developers.google.com/identity/sign-in/android/
    } else if (accountType == null)
        // Sign the user in with information from the Credential.
        signInWithPassword(credential.getId(), credential.getPassword());
    }
}

Handle unsuccessful and incomplete credential requests

Credential requests can fail when:

  • Multiple credentials are saved
  • No credentials are saved
  • User input is required to proceed
  • There is a network or server error

クレデンシャルリクエストは次のケースで失敗する

  • 複数のクレデンシャルが保存されている
  • クレデンシャルが保存されていない
  • 続けてのユーザ入力が必要
  • ネットワークかサーバのエラー

When multiple credentials are saved or user input is required, the hasResolution() method returns true. In this case, call the status object’s startResolutionForResult() method to prompt the user to choose an account. Then, retrieve the user’s chosen credentials from the activity’s onActivityResult() method by passing Credential.EXTRA_KEY to the getParcelableExtra() method.

複数のクレデンシャルが保存されているか, ユーザの入力が必要である場合, hasResulution()メソッドはtrueを返す. このケースではstartResolutionForResult()メソッドを呼びユーザにアカウントの選択を促す ユーザが選択したクレデンシャルはActivityのonActivityResult()メソッドに渡されるIntentgetParcelableExtra()Credential.EXTRA_KEYを指定することで取得できる.

private void resolveResult(Status status, int requestCode) {
    if (status.hasResolution()) {
        try {
            status.startResolutionForResult(this, requestCode);
        } catch (IntentSender.SendIntentException e) {
            Log.e(TAG, "STATUS: Failed to send resolution.", e);
        }
    } else {
        // The user must create an account or sign in manually.
        Log.e(TAG, "STATUS: Unsuccessful credential request had no resolution.");
    }
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    ...

    if (requestCode == RC_READ) {
        if (resultCode == RESULT_OK) {
            Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
            onCredentialRetrieved(credential);
        } else {
            Log.e(TAG, "Credential Read: NOT OK");
            Toast.makeText(this, "Credential Read Failed", Toast.LENGTH_SHORT).show();
        }
    }

    ...

}

When stored credentials are not found, users must create an account or manually sign in. You can expedite the sign-up and sign-in processes by automatically filling some fields of the forms with information from recently-used accounts. See Provide sign-in hints to a user for information on how to prompt the user to select a recently-used account.

保存されているクレデンシャルが見つからない時, ユーザはアカウントを作成して手動でサインインする必要がある. この時, 最近使用したアカウントから情報を得て入力フォームを埋めることでユーザのサインイン/サインアップを手助けできる. Provide sign-in hints to a user ではどのようにしてユーザに最近使用したユーザを選択させるかの方法が載ってある.

On successful sign in, allow users to save their credentials to automate future authentication on all their devices.

サインインが成功すると, 全てのデバイスで今後サインインを自動化するためにユーザはクレデンシャルを保存することができる.

Provide sign-in hints to a user

Requests to retrieve user credentials can fail when a user has not yet saved credentials or when a user has not yet signed up to your app. In these situations, use the Credentials API to retrieve sign-in hints, such as the user’s name and email address. Use these hints to pre-fill your app’s sign-in and sign-up forms, speeding up your app’s on-boarding process.

ユーザがまだクレデンシャルを保存していない場合やまだアプリケーション上でサインアップしていない場合はクレデンシャルの取得に失敗する可能性がある. この場合, Credentials APIを使用してサインインのヒント(ユーザ名やeメールアドレス etc)を得ることができる. ユーザのサインアップ時にはこれらのヒントを使用してあらかじめサインアップのためのフォームに情報を埋めておき素早くサインアップできるように配慮する.

Retrieve sign-in hints and pre-fill the sign-up form

Sign-in hints are available under the following conditions:

  • CredentialRequestResult.getStatus().isSuccess() is false
  • CredentialRequestResult.getStatus().hasResolution() is true
  • CredentialRequestResult.getStatus().getStatusCode() returns SIGN_IN_REQUIRED

To retrieve the sign-in hints, pass a request code to Status.startResolutionForResult() to indicate that sign-in hints are available:

サインインのヒントは次の条件で使用できる.

  • CredentialRequestResult.getStatus().isSuccess() is false
  • CredentialRequestResult.getStatus().hasResolution() is true
  • CredentialRequestResult.getStatus().getStatusCode() returns SIGN_IN_REQUIRED

サインインのヒントを取得し, これが有効であることを示すためにStatus.startResolutionForResult()へリクエストコードを渡す.

static final int RC_READ = 1;
static final int RC_GET_HINTS = 2;

...

private void resolveResult(Status status) {
    int requestCode;
    if (status.hasResolution()) {
        if (status.getStatusCode() == CommonStatusCodes.SIGN_IN_REQUIRED) {
            requestCode = RC_GET_HINTS;
        } else {
            requestCode = RC_READ;
        }
        try {
            status.startResolutionForResult(MainActivity.this, requestCode);
        } catch (IntentSender.SendIntentException e) {
            Log.e(TAG, "STATUS: Failed to send resolution.", e);
        }
    } else {
        // The user must create an account or sign in manually.
        Log.e(TAG, "STATUS: Unsuccessful credential request had no resolution.");
    }
}

The user is prompted to choose an account to use.

Then, in the activity’s onActivityResult() method, retrieve the hints from the Credential.EXTRA_KEY parcel, check whether the user is in your user database, and start the appropriate activity with the credentials hint.

プロンプトを表示してアカウントを選択するようにユーザへ求める.

ActivityのonActivityResult()メソッドでparcelからCredential.EXTRA_KEYを使ってヒントを取得し, ユーザがあなたのデータベースに存在するかどうか確認し, クレデンシャルヒントを付帯させて適切なActivityを起動する.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == RC_GET_HINTS) {
        if (resultCode == RESULT_OK) {
            Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
            Intent intent;
            // Check for the user ID in your user database.
            if (userDatabaseContains(credential.getId())) {
                intent = new Intent(this, SignInActivity.class);
            } else {
                intent = new Intent(this, SignUpNewUserActivity.class);
            }
            intent.putExtra("com.mycompany.myapp.SIGNIN_HINTS", credential);
            startActivity(intent);
        } else {
            Log.e(TAG, "Hint Read: NOT OK");
            Toast.makeText(this, "Hint Read Failed", Toast.LENGTH_SHORT).show();
        }
    }

    ...

}

In the sign-in and sign-up activities, pre-fill the sign-up fields with the sign-in hints that you added to the intent.

サインイン/サインアップのActivityでサインアップ用のフィールドをIntentから得たサインインヒントで予め埋める.

public class SignUpNewUserActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();
        Credential credential = intent.getParcelableExtra("com.mycompany.myapp.SIGNIN_HINTS");

        // Pre-fill sign-up fields
        mUsernameView.setText(credential.getId());
        mDisplaynameView.setText(credential.getName()); // Might be null.

        ...
    }

    ...
}

Store a user’s credentials

After users successfully sign in, create accounts, or change passwords, allow them to store their credentials to automate future authentication in your app.

ユーザのサインインが成功し, アカウントを作成またはパスワードを変更した後, 自動認証のためのクレデンシャルをアプリケーションに保存する.

Store credentials

Create a Credential object containing a user’s sign-in information. For example, to let users store their credentials after successfully signing in with their passwords:

ユーザサインイン情報を含んだCredentialオブジェクトを作成する. 例えばパスワードでログインした後にクレデンシャルを保存する場合は:

Credential credential = new Credential.Builder(email)
        .setPassword(password)
        .build();

Or, for example, after users successfully sign in with their Google accounts:

または, サインインが成功した後にGoogleアカウントを保存する場合.

Credential credential = new Credential.Builder(email)
        .setAccountType(IdentityProviders.GOOGLE)
        .build();

Then, call CredentialsApi.save() to save users’ credentials. If the call to CredentialsApi.save() is not immediately successful, the credentials might be new, in which case the user must confirm the save request. Resolve the save request with startResolutionForResult() to prompt the user for confirmation.

次いで, CredentialsApi.save()を呼び出しクレデンシャルを保存する. CredentialsApi.save()の呼び出しですぐに成功しない場合, 保存しようとしているクレデンシャルが新規作成物であり, ユーザにクレデンシャルの保存の同意を必要としている場合がある.
保存のリクエストを解決するにはstartResolutionForResult()でユーザ確認のプロンプトを表示する.

Auth.CredentialsApi.save(mCredentialsClient, credential).setResultCallback(
            new ResultCallback() {
                @Override
                public void onResult(Status status) {
                    if (status.isSuccess()) {
                        Log.d(TAG, "SAVE: OK");
                        Toast.makeText(this, "Credentials saved", Toast.LENGTH_SHORT).show();
                    } else {
                        if (status.hasResolution()) {
                            // Try to resolve the save request. This will prompt the user if
                            // the credential is new.
                            try {
                                status.startResolutionForResult(this, RC_SAVE);
                            } catch (IntentSender.SendIntentException e) {
                                // Could not resolve the request
                                Log.e(TAG, "STATUS: Failed to send resolution.", e);
                                Toast.makeText(this, "Save failed", Toast.LENGTH_SHORT).show();
                            }
                        } else {
                            // Request has no resolution
                            Toast.makeText(this, "Save failed", Toast.LENGTH_SHORT).show();
                        }
                    }
                }
            });
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    ...

    if (requestCode == RC_SAVE) {
        if (resultCode == RESULT_OK) {
            Log.d(TAG, "SAVE: OK");
            Toast.makeText(this, "Credentials saved", Toast.LENGTH_SHORT).show();
        } else {
            Log.e(TAG, "SAVE: Canceled by user", e);
        }
    }

    ...

}

After storing credentials, retrieve them by calling CredentialsApi.request().

クレデンシャルを保存した後, CredentialsApi.request()でそれを取得する.

Enable automatic sign-in across apps and websites

If you have an app and a website that share a user database or use federated sign-in providers such as Google Sign-In, you can associate the app with the website so that users save their credentials once and then automatically sign in to both the app and the website.

アプリとWebサイトを持ち, ユーザデータベースかGoogle Sign-Inのような連携サインインの仕組みを提供する場合, Webサイトとアプリを関連付けてユーザの保存したクレデンシャルをアプリでも使用して自動サインインに利用できる.

To associate an app with a website, first verify that you own the website by using the Google Search Console, then use the Play Developer Console to make the association.

Webサイトとアプリを関連付けるため, 自前WebサイトをGoogle Search Consoleで有効化し, Play Developer Consoleを使ってアプリとWebサイトを関連付ける.

Prerequisites

Your website must be available through HTTPS.

あなたのWebサイトでHTTPSが使える必要がある.

Verify ownership of your website

If you have not already verified ownership of your website with the Google Search Console, do so by following these steps:

まだ有効化されたWebサイトを持っていないのであれば, 次のステップを踏む.

〜Google Search / Play Developer Consoleの操作については省略〜


Sequence

クレデンシャルが保存済みである場合の正常ケース:

Credential saved

サインインが必要, あるいはアカウントの選択が必要である場合の正常ケース:

Need Signin

ソースコードについてはサンプルコードが公開されている.

以上.