Add 'server/' from commit '800090542d91beae40bc81fc41b67ba61c47da77'
git-subtree-dir: server git-subtree-mainline:6a4054c15agit-subtree-split:800090542d
This commit is contained in:
186
server/kordophone/Bridge/MBIMHTTPConnection.m
Normal file
186
server/kordophone/Bridge/MBIMHTTPConnection.m
Normal file
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// MBIMHTTPConnection.m
|
||||
// CocoaHTTPServer
|
||||
//
|
||||
// Created by James Magahern on 11/16/18.
|
||||
// Copyright © 2018 James Magahern. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MBIMHTTPConnection.h"
|
||||
|
||||
#import "MBIMBridge.h"
|
||||
#import "MBIMBridge_Private.h"
|
||||
#import "MBIMBridgeOperation.h"
|
||||
#import "MBIMAuthToken.h"
|
||||
#import "MBIMUpdateQueue.h"
|
||||
#import "MBIMURLUtilities.h"
|
||||
|
||||
#import <Security/Security.h>
|
||||
#import "HTTPMessage.h"
|
||||
#import "GCDAsyncSocket.h"
|
||||
|
||||
@interface HTTPConnection (/* INTERNAL */)
|
||||
- (BOOL)isAuthenticated;
|
||||
@end
|
||||
|
||||
@implementation MBIMHTTPConnection {
|
||||
NSMutableData *_bodyData;
|
||||
MBIMBridgeOperation *_currentOperation;
|
||||
}
|
||||
|
||||
- (BOOL)isSecureServer
|
||||
{
|
||||
return [[MBIMBridge sharedInstance] usesSSL];
|
||||
}
|
||||
|
||||
- (NSArray *)sslIdentityAndCertificates
|
||||
{
|
||||
return [[MBIMBridge sharedInstance] sslCertificateAndIdentity];
|
||||
}
|
||||
|
||||
- (BOOL)isPasswordProtected:(NSString *)path
|
||||
{
|
||||
if ([[MBIMBridge sharedInstance] usesAccessControl]) {
|
||||
NSURL *url = [NSURL URLWithString:path];
|
||||
NSString *endpointName = [url lastPathComponent];
|
||||
|
||||
Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName];
|
||||
return [operationClass requiresAuthentication];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSString *)passwordForUser:(NSString *)username
|
||||
{
|
||||
MBIMBridge *bridge = [MBIMBridge sharedInstance];
|
||||
if ([username isEqualToString:bridge.authUsername]) {
|
||||
return bridge.authPassword;
|
||||
}
|
||||
|
||||
// nil means "user not in system"
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)isAuthenticated
|
||||
{
|
||||
NSString *authInfo = [request headerField:@"Authorization"];
|
||||
if ([authInfo hasPrefix:@"Bearer"]) {
|
||||
NSArray *bearerAuthTuple = [authInfo componentsSeparatedByString:@" "];
|
||||
if ([bearerAuthTuple count] == 2) {
|
||||
NSString *jwtToken = [bearerAuthTuple objectAtIndex:1];
|
||||
MBIMAuthToken *authToken = [[MBIMAuthToken alloc] initWithTokenString:jwtToken];
|
||||
return [authToken isValid];
|
||||
}
|
||||
}
|
||||
|
||||
return [super isAuthenticated];
|
||||
}
|
||||
|
||||
- (BOOL)useDigestAccessAuthentication
|
||||
{
|
||||
// TODO: should use digest all the time, but it's a bit more complicated. Allow this to be NO if
|
||||
// SSL is on, because then at least basic auth is encrypted
|
||||
return ![[MBIMBridge sharedInstance] usesSSL];
|
||||
}
|
||||
|
||||
- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path
|
||||
{
|
||||
if ([method isEqualToString:@"GET"] || [method isEqualToString:@"POST"]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
|
||||
{
|
||||
__block NSObject<HTTPResponse> *response = nil;
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
MBIMBridgeOperationCompletionBlock completion = ^(NSObject<HTTPResponse> *incomingResponse) {
|
||||
response = incomingResponse;
|
||||
dispatch_semaphore_signal(sema);
|
||||
};
|
||||
|
||||
NSURL *url = [NSURL URLWithString:path];
|
||||
NSString *endpointName = [url lastPathComponent];
|
||||
|
||||
BOOL requestTimedOut = NO;
|
||||
Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName];
|
||||
if (operationClass != nil) {
|
||||
_currentOperation = [[operationClass alloc] initWithRequestURL:url completion:completion];
|
||||
_currentOperation.requestBodyData = _bodyData;
|
||||
_currentOperation.request = self->request;
|
||||
|
||||
[[[MBIMBridge sharedInstance] operationQueue] addOperation:_currentOperation];
|
||||
long status = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60.0 * NSEC_PER_SEC)));
|
||||
if (status != 0) {
|
||||
requestTimedOut = YES;
|
||||
}
|
||||
} else {
|
||||
response = [[HTTPErrorResponse alloc] initWithErrorCode:404];
|
||||
}
|
||||
|
||||
if (requestTimedOut) {
|
||||
response = [_currentOperation cancelAndReturnTimeoutResponse];
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
- (WebSocket *)webSocketForURI:(NSString *)path
|
||||
{
|
||||
NSURL *url = [NSURL URLWithString:path];
|
||||
NSString *endpointName = [url lastPathComponent];
|
||||
NSString *authTokenString = [url valueForQueryItemWithName:@"token"];
|
||||
MBIMAuthToken *queryAuthToken = [[MBIMAuthToken alloc] initWithTokenString:authTokenString];
|
||||
|
||||
NSLog(@"Websocket for URI: %@ | authenticated request: %@", path, [self isAuthenticated] ? @"YES" : @"NO");
|
||||
if ([endpointName isEqualToString:@"updates"]) {
|
||||
if (![self isAuthenticated] && ![queryAuthToken isValid]) {
|
||||
NSLog(@"Websocket: auth invalid, rejecting.");
|
||||
NSLog(@"Query Token: %@, raw: %@", queryAuthToken, authTokenString);
|
||||
|
||||
|
||||
// Respond with 401 unauthorized
|
||||
HTTPMessage *response = [[HTTPMessage alloc] initResponseWithStatusCode:401 description:nil version:HTTPVersion1_1];
|
||||
[response setHeaderField:@"Content-Length" value:@"0"];
|
||||
|
||||
NSData *responseData = [self preprocessErrorResponse:response];
|
||||
[asyncSocket writeData:responseData withTimeout:30 tag:90];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSLog(@"Vending websocket for consumer");
|
||||
return [[MBIMUpdateQueue sharedInstance] vendUpdateWebSocketConsumerForRequest:request socket:asyncSocket];
|
||||
}
|
||||
|
||||
return [super webSocketForURI:path];
|
||||
}
|
||||
|
||||
- (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path
|
||||
{
|
||||
if ([method isEqualToString:@"POST"]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)prepareForBodyWithSize:(UInt64)contentLength
|
||||
{
|
||||
_bodyData = [[NSMutableData alloc] initWithCapacity:contentLength];
|
||||
}
|
||||
|
||||
- (void)processBodyData:(NSData *)postDataChunk
|
||||
{
|
||||
[_bodyData appendData:postDataChunk];
|
||||
}
|
||||
|
||||
- (void)die
|
||||
{
|
||||
[_currentOperation cancel];
|
||||
[super die];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user