const { Controller } = require('libflitter') const FlitterProfileMapper = require('../../classes/saml/FlitterProfileMapper') const samlp = require('samlp') class SAMLController extends Controller { static get services() { return [...super.services, 'saml', 'output', 'Vue', 'configs', 'models'] } 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 }) // 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', }) } } 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