Files
Verso/services/web/test/unit/src/User/SAMLIdentityManagerTests.js
T
Ersun WarnckeandCopybot 051700688b handle saml array values and first/last name
GitOrigin-RevId: f571cb466ac8618f09e6a77682bff1420060e457
2020-01-07 04:21:14 +00:00

216 lines
6.3 KiB
JavaScript

const sinon = require('sinon')
const chai = require('chai')
const { expect } = chai
const SandboxedModule = require('sandboxed-module')
const modulePath = '../../../../app/src/Features/User/SAMLIdentityManager.js'
describe('SAMLIdentityManager', function() {
beforeEach(function() {
this.Errors = {
EmailExistsError: sinon.stub(),
NotFoundError: sinon.stub(),
SAMLIdentityExistsError: sinon.stub(),
SAMLUserNotFoundError: sinon.stub()
}
this.user = {
_id: 'user-id-1',
email: 'not-linked@overleaf.com',
emails: [{ email: 'not-linked@overleaf.com' }],
samlIdentifiers: []
}
this.userAlreadyLinked = {
_id: 'user-id-2',
email: 'linked@overleaf.com',
emails: [{ email: 'linked@overleaf.com', samlProviderId: '1' }],
samlIdentifiers: [{ externalUserId: 'linked-id', providerId: '1' }]
}
this.userEmailExists = {
_id: 'user-id-3',
email: 'exists@overleaf.com',
emails: [{ email: 'exists@overleaf.com' }],
samlIdentifiers: []
}
this.institution = {
name: 'Overleaf University'
}
this.InstitutionsAPI = {
promises: {
addEntitlement: sinon.stub().resolves(),
removeEntitlement: sinon.stub().resolves()
}
}
this.logger = {
error: sinon.stub(),
warn: sinon.stub()
}
this.SAMLIdentityManager = SandboxedModule.require(modulePath, {
requires: {
'../Email/EmailHandler': (this.EmailHandler = {
sendEmail: sinon.stub().yields()
}),
'../Errors/Errors': this.Errors,
'../../models/User': {
User: (this.User = {
findOneAndUpdate: sinon.stub(),
findOne: sinon.stub().returns({
exec: sinon.stub().resolves()
}),
update: sinon.stub().returns({
exec: sinon.stub().resolves()
})
})
},
'../User/UserGetter': (this.UserGetter = {
getUser: sinon.stub(),
promises: {
getUser: sinon.stub().resolves(this.user),
getUserByAnyEmail: sinon.stub().resolves()
}
}),
'../User/UserUpdater': (this.UserUpdater = {
addEmailAddress: sinon.stub()
}),
'../Institutions/InstitutionsAPI': this.InstitutionsAPI,
'logger-sharelatex': this.logger
}
})
})
describe('getUser', function() {
it('should throw an error if missing provider ID and/or external user ID', async function() {
let error
try {
await this.SAMLIdentityManager.getUser(null, null)
} catch (e) {
error = e
} finally {
expect(error).to.exist
}
})
})
describe('linkAccounts', function() {
it('should throw an error if missing data', async function() {
let error
try {
await this.SAMLIdentityManager.linkAccounts(null, null, null, null)
} catch (e) {
error = e
} finally {
expect(error).to.exist
}
})
describe('when email is already associated with another Overleaf account', function() {
beforeEach(function() {
this.UserGetter.promises.getUserByAnyEmail.resolves(
this.userEmailExists
)
})
it('should throw an EmailExistsError error', async function() {
let error
try {
await this.SAMLIdentityManager.linkAccounts(
'user-id-1',
'not-linked-id',
'exists@overleaf.com',
'provider-id',
true
)
} catch (e) {
error = e
} finally {
expect(error).to.be.instanceof(this.Errors.EmailExistsError)
expect(this.User.findOneAndUpdate).to.not.have.been.called
}
})
})
describe('when institution identifier is already associated with another Overleaf account', function() {
beforeEach(function() {
this.UserGetter.promises.getUserByAnyEmail.resolves(
this.userAlreadyLinked
)
})
it('should throw an SAMLIdentityExistsError error', async function() {
let error
try {
await this.SAMLIdentityManager.linkAccounts(
'user-id-1',
'already-linked-id',
'linked@overleaf.com',
'provider-id',
true
)
} catch (e) {
error = e
} finally {
expect(error).to.be.instanceof(this.Errors.SAMLIdentityExistsError)
expect(this.User.findOneAndUpdate).to.not.have.been.called
}
})
})
})
describe('unlinkAccounts', function() {
it('should send an email notification email', function() {
this.SAMLIdentityManager.unlinkAccounts(
this.user._id,
this.user.email,
'1',
'Overleaf University',
() => {
expect(this.User.update).to.have.been.called
expect(this.EmailHandler.sendEmail).to.have.been.called
}
)
})
})
describe('entitlementAttributeMatches', function() {
it('should return true when entitlement matches on string', function() {
this.SAMLIdentityManager.entitlementAttributeMatches(
'foo bar',
'bar'
).should.equal(true)
})
it('should return false when entitlement does not match on string', function() {
this.SAMLIdentityManager.entitlementAttributeMatches(
'foo bar',
'bam'
).should.equal(false)
})
it('should return false on an invalid matcher', function() {
this.SAMLIdentityManager.entitlementAttributeMatches(
'foo bar',
'('
).should.equal(false)
})
it('should log error on an invalid matcher', function() {
this.SAMLIdentityManager.entitlementAttributeMatches('foo bar', '(')
this.logger.error.firstCall.args[0].err.message.should.equal(
'Invalid regular expression: /(/: Unterminated group'
)
})
it('should return true when entitlement matches on array', function() {
this.SAMLIdentityManager.entitlementAttributeMatches(
['foo', 'bar'],
'bar'
).should.equal(true)
})
it('should return false when entitlement does not match array', function() {
this.SAMLIdentityManager.entitlementAttributeMatches(
['foo', 'bar'],
'bam'
).should.equal(false)
})
})
})