mirror of https://github.com/grpc/grpc-node.git
Added auth functionality and interop tests
This commit is contained in:
parent
924cd36e18
commit
5ab7deb5e4
32
index.js
32
index.js
|
@ -73,6 +73,36 @@ function load(filename) {
|
|||
return loadObject(builder.ns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a function that a client can use to update metadata with authentication
|
||||
* information from a Google Auth credential object.
|
||||
* @param {Object} credential The credential object to use
|
||||
* @return {function(Object, callback)} Metadata updater function
|
||||
*/
|
||||
function getGoogleAuthDelegate(credential) {
|
||||
/**
|
||||
* Update a metadata object with authentication information.
|
||||
* @param {Object} metadata Metadata object
|
||||
* @param {function(Error, Object)} callback
|
||||
*/
|
||||
return function updateMetadata(metadata, callback) {
|
||||
metadata = _.clone(metadata);
|
||||
if (metadata.Authorization) {
|
||||
metadata.Authorization = _.clone(metadata.Authorization);
|
||||
} else {
|
||||
metadata.Authorization = [];
|
||||
}
|
||||
credential.getAccessToken(function(err, token) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
metadata.Authorization.push('Bearer ' + token);
|
||||
callback(null, metadata);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* See docs for loadObject
|
||||
*/
|
||||
|
@ -106,3 +136,5 @@ exports.Credentials = grpc.Credentials;
|
|||
* ServerCredentials factories
|
||||
*/
|
||||
exports.ServerCredentials = grpc.ServerCredentials;
|
||||
|
||||
exports.getGoogleAuthDelegate = getGoogleAuthDelegate;
|
||||
|
|
|
@ -35,9 +35,14 @@ var fs = require('fs');
|
|||
var path = require('path');
|
||||
var grpc = require('..');
|
||||
var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
|
||||
var GoogleAuth = require('googleauth');
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
var AUTH_SCOPE = 'https://www.googleapis.com/auth/xapi.zoo';
|
||||
var AUTH_SCOPE_RESPONSE = 'xapi.zoo';
|
||||
var AUTH_USER = '155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk@developer.gserviceaccount.com';
|
||||
|
||||
/**
|
||||
* Create a buffer filled with size zeroes
|
||||
* @param {number} size The length of the buffer
|
||||
|
@ -255,6 +260,45 @@ function cancelAfterFirstResponse(client, done) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Run one of the authentication tests.
|
||||
* @param {Client} client The client to test against
|
||||
* @param {function} done Callback to call when the test is completed. Included
|
||||
* primarily for use with mocha
|
||||
*/
|
||||
function authTest(client, done) {
|
||||
(new GoogleAuth()).getApplicationDefault(function(err, credential) {
|
||||
assert.ifError(err);
|
||||
if (credential.createScopedRequired()) {
|
||||
credential = credential.createScoped(AUTH_SCOPE);
|
||||
}
|
||||
client.updateMetadata = grpc.getGoogleAuthDelegate(credential);
|
||||
var arg = {
|
||||
response_type: testProto.PayloadType.COMPRESSABLE,
|
||||
response_size: 314159,
|
||||
payload: {
|
||||
body: zeroBuffer(271828)
|
||||
},
|
||||
fill_username: true,
|
||||
fill_oauth_scope: true
|
||||
};
|
||||
var call = client.unaryCall(arg, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.payload.type, testProto.PayloadType.COMPRESSABLE);
|
||||
assert.strictEqual(resp.payload.body.limit - resp.payload.body.offset,
|
||||
314159);
|
||||
assert.strictEqual(resp.username, AUTH_USER);
|
||||
assert.strictEqual(resp.oauth_scope, AUTH_SCOPE_RESPONSE);
|
||||
});
|
||||
call.on('status', function(status) {
|
||||
assert.strictEqual(status.code, grpc.status.OK);
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Map from test case names to test functions
|
||||
*/
|
||||
|
@ -266,7 +310,9 @@ var test_cases = {
|
|||
ping_pong: pingPong,
|
||||
empty_stream: emptyStream,
|
||||
cancel_after_begin: cancelAfterBegin,
|
||||
cancel_after_first_response: cancelAfterFirstResponse
|
||||
cancel_after_first_response: cancelAfterFirstResponse,
|
||||
compute_engine_creds: authTest,
|
||||
service_account_creds: authTest
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,6 +36,12 @@ message SimpleRequest {
|
|||
|
||||
// Optional input payload sent along with the request.
|
||||
optional Payload payload = 3;
|
||||
|
||||
// Whether SimpleResponse should include username.
|
||||
optional bool fill_username = 4;
|
||||
|
||||
// Whether SimpleResponse should include OAuth scope.
|
||||
optional bool fill_oauth_scope = 5;
|
||||
}
|
||||
|
||||
// Unary response, as configured by the request.
|
||||
|
@ -44,7 +50,9 @@ message SimpleResponse {
|
|||
optional Payload payload = 1;
|
||||
// The user the request came from, for verifying authentication was
|
||||
// successful when the client expected it.
|
||||
optional int64 effective_gaia_user_id = 2;
|
||||
optional string username = 2;
|
||||
// OAuth scope.
|
||||
optional string oauth_scope = 3;
|
||||
}
|
||||
|
||||
// Client-streaming request.
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"mocha": "~1.21.0",
|
||||
"minimist": "^1.1.0"
|
||||
"minimist": "^1.1.0",
|
||||
"googleauth": "google/google-auth-library-nodejs"
|
||||
},
|
||||
"main": "index.js"
|
||||
}
|
||||
|
|
193
src/client.js
193
src/client.js
|
@ -224,25 +224,32 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
|
|||
emitter.cancel = function cancel() {
|
||||
call.cancel();
|
||||
};
|
||||
var client_batch = {};
|
||||
client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
|
||||
client_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
|
||||
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
||||
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
client_batch[grpc.opType.RECV_MESSAGE] = true;
|
||||
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(client_batch, function(err, response) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
this.updateMetadata(metadata, function(error, metadata) {
|
||||
if (error) {
|
||||
call.cancel();
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
if (response.status.code != grpc.status.OK) {
|
||||
callback(response.status);
|
||||
return;
|
||||
}
|
||||
emitter.emit('status', response.status);
|
||||
emitter.emit('metadata', response.metadata);
|
||||
callback(null, deserialize(response.read));
|
||||
var client_batch = {};
|
||||
client_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
|
||||
client_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
|
||||
client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
||||
client_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
client_batch[grpc.opType.RECV_MESSAGE] = true;
|
||||
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(client_batch, function(err, response) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if (response.status.code != grpc.status.OK) {
|
||||
callback(response.status);
|
||||
return;
|
||||
}
|
||||
emitter.emit('status', response.status);
|
||||
emitter.emit('metadata', response.metadata);
|
||||
callback(null, deserialize(response.read));
|
||||
});
|
||||
});
|
||||
return emitter;
|
||||
}
|
||||
|
@ -279,30 +286,37 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
|
|||
metadata = {};
|
||||
}
|
||||
var stream = new ClientWritableStream(call, serialize);
|
||||
var metadata_batch = {};
|
||||
metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
|
||||
metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
call.startBatch(metadata_batch, function(err, response) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
this.updateMetadata(metadata, function(error, metadata) {
|
||||
if (error) {
|
||||
call.cancel();
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
stream.emit('metadata', response.metadata);
|
||||
});
|
||||
var client_batch = {};
|
||||
client_batch[grpc.opType.RECV_MESSAGE] = true;
|
||||
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(client_batch, function(err, response) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if (response.status.code != grpc.status.OK) {
|
||||
callback(response.status);
|
||||
return;
|
||||
}
|
||||
stream.emit('status', response.status);
|
||||
callback(null, deserialize(response.read));
|
||||
var metadata_batch = {};
|
||||
metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
|
||||
metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
call.startBatch(metadata_batch, function(err, response) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
stream.emit('metadata', response.metadata);
|
||||
});
|
||||
var client_batch = {};
|
||||
client_batch[grpc.opType.RECV_MESSAGE] = true;
|
||||
client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(client_batch, function(err, response) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if (response.status.code != grpc.status.OK) {
|
||||
callback(response.status);
|
||||
return;
|
||||
}
|
||||
stream.emit('status', response.status);
|
||||
callback(null, deserialize(response.read));
|
||||
});
|
||||
});
|
||||
return stream;
|
||||
}
|
||||
|
@ -339,24 +353,31 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
|
|||
metadata = {};
|
||||
}
|
||||
var stream = new ClientReadableStream(call, deserialize);
|
||||
var start_batch = {};
|
||||
start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
|
||||
start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
start_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
|
||||
start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
||||
call.startBatch(start_batch, function(err, response) {
|
||||
if (err) {
|
||||
throw err;
|
||||
this.updateMetadata(metadata, function(error, metadata) {
|
||||
if (error) {
|
||||
call.cancel();
|
||||
stream.emit('error', error);
|
||||
return;
|
||||
}
|
||||
stream.emit('metadata', response.metadata);
|
||||
});
|
||||
var status_batch = {};
|
||||
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(status_batch, function(err, response) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
stream.emit('status', response.status);
|
||||
var start_batch = {};
|
||||
start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
|
||||
start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
start_batch[grpc.opType.SEND_MESSAGE] = serialize(argument);
|
||||
start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true;
|
||||
call.startBatch(start_batch, function(err, response) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
stream.emit('metadata', response.metadata);
|
||||
});
|
||||
var status_batch = {};
|
||||
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(status_batch, function(err, response) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
stream.emit('status', response.status);
|
||||
});
|
||||
});
|
||||
return stream;
|
||||
}
|
||||
|
@ -391,22 +412,29 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
|
|||
metadata = {};
|
||||
}
|
||||
var stream = new ClientDuplexStream(call, serialize, deserialize);
|
||||
var start_batch = {};
|
||||
start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
|
||||
start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
call.startBatch(start_batch, function(err, response) {
|
||||
if (err) {
|
||||
throw err;
|
||||
this.updateMetadata(metadata, function(error, metadata) {
|
||||
if (error) {
|
||||
call.cancel();
|
||||
stream.emit('error', error);
|
||||
return;
|
||||
}
|
||||
stream.emit('metadata', response.metadata);
|
||||
});
|
||||
var status_batch = {};
|
||||
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(status_batch, function(err, response) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
stream.emit('status', response.status);
|
||||
var start_batch = {};
|
||||
start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata;
|
||||
start_batch[grpc.opType.RECV_INITIAL_METADATA] = true;
|
||||
call.startBatch(start_batch, function(err, response) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
stream.emit('metadata', response.metadata);
|
||||
});
|
||||
var status_batch = {};
|
||||
status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
|
||||
call.startBatch(status_batch, function(err, response) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
stream.emit('status', response.status);
|
||||
});
|
||||
});
|
||||
return stream;
|
||||
}
|
||||
|
@ -438,8 +466,17 @@ function makeClientConstructor(service) {
|
|||
* @constructor
|
||||
* @param {string} address The address of the server to connect to
|
||||
* @param {Object} options Options to pass to the underlying channel
|
||||
* @param {function(Object, function)=} updateMetadata function to update the
|
||||
* metadata for each request
|
||||
*/
|
||||
function Client(address, options) {
|
||||
function Client(address, options, updateMetadata) {
|
||||
if (updateMetadata) {
|
||||
this.updateMetadata = updateMetadata;
|
||||
} else {
|
||||
this.updateMetadata = function(metadata, callback) {
|
||||
callback(null, metadata);
|
||||
};
|
||||
}
|
||||
this.channel = new grpc.Channel(address, options);
|
||||
}
|
||||
|
||||
|
@ -458,11 +495,13 @@ function makeClientConstructor(service) {
|
|||
method_type = 'unary';
|
||||
}
|
||||
}
|
||||
Client.prototype[decapitalize(method.name)] =
|
||||
requester_makers[method_type](
|
||||
prefix + capitalize(method.name),
|
||||
common.serializeCls(method.resolvedRequestType.build()),
|
||||
common.deserializeCls(method.resolvedResponseType.build()));
|
||||
var serialize = common.serializeCls(method.resolvedRequestType.build());
|
||||
var deserialize = common.deserializeCls(
|
||||
method.resolvedResponseType.build());
|
||||
Client.prototype[decapitalize(method.name)] = requester_makers[method_type](
|
||||
prefix + capitalize(method.name), serialize, deserialize);
|
||||
Client.prototype[decapitalize(method.name)].serialize = serialize;
|
||||
Client.prototype[decapitalize(method.name)].deserialize = deserialize;
|
||||
});
|
||||
|
||||
Client.service = service;
|
||||
|
|
Loading…
Reference in New Issue