Mutual authentication(two-way authentication) Callout (クライアント認証 編)

サーバ編はこちら

Callout の構成としては以下の通り。

  • Server: Nginx (ssl.mydomain.com という Virtual ドメイン)
  • Client : Salesforce
  • Salesforce を Client とする場合、クライアント認証で利用できる証明書は、自己署名証明書と認証機関署名証明書の 2 種類となる。自己署名証明書は Salesforce が署名しており、認証機関署名証明書は他の CA が署名した証明書となる。認証機関署名証明書 を作成するには、画面から CSR を作成し CA で署名した証明書(CRT)を再度インポートする必要がある。自己署名証明書は、Salesforce が署名しているので、利用するにはサーバ側でその旨の設定をする必要がある。今回は、自己署名証明書を利用する。

    自己署名証明書の作成

    [管理者設定] | [セキュリティコントロール] | [証明書と鍵の管理] より、”自己署名証明書の作成” をクリックしフォームを入力することで作成できる。その後、画面上からダウンロードできるようになる。

    サーバ側の設定

    証明書の中身を確認する。

    $ openssl x509 -text -noout -in SFDCSelfSignedCert.crt
    

    自己署名証明書は自身の鍵で署名されているので、そのままサーバ側で配置する。

    # vi /etc/nginx/sites-available/ssl.mydomain.com
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      # for SSL(Client certificate)
      ssl_verify_client on;
      ssl_client_certificate /etc/nginx/ssl/SFDCSelfSignedCert.crt;
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    # service nginx restart
    

    クライアント側の設定

    クライアント側から明示的に証明書を利用するように、Callout を実施する。

    String endPoint = 'https://ssl.mydomain.com/index.html';
    HttpRequest req = new HttpRequest();
    
    req.setEndpoint(endPoint);
    req.setMethod('GET');
    req.setTimeout(10000);
    req.setClientCertificateName('SFDCSelfSignedCert');
    
    Http http = new Http();
    HttpResponse res = http.send(req);
    System.debug('zzz getStatusCode: ' + res.getStatusCode());
    System.debug('zzz getBody: ' + res.getBody());
    

    クライアント証明書を指定しないと、以下のエラーとなる。

    400 Bad Request
    No required SSL certificate was sent
    

    サーバー側のログ(/var/log/nginx/ssl-error.log info)でも確認できる。

    2015/03/11 16:34:55 [info] 17277#0: *2 client sent no required SSL certificate while reading client request headers, client: xx.xx.xx.xx, server: ssl.mydomain.com, request: "GET /index.html HTTP/1.1", host: "ssl.mydomain.com"
    

    証明書を利用した成功時のログ。

    2015/03/11 16:46:08 [info] 17279#0: *5 client sent invalid header line: "SFDC_STACK_DEPTH: 1" while reading client request headers, client: xx.xx.xx.xx, server: ssl.mydomain.com, request: "GET /index.html HTTP/1.1"