Merge pull request #2466 from overleaf/jel-sso-beta-dashboard

Beta testing SSO on the dashboard

GitOrigin-RevId: 9899f0ed0212180fde40e9e19bfd53bccafa3e7a
This commit is contained in:
nate stemen 2020-01-02 14:22:06 -05:00 committed by Copybot
parent 84f81d0eac
commit 074d457f98
3 changed files with 77 additions and 23 deletions

View file

@ -38,6 +38,21 @@ const V1Handler = require('../V1/V1Handler')
const UserController = require('../User/UserController') const UserController = require('../User/UserController')
const SystemMessageManager = require('../SystemMessages/SystemMessageManager') const SystemMessageManager = require('../SystemMessages/SystemMessageManager')
const _ssoAvailable = (affiliation, session, linkedInstitutionIds) => {
if (!affiliation.institution) return false
// Could have multiple emails at the same institution, and if any are
// linked to the institution then do not show notification for others
if (
linkedInstitutionIds.indexOf(affiliation.institution.id.toString()) === -1
) {
if (affiliation.institution.ssoEnabled) return true
if (affiliation.institution.ssoBeta && session.samlBeta) return true
return false
}
return false
}
const ProjectController = { const ProjectController = {
_isInPercentageRollout(rolloutName, objectId, percentage) { _isInPercentageRollout(rolloutName, objectId, percentage) {
if (Settings.bypassPercentageRollouts === true) { if (Settings.bypassPercentageRollouts === true) {
@ -440,28 +455,19 @@ const ProjectController = {
} }
// Institution SSO Notifications // Institution SSO Notifications
if (Features.hasFeature('saml') || req.session.samlBeta) { if (Features.hasFeature('saml')) {
const samlSession = req.session.saml const samlSession = req.session.saml
// Notification: SSO Available // Notification: SSO Available
// Could have multiple emails at the same institution, and if any are
// linked to the institution then do not show notification for others
const linkedInstitutionIds = [] const linkedInstitutionIds = []
const linkedInstitutionEmails = []
user.emails.forEach(email => { user.emails.forEach(email => {
if (email.samlProviderId) { if (email.samlProviderId) {
linkedInstitutionEmails.push(email.email)
linkedInstitutionIds.push(email.samlProviderId) linkedInstitutionIds.push(email.samlProviderId)
} }
}) })
if (Array.isArray(userAffiliations)) { if (Array.isArray(userAffiliations)) {
userAffiliations.forEach(affiliation => { userAffiliations.forEach(affiliation => {
if ( if (
affiliation.institution && _ssoAvailable(affiliation, req.session, linkedInstitutionIds)
affiliation.institution.ssoEnabled &&
linkedInstitutionEmails.indexOf(affiliation.email) === -1 &&
linkedInstitutionIds.indexOf(
affiliation.institution.id.toString()
) === -1
) { ) {
notificationsInstitution.push({ notificationsInstitution.push({
email: affiliation.email, email: affiliation.email,

View file

@ -101,21 +101,29 @@ define(['base'], function(App) {
UserAffiliationsDataService UserAffiliationsDataService
) { ) {
$scope.userEmails = [] $scope.userEmails = []
const _ssoAvailable = email => {
if (!ExposedSettings.hasSamlFeature) return false
if (!email.affiliation || !email.affiliation.institution) return false
if (email.affiliation.institution.ssoEnabled) return true
if (
ExposedSettings.hasSamlBeta &&
email.affiliation.institution.ssoBeta
) {
return true
}
return false
}
$scope.showConfirmEmail = email => { $scope.showConfirmEmail = email => {
if (ExposedSettings.emailConfirmationDisabled) { if (ExposedSettings.emailConfirmationDisabled) {
return false return false
} }
if (!email.confirmedAt && !email.hide) { if (!email.confirmedAt && !email.hide) {
if ( if (_ssoAvailable(email)) {
email.affiliation &&
email.affiliation.institution &&
email.affiliation.institution.ssoEnabled &&
(ExposedSettings.hasSamlBeta || ExposedSettings.hasSamlFeature)
) {
return false return false
} }
return true return true
} }
return false
} }
for (let userEmail of Array.from($scope.userEmails)) { for (let userEmail of Array.from($scope.userEmails)) {
userEmail.hide = false userEmail.hide = false

View file

@ -110,10 +110,7 @@ describe('ProjectController', function() {
} }
} }
this.Features = { this.Features = {
hasFeature: sinon hasFeature: sinon.stub()
.stub()
.withArgs('saml')
.returns(false)
} }
this.BrandVariationsHandler = { this.BrandVariationsHandler = {
getBrandVariationById: sinon getBrandVariationById: sinon
@ -129,6 +126,7 @@ describe('ProjectController', function() {
institution: { institution: {
id: 1, id: 1,
name: 'Overleaf', name: 'Overleaf',
ssoBeta: false,
ssoEnabled: true ssoEnabled: true
} }
} }
@ -705,11 +703,13 @@ describe('ProjectController', function() {
}) })
}) })
describe('When Institution SSO is released', function() { describe('With Institution SSO feature', function() {
beforeEach(function(done) { beforeEach(function(done) {
this.institutionEmail = 'test@overleaf.com' this.institutionEmail = 'test@overleaf.com'
this.institutionName = 'Overleaf' this.institutionName = 'Overleaf'
this.Features.hasFeature.withArgs('saml').returns(true) this.Features.hasFeature.withArgs('saml').returns(true)
this.Features.hasFeature.withArgs('affiliations').returns(true)
this.Features.hasFeature.withArgs('overleaf-integration').returns(true)
done() done()
}) })
it('should show institution SSO available notification', function() { it('should show institution SSO available notification', function() {
@ -849,9 +849,49 @@ describe('ProjectController', function() {
this.ProjectController.projectListPage(this.req, this.res) this.ProjectController.projectListPage(this.req, this.res)
}) })
}) })
describe('Institution with SSO beta testable', function() {
beforeEach(function(done) {
this.getUserAffiliations.yields(null, [
{
email: 'beta@beta.com',
institution: {
id: 2,
name: 'Beta University',
ssoBeta: true,
ssoEnabled: false
}
}
])
done()
})
it('should show institution SSO available notification when on a beta testing session', function() {
this.req.session.samlBeta = true
this.res.render = (pageName, opts) => {
expect(opts.notificationsInstitution).to.deep.include({
email: 'beta@beta.com',
institutionId: 2,
institutionName: 'Beta University',
templateKey: 'notification_institution_sso_available'
})
}
this.ProjectController.projectListPage(this.req, this.res)
})
it('should not show institution SSO available notification when not on a beta testing session', function() {
this.req.session.samlBeta = false
this.res.render = (pageName, opts) => {
expect(opts.notificationsInstitution).to.deep.not.include({
email: 'test@overleaf.com',
institutionId: 1,
institutionName: 'Overleaf',
templateKey: 'notification_institution_sso_available'
})
}
this.ProjectController.projectListPage(this.req, this.res)
})
})
}) })
describe('When Institution SSO is not released', function() { describe('Without Institution SSO feature', function() {
beforeEach(function(done) { beforeEach(function(done) {
this.Features.hasFeature.withArgs('saml').returns(false) this.Features.hasFeature.withArgs('saml').returns(false)
done() done()