blob: 294600c85a93b66ca3da31614ccb5366a55cd2c5 [file] [log] [blame]
murgatroid99153b09d2015-09-25 16:04:03 -07001/*
2 *
3 * Copyright 2015, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34'use strict';
35
36var assert = require('assert');
37var fs = require('fs');
38var path = require('path');
39
40var grpc = require('..');
41
murgatroid999c43b002015-09-28 16:31:16 -070042/**
43 * This is used for testing functions with multiple asynchronous calls that
44 * can happen in different orders. This should be passed the number of async
45 * function invocations that can occur last, and each of those should call this
46 * function's return value
47 * @param {function()} done The function that should be called when a test is
48 * complete.
49 * @param {number} count The number of calls to the resulting function if the
50 * test passes.
51 * @return {function()} The function that should be called at the end of each
52 * sequence of asynchronous functions.
53 */
54function multiDone(done, count) {
55 return function() {
56 count -= 1;
57 if (count <= 0) {
58 done();
59 }
60 };
61}
62
murgatroid997cfee082015-10-13 13:49:55 -070063var fakeSuccessfulGoogleCredentials = {
64 getRequestMetadata: function(service_url, callback) {
65 setTimeout(function() {
66 callback(null, {Authorization: 'success'});
67 }, 0);
68 }
69};
70
71var fakeFailingGoogleCredentials = {
72 getRequestMetadata: function(service_url, callback) {
73 setTimeout(function() {
murgatroid99c90b1092015-10-27 10:58:24 -070074 callback(new Error('Authentication failure'));
murgatroid997cfee082015-10-13 13:49:55 -070075 }, 0);
76 }
77};
78
murgatroid99a9172d22015-12-09 16:12:37 -080079var key_data, pem_data, ca_data;
80
81before(function() {
82 var key_path = path.join(__dirname, './data/server1.key');
83 var pem_path = path.join(__dirname, './data/server1.pem');
84 var ca_path = path.join(__dirname, '../test/data/ca.pem');
85 key_data = fs.readFileSync(key_path);
86 pem_data = fs.readFileSync(pem_path);
87 ca_data = fs.readFileSync(ca_path);
88});
89
90describe('channel credentials', function() {
91 describe('#createSsl', function() {
92 it('works with no arguments', function() {
93 var creds;
94 assert.doesNotThrow(function() {
95 creds = grpc.credentials.createSsl();
96 });
97 assert.notEqual(creds, null);
98 });
99 it('works with just one Buffer argument', function() {
100 var creds;
101 assert.doesNotThrow(function() {
102 creds = grpc.credentials.createSsl(ca_data);
103 });
104 assert.notEqual(creds, null);
105 });
106 it('works with 3 Buffer arguments', function() {
107 var creds;
108 assert.doesNotThrow(function() {
109 creds = grpc.credentials.createSsl(ca_data, key_data, pem_data);
110 });
111 assert.notEqual(creds, null);
112 });
113 it('works if the first argument is null', function() {
114 var creds;
115 assert.doesNotThrow(function() {
116 creds = grpc.credentials.createSsl(null, key_data, pem_data);
117 });
118 assert.notEqual(creds, null);
119 });
120 it('fails if the first argument is a non-Buffer value', function() {
121 assert.throws(function() {
122 grpc.credentials.createSsl('test');
123 }, TypeError);
124 });
125 it('fails if the second argument is a non-Buffer value', function() {
126 assert.throws(function() {
127 grpc.credentials.createSsl(null, 'test', pem_data);
128 }, TypeError);
129 });
130 it('fails if the third argument is a non-Buffer value', function() {
131 assert.throws(function() {
132 grpc.credentials.createSsl(null, key_data, 'test');
133 }, TypeError);
134 });
135 it('fails if only 1 of the last 2 arguments is provided', function() {
136 assert.throws(function() {
137 grpc.credentials.createSsl(null, key_data);
138 });
139 assert.throws(function() {
140 grpc.credentials.createSsl(null, null, pem_data);
141 });
142 });
143 });
144});
145
146describe('server credentials', function() {
147 describe('#createSsl', function() {
148 it('accepts a buffer and array as the first 2 arguments', function() {
149 var creds;
150 assert.doesNotThrow(function() {
151 creds = grpc.ServerCredentials.createSsl(ca_data, []);
152 });
153 assert.notEqual(creds, null);
154 });
155 it('accepts a boolean as the third argument', function() {
156 var creds;
157 assert.doesNotThrow(function() {
158 creds = grpc.ServerCredentials.createSsl(ca_data, [], true);
159 });
160 assert.notEqual(creds, null);
161 });
162 it('accepts an object with two buffers in the second argument', function() {
163 var creds;
164 assert.doesNotThrow(function() {
165 creds = grpc.ServerCredentials.createSsl(null,
166 [{private_key: key_data,
167 cert_chain: pem_data}]);
168 });
169 assert.notEqual(creds, null);
170 });
171 it('accepts multiple objects in the second argument', function() {
172 var creds;
173 assert.doesNotThrow(function() {
174 creds = grpc.ServerCredentials.createSsl(null,
175 [{private_key: key_data,
176 cert_chain: pem_data},
177 {private_key: key_data,
178 cert_chain: pem_data}]);
179 });
180 assert.notEqual(creds, null);
181 });
182 it('fails if the second argument is not an Array', function() {
183 assert.throws(function() {
184 grpc.ServerCredentials.createSsl(ca_data, 'test');
185 }, TypeError);
186 });
187 it('fails if the first argument is a non-Buffer value', function() {
188 assert.throws(function() {
189 grpc.ServerCredentials.createSsl('test', []);
190 }, TypeError);
191 });
192 it('fails if the third argument is a non-boolean value', function() {
193 assert.throws(function() {
194 grpc.ServerCredentials.createSsl(ca_data, [], 'test');
195 }, TypeError);
196 });
197 it('fails if the array elements are not objects', function() {
198 assert.throws(function() {
199 grpc.ServerCredentials.createSsl(ca_data, 'test');
200 }, TypeError);
201 });
202 it('fails if the object does not have a Buffer private_key', function() {
203 assert.throws(function() {
204 grpc.ServerCredentials.createSsl(null,
205 [{private_key: 'test',
206 cert_chain: pem_data}]);
207 }, TypeError);
208 });
209 it('fails if the object does not have a Buffer cert_chain', function() {
210 assert.throws(function() {
211 grpc.ServerCredentials.createSsl(null,
212 [{private_key: key_data,
213 cert_chain: 'test'}]);
214 }, TypeError);
215 });
216 });
217});
218
murgatroid99a5a897d2015-09-28 16:38:38 -0700219describe('client credentials', function() {
murgatroid99153b09d2015-09-25 16:04:03 -0700220 var Client;
221 var server;
222 var port;
223 var client_ssl_creds;
224 var client_options = {};
225 before(function() {
226 var proto = grpc.load(__dirname + '/test_service.proto');
227 server = new grpc.Server();
228 server.addProtoService(proto.TestService.service, {
229 unary: function(call, cb) {
230 call.sendMetadata(call.metadata);
231 cb(null, {});
232 },
233 clientStream: function(stream, cb){
234 stream.on('data', function(data) {});
235 stream.on('end', function() {
236 stream.sendMetadata(stream.metadata);
237 cb(null, {});
238 });
239 },
240 serverStream: function(stream) {
241 stream.sendMetadata(stream.metadata);
242 stream.end();
243 },
244 bidiStream: function(stream) {
245 stream.on('data', function(data) {});
246 stream.on('end', function() {
247 stream.sendMetadata(stream.metadata);
248 stream.end();
249 });
250 }
251 });
murgatroid99153b09d2015-09-25 16:04:03 -0700252 var creds = grpc.ServerCredentials.createSsl(null,
253 [{private_key: key_data,
254 cert_chain: pem_data}]);
murgatroid99153b09d2015-09-25 16:04:03 -0700255 port = server.bind('localhost:0', creds);
256 server.start();
257
258 Client = proto.TestService;
murgatroid99153b09d2015-09-25 16:04:03 -0700259 client_ssl_creds = grpc.credentials.createSsl(ca_data);
260 var host_override = 'foo.test.google.fr';
261 client_options['grpc.ssl_target_name_override'] = host_override;
262 client_options['grpc.default_authority'] = host_override;
263 });
264 after(function() {
265 server.forceShutdown();
266 });
murgatroid999c43b002015-09-28 16:31:16 -0700267 it('Should accept SSL creds for a client', function(done) {
268 var client = new Client('localhost:' + port, client_ssl_creds,
269 client_options);
270 client.unary({}, function(err, data) {
271 assert.ifError(err);
272 done();
273 });
274 });
275 it('Should update metadata with SSL creds', function(done) {
murgatroid99153b09d2015-09-25 16:04:03 -0700276 var metadataUpdater = function(service_url, callback) {
277 var metadata = new grpc.Metadata();
278 metadata.set('plugin_key', 'plugin_value');
279 callback(null, metadata);
280 };
281 var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
murgatroid99be13d812015-10-09 14:45:30 -0700282 var combined_creds = grpc.credentials.combineChannelCredentials(
283 client_ssl_creds, creds);
murgatroid99153b09d2015-09-25 16:04:03 -0700284 var client = new Client('localhost:' + port, combined_creds,
285 client_options);
286 var call = client.unary({}, function(err, data) {
287 assert.ifError(err);
murgatroid99153b09d2015-09-25 16:04:03 -0700288 });
289 call.on('metadata', function(metadata) {
290 assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
291 done();
292 });
293 });
murgatroid999c43b002015-09-28 16:31:16 -0700294 it('Should update metadata for two simultaneous calls', function(done) {
295 done = multiDone(done, 2);
296 var metadataUpdater = function(service_url, callback) {
297 var metadata = new grpc.Metadata();
298 metadata.set('plugin_key', 'plugin_value');
299 callback(null, metadata);
300 };
301 var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
murgatroid99be13d812015-10-09 14:45:30 -0700302 var combined_creds = grpc.credentials.combineChannelCredentials(
303 client_ssl_creds, creds);
murgatroid999c43b002015-09-28 16:31:16 -0700304 var client = new Client('localhost:' + port, combined_creds,
305 client_options);
306 var call = client.unary({}, function(err, data) {
307 assert.ifError(err);
308 });
309 call.on('metadata', function(metadata) {
310 assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
311 done();
312 });
313 var call2 = client.unary({}, function(err, data) {
314 assert.ifError(err);
315 });
316 call2.on('metadata', function(metadata) {
317 assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
318 done();
319 });
320 });
murgatroid996fe015e2015-10-12 13:18:06 -0700321 it.skip('should propagate errors that the updater emits', function(done) {
322 var metadataUpdater = function(service_url, callback) {
323 var error = new Error('Authentication error');
324 error.code = grpc.status.UNAUTHENTICATED;
325 callback(error);
326 };
327 var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
328 var combined_creds = grpc.credentials.combineChannelCredentials(
329 client_ssl_creds, creds);
330 var client = new Client('localhost:' + port, combined_creds,
331 client_options);
332 client.unary({}, function(err, data) {
333 assert(err);
334 assert.strictEqual(err.message, 'Authentication error');
335 assert.strictEqual(err.code, grpc.status.UNAUTHENTICATED);
336 done();
337 });
338 });
murgatroid997cfee082015-10-13 13:49:55 -0700339 it('should successfully wrap a Google credential', function(done) {
340 var creds = grpc.credentials.createFromGoogleCredential(
341 fakeSuccessfulGoogleCredentials);
342 var combined_creds = grpc.credentials.combineChannelCredentials(
343 client_ssl_creds, creds);
344 var client = new Client('localhost:' + port, combined_creds,
345 client_options);
346 var call = client.unary({}, function(err, data) {
347 assert.ifError(err);
348 });
349 call.on('metadata', function(metadata) {
murgatroid99c52dfac2015-10-13 15:37:34 -0700350 assert.deepEqual(metadata.get('authorization'), ['success']);
murgatroid997cfee082015-10-13 13:49:55 -0700351 done();
352 });
353 });
murgatroid997c0dbf82015-10-20 16:10:20 -0700354 it('Should not add metadata with just SSL credentials', function(done) {
murgatroid995901d902015-10-21 14:03:19 -0700355 // Tests idempotency of credentials composition
murgatroid997c0dbf82015-10-20 16:10:20 -0700356 var metadataUpdater = function(service_url, callback) {
357 var metadata = new grpc.Metadata();
358 metadata.set('plugin_key', 'plugin_value');
359 callback(null, metadata);
360 };
361 var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
murgatroid995901d902015-10-21 14:03:19 -0700362 grpc.credentials.combineChannelCredentials(client_ssl_creds, creds);
murgatroid997c0dbf82015-10-20 16:10:20 -0700363 var client = new Client('localhost:' + port, client_ssl_creds,
364 client_options);
365 var call = client.unary({}, function(err, data) {
366 assert.ifError(err);
367 });
368 call.on('metadata', function(metadata) {
369 assert.deepEqual(metadata.get('plugin_key'), []);
370 done();
371 });
372 });
murgatroid997cfee082015-10-13 13:49:55 -0700373 it.skip('should get an error from a Google credential', function(done) {
374 var creds = grpc.credentials.createFromGoogleCredential(
375 fakeFailingGoogleCredentials);
376 var combined_creds = grpc.credentials.combineChannelCredentials(
377 client_ssl_creds, creds);
378 var client = new Client('localhost:' + port, combined_creds,
379 client_options);
380 client.unary({}, function(err, data) {
381 assert(err);
murgatroid99c90b1092015-10-27 10:58:24 -0700382 assert.strictEqual(err.message, 'Authentication failure');
murgatroid997cfee082015-10-13 13:49:55 -0700383 done();
384 });
385 });
murgatroid999c43b002015-09-28 16:31:16 -0700386 describe('Per-rpc creds', function() {
387 var client;
388 var updater_creds;
389 before(function() {
390 client = new Client('localhost:' + port, client_ssl_creds,
391 client_options);
392 var metadataUpdater = function(service_url, callback) {
393 var metadata = new grpc.Metadata();
394 metadata.set('plugin_key', 'plugin_value');
395 callback(null, metadata);
396 };
397 updater_creds = grpc.credentials.createFromMetadataGenerator(
398 metadataUpdater);
399 });
400 it('Should update metadata on a unary call', function(done) {
401 var call = client.unary({}, function(err, data) {
402 assert.ifError(err);
403 }, null, {credentials: updater_creds});
404 call.on('metadata', function(metadata) {
405 assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
406 done();
407 });
408 });
409 it('should update metadata on a client streaming call', function(done) {
410 var call = client.clientStream(function(err, data) {
411 assert.ifError(err);
412 }, null, {credentials: updater_creds});
413 call.on('metadata', function(metadata) {
414 assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
415 done();
416 });
417 call.end();
418 });
419 it('should update metadata on a server streaming call', function(done) {
420 var call = client.serverStream({}, null, {credentials: updater_creds});
421 call.on('data', function() {});
422 call.on('metadata', function(metadata) {
423 assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
424 done();
425 });
426 });
427 it('should update metadata on a bidi streaming call', function(done) {
428 var call = client.bidiStream(null, {credentials: updater_creds});
429 call.on('data', function() {});
430 call.on('metadata', function(metadata) {
431 assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
432 done();
433 });
434 call.end();
435 });
murgatroid995f709ca2015-09-30 14:22:54 -0700436 it('should be able to use multiple plugin credentials', function(done) {
437 var altMetadataUpdater = function(service_url, callback) {
438 var metadata = new grpc.Metadata();
439 metadata.set('other_plugin_key', 'other_plugin_value');
440 callback(null, metadata);
441 };
442 var alt_updater_creds = grpc.credentials.createFromMetadataGenerator(
443 altMetadataUpdater);
444 var combined_updater = grpc.credentials.combineCallCredentials(
445 updater_creds, alt_updater_creds);
446 var call = client.unary({}, function(err, data) {
447 assert.ifError(err);
murgatroid99be13d812015-10-09 14:45:30 -0700448 }, null, {credentials: combined_updater});
murgatroid995f709ca2015-09-30 14:22:54 -0700449 call.on('metadata', function(metadata) {
450 assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']);
451 assert.deepEqual(metadata.get('other_plugin_key'),
452 ['other_plugin_value']);
453 done();
454 });
455 });
murgatroid999c43b002015-09-28 16:31:16 -0700456 });
murgatroid99153b09d2015-09-25 16:04:03 -0700457});