You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CoreID/app/controllers/api/v1/App.controller.js

361 lines
17 KiB

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)
.message(req.T('api.application_not_found'))
.api()
if ( !req.user.can(`app:${application.id}:view`) )
return res.status(401)
.message(req.T('api.insufficient_permissions'))
.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)
.message(req.T('api.insufficient_permissions'))
.api()
const required_fields = ['name', 'identifier']
for ( const field of required_fields ) {
if ( !req.body[field] )
return res.status(400)
.message(`${req.T('api.missing_field')} ${field}`)
.api()
}
// Make sure the identifier is properly formatted
if ( !(new RegExp('^[a-zA-Z0-9_]*$')).test(req.body.identifier) )
return res.status(400)
.message(`${req.T('api.improper_field')} identifier ${req.T('api.alphanum_underscores')}`)
.api()
// Make sure the identifier is unique
const existing_app = await Application.findOne({ identifier: req.body.identifier })
if ( existing_app )
return res.status(400)
.message(req.T('api.application_already_exists'))
.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)
.message(`${req.T('api.invalid_ldap_client_id')} ${id}`)
.api()
const other_assoc_app = await Application.findOne({ ldap_client_ids: client.id })
if ( other_assoc_app )
return res.status(400) // TODO translate this
.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)
.message(`${req.T('api.invalid_oauth_client_id')} ${id}`)
.api()
const other_assoc_app = await Application.findOne({ oauth_client_ids: client.id })
if ( other_assoc_app )
return res.status(400) // TODO translate this
.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
}
// Verify RADIUS client IDs
const RadiusClient = this.models.get('radius:Client')
if ( req.body.radius_client_ids ) {
const parsed = typeof req.body.radius_client_ids === 'string' ? this.utility.infer(req.body.radius_client_ids) : req.body.radius_client_ids
const radius_client_ids = Array.isArray(parsed) ? parsed : [parsed]
for ( const id of radius_client_ids ) {
const client = await RadiusClient.findById(id)
if ( !client || !client.active || !req.user.can(`radius:client:${client.id}:view`) )
return res.status(400)
.message(`${req.T('api.invalid_radius_client_id')} ${id}`)
.api()
const other_assoc_app = await Application.findOne({ radius_client_ids: client.id })
if ( other_assoc_app )
return res.status(400) // TODO translate this
.message(`The RADIUS client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`)
.api()
}
application.radius_client_ids = radius_client_ids
}
// 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
}
// 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)
.message(`${req.T('api.invalid_saml_service_provider_id')} ${id}`)
.api()
const other_assoc_app = await Application.findOne({ saml_service_provider_ids: provider.id })
if ( other_assoc_app )
return res.status(400) // TODO translate this
.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)
.message(req.T('api.application_not_found'))
.api()
if ( !req.user.can(`app:${application.id}:update`) )
return res.status(401)
.message(req.T('api.insufficient_permissions'))
.api()
const required_fields = ['name', 'identifier']
for ( const field of required_fields ) {
if ( !req.body[field] )
return res.status(400)
.message(`${req.T('api.missing_field')} ${field}`)
.api()
}
// Make sure the identifier is properly formatted
if ( !(new RegExp('^[a-zA-Z0-9_]*$')).test(req.body.identifier) )
return res.status(400)
.message(`${req.T('api.improper_field')} identifier ${req.T('api.alphanum_underscores')}`)
.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)
.message(req.T('api.application_already_exists'))
.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)
.message(`${req.T('api.invalid_ldap_client_id')} ${id}`)
.api()
const other_assoc_app = await Application.findOne({ ldap_client_ids: client.id })
if ( other_assoc_app && other_assoc_app.id !== application.id )
return res.status(400) // TODO translate this
.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)
.message(`${req.T('api.invalid_oauth_client_id')} ${id}`)
.api()
const other_assoc_app = await Application.findOne({ oauth_client_ids: client.id })
if ( other_assoc_app && other_assoc_app.id !== application.id )
return res.status(400) // TODO translate this
.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 = []
// Verify OAuth client IDs
const RadiusClient = this.models.get('radius:Client')
if ( req.body.radius_client_ids ) {
const parsed = typeof req.body.radius_client_ids === 'string' ? this.utility.infer(req.body.radius_client_ids) : req.body.radius_client_ids
const radius_client_ids = Array.isArray(parsed) ? parsed : [parsed]
for ( const id of radius_client_ids ) {
const client = await RadiusClient.findById(id)
if ( !client || !client.active || !req.user.can(`radius:client:${client.id}:view`) )
return res.status(400)
.message(`${req.T('api.invalid_radius_client_id')} ${id}`)
.api()
const other_assoc_app = await Application.findOne({ radius_client_ids: client.id })
if ( other_assoc_app && other_assoc_app.id !== application.id )
return res.status(400) // TODO translate this
.message(`The RADIUS client ${client.name} is already associated with an existing application (${other_assoc_app.name}).`)
.api()
}
application.radius_client_ids = radius_client_ids
} else application.radius_client_ids = []
// 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 = []
// 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)
.message(`${req.T('api.invalid_saml_service_provider_id')} ${id}`)
.api()
const other_assoc_app = await Application.findOne({ saml_service_provider_ids: provider.id })
if ( other_assoc_app && other_assoc_app.id !== application.id )
return res.status(400) // TODO translate this
.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)
.message(req.T('api.application_not_found'))
.api()
if ( !req.user.can(`app:${application.id}:delete`) )
return res.status(401)
.message(req.T('api.insufficient_permissions'))
.api()
application.active = false
await application.save()
return res.api()
}
}
module.exports = exports = AppController