Added auth functionality and interop tests

pull/590/head
murgatroid99 10 years ago
parent 47b30b0b26
commit 8c3ed009a8
  1. 32
      src/node/index.js
  2. 48
      src/node/interop/interop_client.js
  3. 10
      src/node/interop/messages.proto
  4. 3
      src/node/package.json
  5. 193
      src/node/src/client.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"
}

@ -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);
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);
this.updateMetadata(metadata, function(error, metadata) {
if (error) {
call.cancel();
callback(error);
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;
}
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;
this.updateMetadata(metadata, function(error, metadata) {
if (error) {
call.cancel();
stream.emit('error', error);
return;
}
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;
}
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;
this.updateMetadata(metadata, function(error, metadata) {
if (error) {
call.cancel();
stream.emit('error', error);
return;
}
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…
Cancel
Save