1# Copyright 2015 gRPC authors.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15require 'spec_helper'
16
17def create_channel_creds
18  test_root = File.join(File.dirname(__FILE__), 'testdata')
19  files = ['ca.pem', 'client.key', 'client.pem']
20  creds = files.map { |f| File.open(File.join(test_root, f)).read }
21  GRPC::Core::ChannelCredentials.new(creds[0], creds[1], creds[2])
22end
23
24def client_cert
25  test_root = File.join(File.dirname(__FILE__), 'testdata')
26  cert = File.open(File.join(test_root, 'client.pem')).read
27  fail unless cert.is_a?(String)
28  cert
29end
30
31def create_server_creds
32  test_root = File.join(File.dirname(__FILE__), 'testdata')
33  GRPC.logger.info("test root: #{test_root}")
34  files = ['ca.pem', 'server1.key', 'server1.pem']
35  creds = files.map { |f| File.open(File.join(test_root, f)).read }
36  GRPC::Core::ServerCredentials.new(
37    creds[0],
38    [{ private_key: creds[1], cert_chain: creds[2] }],
39    true) # force client auth
40end
41
42# a test service that checks the cert of its peer
43class SslTestService
44  include GRPC::GenericService
45  rpc :an_rpc, EchoMsg, EchoMsg
46  rpc :a_client_streaming_rpc, stream(EchoMsg), EchoMsg
47  rpc :a_server_streaming_rpc, EchoMsg, stream(EchoMsg)
48  rpc :a_bidi_rpc, stream(EchoMsg), stream(EchoMsg)
49
50  def check_peer_cert(call)
51    error_msg = "want:\n#{client_cert}\n\ngot:\n#{call.peer_cert}"
52    fail(error_msg) unless call.peer_cert == client_cert
53  end
54
55  def an_rpc(req, call)
56    check_peer_cert(call)
57    req
58  end
59
60  def a_client_streaming_rpc(call)
61    check_peer_cert(call)
62    call.each_remote_read.each { |r| GRPC.logger.info(r) }
63    EchoMsg.new
64  end
65
66  def a_server_streaming_rpc(_, call)
67    check_peer_cert(call)
68    [EchoMsg.new, EchoMsg.new]
69  end
70
71  def a_bidi_rpc(requests, call)
72    check_peer_cert(call)
73    requests.each { |r| GRPC.logger.info(r) }
74    [EchoMsg.new, EchoMsg.new]
75  end
76end
77
78SslTestServiceStub = SslTestService.rpc_stub_class
79
80describe 'client-server auth' do
81  RpcServer = GRPC::RpcServer
82
83  before(:all) do
84    server_opts = {
85      poll_period: 1
86    }
87    @srv = new_rpc_server_for_testing(**server_opts)
88    port = @srv.add_http2_port('0.0.0.0:0', create_server_creds)
89    @srv.handle(SslTestService)
90    @srv_thd = Thread.new { @srv.run }
91    @srv.wait_till_running
92
93    client_opts = {
94      channel_args: {
95        GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr'
96      }
97    }
98    @stub = SslTestServiceStub.new("localhost:#{port}",
99                                   create_channel_creds,
100                                   **client_opts)
101  end
102
103  after(:all) do
104    expect(@srv.stopped?).to be(false)
105    @srv.stop
106    @srv_thd.join
107  end
108
109  it 'client-server auth with unary RPCs' do
110    @stub.an_rpc(EchoMsg.new)
111  end
112
113  it 'client-server auth with client streaming RPCs' do
114    @stub.a_client_streaming_rpc([EchoMsg.new, EchoMsg.new])
115  end
116
117  it 'client-server auth with server streaming RPCs' do
118    responses = @stub.a_server_streaming_rpc(EchoMsg.new)
119    responses.each { |r| GRPC.logger.info(r) }
120  end
121
122  it 'client-server auth with bidi RPCs' do
123    responses = @stub.a_bidi_rpc([EchoMsg.new, EchoMsg.new])
124    responses.each { |r| GRPC.logger.info(r) }
125  end
126end
127