it('allows multiple custom provider names', async (flags) => { const mock = await Mock.v1(flags); const server = Hapi.server({ host: 'localhost', port: 8080 }); await server.register(Bell); server.auth.strategy('custom_1', 'bell', { password: '******', isSecure: false, clientId: 'test', clientSecret: 'secret', provider: Hoek.merge(Hoek.clone(mock.provider), { name: 'custom_1' }), cookie: 'ring_1' }); server.auth.strategy('custom_2', 'bell', { password: '******', isSecure: false, clientId: 'test', clientSecret: 'secret', provider: Hoek.merge(Hoek.clone(mock.provider), { name: 'custom_2' }), cookie: 'ring_2' }); server.route({ method: '*', path: '/login_1', options: { auth: 'custom_1', handler: function (request, h) { return request.auth.credentials; } } }); server.route({ method: '*', path: '/login_2', options: { auth: 'custom_2', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login_1'); expect(res1.headers['set-cookie'][0]).to.contain('ring_1='); const res2 = await server.inject('/login_2'); expect(res2.headers['set-cookie'][0]).to.contain('ring_2='); });
it('authenticates with mock and custom method with custom GET parameters', async (flags) => { const mock = await Mock.v1(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.twitter({ getMethod: 'custom/method', getParams: { param1: 'custom', param2: 'params' } }); Hoek.merge(custom, mock.provider); Mock.override('https://api.twitter.com/1.1/custom/method.json', { property: 'something' }); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'twitter', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: 'final', secret: 'secret', query: {}, profile: { id: '1234567890', username: '******', displayName: undefined, raw: { property: 'something' } } }); });
it('authenticates with mock and custom uri ', async (flags) => { const mock = await Mock.v2(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.pingfed({ uri: 'https://login-dev.ext.hpe.com' }); Hoek.merge(custom, mock.provider); const profile = { id: '*****@*****.**', displayName: '*****@*****.**', username: '******', email: '*****@*****.**', sub: '*****@*****.**' }; Mock.override('https://login-dev.ext.hpe.com/idp/userinfo.openid', profile); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'pingfed', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: '456', expiresIn: 3600, refreshToken: undefined, query: {}, profile: { id: '*****@*****.**', displayName: '*****@*****.**', username: '******', email: '*****@*****.**', raw: profile } }); });
it('authenticates with mock', async (flags) => { const mock = await Mock.v1(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.tumblr(); Hoek.merge(custom, mock.provider); const profile = { response: { user: { name: 'username' } } }; Mock.override('https://api.tumblr.com/v2/user/info', profile); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'tumblr', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: 'final', secret: 'secret', query: {}, profile: { username: '******', raw: { name: 'username' } } }); });
internals.defaults = function (node, base) { base = base || {}; if (typeof node === 'object' && (Array.isArray(base) === Array.isArray(node))) { return Hoek.merge(Hoek.clone(base), Hoek.clone(node)); } return node; };
it('authenticates with mock (without extended profile)', async (flags) => { const mock = await Mock.v2(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.slack({ extendedProfile: false }); Hoek.merge(custom, mock.provider); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'slack', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: '456', refreshToken: undefined, expiresIn: 3600, query: {}, profile: { scope: undefined, access_token: '456' } }); });
it('authenticates with mock and custom uri', async (flags) => { const mock = await Mock.v2(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.okta({ uri: 'http://example.com' }); expect(custom.auth).to.equal('http://example.com/oauth2/v1/authorize'); expect(custom.token).to.equal('http://example.com/oauth2/v1/token'); Hoek.merge(custom, mock.provider); const profile = { sub: '1234567890', nickname: 'steve_smith', given_name: 'steve', middle_name: 'jared', family_name: 'smith', email: '*****@*****.**' }; Mock.override('http://example.com/oauth2/v1/userinfo', profile); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'okta', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: '456', expiresIn: 3600, refreshToken: undefined, query: {}, profile: { id: '1234567890', username: '******', displayName: 'steve_smith', firstName: 'steve', lastName: 'smith', email: '*****@*****.**', raw: profile } }); });
it('authenticates with mock (no preferred email)', async (flags) => { const mock = await Mock.v2(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.live(); Hoek.merge(custom, mock.provider); const profile = { id: '1234567890', username: '******', name: 'steve', first_name: 'steve', last_name: 'smith', emails: { account: '*****@*****.**' } }; Mock.override('https://apis.live.net/v5.0/me', profile); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'live', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: '456', expiresIn: 3600, refreshToken: undefined, query: {}, profile: { id: '1234567890', username: '******', displayName: 'steve', name: { first: 'steve', last: 'smith' }, email: '*****@*****.**', raw: profile } }); });
it('authenticates with mock', async (flags) => { const mock = await Mock.v2(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.slack(); Hoek.merge(custom, mock.provider); const profile = { ok: true, url: 'https:\/\/example.slack.com\/', team: 'Example', user: '******', team_id: 'T12345', user_id: 'U12345' }; Mock.override('https://slack.com/api/auth.test', profile); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'slack', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: '456', refreshToken: undefined, expiresIn: 3600, query: {}, profile: { access_token: '456', scope: undefined, user: '******', user_id: 'U12345', raw: profile } }); });
it('authenticates with mock', async (flags) => { const mock = await Mock.v2(flags, { code: 201 }); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.medium(); Hoek.merge(custom, mock.provider); const profile = { data: { id: '5303d74c64f66366f00cb9b2a94f3251bf5', username: '******', name: 'Jamie Talbot', url: 'https://medium.com/@majelbstoat', imageUrl: 'https://images.medium.com/0*fkfQiTzT7TlUGGyI.png' } }; Mock.override('https://api.medium.com/v1/me', profile); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'medium', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: '456', expiresIn: 3600, refreshToken: undefined, query: {}, profile: { id: '5303d74c64f66366f00cb9b2a94f3251bf5', username: '******', displayName: 'Jamie Talbot', raw: { id: '5303d74c64f66366f00cb9b2a94f3251bf5', username: '******', name: 'Jamie Talbot', url: 'https://medium.com/@majelbstoat', imageUrl: 'https://images.medium.com/0*fkfQiTzT7TlUGGyI.png' } } }); });
it('authenticates with mock', async (flags) => { const mock = await Mock.v2(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.reddit(); Hoek.merge(custom, mock.provider); const profile = { name: 'john', created: 0, created_utc: 0, hide_from_robots: true, gold_creddits: 0, link_karma: 0, comment_karma: 0, over_18: true, is_gold: false, is_mod: true, gold_expiration: null, has_verified_email: true, id: 'abcde', inbox_count: 0 }; Mock.override('https://oauth.reddit.com/api/v1/me', profile); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'reddit', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: '456', expiresIn: 3600, refreshToken: undefined, query: {}, profile }); });
return async function (request, h) { const { uri, headers } = await settings.mapUri(request); const protocol = uri.split(':', 1)[0]; const options = { headers: {}, payload: request.payload, redirects: settings.redirects, timeout: settings.timeout, agent: internals.agent(protocol, settings, request) }; const bind = request.route.settings.bind; if (settings.passThrough) { options.headers = Hoek.clone(request.headers); delete options.headers.host; delete options.headers['content-length']; if (settings.acceptEncoding === false) { // Defaults to true delete options.headers['accept-encoding']; } if (options.headers.cookie) { delete options.headers.cookie; const cookieHeader = request.server.states.passThrough(request.headers.cookie, settings.localStatePassThrough); if (cookieHeader) { if (typeof cookieHeader !== 'string') { throw cookieHeader; // Error } options.headers.cookie = cookieHeader; } } } if (headers) { Hoek.merge(options.headers, headers); } if (settings.xforward && request.info.remotePort) { options.headers['x-forwarded-for'] = (options.headers['x-forwarded-for'] ? options.headers['x-forwarded-for'] + ',' : '') + request.info.remoteAddress; options.headers['x-forwarded-port'] = options.headers['x-forwarded-port'] || request.info.remotePort; options.headers['x-forwarded-proto'] = options.headers['x-forwarded-proto'] || request.server.info.protocol; options.headers['x-forwarded-host'] = options.headers['x-forwarded-host'] || request.info.host; } if (settings.ciphers) { options.ciphers = settings.ciphers; } if (settings.secureProtocol) { options.secureProtocol = settings.secureProtocol; } const contentType = request.headers['content-type']; if (contentType) { options.headers['content-type'] = contentType; } let ttl = null; let downstreamStartTime; if (settings.downstreamResponseTime) { downstreamStartTime = process.hrtime(); } const promise = settings.httpClient.request(request.method, uri, options); if (settings.onRequest) { settings.onRequest(promise.req); } try { var res = await promise; if (settings.downstreamResponseTime) { const downstreamResponseTime = process.hrtime(downstreamStartTime); request.log(['h2o2', 'success'], { downstreamResponseTime: downstreamResponseTime[0] * internals.NS_PER_SEC + downstreamResponseTime[1] }); } } catch (err) { if (settings.downstreamResponseTime) { const downstreamResponseTime = process.hrtime(downstreamStartTime); request.log(['h2o2', 'error'], { downstreamResponseTime: downstreamResponseTime[0] * internals.NS_PER_SEC + downstreamResponseTime[1] }); } if (settings.onResponse) { return settings.onResponse.call(bind, err, res, request, h, settings, ttl); } throw err; } if (settings._upstreamTtl) { const cacheControlHeader = res.headers['cache-control']; if (cacheControlHeader) { const cacheControl = settings.httpClient.parseCacheControl(cacheControlHeader); if (cacheControl) { ttl = cacheControl['max-age'] * 1000; } } } if (settings.onResponse) { return settings.onResponse.call(bind, null, res, request, h, settings, ttl); } return h.response(res) .ttl(ttl) .code(res.statusCode) .passThrough(!!settings.passThrough); };
it('authenticates with mock', async (flags) => { const mock = await Mock.v2(flags); const server = Hapi.server({ host: 'localhost', port: 80 }); await server.register(Bell); const custom = Bell.providers.bitbucket(); Hoek.merge(custom, mock.provider); Mock.override('https://api.bitbucket.org/2.0/user', { repositories: [{}], uuid: '1E9C5160-E436-11E5-9897-4FCB70D5A8C7', username: '******', display_name: 'steve' }); server.auth.strategy('custom', 'bell', { password: '******', isSecure: false, clientId: 'bitbucket', clientSecret: 'secret', provider: custom }); server.route({ method: '*', path: '/login', config: { auth: 'custom', handler: function (request, h) { return request.auth.credentials; } } }); const res1 = await server.inject('/login'); const cookie = res1.headers['set-cookie'][0].split(';')[0] + ';'; const res2 = await mock.server.inject(res1.headers.location); const res3 = await server.inject({ url: res2.headers.location, headers: { cookie } }); expect(res3.result).to.equal({ provider: 'custom', token: '456', refreshToken: undefined, expiresIn: 3600, query: {}, profile: { id: '1E9C5160-E436-11E5-9897-4FCB70D5A8C7', username: '******', displayName: 'steve', raw: { repositories: [{}], uuid: '1E9C5160-E436-11E5-9897-4FCB70D5A8C7', username: '******', display_name: 'steve' } } }); });