Skip to content

Commit

Permalink
Merge pull request grpc#2758 from jcanizales/make-http-not-subtle
Browse files Browse the repository at this point in the history
Require very explicit registration of non-SSL hosts in Objective-C.
  • Loading branch information
jcanizales committed Aug 7, 2015
2 parents 18d5aa7 + 015ab35 commit be222f8
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 30 deletions.
11 changes: 10 additions & 1 deletion src/objective-c/GRPCClient/GRPCCall+Tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,22 @@

#import "GRPCCall.h"

// Methods to let tune down the security of gRPC connections for specific hosts. These shouldn't be
// used in releases, but are sometimes needed for testing.
@interface GRPCCall (Tests)

// Establish all SSL connections to the provided host using the passed SSL target name and the root
// certificates found in the file at |certsPath|.
// Must be called before any gRPC call to that host is made.
//
// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to
// more than one invocation of the methods of this category.
+ (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName
forHost:(NSString *)host;

// Establish all connections to the provided host using cleartext instead of SSL.
//
// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to
// more than one invocation of the methods of this category.
+ (void)useInsecureConnectionsForHost:(NSString *)host;
@end
8 changes: 7 additions & 1 deletion src/objective-c/GRPCClient/GRPCCall+Tests.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,18 @@
#import "private/GRPCHost.h"

@implementation GRPCCall (Tests)

+ (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName
forHost:(NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.secure = YES;
hostConfig.pathToCertificates = certsPath;
hostConfig.hostNameOverride = testName;
}

+ (void)useInsecureConnectionsForHost:(NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.secure = NO;
}

@end
39 changes: 15 additions & 24 deletions src/objective-c/GRPCClient/private/GRPCHost.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,14 @@ - (instancetype)init {
// Default initializer.
- (instancetype)initWithAddress:(NSString *)address {

// Verify and normalize the address, and decide whether to use SSL.
if (![address rangeOfString:@"://"].length) {
// No scheme provided; assume https.
address = [@"https://" stringByAppendingString:address];
// To provide a default port, we try to interpret the address. If it's just a host name without
// scheme and without port, we'll use port 443. If it has a scheme, we pass it untouched to the C
// gRPC library.
// TODO(jcanizales): Add unit tests for the types of addresses we want to let pass untouched.
NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]];
if (hostURL && !hostURL.port) {
address = [hostURL.host stringByAppendingString:@":443"];
}
NSURL *hostURL = [NSURL URLWithString:address];
if (!hostURL) {
[NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", address];
}
NSString *scheme = hostURL.scheme;
if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]) {
[NSException raise:NSInvalidArgumentException format:@"URL scheme %@ isn't supported.", scheme];
}
// If the user didn't specify a port (hostURL.port is nil), provide a default one.
NSNumber *port = hostURL.port ?: [scheme isEqualToString:@"https"] ? @443 : @80;
address = [@[hostURL.host, port] componentsJoinedByString:@":"];

// Look up the GRPCHost in the cache.
static NSMutableDictionary *hostCache;
Expand All @@ -84,19 +76,15 @@ - (instancetype)initWithAddress:(NSString *)address {
@synchronized(hostCache) {
GRPCHost *cachedHost = hostCache[address];
if (cachedHost) {
// We could verify here that the cached host uses the same protocol that we're expecting. But
// creating non-SSL channels by adding "http://" to the address is going away (to make the use
// of insecure channels less subtle), so it's not worth it now.
return cachedHost;
}

if ((self = [super init])) {
_address = address;
_secure = [scheme isEqualToString:@"https"];
hostCache[address] = self;
}
return self;
if ((self = [super init])) {
_address = address;
_secure = YES;
hostCache[address] = self;
}
return self;
}

- (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue {
Expand Down Expand Up @@ -131,4 +119,7 @@ - (NSString *)hostName {
return _hostNameOverride ?: _address;
}

// TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride|
// have been set. Don't let set either of the latter if |secure| has been set to |NO|.

@end
7 changes: 5 additions & 2 deletions src/objective-c/tests/GRPCClientTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#import <XCTest/XCTest.h>

#import <GRPCClient/GRPCCall.h>
#import <GRPCClient/GRPCCall+Tests.h>
#import <ProtoRPC/ProtoMethod.h>
#import <RemoteTest/Messages.pbobjc.h>
#import <RxLibrary/GRXWriteable.h>
Expand All @@ -43,8 +44,7 @@
// These are a few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall)
// rather than a generated proto library on top of it.

// grpc-test.sandbox.google.com
static NSString * const kHostAddress = @"http://localhost:5050";
static NSString * const kHostAddress = @"localhost:5050";
static NSString * const kPackage = @"grpc.testing";
static NSString * const kService = @"TestService";

Expand All @@ -58,6 +58,9 @@ @interface GRPCClientTests : XCTestCase
@implementation GRPCClientTests

- (void)setUp {
// Register test server as non-SSL.
[GRPCCall useInsecureConnectionsForHost:kHostAddress];

// This method isn't implemented by the remote server.
kInexistentMethod = [[ProtoMethod alloc] initWithPackage:kPackage
service:kService
Expand Down
2 changes: 1 addition & 1 deletion src/objective-c/tests/InteropTests.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
// https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md

@interface InteropTests : XCTestCase
// Returns @"http://localhost:5050".
// Returns @"localhost:5050".
// Override in a subclass to perform the same tests against a different address.
// For interop tests, use @"grpc-test.sandbox.google.com".
+ (NSString *)host;
Expand Down
10 changes: 9 additions & 1 deletion src/objective-c/tests/InteropTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include <grpc/status.h>

#import <GRPCClient/GRPCCall+Tests.h>
#import <ProtoRPC/ProtoRPC.h>
#import <RemoteTest/Empty.pbobjc.h>
#import <RemoteTest/Messages.pbobjc.h>
Expand Down Expand Up @@ -75,15 +76,22 @@ + (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize {
}
@end

#pragma mark Tests

static NSString * const kLocalCleartextHost = @"localhost:5050";

@implementation InteropTests {
RMTTestService *_service;
}

+ (NSString *)host {
return @"http://localhost:5050";
return kLocalCleartextHost;
}

- (void)setUp {
// Register test server as non-SSL.
[GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost];

_service = [[RMTTestService alloc] initWithHost:self.class.host];
}

Expand Down

0 comments on commit be222f8

Please sign in to comment.