UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

1,372 lines (1,221 loc) 44 kB
should = require "should" http = require "http" https = require "https" fs = require "fs" request = require "supertest" config = require "../../lib/config/config" config.authentication = config.get('authentication') config.tlsClientLookup = config.get('tlsClientLookup') Channel = require("../../lib/model/channels").Channel Client = require("../../lib/model/clients").Client Transaction = require("../../lib/model/transactions").Transaction Keystore = require("../../lib/model/keystore").Keystore testUtils = require "../testUtils" server = require "../../lib/server" FormData = require 'form-data' describe "e2e Integration Tests", -> describe "Authentication and authorisation tests", -> describe "Mutual TLS", -> mockServer = null before (done) -> config.authentication.enableMutualTLSAuthentication = true config.authentication.enableBasicAuthentication = false #Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint" urlPattern: "test/mock" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] channel1.save (err) -> testClientDoc1 = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordHash: "" certFingerprint: "6D:BF:A5:BE:D7:F5:01:C2:EC:D0:BC:74:A4:12:5A:6F:36:C4:77:5C" testClientDoc2 = clientID: "testApp2" clientDomain: "ca.openhim.org" name: "TEST Client 2" roles: [ "OpenMRS_PoC" "PoC" ] passwordHash: "" certFingerprint: "18:B7:F9:52:FA:37:86:C5:F5:63:DA:8B:FA:E6:6B:4D:FB:A0:27:ED" client1 = new Client testClientDoc1 client2 = new Client testClientDoc2 Client.remove {}, -> client1.save -> client2.save -> # remove default keystore Keystore.remove {}, -> keystore = new Keystore key: fs.readFileSync 'test/resources/server-tls/key.pem' cert: data: fs.readFileSync 'test/resources/server-tls/cert.pem' fingerprint: '23:37:6A:5E:A9:13:A4:8C:66:C5:BB:9F:0E:0D:68:9B:99:80:10:FC' ca: [ data: fs.readFileSync 'test/resources/client-tls/cert.pem' fingerprint: '6D:BF:A5:BE:D7:F5:01:C2:EC:D0:BC:74:A4:12:5A:6F:36:C4:77:5C' , data: fs.readFileSync 'test/resources/trust-tls/chain/intermediate.cert.pem' fingerprint: '3B:21:0A:F1:D2:ED:4F:9B:9C:02:71:DF:4E:14:1B:3E:32:F5:B9:BB' , data: fs.readFileSync 'test/resources/trust-tls/chain/ca.cert.pem' fingerprint: '18:B7:F9:52:FA:37:86:C5:F5:63:DA:8B:FA:E6:6B:4D:FB:A0:27:ED' ] keystore.save (err) -> done err if err mockServer = testUtils.createMockServer 201, "Mock response body\n", 1232, -> done() after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint" }, -> Client.remove { clientID: "testApp" }, -> Client.remove { clientID: "testApp2" }, -> mockServer.close -> done() afterEach (done) -> server.stop -> done() it "should forward a request to the configured routes if the client is authenticated and authorised", (done) -> server.start httpPort: 5001, httpsPort: 5000, -> options = host: "localhost" path: "/test/mock" port: 5000 cert: fs.readFileSync "test/resources/client-tls/cert.pem" key: fs.readFileSync "test/resources/client-tls/key.pem" ca: [ fs.readFileSync "test/resources/server-tls/cert.pem" ] req = https.request options, (res) -> res.statusCode.should.be.exactly 201 done() req.end() it "should reject a request when using an invalid cert", (done) -> server.start httpPort: 5001, httpsPort: 5000, -> options = host: "localhost" path: "/test/mock" port: 5000 cert: fs.readFileSync "test/resources/client-tls/invalid-cert.pem" key: fs.readFileSync "test/resources/client-tls/invalid-key.pem" ca: [ fs.readFileSync "test/resources/server-tls/cert.pem" ] req = https.request options, (res) -> res.statusCode.should.be.exactly 401 done() req.end() it "should authenticate a client further up the chain if 'in-chain' config is set", (done) -> config.tlsClientLookup.type = "in-chain" server.start httpPort: 5001, httpsPort: 5000, -> options = host: "localhost" path: "/test/mock" port: 5000 cert: fs.readFileSync "test/resources/trust-tls/chain/test.openhim.org.cert.pem" key: fs.readFileSync "test/resources/trust-tls/chain/test.openhim.org.key.pem" ca: [ fs.readFileSync "test/resources/server-tls/cert.pem" ] req = https.request options, (res) -> res.statusCode.should.be.exactly 201 done() req.end() it "should reject a request with an invalid cert if 'in-chain' config is set", (done) -> config.tlsClientLookup.type = "in-chain" server.start httpPort: 5001, httpsPort: 5000, -> options = host: "localhost" path: "/test/mock" port: 5000 cert: fs.readFileSync "test/resources/client-tls/invalid-cert.pem" key: fs.readFileSync "test/resources/client-tls/invalid-key.pem" ca: [ fs.readFileSync "test/resources/server-tls/cert.pem" ] req = https.request options, (res) -> res.statusCode.should.be.exactly 401 done() req.end() it "should NOT authenticate a client further up the chain if 'strict' config is set", (done) -> config.tlsClientLookup.type = "strict" server.start httpPort: 5001, httpsPort: 5000, -> options = host: "localhost" path: "/test/mock" port: 5000 cert: fs.readFileSync "test/resources/trust-tls/chain/test.openhim.org.cert.pem" key: fs.readFileSync "test/resources/trust-tls/chain/test.openhim.org.key.pem" ca: [ fs.readFileSync "test/resources/server-tls/cert.pem" ] req = https.request options, (res) -> res.statusCode.should.be.exactly 401 done() req.end() describe "Basic Authentication", -> mockServer = null before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true #Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint" urlPattern: "test/mock" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] channel1.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "openhim.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "bcrypt" passwordHash: "$2a$10$w8GyqInkl72LMIQNpMM/fenF6VsVukyya.c6fh/GRtrKq05C2.Zgy" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> mockServer = testUtils.createMockServer 200, "Mock response body 1\n", 1232, -> done() after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint" }, -> Client.remove { clientID: "testApp" }, -> mockServer.close -> done() afterEach (done) -> server.stop -> done() describe "with no credentials", -> it "should `throw` 401", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mock") .expect(401) .end (err, res) -> if err done err else done() describe "with incorrect credentials", -> it "should `throw` 401", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mock") .auth("incorrect_user", "incorrect_password") .expect(401) .expect('WWW-Authenticate', 'Basic') .end (err, res) -> if err done err else done() describe "with correct credentials", -> it "should return 200 OK", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mock") .auth("testApp", "password") .expect(200) .end (err, res) -> if err done err else done() describe "POST and PUT tests", -> mockServer = null mockServerWithReturn = null testDoc = "<test>test message</test>" before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true #Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint" urlPattern: "/test/mock" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] channel2 = new Channel name: "TEST DATA - Mock With Return endpoint" urlPattern: "/gmo" allow: [ "PoC" ] routes: [ name: "test route return" host: "localhost" port: 1499 primary: true ] channel3 = new Channel name: "TEST DATA - Mock With Return endpoint public" urlPattern: "/public" allow: [ ] authType: "public" routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] channel4 = new Channel name: "TEST DATA - Mock With Return endpoint private - whitelist" urlPattern: "/private" allow: [ ] whitelist: ['::ffff:127.0.0.1', '127.0.0.1'] #localhost in IPV6 authType: "public" routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] channel5 = new Channel name: "TEST DATA - whitelist but un-authorised" urlPattern: "/un-auth" allow: [ 'private' ] whitelist: ['::ffff:127.0.0.1', '127.0.0.1'] #localhost in IPV6 authType: "private" routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] channel6 = new Channel name: "TEST DATA - whitelist but authorised" urlPattern: "/auth" allow: [ 'PoC' ] whitelist: ['::ffff:127.0.0.1', '127.0.0.1'] #localhost in IPV6 authType: "private" routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] channel1.save (err) -> channel2.save (err)-> channel3.save (err) -> channel4.save (err) -> channel5.save (err) -> channel6.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> # Create mock endpoint to forward requests to mockServer = testUtils.createMockServerForPost(201, 400, testDoc) mockServerWithReturn = testUtils.createMockServerForPostWithReturn(201, 400, testDoc) mockServer.listen 1232, () -> mockServerWithReturn.listen 1499, done after (done) -> Channel.remove {}, -> Client.remove { clientID: "testApp" }, -> mockServer.close -> mockServerWithReturn.close -> done() afterEach (done) -> server.stop -> done() it "should return 201 CREATED on POST", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .post("/test/mock") .send(testDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() it "should return 201 CREATED on POST - Public Channel", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .post("/public") .send(testDoc) .expect(201) .end (err, res) -> if err done err else done() it "should return 201 CREATED on POST - Public Channel with whitelisted ip", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .post("/private") .send(testDoc) .expect(201) .end (err, res) -> if err done err else done() it "should deny access on POST - Private Channel with whitelisted IP but incorrect client role", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .post("/un-auth") .send(testDoc) .auth("testApp", "password") .expect(401) .end (err, res) -> if err done err else done() it "should return 201 CREATED on POST - Private Channel with whitelisted IP and correct client role", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .post("/auth") .send(testDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() it "should return 201 CREATED on PUT", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .put("/test/mock") .send(testDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() it "should decompress gzip", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .put("/gmo") .set('Accept-Encoding', '') #Unset encoding, because supertest defaults to gzip,deflate .send(testDoc) .auth("testApp", "password") .expect(201) .expect(testDoc, done) it "should returned gzipped response", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .put("/gmo") .set('Accept-Encoding', 'gzip') .send(testDoc) .auth("testApp", "password") .expect(201) .expect("content-encoding", "gzip") .expect(testDoc) .end (err, res) -> if err done err else done() describe "HTTP header tests", -> mockServer = null testDoc = "<test>test message</test>" before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true #Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint" urlPattern: "test/mock" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 6262 primary: true ] channel1.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> # Create mock endpoint to forward requests to mockServer = testUtils.createMockServer 201, testDoc, 6262, -> done() after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint" }, -> Client.remove { clientID: "testApp" }, -> mockServer.close -> done() afterEach (done) -> server.stop -> done() it "should keep HTTP headers of the response intact", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mock") .send(testDoc) .auth("testApp", "password") .expect(201) .expect('Content-Type', 'text/plain; charset=utf-8') .end (err, res) -> if err done err else done() describe "HTTP body content matching - XML", -> mockServer = null testXMLDoc = """ <careServicesRequest> <function uuid='4e8bbeb9-f5f5-11e2-b778-0800200c9a66'> <codedType code="2221" codingScheme="ISCO-08" /> <address> <addressLine component='city'>Kigali</addressLine> </address> <max>5</max> </function> </careServicesRequest> """ before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true #Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint" urlPattern: "test/mock" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] matchContentTypes: [ "text/xml" ] matchContentXpath: "string(/careServicesRequest/function/@uuid)" matchContentValue: "4e8bbeb9-f5f5-11e2-b778-0800200c9a66" channel1.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> # Create mock endpoint to forward requests to mockServer = testUtils.createMockServerForPost(201, 400, testXMLDoc) mockServer.listen 1232, done after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint" }, -> Client.remove { clientID: "testApp" }, -> mockServer.close -> done() afterEach (done) -> server.stop -> done() it "should return 201 CREATED on POST", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .post("/test/mock") .set("Content-Type", "text/xml") .send(testXMLDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() it "should return 201 CREATED on PUT", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .put("/test/mock") .set("Content-Type", "text/xml") .send(testXMLDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() describe "HTTP body content matching - JSON", -> mockServer = null testJSONDoc = ''' { "functionId": 1234, "personId": "987", "name": "John Smith" } ''' before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true #Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint" urlPattern: "test/mock" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] matchContentTypes: [ "text/x-json", "application/json" ] matchContentJson: "functionId" matchContentValue: "1234" channel1.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> # Create mock endpoint to forward requests to mockServer = testUtils.createMockServerForPost(201, 400, testJSONDoc) mockServer.listen 1232, done after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint" }, -> Client.remove { clientID: "testApp" }, -> mockServer.close -> done() afterEach (done) -> server.stop -> done() it "should return 201 CREATED on POST", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .post("/test/mock") .set("Content-Type", "application/json") .send(testJSONDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() it "should return 201 CREATED on PUT", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .put("/test/mock") .set("Content-Type", "application/json") .send(testJSONDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() describe "HTTP body content matching - RegEx", -> mockServer = null testRegExDoc = "facility: OMRS123" before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true #Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint" urlPattern: "test/mock" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] matchContentRegex: "\\s[A-Z]{4}\\d{3}" channel1.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> # Create mock endpoint to forward requests to mockServer = testUtils.createMockServerForPost(201, 400, testRegExDoc) mockServer.listen 1232, done after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint" }, -> Client.remove { clientID: "testApp" }, -> mockServer.close -> done() afterEach (done) -> server.stop -> done() it "should return 201 CREATED on POST", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .post("/test/mock") .send(testRegExDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() it "should return 201 CREATED on PUT", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .put("/test/mock") .send(testRegExDoc) .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else done() describe "mediator tests", -> mockServer = null mediatorResponse = status: "Successful" response: status: 200 headers: {} body: "<transaction response>" timestamp: new Date orchestrations: [ name: "Lab API" request: path: "api/patient/lab" headers: "Content-Type": "text/plain" body: "<route request>" method: "POST" timestamp: new Date response: status: 200 headers: {} body: "<route response>" timestamp: new Date ] properties: orderId: "TEST00001" documentId: "1f49c3e0-3cec-4292-b495-5bd41433a048" before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true mediatorChannel = new Channel name: "TEST DATA - Mock mediator endpoint" urlPattern: "test/mediator" allow: [ "PoC" ] routes: [ name: "mediator route" host: "localhost" port: 1244 primary: true ] mediatorChannel.save (err) -> testAppDoc = clientID: "mediatorTestApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> mockServer = testUtils.createMockMediatorServer 200, mediatorResponse, 1244, -> done() beforeEach (done) -> Transaction.remove {}, done after (done) -> Channel.remove { name: "TEST DATA - Mock mediator endpoint" }, -> Client.remove { clientID: "mediatorTestApp" }, -> mockServer.close -> done() afterEach (done) -> server.stop -> Transaction.remove {}, -> done() describe "mediator response processing", -> it "should return the specified mediator response element as the actual response", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mediator") .auth("mediatorTestApp", "password") .expect(200) .expect(mediatorResponse.response.body, done) it "should setup the correct metadata on the transaction as specified by the mediator response", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mediator") .auth("mediatorTestApp", "password") .expect(200) .end (err, res) -> if err done err else setTimeout ( -> Transaction.findOne {}, (err, res) -> res.status.should.be.equal mediatorResponse.status res.orchestrations.length.should.be.exactly 1 res.orchestrations[0].name.should.be.equal mediatorResponse.orchestrations[0].name should.exist res.properties res.properties.orderId.should.be.equal mediatorResponse.properties.orderId done() ), 150 * global.testTimeoutFactor describe "Multipart form data tests", -> mockServer = null before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true mediatorResponse = status: "Successful" response: status: 200 headers: {} body: "<transaction response>" timestamp: new Date orchestrations: [ name: "Lab API" request: path: "api/patient/lab" headers: "Content-Type": "text/plain" body: "<route request>" method: "POST" timestamp: new Date response: status: 200 headers: {} body: "<route response>" timestamp: new Date ] #Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint - multipart" urlPattern: "/test/multipart" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1276 primary: true ] channel1.save (err) -> testAppDoc = clientID: "testAppMultipart" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> mockServer = testUtils.createMockMediatorServer 200, mediatorResponse, 1276, -> done() after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint - multipart" }, -> Client.remove { clientID: "testAppMultipart" }, -> done() afterEach (done) -> server.stop -> done() it "should return 201 CREATED on POST", (done) -> server.start httpPort: 5001, -> form = new FormData() form.append('my_field', 'my value') form.append('unix', fs.readFileSync "test/resources/files/unix.txt") form.append('mac', fs.readFileSync "test/resources/files/mac.txt") form.append('msdos', fs.readFileSync "test/resources/files/msdos.txt") form.submit host: "localhost" port: 5001 path: "/test/multipart" auth: "testAppMultipart:password" method: "post" , (err, res) -> res.statusCode.should.equal 200 res.on "data", (chunk) -> # chunk.should.be.ok if err done err else done() describe "URL rewriting e2e test", -> mockServer = null jsonResponse = href: 'http://localhost:1232/test/mock' before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true # Setup some test data channel1 = new Channel name: "TEST DATA - Mock endpoint" urlPattern: "test/mock" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1232 primary: true ] rewriteUrls: true channel1.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> # Create mock endpoint to forward requests to mockServer = testUtils.createMockServer 201, JSON.stringify(jsonResponse), 1232, -> done() after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint" }, -> Client.remove { clientID: "testApp" }, -> mockServer.close -> done() afterEach (done) -> server.stop -> done() it "should rewrite response urls", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mock") .auth("testApp", "password") .expect(201) .end (err, res) -> if err done err else response = JSON.parse res.text response.href.should.be.exactly 'http://localhost:5001/test/mock' done() describe "Routes enabled/disabled tests", -> mockServer1 = null mockServer2 = null channel1 = new Channel name: "TEST DATA - Mock endpoint 1" urlPattern: "^/test/channel1$" allow: [ "PoC" ] routes: [ { name: "test route" host: "localhost" port: 1233 primary: true }, { name: "test route 2" host: "localhost" port: 1234 } ] channel2 = new Channel name: "TEST DATA - Mock endpoint 2" urlPattern: "^/test/channel2$" allow: [ "PoC" ] routes: [ { name: "test route" host: "localhost" port: 1233 status: 'disabled' }, { name: "test route 2" host: "localhost" port: 1234 primary: true status: 'enabled' } ] channel3 = new Channel name: "TEST DATA - Mock endpoint 3" urlPattern: "^/test/channel3$" allow: [ "PoC" ] routes: [ { name: "test route" host: "localhost" port: 1233 primary: true status: 'enabled' }, { name: "test route 2" host: "localhost" port: 1234 primary: true status: 'disabled' } ] before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true channel1.save (err) -> channel2.save (err) -> channel3.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> # Create mock endpoint to forward requests to mockServer1 = testUtils.createMockServer 200, 'target1', 1233, -> mockServer2 = testUtils.createMockServer 200, 'target2', 1234, -> done() after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint 1" }, -> Channel.remove { name: "TEST DATA - Mock endpoint 2" }, -> Channel.remove { name: "TEST DATA - Mock endpoint 3" }, -> Client.remove { clientID: "testApp" }, -> mockServer1.close -> mockServer2.close -> done() afterEach (done) -> server.stop -> Transaction.remove {}, done beforeEach (done) -> Transaction.remove {}, done it "should route transactions to routes that have no status specified (default: enabled)", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/channel1") .auth("testApp", "password") .expect(200) .end (err, res) -> if err done err else res.text.should.be.exactly 'target1' # routes are async setTimeout ( -> Transaction.findOne {}, (err, trx) -> return done err if err trx.routes.length.should.be.exactly 1 trx.routes[0].should.have.property 'name', 'test route 2' trx.routes[0].response.body.should.be.exactly 'target2' done() ), 150 * global.testTimeoutFactor it "should NOT route transactions to disabled routes", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/channel2") .auth("testApp", "password") .expect(200) .end (err, res) -> if err done err else res.text.should.be.exactly 'target2' # routes are async setTimeout ( -> Transaction.findOne {}, (err, trx) -> return done err if err trx.routes.length.should.be.exactly 0 done() ), 150 * global.testTimeoutFactor it "should ignore disabled primary routes (multiple primary routes)", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/channel3") .auth("testApp", "password") .expect(200) .end (err, res) -> if err done err else res.text.should.be.exactly 'target1' # routes are async setTimeout ( -> Transaction.findOne {}, (err, trx) -> return done err if err trx.routes.length.should.be.exactly 0 done() ), 150 * global.testTimeoutFactor describe "Channel priority tests", -> mockServer1 = null mockServer2 = null channel1 = new Channel name: "TEST DATA - Mock endpoint 1" urlPattern: "^/test/undefined/priority$" allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1234 primary: true ] channel2 = new Channel name: "TEST DATA - Mock endpoint 2" urlPattern: "^/.*$" priority: 3 allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1233 primary: true ] channel3 = new Channel name: "TEST DATA - Mock endpoint 3" urlPattern: "^/test/mock$" priority: 2 allow: [ "PoC" ] routes: [ name: "test route" host: "localhost" port: 1234 primary: true ] before (done) -> config.authentication.enableMutualTLSAuthentication = false config.authentication.enableBasicAuthentication = true channel1.save (err) -> channel2.save (err) -> channel3.save (err) -> testAppDoc = clientID: "testApp" clientDomain: "test-client.jembi.org" name: "TEST Client" roles: [ "OpenMRS_PoC" "PoC" ] passwordAlgorithm: "sha512" passwordHash: "28dce3506eca8bb3d9d5a9390135236e8746f15ca2d8c86b8d8e653da954e9e3632bf9d85484ee6e9b28a3ada30eec89add42012b185bd9a4a36a07ce08ce2ea" passwordSalt: "1234567890" cert: "" client = new Client testAppDoc client.save (error, newAppDoc) -> # Create mock endpoint to forward requests to mockServer1 = testUtils.createMockServer 200, 'target1', 1233, -> mockServer2 = testUtils.createMockServer 200, 'target2', 1234, -> done() after (done) -> Channel.remove { name: "TEST DATA - Mock endpoint 1" }, -> Channel.remove { name: "TEST DATA - Mock endpoint 2" }, -> Channel.remove { name: "TEST DATA - Mock endpoint 3" }, -> Channel.remove { name: "TEST DATA - Mock endpoint 4" }, -> Client.remove { clientID: "testApp" }, -> mockServer1.close -> mockServer2.close -> done() afterEach (done) -> server.stop -> done() it "should route to the channel with higher priority if multiple channels match a request", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mock") .auth("testApp", "password") .expect(200) .end (err, res) -> if err done err else res.text.should.be.exactly 'target2' #should route to target2 via channel3 done() it "should treat a channel with an undefined priority with lowest priority", (done) -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/undefined/priority") .auth("testApp", "password") .expect(200) .end (err, res) -> if err done err else res.text.should.be.exactly 'target1' #should route to target1 via channel2 done() it "should deny access if multiple channels match but the top priority channel denies access", (done) -> channel4 = new Channel name: "TEST DATA - Mock endpoint 4" urlPattern: "^/test/mock$" priority: 1 allow: [ "something else" ] routes: [ name: "test route" host: "localhost" port: 1234 primary: true ] channel4.save () -> server.start httpPort: 5001, -> request("http://localhost:5001") .get("/test/mock") .auth("testApp", "password") .expect(401) .end (err, res) -> if err done err else done()