2020-05-17 04:55:08 +00:00
|
|
|
const { Controller } = require('libflitter')
|
|
|
|
|
|
|
|
class AppController extends Controller {
|
|
|
|
static get services() {
|
|
|
|
return [...super.services, 'models', 'utility']
|
|
|
|
}
|
|
|
|
|
|
|
|
async get_applications(req, res, next) {
|
|
|
|
const Application = this.models.get('Application')
|
|
|
|
const applications = await Application.find({ active: true })
|
|
|
|
const data = []
|
|
|
|
|
|
|
|
for ( const app of applications ) {
|
|
|
|
if ( req.user.can(`app:${app.id}:view`) ) {
|
|
|
|
data.push(await app.to_api())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res.api(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
async get_application(req, res, next) {
|
|
|
|
const Application = this.models.get('Application')
|
|
|
|
const application = await Application.findById(req.params.id)
|
|
|
|
|
|
|
|
if ( !application || !application.active )
|
|
|
|
return res.status(404)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.application_not_found'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
if ( !req.user.can(`app:${application.id}:view`) )
|
|
|
|
return res.status(401)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.insufficient_permissions'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
return res.api(await application.to_api())
|
|
|
|
}
|
|
|
|
|
|
|
|
async create_application(req, res, next) {
|
|
|
|
const Application = this.models.get('Application')
|
|
|
|
|
|
|
|
if ( !req.user.can('app:create') )
|
|
|
|
return res.status(401)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.insufficient_permissions'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const required_fields = ['name', 'identifier']
|
|
|
|
for ( const field of required_fields ) {
|
|
|
|
if ( !req.body[field] )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.missing_field')} ${field}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the identifier is properly formatted
|
|
|
|
if ( !(new RegExp('^[a-zA-Z0-9_]*$')).test(req.body.identifier) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.improper_field')} identifier ${req.T('api.alphanum_underscores')}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
// Make sure the identifier is unique
|
|
|
|
const existing_app = await Application.findOne({ identifier: req.body.identifier })
|
|
|
|
if ( existing_app )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.application_already_exists'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const application = new Application({
|
|
|
|
name: req.body.name,
|
|
|
|
identifier: req.body.identifier,
|
|
|
|
description: req.body.description,
|
|
|
|
})
|
|
|
|
|
|
|
|
// Verify LDAP client IDs
|
|
|
|
const LDAPClient = this.models.get('ldap:Client')
|
|
|
|
if ( req.body.ldap_client_ids ) {
|
|
|
|
const parsed = typeof req.body.ldap_client_ids === 'string' ? this.utility.infer(req.body.ldap_client_ids) : req.body.ldap_client_ids
|
|
|
|
const ldap_client_ids = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
for ( const id of ldap_client_ids ) {
|
|
|
|
const client = await LDAPClient.findById(id)
|
|
|
|
if ( !client || !client.active || !req.user.can(`ldap:client:${client.id}:view`) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.invalid_ldap_client_id')} ${id}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const other_assoc_app = await Application.findOne({ ldap_client_ids: client.id })
|
|
|
|
if ( other_assoc_app )
|
2020-05-30 23:00:12 +00:00
|
|
|
return res.status(400) // TODO translate this
|
2020-05-17 04:55:08 +00:00
|
|
|
.message(`The LDAP client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`)
|
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
application.ldap_client_ids = ldap_client_ids
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify OAuth client IDs
|
|
|
|
const OAuthClient = this.models.get('oauth:Client')
|
|
|
|
if ( req.body.oauth_client_ids ) {
|
|
|
|
const parsed = typeof req.body.oauth_client_ids === 'string' ? this.utility.infer(req.body.oauth_client_ids) : req.body.oauth_client_ids
|
|
|
|
const oauth_client_ids = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
for ( const id of oauth_client_ids ) {
|
|
|
|
const client = await OAuthClient.findById(id)
|
|
|
|
if ( !client || !client.active || !req.user.can(`oauth:client:${client.id}:view`) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.invalid_oauth_client_id')} ${id}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const other_assoc_app = await Application.findOne({ oauth_client_ids: client.id })
|
|
|
|
if ( other_assoc_app )
|
2020-05-30 23:00:12 +00:00
|
|
|
return res.status(400) // TODO translate this
|
2020-05-17 04:55:08 +00:00
|
|
|
.message(`The OAuth2 client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`)
|
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
application.oauth_client_ids = oauth_client_ids
|
|
|
|
}
|
|
|
|
|
2020-08-13 06:56:33 +00:00
|
|
|
// Verify OpenID client IDs
|
|
|
|
const OpenIDClient = this.models.get('openid:Client')
|
|
|
|
if ( req.body.openid_client_ids ) {
|
|
|
|
const parsed = typeof req.body.openid_client_ids === 'string' ? this.utility.infer(req.body.openid_client_ids) : req.body.openid_client_ids
|
|
|
|
const openid_client_ids = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
for ( const id of openid_client_ids ) {
|
|
|
|
const client = await OpenIDClient.findById(id)
|
|
|
|
if ( !client )
|
|
|
|
return res.status(400)
|
|
|
|
.message(`${req.T('api.invalid_oauth_client_id')} ${id}`)
|
|
|
|
.api()
|
|
|
|
|
|
|
|
const other_assoc_app = await Application.findOne({ openid_client_ids: client.id })
|
|
|
|
if ( other_assoc_app )
|
|
|
|
return res.status(400) // TODO translate this
|
|
|
|
.message(`The OpenID Connect client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`)
|
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
application.openid_client_ids = openid_client_ids
|
|
|
|
}
|
|
|
|
|
2020-05-17 04:55:08 +00:00
|
|
|
// Verify SAML service provider IDs
|
|
|
|
const ServiceProvider = this.models.get('saml:ServiceProvider')
|
|
|
|
if ( req.body.saml_service_provider_ids ) {
|
|
|
|
const parsed = typeof req.body.saml_service_provider_ids === 'string' ? this.utility.infer(req.body.saml_service_provider_ids) : req.body.saml_service_provider_ids
|
|
|
|
const saml_service_provider_ids = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
for ( const id of saml_service_provider_ids ) {
|
|
|
|
const provider = await ServiceProvider.findById(id)
|
|
|
|
if ( !provider || !provider.active || !req.user.can(`saml:provider:${provider.id}:view`) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.invalid_saml_service_provider_id')} ${id}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const other_assoc_app = await Application.findOne({ saml_service_provider_ids: provider.id })
|
|
|
|
if ( other_assoc_app )
|
2020-05-30 23:00:12 +00:00
|
|
|
return res.status(400) // TODO translate this
|
2020-05-17 04:55:08 +00:00
|
|
|
.message(`The SAML service provider ${provider.name} is already associated with an existing application (${other_assoc_app.name}).`)
|
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
application.saml_service_provider_ids = saml_service_provider_ids
|
|
|
|
}
|
|
|
|
|
|
|
|
await application.save()
|
|
|
|
return res.api(await application.to_api())
|
|
|
|
}
|
|
|
|
|
|
|
|
async update_application(req, res, next) {
|
|
|
|
const Application = this.models.get('Application')
|
|
|
|
const application = await Application.findById(req.params.id)
|
|
|
|
|
|
|
|
if ( !application || !application.active )
|
|
|
|
return res.status(404)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.application_not_found'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
if ( !req.user.can(`app:${application.id}:update`) )
|
|
|
|
return res.status(401)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.insufficient_permissions'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const required_fields = ['name', 'identifier']
|
|
|
|
for ( const field of required_fields ) {
|
|
|
|
if ( !req.body[field] )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.missing_field')} ${field}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the identifier is properly formatted
|
|
|
|
if ( !(new RegExp('^[a-zA-Z0-9_]*$')).test(req.body.identifier) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.improper_field')} identifier ${req.T('api.alphanum_underscores')}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
// Make sure the identifier is unique
|
|
|
|
const existing_app = await Application.findOne({ identifier: req.body.identifier })
|
|
|
|
if ( existing_app && existing_app.id !== application.id )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.application_already_exists'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
// Verify LDAP client IDs
|
|
|
|
const LDAPClient = this.models.get('ldap:Client')
|
|
|
|
if ( req.body.ldap_client_ids ) {
|
|
|
|
const parsed = typeof req.body.ldap_client_ids === 'string' ? this.utility.infer(req.body.ldap_client_ids) : req.body.ldap_client_ids
|
|
|
|
const ldap_client_ids = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
for ( const id of ldap_client_ids ) {
|
|
|
|
const client = await LDAPClient.findById(id)
|
|
|
|
if ( !client || !client.active || !req.user.can(`ldap:client:${client.id}:view`) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.invalid_ldap_client_id')} ${id}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const other_assoc_app = await Application.findOne({ ldap_client_ids: client.id })
|
|
|
|
if ( other_assoc_app && other_assoc_app.id !== application.id )
|
2020-05-30 23:00:12 +00:00
|
|
|
return res.status(400) // TODO translate this
|
2020-05-17 04:55:08 +00:00
|
|
|
.message(`The LDAP client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`)
|
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
application.ldap_client_ids = ldap_client_ids
|
|
|
|
} else application.ldap_client_ids = []
|
|
|
|
|
|
|
|
// Verify OAuth client IDs
|
|
|
|
const OAuthClient = this.models.get('oauth:Client')
|
|
|
|
if ( req.body.oauth_client_ids ) {
|
|
|
|
const parsed = typeof req.body.oauth_client_ids === 'string' ? this.utility.infer(req.body.oauth_client_ids) : req.body.oauth_client_ids
|
|
|
|
const oauth_client_ids = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
for ( const id of oauth_client_ids ) {
|
|
|
|
const client = await OAuthClient.findById(id)
|
|
|
|
if ( !client || !client.active || !req.user.can(`oauth:client:${client.id}:view`) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.invalid_oauth_client_id')} ${id}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const other_assoc_app = await Application.findOne({ oauth_client_ids: client.id })
|
|
|
|
if ( other_assoc_app && other_assoc_app.id !== application.id )
|
2020-05-30 23:00:12 +00:00
|
|
|
return res.status(400) // TODO translate this
|
2020-05-17 04:55:08 +00:00
|
|
|
.message(`The OAuth2 client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`)
|
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
application.oauth_client_ids = oauth_client_ids
|
|
|
|
} else application.oauth_client_ids = []
|
|
|
|
|
2020-08-13 06:56:33 +00:00
|
|
|
// Verify OpenID client IDs
|
|
|
|
const OpenIDClient = this.models.get('openid:Client')
|
|
|
|
if ( req.body.openid_client_ids ) {
|
|
|
|
const parsed = typeof req.body.openid_client_ids === 'string' ? this.utility.infer(req.body.openid_client_ids) : req.body.openid_client_ids
|
|
|
|
const openid_client_ids = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
for ( const id of openid_client_ids ) {
|
|
|
|
const client = await OpenIDClient.findById(id)
|
|
|
|
if ( !client )
|
|
|
|
return res.status(400)
|
|
|
|
.message(`${req.T('api.invalid_oauth_client_id')} ${id}`)
|
|
|
|
.api()
|
|
|
|
|
|
|
|
const other_assoc_app = await Application.findOne({ openid_client_ids: client.id })
|
|
|
|
if ( other_assoc_app && other_assoc_app.id !== application.id )
|
|
|
|
return res.status(400) // TODO translate this
|
|
|
|
.message(`The OpenID Connect client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`)
|
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
application.openid_client_ids = openid_client_ids
|
|
|
|
} else application.openid_client_ids = []
|
|
|
|
|
2020-05-17 04:55:08 +00:00
|
|
|
// Verify SAML service provider IDs
|
|
|
|
const ServiceProvider = this.models.get('saml:ServiceProvider')
|
|
|
|
if ( req.body.saml_service_provider_ids ) {
|
|
|
|
const parsed = typeof req.body.saml_service_provider_ids === 'string' ? this.utility.infer(req.body.saml_service_provider_ids) : req.body.saml_service_provider_ids
|
|
|
|
const saml_service_provider_ids = Array.isArray(parsed) ? parsed : [parsed]
|
|
|
|
for ( const id of saml_service_provider_ids ) {
|
|
|
|
const provider = await ServiceProvider.findById(id)
|
|
|
|
if ( !provider || !provider.active || !req.user.can(`saml:provider:${provider.id}:view`) )
|
|
|
|
return res.status(400)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(`${req.T('api.invalid_saml_service_provider_id')} ${id}`)
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
const other_assoc_app = await Application.findOne({ saml_service_provider_ids: provider.id })
|
|
|
|
if ( other_assoc_app && other_assoc_app.id !== application.id )
|
2020-05-30 23:00:12 +00:00
|
|
|
return res.status(400) // TODO translate this
|
2020-05-17 04:55:08 +00:00
|
|
|
.message(`The SAML service provider ${provider.name} is already associated with an existing application (${other_assoc_app.name}).`)
|
|
|
|
.api()
|
|
|
|
}
|
|
|
|
|
|
|
|
application.saml_service_provider_ids = saml_service_provider_ids
|
|
|
|
} else application.saml_service_provider_ids = []
|
|
|
|
|
|
|
|
application.name = req.body.name
|
|
|
|
application.identifier = req.body.identifier
|
|
|
|
application.description = req.body.description
|
|
|
|
await application.save()
|
|
|
|
return res.api(await application.to_api())
|
|
|
|
}
|
|
|
|
|
|
|
|
async delete_application(req, res, next) {
|
|
|
|
const Application = this.models.get('Application')
|
|
|
|
const application = await Application.findById(req.params.id)
|
|
|
|
|
|
|
|
if ( !application || !application.active )
|
|
|
|
return res.status(404)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.application_not_found'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
if ( !req.user.can(`app:${application.id}:delete`) )
|
|
|
|
return res.status(401)
|
2020-05-31 01:16:10 +00:00
|
|
|
.message(req.T('api.insufficient_permissions'))
|
2020-05-17 04:55:08 +00:00
|
|
|
.api()
|
|
|
|
|
|
|
|
application.active = false
|
|
|
|
await application.save()
|
|
|
|
return res.api()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = exports = AppController
|