2020-05-04 01:16:54 +00:00
|
|
|
const { Controller } = require('libflitter')
|
|
|
|
const FlitterProfileMapper = require('../../classes/saml/FlitterProfileMapper')
|
|
|
|
const samlp = require('samlp')
|
|
|
|
|
|
|
|
class SAMLController extends Controller {
|
|
|
|
static get services() {
|
2020-05-17 04:55:08 +00:00
|
|
|
return [...super.services, 'saml', 'output', 'Vue', 'configs', 'models']
|
2020-05-04 01:16:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async get_metadata(req, res, next) {
|
|
|
|
return samlp.metadata({
|
|
|
|
issuer: this.saml.config().provider_name,
|
|
|
|
cert: await this.saml.public_cert(),
|
|
|
|
logoutEndpointPaths: {
|
|
|
|
redirect: '/saml/logout',
|
|
|
|
},
|
|
|
|
redirectEndpointPath: '/saml/sso',
|
|
|
|
postEndpointPath: '/saml/sso',
|
|
|
|
})(req, res, next)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO some sort of first-logon flow
|
|
|
|
async get_sso(req, res, next) {
|
|
|
|
const index = await req.saml.participants.issue({ service_provider: req.saml_request.service_provider })
|
|
|
|
|
2020-05-17 04:55:08 +00:00
|
|
|
// Apply the appropriate IAM policy if this SAML SP is associated with an App
|
|
|
|
// If the SAML service provider has no associated application, just allow it
|
|
|
|
// TODO test this
|
|
|
|
const associated_app = await req.saml_request.service_provider.application()
|
|
|
|
if ( associated_app ) {
|
|
|
|
const Policy = this.models.get('iam:Policy')
|
|
|
|
const can_access = await Policy.check_user_access(req.user, associated_app.id)
|
|
|
|
if ( !can_access ) {
|
|
|
|
return this.Vue.auth_message(res, {
|
|
|
|
message: `Sorry, you don't have permission to access this application. Please ask your administrator to grant you access to ${associated_app.name}.`,
|
|
|
|
next_destination: '/dash',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-04 01:16:54 +00:00
|
|
|
return samlp.auth({
|
|
|
|
issuer: this.saml.config().provider_name,
|
|
|
|
cert: await this.saml.public_cert(),
|
|
|
|
key: await this.saml.private_key(),
|
|
|
|
getPostURL: (wtrealm, wreply, req, callback) => {
|
|
|
|
this.output.debug(`SAML Redirect URL: ${req.saml_request.service_provider.acs_url}`)
|
|
|
|
return callback(null, req.saml_request.service_provider.acs_url) // fetch this from registered SAML app
|
|
|
|
},
|
|
|
|
profileMapper: user => new FlitterProfileMapper(user),
|
|
|
|
destination: req.saml_request.service_provider.acs_url,
|
|
|
|
sessionIndex: index,
|
|
|
|
})(req, res, next)
|
|
|
|
}
|
|
|
|
|
|
|
|
async post_logout(req, res, next) {
|
|
|
|
return res.api({
|
|
|
|
saml: req.saml_request,
|
|
|
|
body: req.body,
|
|
|
|
query: req.query,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
async get_logout(req, res, next) {
|
|
|
|
return samlp.logout({
|
|
|
|
deflate: true,
|
|
|
|
issuer: this.saml.config().provider_name,
|
|
|
|
cert: await this.saml.public_cert(),
|
|
|
|
key: await this.saml.private_key(),
|
|
|
|
protocolBinding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
|
|
|
clearIdPSession: done => {
|
|
|
|
this.output.info(`Clearing IdP session for user: ${req.user.uid}`)
|
|
|
|
req.saml.participants.clear().then(async () => {
|
|
|
|
if ( this.saml.config().slo.end_coreid_session ) {
|
|
|
|
await req.user.get_provider().logout(req)
|
|
|
|
|
|
|
|
// show logout page
|
|
|
|
return this.Vue.auth_message(res, {
|
|
|
|
message: `You have been successfully logged out from ${this.configs.get('app.name')}.`,
|
|
|
|
next_destination: '/',
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
return this.Vue.auth_message(res, {
|
|
|
|
message: `You have been successfully logged out.`,
|
|
|
|
next_destination: '/',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
sessionParticipants: await req.saml.participants.wrapper(),
|
|
|
|
})(req, res, next)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = exports = SAMLController
|