const AuthUser = require('flitter-auth/model/User') const LDAP = require('ldapjs') const ActiveScope = require('../scopes/ActiveScope') const MFAToken = require('./MFAToken.model') const PasswordReset = require('./PasswordReset.model') const AppAuthorization = require('./AppAuthorization.model') const AppPassword = require('./AppPassword.model') const uuid = require('uuid/v4') /* * Auth user model. This inherits fields and methods from the default * flitter-auth/model/User model, however you can override methods and * properties here as you need. */ class User extends AuthUser { static get services() { return [...super.services, 'auth', 'ldap_server', 'configs', 'models', 'app'] } static get schema() { return {...super.schema, ...{ // other schema fields here first_name: String, last_name: String, tagline: String, email: String, ldap_visible: {type: Boolean, default: true}, active: {type: Boolean, default: true}, mfa_token: MFAToken, password_resets: [PasswordReset], app_passwords: [AppPassword], app_authorizations: [AppAuthorization], mfa_enabled: {type: Boolean, default: false}, mfa_enable_date: Date, create_date: {type: Date, default: () => new Date}, photo_file_id: String, }} } async photo() { const File = this.models.get('upload::File') return File.findById(this.photo_file_id) } has_authorized(client) { return this.app_authorizations.some(x => x.client_id === client.id) } get_authorization(client) { for ( const auth of this.app_authorizations ) { if ( auth.client_id === client.id ) return auth } } authorize(client) { if ( !this.has_authorized(client) ) { const client_rec = new AppAuthorization({ client_id: client.id, api_scopes: client.api_scopes, }, this) this.app_authorizations.push(client_rec) } else { const client_rec = this.get_authorization(client) client_rec.api_scopes = client.api_scopes } } async to_api() { return { id: this.id, uid: this.uid, first_name: this.first_name, last_name: this.last_name, email: this.email, tagline: this.tagline, group_ids: (await this.groups()).map(x => x.id), } } static scopes = [ new ActiveScope({}) ] static async ldap_directory() { return this.find({ldap_visible: true}) } // TODO just in case we need this later get can_login() { return true } async sessions() { const Session = require('../Session') this.app.di().inject(Session) return Session.find({ 'session.auth.user_id': this.id }) } async kickout() { // TODO handle SAML session participants const sessions = await this.sessions() for ( const session of sessions ) { delete session.session.auth delete session.session.mfa_remember await session.save() } } // Prefer soft delete because of the active scope async delete() { this.active = false await this.save() } async check_password(password) { return this.get_provider().check_user_auth(this, password) } async check_app_password(password) { for ( const pw of this.app_passwords ) { if ( await pw.verify(password) ) return true } return false } async reset_password(new_password, reason = 'user') { const reset = new PasswordReset({ reason, old_hash: this.password, }, this) await reset.set_hash(new_password) this.password = reset.hash this.password_resets.push(reset) return reset } async app_password(name) { const gen = uuid().replace(/-/g, '') const pw = new AppPassword({ name }, this) await pw.set_hash(gen) this.app_passwords.push(pw) return { password: gen, record: pw } } async groups() { const Group = this.models.get('auth:Group') return Group.find({ active: true, user_ids: this.id }) } async ldap_groups() { const Group = this.models.get('ldap:Group') return await Group.find({ $or: [ { user_ids: this.id }, { role: { $in: this.roles } }, ], }) } async to_ldap() { const ldap_data = { uid: this.uid, uuid: this.uuid, cn: this.first_name, sn: this.last_name, gecos: `${this.first_name} ${this.last_name}`, mail: this.email, objectClass: 'inetOrgPerson', } if ( this.tagline ) ldap_data.extras_tagline = this.tagline const addl_data = JSON.parse(this.data) for ( const key in addl_data ) { if ( !addl_data.hasOwnProperty(key) || !key.startsWith('ldap_') ) continue ldap_data[`data${key.substr(4)}`] = `${addl_data[key]}` } const ldap_groups = await this.ldap_groups() if ( ldap_groups.length > 0 ) { ldap_data.memberOf = ldap_groups.map(x => x.dn.format(this.configs.get('ldap:server.format'))) ldap_data.memberof = ldap_groups.map(x => x.dn.format(this.configs.get('ldap:server.format'))) } return ldap_data } get dn() { return LDAP.parseDN(`uid=${this.uid},${this.ldap_server.auth_dn().format(this.configs.get('ldap:server.format'))}`) } } module.exports = exports = User