Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
251aa6cf97
|
|||
|
60003d64d5
|
|||
|
535dde13ff
|
|||
|
63d102296f
|
|||
|
77d203b2b0
|
|||
|
fcbf25e3ce
|
|||
|
084ec7bbc1
|
|||
|
6b3339a883
|
|||
|
8f1bbfef56
|
|||
|
e400e16ccc
|
|||
|
97096f619f
|
|||
|
2d97b77bbf
|
|||
|
5916222f7b
|
|||
|
bb79d52911
|
|||
|
2e05ec77c8
|
|||
|
433af8261f
|
|||
|
59d831c61f
|
|||
|
fac3431375
|
|||
|
7c8a05aa4f
|
|||
|
1cd306157a
|
|||
|
5eb0487c77
|
|||
|
3f2680671b
|
|||
|
fd06e17d7d
|
|||
|
efdea10b14
|
|||
|
ce7349565e
|
|||
|
a4695a7ecd
|
|||
|
fcb5b58b11
|
|||
|
96a614c1af
|
21
.drone.yml
21
.drone.yml
@@ -24,12 +24,33 @@ steps:
|
|||||||
from_secret: deploy_ssh_port
|
from_secret: deploy_ssh_port
|
||||||
script:
|
script:
|
||||||
- cd /home/coreid/CoreID
|
- cd /home/coreid/CoreID
|
||||||
|
- git checkout master
|
||||||
|
- git pull
|
||||||
|
- git checkout ${DRONE_TAG}
|
||||||
- git pull
|
- git pull
|
||||||
- yarn install
|
- yarn install
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- tag
|
- tag
|
||||||
- promote
|
- promote
|
||||||
|
- name: restart production services
|
||||||
|
image: appleboy/drone-ssh
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
from_secret: deploy_ssh_host
|
||||||
|
username:
|
||||||
|
from_secret: deploy_ssh_admin_user
|
||||||
|
key:
|
||||||
|
from_secret: deploy_ssh_key
|
||||||
|
port:
|
||||||
|
from_secret: deploy_ssh_port
|
||||||
|
script:
|
||||||
|
- systemctl restart coreid-www
|
||||||
|
- systemctl restart coreid-jobs
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
|
- promote
|
||||||
- name: send success notifications
|
- name: send success notifications
|
||||||
image: plugins/webhook
|
image: plugins/webhook
|
||||||
settings:
|
settings:
|
||||||
|
|||||||
35
app/assets/error-log.js
Normal file
35
app/assets/error-log.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
window.COREID_ERROR_LOG_URL = window.COREID_ERROR_LOG_URL || '/api/v1/log-error'
|
||||||
|
|
||||||
|
async function logError(error) {
|
||||||
|
try {
|
||||||
|
await fetch(window.COREID_ERROR_LOG_URL, {
|
||||||
|
method: 'POST',
|
||||||
|
cache: 'no-cache',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
full_url: window.location.href,
|
||||||
|
trace: [
|
||||||
|
error.name + ': ' + error.message,
|
||||||
|
error.stack,
|
||||||
|
].join('\n')
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
;(function() {
|
||||||
|
var old_onerror = window.onerror
|
||||||
|
|
||||||
|
window.onerror = function(msg, src, line, col, error) {
|
||||||
|
logError(error).then(function() {
|
||||||
|
if ( typeof old_onerror === 'function' ) {
|
||||||
|
try {
|
||||||
|
old_onerror(msg, src, line, col, error)
|
||||||
|
} catch(e) {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})()
|
||||||
3
app/assets/lib/axios/axios.min.js
vendored
3
app/assets/lib/axios/axios.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
3
app/assets/lib/popper/popper-1.16.0.min.js
vendored
3
app/assets/lib/popper/popper-1.16.0.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -18,6 +18,11 @@ class CoreIDAdapter {
|
|||||||
expiresAt = new Date(Date.now() + (expiresIn * 1000))
|
expiresAt = new Date(Date.now() + (expiresIn * 1000))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( payload.uid ) {
|
||||||
|
payload.originalUid = payload.uid
|
||||||
|
payload.uid = payload.uid.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
await this.coll().updateOne(
|
await this.coll().updateOne(
|
||||||
{ _id },
|
{ _id },
|
||||||
{ $set: { payload, ...(expiresAt ? { expiresAt } : undefined) } },
|
{ $set: { payload, ...(expiresAt ? { expiresAt } : undefined) } },
|
||||||
@@ -34,6 +39,11 @@ class CoreIDAdapter {
|
|||||||
).limit(1).next()
|
).limit(1).next()
|
||||||
|
|
||||||
if (!result) return undefined
|
if (!result) return undefined
|
||||||
|
|
||||||
|
if ( result?.payload?.originalUid ) {
|
||||||
|
result.payload.uid = result.payload.originalUid
|
||||||
|
}
|
||||||
|
|
||||||
return result.payload
|
return result.payload
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,11 +59,16 @@ class CoreIDAdapter {
|
|||||||
|
|
||||||
async findByUid(uid) {
|
async findByUid(uid) {
|
||||||
const result = await this.coll().find(
|
const result = await this.coll().find(
|
||||||
{ 'payload.uid': uid },
|
{ 'payload.uid': uid.toLowerCase() },
|
||||||
{ payload: 1 },
|
{ payload: 1 },
|
||||||
).limit(1).next()
|
).limit(1).next()
|
||||||
|
|
||||||
if (!result) return undefined
|
if (!result) return undefined
|
||||||
|
|
||||||
|
if ( result?.payload?.originalUid ) {
|
||||||
|
result.payload.uid = result.payload.originalUid
|
||||||
|
}
|
||||||
|
|
||||||
return result.payload
|
return result.payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class FlitterProfileMapper {
|
|||||||
getClaims() {
|
getClaims() {
|
||||||
const claims = {}
|
const claims = {}
|
||||||
|
|
||||||
claims[this.map.nameIdentifier] = this.user.uid
|
claims[this.map.nameIdentifier] = this.user.uid.toLowerCase()
|
||||||
claims[this.map.email] = this.user.email
|
claims[this.map.email] = this.user.email
|
||||||
claims[this.map.name] = `${this.user.first_name} ${this.user.last_name}`
|
claims[this.map.name] = `${this.user.first_name} ${this.user.last_name}`
|
||||||
claims[this.map.givenname] = this.user.first_name
|
claims[this.map.givenname] = this.user.first_name
|
||||||
@@ -54,7 +54,7 @@ class FlitterProfileMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNameIdentifier() {
|
getNameIdentifier() {
|
||||||
return { nameIdentifier: this.user.uid }
|
return { nameIdentifier: this.user.uid.toLowerCase() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ class Home extends Controller {
|
|||||||
async tmpl(req, res) {
|
async tmpl(req, res) {
|
||||||
return res.page('tmpl', {...this.Vue.data(), ...this.Vue.session(req)})
|
return res.page('tmpl', {...this.Vue.data(), ...this.Vue.session(req)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async log_front_end_error(req, res, next) {
|
||||||
|
const FrontEndError = this.models.get('FrontEndError')
|
||||||
|
await FrontEndError.log(req)
|
||||||
|
return res.api()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Home
|
module.exports = Home
|
||||||
|
|||||||
@@ -119,14 +119,12 @@ class OpenIDController extends Controller {
|
|||||||
uid, prompt, params, session,
|
uid, prompt, params, session,
|
||||||
} = await this.openid_connect.provider.interactionDetails(req, res)
|
} = await this.openid_connect.provider.interactionDetails(req, res)
|
||||||
|
|
||||||
console.log({uid, prompt, params, session})
|
|
||||||
|
|
||||||
const name = prompt.name
|
const name = prompt.name
|
||||||
if ( typeof this[name] !== 'function' ) {
|
if ( typeof this[name] !== 'function' ) {
|
||||||
return this.fail(res, 'Sorry, something has gone wrong.')
|
return this.fail(res, 'Sorry, something has gone wrong.')
|
||||||
}
|
}
|
||||||
|
|
||||||
return this[name](req, res, { uid, prompt, params, session })
|
return this[name](req, res, { uid: uid.toLowerCase(), prompt, params, session })
|
||||||
}
|
}
|
||||||
|
|
||||||
async consent(req, res, { uid, prompt, params, session }) {
|
async consent(req, res, { uid, prompt, params, session }) {
|
||||||
@@ -142,13 +140,13 @@ class OpenIDController extends Controller {
|
|||||||
const Policy = this.models.get('iam:Policy')
|
const Policy = this.models.get('iam:Policy')
|
||||||
const application = await Application.findOne({ openid_client_ids: params.client_id })
|
const application = await Application.findOne({ openid_client_ids: params.client_id })
|
||||||
if ( !application ) {
|
if ( !application ) {
|
||||||
this.output.warning('IAM Denial!')
|
this.output.warn('IAM Denial!')
|
||||||
return this.Vue.auth_message(res, {
|
return this.Vue.auth_message(res, {
|
||||||
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
|
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
|
||||||
next_destination: '/dash',
|
next_destination: '/dash',
|
||||||
})
|
})
|
||||||
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
|
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
|
||||||
this.output.warning('IAM Denial!')
|
this.output.warn('IAM Denial!')
|
||||||
return this.Vue.auth_message(res, {
|
return this.Vue.auth_message(res, {
|
||||||
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
||||||
next_destination: '/dash',
|
next_destination: '/dash',
|
||||||
@@ -172,7 +170,7 @@ class OpenIDController extends Controller {
|
|||||||
{
|
{
|
||||||
text: req.T('common.grant'),
|
text: req.T('common.grant'),
|
||||||
action: 'redirect',
|
action: 'redirect',
|
||||||
next: `/openid/interaction/${uid}/grant`,
|
next: `/openid/interaction/${uid.toLowerCase()}/grant`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -180,7 +178,7 @@ class OpenIDController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async login(req, res, { uid, prompt, params, session }) {
|
async login(req, res, { uid, prompt, params, session }) {
|
||||||
return res.redirect(`/openid/interaction/${uid}/start-session`)
|
return res.redirect(`/openid/interaction/${uid.toLowerCase()}/start-session`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -202,13 +200,13 @@ class OpenIDController extends Controller {
|
|||||||
const Policy = this.models.get('iam:Policy')
|
const Policy = this.models.get('iam:Policy')
|
||||||
const application = await Application.findOne({ openid_client_ids: params.client_id })
|
const application = await Application.findOne({ openid_client_ids: params.client_id })
|
||||||
if ( !application ) {
|
if ( !application ) {
|
||||||
this.output.warning('IAM Denial!')
|
this.output.warn('IAM Denial!')
|
||||||
return this.Vue.auth_message(res, {
|
return this.Vue.auth_message(res, {
|
||||||
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
|
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
|
||||||
next_destination: '/dash',
|
next_destination: '/dash',
|
||||||
})
|
})
|
||||||
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
|
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
|
||||||
this.output.warning('IAM Denial!')
|
this.output.warn('IAM Denial!')
|
||||||
return this.Vue.auth_message(res, {
|
return this.Vue.auth_message(res, {
|
||||||
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
||||||
next_destination: '/dash',
|
next_destination: '/dash',
|
||||||
@@ -238,13 +236,13 @@ class OpenIDController extends Controller {
|
|||||||
const Policy = this.models.get('iam:Policy')
|
const Policy = this.models.get('iam:Policy')
|
||||||
const application = await Application.findOne({ openid_client_ids: params.client_id })
|
const application = await Application.findOne({ openid_client_ids: params.client_id })
|
||||||
if ( !application ) {
|
if ( !application ) {
|
||||||
this.output.warning('IAM Denial!')
|
this.output.warn('IAM Denial!')
|
||||||
return this.Vue.auth_message(res, {
|
return this.Vue.auth_message(res, {
|
||||||
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
|
message: req.T('saml.no_access').replace('APP_NAME', 'this application'),
|
||||||
next_destination: '/dash',
|
next_destination: '/dash',
|
||||||
})
|
})
|
||||||
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
|
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
|
||||||
this.output.warning('IAM Denial!')
|
this.output.warn('IAM Denial!')
|
||||||
return this.Vue.auth_message(res, {
|
return this.Vue.auth_message(res, {
|
||||||
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
||||||
next_destination: '/dash',
|
next_destination: '/dash',
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class AuthController extends Controller {
|
|||||||
const user = new User({
|
const user = new User({
|
||||||
first_name: req.body.first_name,
|
first_name: req.body.first_name,
|
||||||
last_name: req.body.last_name,
|
last_name: req.body.last_name,
|
||||||
uid: req.body.uid,
|
uid: req.body.uid.toLowerCase(),
|
||||||
email: req.body.email,
|
email: req.body.email,
|
||||||
trap: 'password_reset', // Force user to reset password
|
trap: 'password_reset', // Force user to reset password
|
||||||
})
|
})
|
||||||
@@ -297,7 +297,7 @@ class AuthController extends Controller {
|
|||||||
.api()
|
.api()
|
||||||
|
|
||||||
const user = new User({
|
const user = new User({
|
||||||
uid: req.body.uid,
|
uid: req.body.uid.toLowerCase(),
|
||||||
email: req.body.email,
|
email: req.body.email,
|
||||||
first_name: req.body.first_name,
|
first_name: req.body.first_name,
|
||||||
last_name: req.body.last_name,
|
last_name: req.body.last_name,
|
||||||
@@ -417,7 +417,7 @@ class AuthController extends Controller {
|
|||||||
|
|
||||||
user.first_name = req.body.first_name
|
user.first_name = req.body.first_name
|
||||||
user.last_name = req.body.last_name
|
user.last_name = req.body.last_name
|
||||||
user.uid = req.body.uid
|
user.uid = req.body.uid.toLowerCase()
|
||||||
user.email = req.body.email
|
user.email = req.body.email
|
||||||
|
|
||||||
if ( req.body.tagline )
|
if ( req.body.tagline )
|
||||||
@@ -493,7 +493,7 @@ class AuthController extends Controller {
|
|||||||
|
|
||||||
if ( is_valid ) {
|
if ( is_valid ) {
|
||||||
const User = this.models.get('auth:User')
|
const User = this.models.get('auth:User')
|
||||||
const user = await User.findOne({uid: req.body.username})
|
const user = await User.findOne({uid: req.body.username.toLowerCase()})
|
||||||
if ( !user || !user.can_login ) is_valid = false
|
if ( !user || !user.can_login ) is_valid = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -511,7 +511,7 @@ class AuthController extends Controller {
|
|||||||
const data = {}
|
const data = {}
|
||||||
if ( req.body.username ) {
|
if ( req.body.username ) {
|
||||||
const existing_user = await User.findOne({
|
const existing_user = await User.findOne({
|
||||||
uid: req.body.username,
|
uid: req.body.username.toLowerCase(),
|
||||||
})
|
})
|
||||||
|
|
||||||
data.username_taken = !!existing_user
|
data.username_taken = !!existing_user
|
||||||
@@ -544,7 +544,8 @@ class AuthController extends Controller {
|
|||||||
.message(req.T('auth.unable_to_complete'))
|
.message(req.T('auth.unable_to_complete'))
|
||||||
.api({ errors })
|
.api({ errors })
|
||||||
|
|
||||||
const login_args = await flitter.get_login_args(req.body)
|
const [username, ...other_args] = await flitter.get_login_args(req.body)
|
||||||
|
const login_args = [username.toLowerCase(), ...other_args]
|
||||||
const user = await flitter.login.apply(flitter, login_args)
|
const user = await flitter.login.apply(flitter, login_args)
|
||||||
|
|
||||||
if ( !user )
|
if ( !user )
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class LDAPController extends Controller {
|
|||||||
|
|
||||||
// Make sure the uid is free
|
// Make sure the uid is free
|
||||||
const User = this.models.get('auth:User')
|
const User = this.models.get('auth:User')
|
||||||
const existing_user = await User.findOne({ uid: req.body.uid })
|
const existing_user = await User.findOne({ uid: req.body.uid.toLowerCase() })
|
||||||
if ( existing_user )
|
if ( existing_user )
|
||||||
return res.status(400)
|
return res.status(400)
|
||||||
.message(req.T('api.user_already_exists'))
|
.message(req.T('api.user_already_exists'))
|
||||||
@@ -113,7 +113,7 @@ class LDAPController extends Controller {
|
|||||||
// Create the client
|
// Create the client
|
||||||
const Client = this.models.get('ldap:Client')
|
const Client = this.models.get('ldap:Client')
|
||||||
const client = await Client.create({
|
const client = await Client.create({
|
||||||
uid: req.body.uid,
|
uid: req.body.uid.toLowerCase(),
|
||||||
password: req.body.password,
|
password: req.body.password,
|
||||||
name: req.body.name,
|
name: req.body.name,
|
||||||
})
|
})
|
||||||
@@ -210,16 +210,16 @@ class LDAPController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the uid
|
// Update the uid
|
||||||
if ( req.body.uid !== user.uid ) {
|
if ( req.body.uid.toLowerCase() !== user.uid ) {
|
||||||
// Make sure the UID is free
|
// Make sure the UID is free
|
||||||
const User = this.models.get('auth:User')
|
const User = this.models.get('auth:User')
|
||||||
const existing_user = await User.findOne({ uid: req.body.uid })
|
const existing_user = await User.findOne({ uid: req.body.uid.toLowerCase() })
|
||||||
if ( existing_user )
|
if ( existing_user )
|
||||||
return res.status(400)
|
return res.status(400)
|
||||||
.message(req.T('api.user_already_exists'))
|
.message(req.T('api.user_already_exists'))
|
||||||
.api()
|
.api()
|
||||||
|
|
||||||
user.uid = req.body.uid
|
user.uid = req.body.uid.toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the password
|
// Update the password
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const Oauth2Controller = require('flitter-auth/controllers/Oauth2')
|
|||||||
*/
|
*/
|
||||||
class Oauth2 extends Oauth2Controller {
|
class Oauth2 extends Oauth2Controller {
|
||||||
static get services() {
|
static get services() {
|
||||||
return [...super.services, 'Vue', 'configs', 'models']
|
return [...super.services, 'Vue', 'configs', 'models', 'output']
|
||||||
}
|
}
|
||||||
|
|
||||||
async authorize_post(req, res, next) {
|
async authorize_post(req, res, next) {
|
||||||
@@ -18,6 +18,24 @@ class Oauth2 extends Oauth2Controller {
|
|||||||
const StarshipClient = this.models.get('oauth:Client')
|
const StarshipClient = this.models.get('oauth:Client')
|
||||||
const starship_client = await StarshipClient.findOne({ active: true, uuid: client.clientID })
|
const starship_client = await StarshipClient.findOne({ active: true, uuid: client.clientID })
|
||||||
|
|
||||||
|
// Make sure the user has IAM access before proceeding
|
||||||
|
const Application = this.models.get('Application')
|
||||||
|
const Policy = this.models.get('iam:Policy')
|
||||||
|
const application = await Application.findOne({ oauth_client_ids: starship_client.id })
|
||||||
|
if ( !application ) {
|
||||||
|
this.output.warn('IAM Denial!')
|
||||||
|
return this.Vue.auth_message(res, {
|
||||||
|
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
||||||
|
next_destination: '/dash',
|
||||||
|
})
|
||||||
|
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
|
||||||
|
this.output.warn('IAM Denial!')
|
||||||
|
return this.Vue.auth_message(res, {
|
||||||
|
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
||||||
|
next_destination: '/dash',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
req.user.authorize(starship_client)
|
req.user.authorize(starship_client)
|
||||||
await req.user.save()
|
await req.user.save()
|
||||||
return super.authorize_post(req, res, next)
|
return super.authorize_post(req, res, next)
|
||||||
@@ -31,6 +49,24 @@ class Oauth2 extends Oauth2Controller {
|
|||||||
const StarshipClient = this.models.get('oauth:Client')
|
const StarshipClient = this.models.get('oauth:Client')
|
||||||
const starship_client = await StarshipClient.findOne({ active: true, uuid: client.clientID })
|
const starship_client = await StarshipClient.findOne({ active: true, uuid: client.clientID })
|
||||||
|
|
||||||
|
// Make sure the user has IAM access before proceeding
|
||||||
|
const Application = this.models.get('Application')
|
||||||
|
const Policy = this.models.get('iam:Policy')
|
||||||
|
const application = await Application.findOne({ oauth_client_ids: starship_client.id })
|
||||||
|
if ( !application ) {
|
||||||
|
this.output.warn('IAM Denial!')
|
||||||
|
return this.Vue.auth_message(res, {
|
||||||
|
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
||||||
|
next_destination: '/dash',
|
||||||
|
})
|
||||||
|
} else if ( !(await Policy.check_user_access(req.user, application.id)) ) {
|
||||||
|
this.output.warn('IAM Denial!')
|
||||||
|
return this.Vue.auth_message(res, {
|
||||||
|
message: req.T('saml.no_access').replace('APP_NAME', application.name),
|
||||||
|
next_destination: '/dash',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if ( req.user.has_authorized(starship_client) ) {
|
if ( req.user.has_authorized(starship_client) ) {
|
||||||
return this.Vue.invoke_action(res, {
|
return this.Vue.invoke_action(res, {
|
||||||
text: 'Grant Access',
|
text: 'Grant Access',
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class SAMLController extends Controller {
|
|||||||
key: await this.saml.private_key(),
|
key: await this.saml.private_key(),
|
||||||
protocolBinding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
protocolBinding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
|
||||||
clearIdPSession: done => {
|
clearIdPSession: done => {
|
||||||
this.output.info(`${req.T('saml.clear_idp_session')} ${req.user.uid}`)
|
this.output.info(`${req.T('saml.clear_idp_session')} ${req.user.uid.toLowerCase()}`)
|
||||||
req.saml.participants.clear().then(async () => {
|
req.saml.participants.clear().then(async () => {
|
||||||
if ( this.saml.config().slo.end_coreid_session ) {
|
if ( this.saml.config().slo.end_coreid_session ) {
|
||||||
await req.user.logout(req)
|
await req.user.logout(req)
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class LDAPController extends Injectable {
|
|||||||
const item = await this.get_resource_from_dn(req.dn)
|
const item = await this.get_resource_from_dn(req.dn)
|
||||||
if ( !item ) {
|
if ( !item ) {
|
||||||
this.output.debug(`Bind failure: ${req.dn} not found`)
|
this.output.debug(`Bind failure: ${req.dn} not found`)
|
||||||
return next(new LDAP.NoSuchObject())
|
return next(new LDAP.NoSuchObjectError())
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the object is can-able, make sure it can bind
|
// If the object is can-able, make sure it can bind
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class UsersController extends LDAPController {
|
|||||||
first_name: req_data.cn ? req_data.cn[0] : '',
|
first_name: req_data.cn ? req_data.cn[0] : '',
|
||||||
last_name: req_data.sn ? req_data.sn[0] : '',
|
last_name: req_data.sn ? req_data.sn[0] : '',
|
||||||
email: req_data.mail ? req_data.mail[0] : '',
|
email: req_data.mail ? req_data.mail[0] : '',
|
||||||
username: req_data.uid ? req_data.uid[0] : '',
|
username: req_data.uid ? req_data.uid[0].toLowerCase() : '',
|
||||||
password: req_data.userpassword ? req_data.userpassword[0] : '',
|
password: req_data.userpassword ? req_data.userpassword[0] : '',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,10 +218,12 @@ class UsersController extends LDAPController {
|
|||||||
// TODO flitter-orm chunk query
|
// TODO flitter-orm chunk query
|
||||||
// TODO generalize scoped search logic
|
// TODO generalize scoped search logic
|
||||||
async search_people(req, res, next) {
|
async search_people(req, res, next) {
|
||||||
if ( !req.user.can('ldap:search:users') ) {
|
if ( !req.user.can('ldap:search:users:me') ) {
|
||||||
return next(new LDAP.InsufficientAccessRightsError())
|
return next(new LDAP.InsufficientAccessRightsError())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const can_search_all = req.user.can('ldap:search:users')
|
||||||
|
|
||||||
const iam_targets = this.parse_iam_targets(req.filter)
|
const iam_targets = this.parse_iam_targets(req.filter)
|
||||||
if ( req.scope === 'base' ) {
|
if ( req.scope === 'base' ) {
|
||||||
// If scope is base, check if the base DN matches the filter.
|
// If scope is base, check if the base DN matches the filter.
|
||||||
@@ -231,7 +233,12 @@ class UsersController extends LDAPController {
|
|||||||
const user = await this.get_resource_from_dn(req.dn)
|
const user = await this.get_resource_from_dn(req.dn)
|
||||||
|
|
||||||
// Make sure the user is ldap visible && match the filter
|
// Make sure the user is ldap visible && match the filter
|
||||||
if ( user && user.ldap_visible && req.filter.matches(await user.to_ldap(iam_targets)) ) {
|
if (
|
||||||
|
user
|
||||||
|
&& user.ldap_visible
|
||||||
|
&& req.filter.matches(await user.to_ldap(iam_targets))
|
||||||
|
&& (req.user.id === user.id || can_search_all)
|
||||||
|
) {
|
||||||
|
|
||||||
// If so, send the object
|
// If so, send the object
|
||||||
res.send({
|
res.send({
|
||||||
@@ -255,6 +262,7 @@ class UsersController extends LDAPController {
|
|||||||
// Fetch the LDAP-visible users
|
// Fetch the LDAP-visible users
|
||||||
const users = await this.User.ldap_directory()
|
const users = await this.User.ldap_directory()
|
||||||
for ( const user of users ) {
|
for ( const user of users ) {
|
||||||
|
if ( user.id !== req.user.id && !can_search_all ) continue
|
||||||
|
|
||||||
// Make sure the user os of the appropriate scope
|
// Make sure the user os of the appropriate scope
|
||||||
if ( req.dn.equals(user.dn) || user.dn.parent().equals(req.dn) ) {
|
if ( req.dn.equals(user.dn) || user.dn.parent().equals(req.dn) ) {
|
||||||
@@ -283,6 +291,7 @@ class UsersController extends LDAPController {
|
|||||||
this.output.debug(`Filter:`)
|
this.output.debug(`Filter:`)
|
||||||
this.output.debug(this.filter_to_obj(req.filter.json))
|
this.output.debug(this.filter_to_obj(req.filter.json))
|
||||||
for ( const user of users ) {
|
for ( const user of users ) {
|
||||||
|
if ( user.id !== req.user.id && !can_search_all ) continue
|
||||||
this.output.debug(`Checking ${user.uid}...`)
|
this.output.debug(`Checking ${user.uid}...`)
|
||||||
this.output.debug(`DN: ${user.dn}`)
|
this.output.debug(`DN: ${user.dn}`)
|
||||||
this.output.debug(`Req DN equals: ${req.dn.equals(user.dn)}`)
|
this.output.debug(`Req DN equals: ${req.dn.equals(user.dn)}`)
|
||||||
@@ -290,6 +299,7 @@ class UsersController extends LDAPController {
|
|||||||
|
|
||||||
// Make sure the user is of appropriate scope
|
// Make sure the user is of appropriate scope
|
||||||
if ( req.dn.equals(user.dn) || req.dn.parentOf(user.dn) ) {
|
if ( req.dn.equals(user.dn) || req.dn.parentOf(user.dn) ) {
|
||||||
|
this.output.debug(await user.to_ldap())
|
||||||
this.output.debug(`Matches sub scope. Matches filter? ${req.filter.matches(await user.to_ldap(iam_targets))}`)
|
this.output.debug(`Matches sub scope. Matches filter? ${req.filter.matches(await user.to_ldap(iam_targets))}`)
|
||||||
|
|
||||||
// Check if filter matches
|
// Check if filter matches
|
||||||
@@ -317,7 +327,7 @@ class UsersController extends LDAPController {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if ( typeof dn === 'string' ) dn = LDAP.parseDN(dn)
|
if ( typeof dn === 'string' ) dn = LDAP.parseDN(dn)
|
||||||
return dn.rdns[0].attrs[uid_field].value
|
return dn.rdns[0].attrs[uid_field].value.toLowerCase()
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +335,7 @@ class UsersController extends LDAPController {
|
|||||||
const uid = this.get_uid_from_dn(dn)
|
const uid = this.get_uid_from_dn(dn)
|
||||||
if ( uid ) {
|
if ( uid ) {
|
||||||
const User = this.models.get('auth:User')
|
const User = this.models.get('auth:User')
|
||||||
return User.findOne({uid, ldap_visible: true})
|
return User.findOne({uid: uid.toLowerCase(), ldap_visible: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
app/models/FrontEndError.model.js
Normal file
29
app/models/FrontEndError.model.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
const { Model } = require('flitter-orm')
|
||||||
|
|
||||||
|
class FrontEndErrorModel extends Model {
|
||||||
|
static get schema() {
|
||||||
|
return {
|
||||||
|
user_agent: String,
|
||||||
|
logged_at: { type: Date, default: () => new Date },
|
||||||
|
user_id: String,
|
||||||
|
session_id: String,
|
||||||
|
full_url: String,
|
||||||
|
trace: String,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async log(request) {
|
||||||
|
const err = new this({
|
||||||
|
user_agent: request.get('user-agent'),
|
||||||
|
user_id: request?.user?.id,
|
||||||
|
session_id: request.sessionID,
|
||||||
|
full_url: request.body.full_url,
|
||||||
|
trace: request.body.trace,
|
||||||
|
})
|
||||||
|
|
||||||
|
await err.save()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = FrontEndErrorModel
|
||||||
@@ -173,7 +173,7 @@ class User extends AuthUser {
|
|||||||
const Policy = this.models.get('iam:Policy')
|
const Policy = this.models.get('iam:Policy')
|
||||||
|
|
||||||
const ldap_data = {
|
const ldap_data = {
|
||||||
uid: this.uid,
|
uid: this.uid.toLowerCase(),
|
||||||
uuid: this.uuid,
|
uuid: this.uuid,
|
||||||
cn: this.first_name,
|
cn: this.first_name,
|
||||||
sn: this.last_name,
|
sn: this.last_name,
|
||||||
@@ -213,7 +213,7 @@ class User extends AuthUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get dn() {
|
get dn() {
|
||||||
return LDAP.parseDN(`uid=${this.uid},${this.ldap_server.auth_dn().format(this.configs.get('ldap:server.format'))}`)
|
return LDAP.parseDN(`uid=${this.uid.toLowerCase()},${this.ldap_server.auth_dn().format(this.configs.get('ldap:server.format'))}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following are used by OpenID connect
|
// The following are used by OpenID connect
|
||||||
@@ -227,15 +227,15 @@ class User extends AuthUser {
|
|||||||
given_name: this.first_name,
|
given_name: this.first_name,
|
||||||
locale: 'en_US', // TODO
|
locale: 'en_US', // TODO
|
||||||
name: `${this.first_name} ${this.last_name}`,
|
name: `${this.first_name} ${this.last_name}`,
|
||||||
preferred_username: this.uid,
|
preferred_username: this.uid.toLowerCase(),
|
||||||
username: this.uid,
|
username: this.uid.toLowerCase(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findByLogin(login) {
|
static async findByLogin(login) {
|
||||||
return this.findOne({
|
return this.findOne({
|
||||||
active: true,
|
active: true,
|
||||||
uid: login,
|
uid: login.toLowerCase(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class PolicyModel extends Model {
|
|||||||
if ( this.entity_type === 'user' ) {
|
if ( this.entity_type === 'user' ) {
|
||||||
const User = this.models.get('auth:User')
|
const User = this.models.get('auth:User')
|
||||||
const user = await User.findById(this.entity_id)
|
const user = await User.findById(this.entity_id)
|
||||||
entity_display = `User: ${user.last_name}, ${user.first_name} (${user.uid})`
|
entity_display = `User: ${user.last_name}, ${user.first_name} (${user.uid.toLowerCase()})`
|
||||||
} else if ( this.entity_type === 'group' ) {
|
} else if ( this.entity_type === 'group' ) {
|
||||||
const Group = this.models.get('auth:Group')
|
const Group = this.models.get('auth:Group')
|
||||||
const group = await Group.findById(this.entity_id)
|
const group = await Group.findById(this.entity_id)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class ClientModel extends Model {
|
|||||||
const user = new User({
|
const user = new User({
|
||||||
first_name: name,
|
first_name: name,
|
||||||
last_name: '(LDAP Agent)',
|
last_name: '(LDAP Agent)',
|
||||||
uid,
|
uid: uid.toLowerCase(),
|
||||||
roles: ['ldap_client'],
|
roles: ['ldap_client'],
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ class ClientModel extends Model {
|
|||||||
id: this.id,
|
id: this.id,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
user_id: user.id,
|
user_id: user.id,
|
||||||
uid: user.uid,
|
uid: user.uid.toLowerCase(),
|
||||||
last_invocation: this.last_invocation,
|
last_invocation: this.last_invocation,
|
||||||
permissions: [...user.permissions, ...role_permissions],
|
permissions: [...user.permissions, ...role_permissions],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class SessionParticipantStore extends Injectable {
|
|||||||
async issue({ service_provider }) {
|
async issue({ service_provider }) {
|
||||||
const sp = new this.SessionParticipant({
|
const sp = new this.SessionParticipant({
|
||||||
service_provider_id: service_provider.id,
|
service_provider_id: service_provider.id,
|
||||||
name_id: this.request.user.uid,
|
name_id: this.request.user.uid.toLowerCase(),
|
||||||
// session_index: this.get_index(),
|
// session_index: this.get_index(),
|
||||||
slo_url: service_provider.slo_url,
|
slo_url: service_provider.slo_url,
|
||||||
// TODO sp_cert,
|
// TODO sp_cert,
|
||||||
|
|||||||
@@ -8,22 +8,35 @@ class PermissionMiddleware extends Middleware {
|
|||||||
async test(req, res, next, { check }) {
|
async test(req, res, next, { check }) {
|
||||||
const Policy = this.models.get('iam:Policy')
|
const Policy = this.models.get('iam:Policy')
|
||||||
|
|
||||||
|
if ( !req.additional_api_log_data ) req.additional_api_log_data = {}
|
||||||
|
req.additional_api_log_data.permission_check = check
|
||||||
|
|
||||||
// If the request was authorized using an OAuth2 bearer token,
|
// If the request was authorized using an OAuth2 bearer token,
|
||||||
// make sure the associated client has permission to access this endpoint.
|
// make sure the associated client has permission to access this endpoint.
|
||||||
if ( req?.oauth?.client ) {
|
if ( req?.oauth?.client ) {
|
||||||
if ( !req.oauth.client.can(check) ) {
|
if ( !req.oauth.client.can(check) ) {
|
||||||
const reason = 'oauth-permission-fail'
|
const reason = 'oauth-permission-fail'
|
||||||
await this.activity.api_access_denial({
|
const fail_activity = await this.activity.api_access_denial({
|
||||||
req,
|
req,
|
||||||
reason,
|
reason,
|
||||||
check,
|
check,
|
||||||
oauth_client_id: req.oauth.client.id,
|
oauth_client_id: req.oauth.client.uuid,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
req.additional_api_log_data.permission_check_succeeded = false
|
||||||
|
req.additional_api_log_data.permission_check_activity_id = fail_activity.id
|
||||||
|
|
||||||
return res.status(401)
|
return res.status(401)
|
||||||
.message('Insufficient permissions (OAuth2 Client).')
|
.message('Insufficient permissions (OAuth2 Client).')
|
||||||
.api()
|
.api()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.additional_api_log_data.permission_check_succeeded = true
|
||||||
|
|
||||||
|
// If the oauth2 client has this permission, then allow the request to continue,
|
||||||
|
// even if the user does not.
|
||||||
|
// OAuth2Clients need to be able to query users via the API.
|
||||||
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
const policy_denied = await Policy.check_user_denied(req.user, check)
|
const policy_denied = await Policy.check_user_denied(req.user, check)
|
||||||
@@ -33,13 +46,18 @@ class PermissionMiddleware extends Middleware {
|
|||||||
if ( policy_denied || (!req.user.can(check) && !policy_access) ) {
|
if ( policy_denied || (!req.user.can(check) && !policy_access) ) {
|
||||||
// Record the failed API access
|
// Record the failed API access
|
||||||
const reason = policy_denied ? 'iam-denial' : (!req.user.can(check) ? 'user-permission-fail' : 'iam-not-granted')
|
const reason = policy_denied ? 'iam-denial' : (!req.user.can(check) ? 'user-permission-fail' : 'iam-not-granted')
|
||||||
await this.activity.api_access_denial({ req, reason, check })
|
const fail_activity = await this.activity.api_access_denial({ req, reason, check })
|
||||||
|
|
||||||
|
req.additional_api_log_data.permission_check_succeeded = false
|
||||||
|
req.additional_api_log_data.permission_check_reason = reason
|
||||||
|
req.additional_api_log_data.permission_check_activity_id = fail_activity.id
|
||||||
|
|
||||||
return res.status(401)
|
return res.status(401)
|
||||||
.message('Insufficient permissions.')
|
.message('Insufficient permissions.')
|
||||||
.api()
|
.api()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.additional_api_log_data.permission_check_succeeded = true
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,21 @@ class APIRouteMiddleware extends Middleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async test(req, res, next, { allow_token = true, allow_user = true }) {
|
async test(req, res, next, { allow_token = true, allow_user = true }) {
|
||||||
|
if ( !req.additional_api_log_data ) req.additional_api_log_data = {}
|
||||||
|
|
||||||
// First, check if there is a user in the session.
|
// First, check if there is a user in the session.
|
||||||
if ( allow_user && req.is_auth ) {
|
if ( allow_user && req.user ) {
|
||||||
|
req.additional_api_log_data.authorized_by = 'user'
|
||||||
return next()
|
return next()
|
||||||
} else if ( allow_token ) {
|
} else if ( allow_token ) {
|
||||||
|
if ( !req.oauth ) req.oauth = {}
|
||||||
|
req.additional_api_log_data.attempted_token_auth = true
|
||||||
|
|
||||||
return req.app.oauth2.authorise()(req, res, async e => {
|
return req.app.oauth2.authorise()(req, res, async e => {
|
||||||
if ( e ) return next(e)
|
if ( e ) return next(e)
|
||||||
|
|
||||||
|
req.additional_api_log_data.authorized_by = 'token'
|
||||||
|
|
||||||
// Look up the OAuth2 client an inject it into the route
|
// Look up the OAuth2 client an inject it into the route
|
||||||
if ( req.user && req.user.id ) {
|
if ( req.user && req.user.id ) {
|
||||||
const User = this.models.get('auth:User')
|
const User = this.models.get('auth:User')
|
||||||
@@ -42,6 +51,9 @@ class APIRouteMiddleware extends Middleware {
|
|||||||
.message('This OAuth2 client is no longer authorized.')
|
.message('This OAuth2 client is no longer authorized.')
|
||||||
.api()
|
.api()
|
||||||
|
|
||||||
|
req.additional_api_log_data.token_client_id = client.uuid
|
||||||
|
req.additional_api_log_data.token = bearer
|
||||||
|
|
||||||
req.oauth.token = token
|
req.oauth.token = token
|
||||||
req.oauth.client = client
|
req.oauth.client = client
|
||||||
} else
|
} else
|
||||||
@@ -51,9 +63,9 @@ class APIRouteMiddleware extends Middleware {
|
|||||||
|
|
||||||
next()
|
next()
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
return res.status(401).api()
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(401).api()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ const index = {
|
|||||||
'middleware::auth:GuestOnly',
|
'middleware::auth:GuestOnly',
|
||||||
'controller::api:v1:Password.request_reset',
|
'controller::api:v1:Password.request_reset',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'/api/v1/log-error': [
|
||||||
|
'controller::Home.log_front_end_error'
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class MFAService extends Service {
|
|||||||
secret(user) {
|
secret(user) {
|
||||||
return speakeasy.generateSecret({
|
return speakeasy.generateSecret({
|
||||||
length: this.configs.get('auth.mfa.secret_length') ?? 20,
|
length: this.configs.get('auth.mfa.secret_length') ?? 20,
|
||||||
name: `${this.configs.get('app.name')} (${user.uid})`,
|
name: `${this.configs.get('app.name')} (${user.uid.toLowerCase()})`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class VueService extends Service {
|
|||||||
user: {
|
user: {
|
||||||
first_name: req.user.first_name,
|
first_name: req.user.first_name,
|
||||||
last_name: req.user.last_name,
|
last_name: req.user.last_name,
|
||||||
username: req.user.uid,
|
username: req.user.uid.toLowerCase(),
|
||||||
email: req.user.email,
|
email: req.user.email,
|
||||||
tagline: req.user.tagline,
|
tagline: req.user.tagline,
|
||||||
user_id: req.user.id,
|
user_id: req.user.id,
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ class ActivityService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await activity.save()
|
await activity.save()
|
||||||
|
return activity
|
||||||
}
|
}
|
||||||
|
|
||||||
async mfa_enable({ req }) {
|
async mfa_enable({ req }) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class OpenIDConnectUnit extends Unit {
|
|||||||
clients: [],
|
clients: [],
|
||||||
interactions: {
|
interactions: {
|
||||||
interactions,
|
interactions,
|
||||||
url: (ctx, interaction) => `/openid/interaction/${ctx.oidc.uid}`,
|
url: (ctx, interaction) => `/openid/interaction/${ctx.oidc.uid.toLowerCase()}`,
|
||||||
},
|
},
|
||||||
cookies: {
|
cookies: {
|
||||||
long: { signed: true, maxAge: 24 * 60 * 60 * 1000 }, // 1 day, ms
|
long: { signed: true, maxAge: 24 * 60 * 60 * 1000 }, // 1 day, ms
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class SettingsUnit extends Unit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async go(app) {
|
async go(app) {
|
||||||
|
Error.stackTraceLimit = 50
|
||||||
app.express.set('trust proxy', true)
|
app.express.set('trust proxy', true)
|
||||||
|
|
||||||
const Setting = this.models.get('Setting')
|
const Setting = this.models.get('Setting')
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ html(lang='en')
|
|||||||
.app-container
|
.app-container
|
||||||
block app
|
block app
|
||||||
block script
|
block script
|
||||||
|
script(src='/assets/error-log.js')
|
||||||
script(src='/assets/lib/axios/axios.min.js')
|
script(src='/assets/lib/axios/axios.min.js')
|
||||||
script(src='/assets/lib/jquery/jquery-3.4.1.slim.min.js')
|
script(src='/assets/lib/jquery/jquery-3.4.1.slim.min.js')
|
||||||
script(src='/assets/lib/popper/popper-1.16.0.min.js')
|
script(src='/assets/lib/popper/popper-1.16.0.min.js')
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ const auth_config = {
|
|||||||
|
|
||||||
// LDAP Binding
|
// LDAP Binding
|
||||||
'ldap:bind',
|
'ldap:bind',
|
||||||
|
'ldap:search:users:me',
|
||||||
],
|
],
|
||||||
|
|
||||||
root: ['v1', 'ldap', 'saml', 'profile', 'oauth', 'app', 'auth', 'iam'],
|
root: ['v1', 'ldap', 'saml', 'profile', 'oauth', 'app', 'auth', 'iam'],
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ const server_config = {
|
|||||||
level: env("LOGGING_LEVEL", 2),
|
level: env("LOGGING_LEVEL", 2),
|
||||||
|
|
||||||
include_timestamp: env("LOGGING_TIMESTAMP", false),
|
include_timestamp: env("LOGGING_TIMESTAMP", false),
|
||||||
|
|
||||||
|
api_logging: env('LOG_API_RESPONSES', false),
|
||||||
|
|
||||||
|
error_logging: env('LOG_REQUEST_ERRORS', true),
|
||||||
},
|
},
|
||||||
|
|
||||||
session: {
|
session: {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
"ioredis": "^4.17.1",
|
"ioredis": "^4.17.1",
|
||||||
"is-absolute-url": "^3.0.3",
|
"is-absolute-url": "^3.0.3",
|
||||||
"ldapjs": "^1.0.2",
|
"ldapjs": "^1.0.2",
|
||||||
"libflitter": "^0.53.1",
|
"libflitter": "^0.56.1",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"mongodb": "^3.5.9",
|
"mongodb": "^3.5.9",
|
||||||
"nodemailer": "^6.4.6",
|
"nodemailer": "^6.4.6",
|
||||||
|
|||||||
@@ -3235,10 +3235,10 @@ leven@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3"
|
resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3"
|
||||||
integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=
|
integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=
|
||||||
|
|
||||||
libflitter@^0.53.1:
|
libflitter@^0.56.1:
|
||||||
version "0.53.1"
|
version "0.56.1"
|
||||||
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.53.1.tgz#30b1838763a228fba8b9c820d2cad501c3aa0117"
|
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.56.1.tgz#250166027b9cab727c9deb6b1fa1865428b1eafb"
|
||||||
integrity sha512-EK3okZyt0pmnpsZNx2lYOIcwgtmSOEPh4a5xE3pXM9RVc3dtXXscgJ5h9OvLTIN9WfRc7T5VTdpOjeAK6Xmysg==
|
integrity sha512-QikFtFRa9okKOjOio5ehpQ6hyacCoMbtOlqcXt4I7uU3lntBeP5qSbz1q3x1wUY/AdBc2k70+Eg8BcpGmBEs4Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
colors "^1.3.3"
|
colors "^1.3.3"
|
||||||
connect-mongodb-session "^2.2.0"
|
connect-mongodb-session "^2.2.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user