From 4234785cc4d8edd178223c7f81578fb9f81200d8 Mon Sep 17 00:00:00 2001 From: Hussam Moqhem Date: Thu, 5 May 2016 00:24:01 -0500 Subject: [PATCH 1/2] add support for http basic auth --- spec/index.spec.js | 24 ++++++++++++++++++++++++ src/middlewares.js | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/spec/index.spec.js b/spec/index.spec.js index d2c8984d71..31b8c662e2 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -12,6 +12,30 @@ describe('server', () => { expect(setServerConfiguration.bind(undefined, { appId: 'myId', masterKey: 'mk' })).toThrow('You must provide a serverURL!'); done(); }); + + it('support http basic authentication with masterkey', done => { + request.get({ + url: 'http://localhost:8378/1/classes/TestObject', + headers: { + 'Authorization': 'Basic ' + new Buffer('test:' + 'test').toString('base64') + } + }, (error, response, body) => { + expect(response.statusCode).toEqual(200); + done(); + }); + }); + + it('support http basic authentication with javascriptKey', done => { + request.get({ + url: 'http://localhost:8378/1/classes/TestObject', + headers: { + 'Authorization': 'Basic ' + new Buffer('test:javascript-key=' + 'test').toString('base64') + } + }, (error, response, body) => { + expect(response.statusCode).toEqual(200); + done(); + }); + }); it('fails if database is unreachable', done => { setServerConfiguration({ diff --git a/src/middlewares.js b/src/middlewares.js index 10115d6853..989eebd14f 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -17,13 +17,15 @@ function handleParseHeaders(req, res, next) { var mountPath = req.originalUrl.slice(0, mountPathLength); var mount = req.protocol + '://' + req.get('host') + mountPath; + var basicAuth = httpAuth(req); + var info = { - appId: req.get('X-Parse-Application-Id'), + appId: basicAuth.appId || req.get('X-Parse-Application-Id'), sessionToken: req.get('X-Parse-Session-Token'), - masterKey: req.get('X-Parse-Master-Key'), + masterKey: basicAuth.masterKey || req.get('X-Parse-Master-Key'), installationId: req.get('X-Parse-Installation-Id'), clientKey: req.get('X-Parse-Client-Key'), - javascriptKey: req.get('X-Parse-Javascript-Key'), + javascriptKey: basicAuth.javascriptKey || req.get('X-Parse-Javascript-Key'), dotNetKey: req.get('X-Parse-Windows-Key'), restAPIKey: req.get('X-Parse-REST-API-Key') }; @@ -144,6 +146,33 @@ function handleParseHeaders(req, res, next) { }); } +function httpAuth(req) { + var appId, masterKey, javascriptKey; + var credentialsRegExp = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9\-\._~\+\/]+=*) *$/ + var appIdKeyRegExp = /^([^ :]*):([Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt][-][Kk][Ee][Yy]=)?(.*)/ + // get header + var header = (req.req || req).headers.authorization + // parse header + var match = credentialsRegExp.exec(header || '') + if (match) { + // decode user pass + var appIdKeyMatch = appIdKeyRegExp.exec(decodeBase64(match[1])) + if (appIdKeyMatch) { + appId = appIdKeyMatch[1]; + if (appIdKeyMatch[2]) + javascriptKey = appIdKeyMatch[3]; + else + masterKey = appIdKeyMatch[3]; + } + } + + return {appId: appId, masterKey: masterKey, javascriptKey: javascriptKey}; +} + +function decodeBase64(str) { + return new Buffer(str, 'base64').toString() +} + var allowCrossDomain = function(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); From 6482535b10b787fe58b604118f33951d26ba9528 Mon Sep 17 00:00:00 2001 From: Hussam Moqhem Date: Wed, 18 May 2016 21:41:55 -0500 Subject: [PATCH 2/2] update http auth per flovilmart feedback --- src/middlewares.js | 58 ++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/src/middlewares.js b/src/middlewares.js index 989eebd14f..cce677299d 100644 --- a/src/middlewares.js +++ b/src/middlewares.js @@ -17,18 +17,24 @@ function handleParseHeaders(req, res, next) { var mountPath = req.originalUrl.slice(0, mountPathLength); var mount = req.protocol + '://' + req.get('host') + mountPath; - var basicAuth = httpAuth(req); - var info = { - appId: basicAuth.appId || req.get('X-Parse-Application-Id'), + appId: req.get('X-Parse-Application-Id'), sessionToken: req.get('X-Parse-Session-Token'), - masterKey: basicAuth.masterKey || req.get('X-Parse-Master-Key'), + masterKey: req.get('X-Parse-Master-Key'), installationId: req.get('X-Parse-Installation-Id'), clientKey: req.get('X-Parse-Client-Key'), - javascriptKey: basicAuth.javascriptKey || req.get('X-Parse-Javascript-Key'), + javascriptKey: req.get('X-Parse-Javascript-Key'), dotNetKey: req.get('X-Parse-Windows-Key'), restAPIKey: req.get('X-Parse-REST-API-Key') }; + + var basicAuth = httpAuth(req); + + if (basicAuth) { + info.appId = basicAuth.appId + info.masterKey = basicAuth.masterKey || info.masterKey; + info.javascriptKey = basicAuth.javascriptKey || info.javascriptKey; + } if (req.body) { // Unity SDK sends a _noBody key which needs to be removed. @@ -147,22 +153,34 @@ function handleParseHeaders(req, res, next) { } function httpAuth(req) { - var appId, masterKey, javascriptKey; - var credentialsRegExp = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9\-\._~\+\/]+=*) *$/ - var appIdKeyRegExp = /^([^ :]*):([Jj][Aa][Vv][Aa][Ss][Cc][Rr][Ii][Pp][Tt][-][Kk][Ee][Yy]=)?(.*)/ - // get header - var header = (req.req || req).headers.authorization + if (!(req.req || req).headers.authorization) + return ; + + var header = (req.req || req).headers.authorization; + var appId, masterKey, javascriptKey; + // parse header - var match = credentialsRegExp.exec(header || '') - if (match) { - // decode user pass - var appIdKeyMatch = appIdKeyRegExp.exec(decodeBase64(match[1])) - if (appIdKeyMatch) { - appId = appIdKeyMatch[1]; - if (appIdKeyMatch[2]) - javascriptKey = appIdKeyMatch[3]; - else - masterKey = appIdKeyMatch[3]; + var authPrefix = 'basic '; + + var match = header.toLowerCase().indexOf(authPrefix); + + if (match == 0) { + var encodedAuth = header.substring(authPrefix.length, header.length); + var credentials = decodeBase64(encodedAuth).split(':'); + + if (credentials.length == 2) { + appId = credentials[0]; + var key = credentials[1]; + + var jsKeyPrefix = 'javascript-key='; + + var matchKey = key.indexOf(jsKeyPrefix) + if (matchKey == 0) { + javascriptKey = key.substring(jsKeyPrefix.length, key.length); + } + else { + masterKey = key; + } } }