From b2cf655a8889240bc5e4bd1b17dee3e02301b9c0 Mon Sep 17 00:00:00 2001 From: Lukas Metzger Date: Tue, 17 Apr 2018 21:30:44 +0200 Subject: [PATCH] Added GET /remote/ip endpoint --- backend/src/config/ConfigDefault.php | 3 +- backend/src/controllers/Remote.php | 30 ++++++++++++++++ backend/src/middlewares/ClientIp.php | 53 ++++++++++++++++++++++++++++ backend/src/public/index.php | 3 ++ backend/test/test.sh | 3 +- backend/test/tests/remote-ip.js | 46 ++++++++++++++++++++++++ 6 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 backend/src/controllers/Remote.php create mode 100644 backend/src/middlewares/ClientIp.php create mode 100644 backend/test/tests/remote-ip.js diff --git a/backend/src/config/ConfigDefault.php b/backend/src/config/ConfigDefault.php index 7154429..36cd419 100644 --- a/backend/src/config/ConfigDefault.php +++ b/backend/src/config/ConfigDefault.php @@ -33,7 +33,8 @@ $defaultConfig = [ 'OPT', 'PTR', 'RKEY', 'RP', 'RRSIG', 'SIG', 'SPF', 'SRV', 'TKEY', 'SSHFP', 'TLSA', 'TSIG', 'TXT', 'WKS', 'MBOXFW', 'URL' ] - ] + ], + 'proxys' => [] ]; if (file_exists('../config/ConfigOverride.php')) { diff --git a/backend/src/controllers/Remote.php b/backend/src/controllers/Remote.php new file mode 100644 index 0000000..1712072 --- /dev/null +++ b/backend/src/controllers/Remote.php @@ -0,0 +1,30 @@ +logger = $c->logger; + $this->c = $c; + } + + public function ip(Request $req, Response $res, array $args) + { + return $res->withJson([ + 'ip' => $req->getAttribute('clientIp') + ], 200); + } +} diff --git a/backend/src/middlewares/ClientIp.php b/backend/src/middlewares/ClientIp.php new file mode 100644 index 0000000..6aa4335 --- /dev/null +++ b/backend/src/middlewares/ClientIp.php @@ -0,0 +1,53 @@ +logger = $c->logger; + $this->container = $c; + } + + public function __invoke(Request $req, Response $res, callable $next) + { + $proxys = $this->container['config']['proxys']; + + $headerContent = $req->getHeaderLine('X-Forwarded-For'); + + if (strlen($headerContent) === 0) { + $ip = $_SERVER['REMOTE_ADDR']; + } else { + if (!in_array($_SERVER['REMOTE_ADDR'], $proxys)) { // Client is not trusted proxy + $ip = $_SERVER['REMOTE_ADDR']; + } else { + $parts = array_map('trim', explode(',', $headerContent)); + + $ip = $_SERVER['REMOTE_ADDR']; + + for ($i = count($parts) - 1; $i >= 0; $i--) { + if (in_array($parts[$i], $proxys) && $i > 0) { + $ip = $parts[$i - 1]; + } else { + break; + } + } + } + } + + $req = $req->withAttribute('clientIp', $ip); + return $next($req, $res); + } +} diff --git a/backend/src/public/index.php b/backend/src/public/index.php index 89743ca..fd1b28d 100644 --- a/backend/src/public/index.php +++ b/backend/src/public/index.php @@ -30,6 +30,8 @@ $app = new \Slim\App($container); $app->group('/v1', function () { $this->post('/sessions', '\Controllers\Sessions:post'); + $this->get('/remote/ip', '\Controllers\Remote:ip'); + $this->group('', function () { $this->delete('/sessions/{sessionId}', '\Controllers\Sessions:delete'); @@ -69,6 +71,7 @@ $app->group('/v1', function () { // Add global middlewares $app->add('\Middlewares\LogRequests'); $app->add('\Middlewares\RejectEmptyBody'); +$app->add('\Middlewares\ClientIp'); // Run application $app->run(); diff --git a/backend/test/test.sh b/backend/test/test.sh index bded231..d8c1241 100755 --- a/backend/test/test.sh +++ b/backend/test/test.sh @@ -31,7 +31,8 @@ return [ 'notindb' => '\$2y\$10\$z1dD1Q5u68l5iqEmqnOAVuoR5VWR77HUfxMUycJ9TdDG3H5dLZGVW' ] ] - ] + ], + 'proxys' => ['127.0.0.1'] ]; EOM } diff --git a/backend/test/tests/remote-ip.js b/backend/test/tests/remote-ip.js new file mode 100644 index 0000000..3606ec0 --- /dev/null +++ b/backend/test/tests/remote-ip.js @@ -0,0 +1,46 @@ +const test = require('../testlib'); + +test.run(async function () { + await test('admin', async function (assert, req) { + var res = await req({ + url: '/remote/ip', + method: 'get' + }); + + assert.equal(res.status, 200); + assert.equal(res.data, { ip: '127.0.0.1' }, 'No proxy header should return tcp client ip.'); + + var res = await req({ + url: '/remote/ip', + method: 'get', + headers: { + 'X-Forwarded-For': '1.2.3.4, 127.0.0.1' + } + }); + + assert.equal(res.status, 200); + assert.equal(res.data, { ip: '1.2.3.4' }, 'X-Forwarded-For Test 1'); + + var res = await req({ + url: '/remote/ip', + method: 'get', + headers: { + 'X-Forwarded-For': '4.3.2.1, 1.2.3.4, 127.0.0.1' + } + }); + + assert.equal(res.status, 200); + assert.equal(res.data, { ip: '1.2.3.4' }, 'X-Forwarded-For Test 2'); + + var res = await req({ + url: '/remote/ip', + method: 'get', + headers: { + 'X-Forwarded-For': '4.3.2.1, 1.2.3.4' + } + }); + + assert.equal(res.status, 200); + assert.equal(res.data, { ip: '127.0.0.1' }, 'X-Forwarded-For Test 3'); + }); +}); \ No newline at end of file