Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
fe0a4d5991
|
|||
|
f06ff83dce
|
|||
|
251aa6cf97
|
|||
|
60003d64d5
|
|||
|
535dde13ff
|
|||
|
63d102296f
|
|||
|
77d203b2b0
|
|||
|
fcbf25e3ce
|
|||
|
084ec7bbc1
|
|||
|
6b3339a883
|
|||
|
8f1bbfef56
|
|||
|
e400e16ccc
|
|||
|
97096f619f
|
|||
|
2d97b77bbf
|
@@ -38,14 +38,18 @@ export default class MFAChallengePage extends Component {
|
|||||||
static get props() { return ['app_name'] }
|
static get props() { return ['app_name'] }
|
||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
|
|
||||||
loading = false
|
constructor() {
|
||||||
|
super()
|
||||||
|
|
||||||
verify_code = ''
|
this.loading = false
|
||||||
verify_success = false
|
|
||||||
|
|
||||||
error_message = ''
|
this.verify_code = ''
|
||||||
other_message = ''
|
this.verify_success = false
|
||||||
t = {}
|
|
||||||
|
this.error_message = ''
|
||||||
|
this.other_message = ''
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.t = await T(
|
this.t = await T(
|
||||||
|
|||||||
@@ -28,12 +28,16 @@ export default class MFADisableComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return [] }
|
static get props() { return [] }
|
||||||
|
|
||||||
app_name = ''
|
constructor() {
|
||||||
step = 0
|
super()
|
||||||
loading = false
|
|
||||||
error_message = ''
|
this.app_name = ''
|
||||||
other_message = ''
|
this.step = 0
|
||||||
t = {}
|
this.loading = false
|
||||||
|
this.error_message = ''
|
||||||
|
this.other_message = ''
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.app_name = session.get('app.name')
|
this.app_name = session.get('app.name')
|
||||||
|
|||||||
@@ -38,12 +38,16 @@ export default class MFARecoveryComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return ['app_name'] }
|
static get props() { return ['app_name'] }
|
||||||
|
|
||||||
verify_success = false
|
constructor() {
|
||||||
loading = false
|
super()
|
||||||
recovery_code = ''
|
|
||||||
error_message = ''
|
this.verify_success = false
|
||||||
other_message = ''
|
this.loading = false
|
||||||
t = {}
|
this.recovery_code = ''
|
||||||
|
this.error_message = ''
|
||||||
|
this.other_message = ''
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.t = await T(
|
this.t = await T(
|
||||||
|
|||||||
@@ -61,19 +61,23 @@ export default class MFASetupPage extends Component {
|
|||||||
static get props() { return ['app_name'] }
|
static get props() { return ['app_name'] }
|
||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
|
|
||||||
loading = false
|
constructor() {
|
||||||
step = 0
|
super()
|
||||||
|
|
||||||
qr_data = ''
|
this.loading = false
|
||||||
otpauth_url = ''
|
this.step = 0
|
||||||
secret = ''
|
|
||||||
verify_code = ''
|
|
||||||
|
|
||||||
verify_success = false
|
this.qr_data = ''
|
||||||
|
this.otpauth_url = ''
|
||||||
|
this.secret = ''
|
||||||
|
this.verify_code = ''
|
||||||
|
|
||||||
error_message = ''
|
this.verify_success = false
|
||||||
other_message = ''
|
|
||||||
t = {}
|
this.error_message = ''
|
||||||
|
this.other_message = ''
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.t = await T(
|
this.t = await T(
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ export default class AuthPage extends Component {
|
|||||||
static get props() { return ['app_name', 'message', 'actions'] }
|
static get props() { return ['app_name', 'message', 'actions'] }
|
||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
|
|
||||||
loading = false
|
constructor() {
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
|
||||||
async action_click(index) {
|
async action_click(index) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|||||||
@@ -78,23 +78,27 @@ export default class PasswordResetComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return ['app_name'] }
|
static get props() { return ['app_name'] }
|
||||||
|
|
||||||
step = 0
|
constructor() {
|
||||||
loading = false
|
super()
|
||||||
has_mfa = false
|
|
||||||
|
|
||||||
error_message = ''
|
this.step = 0
|
||||||
other_message = ''
|
this.loading = false
|
||||||
|
this.has_mfa = false
|
||||||
|
|
||||||
step_1_valid = false
|
this.error_message = ''
|
||||||
step_1_calc_time = ''
|
this.other_message = ''
|
||||||
step_1_problem = ''
|
|
||||||
|
|
||||||
step_2_valid = false
|
this.step_1_valid = false
|
||||||
|
this.step_1_calc_time = ''
|
||||||
|
this.step_1_problem = ''
|
||||||
|
|
||||||
password = ''
|
this.step_2_valid = false
|
||||||
confirm_password = ''
|
|
||||||
t = {}
|
this.password = ''
|
||||||
ready = false
|
this.confirm_password = ''
|
||||||
|
this.t = {}
|
||||||
|
this.ready = false
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.has_mfa = !!session.get('user.has_mfa')
|
this.has_mfa = !!session.get('user.has_mfa')
|
||||||
|
|||||||
@@ -63,18 +63,21 @@ export default class AuthLoginForm extends Component {
|
|||||||
] }
|
] }
|
||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
|
|
||||||
username = ''
|
constructor() {
|
||||||
password = ''
|
super()
|
||||||
button_text = ''
|
|
||||||
step_two = false
|
|
||||||
btn_disabled = true
|
|
||||||
loading = false
|
|
||||||
error_message = ''
|
|
||||||
other_message = ''
|
|
||||||
allow_back = true
|
|
||||||
auth_user = false
|
|
||||||
|
|
||||||
t = {}
|
this.username = ''
|
||||||
|
this.password = ''
|
||||||
|
this.button_text = ''
|
||||||
|
this.step_two = false
|
||||||
|
this.btn_disabled = true
|
||||||
|
this.loading = false
|
||||||
|
this.error_message = ''
|
||||||
|
this.other_message = ''
|
||||||
|
this.allow_back = true
|
||||||
|
this.auth_user = false
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
watch_username(new_username, old_username) {
|
watch_username(new_username, old_username) {
|
||||||
this.btn_disabled = !new_username
|
this.btn_disabled = !new_username
|
||||||
|
|||||||
@@ -98,19 +98,23 @@ export default class RegistrationFormComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return ['app_name'] }
|
static get props() { return ['app_name'] }
|
||||||
|
|
||||||
loading = false
|
constructor() {
|
||||||
step = 1
|
super()
|
||||||
other_message = ''
|
|
||||||
error_message = ''
|
|
||||||
message = ''
|
|
||||||
btn_disabled = true
|
|
||||||
button_text = ''
|
|
||||||
|
|
||||||
first_name = ''
|
this.loading = false
|
||||||
last_name = ''
|
this.step = 1
|
||||||
username = ''
|
this.other_message = ''
|
||||||
email = ''
|
this.error_message = ''
|
||||||
t = {}
|
this.message = ''
|
||||||
|
this.btn_disabled = true
|
||||||
|
this.button_text = ''
|
||||||
|
|
||||||
|
this.first_name = ''
|
||||||
|
this.last_name = ''
|
||||||
|
this.username = ''
|
||||||
|
this.email = ''
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
// Batch-load translated phrases
|
// Batch-load translated phrases
|
||||||
|
|||||||
@@ -146,20 +146,24 @@ export default class FormComponent extends Component {
|
|||||||
return ['resource', 'form_id', 'initial_mode']
|
return ['resource', 'form_id', 'initial_mode']
|
||||||
}
|
}
|
||||||
|
|
||||||
definition = {}
|
constructor() {
|
||||||
data = {}
|
super()
|
||||||
uuid = ''
|
|
||||||
title = ''
|
|
||||||
error_message = ''
|
|
||||||
other_message = ''
|
|
||||||
|
|
||||||
access_msg = ''
|
this.definition = {}
|
||||||
can_access = false
|
this.data = {}
|
||||||
|
this.uuid = ''
|
||||||
|
this.title = ''
|
||||||
|
this.error_message = ''
|
||||||
|
this.other_message = ''
|
||||||
|
|
||||||
is_ready = false
|
this.access_msg = ''
|
||||||
mode = ''
|
this.can_access = false
|
||||||
id = ''
|
|
||||||
t = {}
|
this.is_ready = false
|
||||||
|
this.mode = ''
|
||||||
|
this.id = ''
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.definition = {}
|
this.definition = {}
|
||||||
|
|||||||
@@ -65,13 +65,17 @@ export default class ListingComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return ['resource'] }
|
static get props() { return ['resource'] }
|
||||||
|
|
||||||
definition = {}
|
constructor() {
|
||||||
data = []
|
super()
|
||||||
resource_class = {}
|
|
||||||
|
|
||||||
access_msg = ''
|
this.definition = {}
|
||||||
can_access = false
|
this.data = []
|
||||||
t = {}
|
this.resource_class = {}
|
||||||
|
|
||||||
|
this.access_msg = ''
|
||||||
|
this.can_access = false
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.t = await T(
|
this.t = await T(
|
||||||
|
|||||||
@@ -232,35 +232,39 @@ export default class AppSetupComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return [] }
|
static get props() { return [] }
|
||||||
|
|
||||||
step = 0
|
constructor() {
|
||||||
btn_disabled = true
|
super()
|
||||||
btn_back = false
|
|
||||||
btn_hidden = false
|
|
||||||
btn_listing = false
|
|
||||||
|
|
||||||
name = ''
|
this.step = 0
|
||||||
identifier = ''
|
this.btn_disabled = true
|
||||||
type = '' // ldap | saml | oauth
|
this.btn_back = false
|
||||||
oauth_redirect_uri = ''
|
this.btn_hidden = false
|
||||||
|
this.btn_listing = false
|
||||||
|
|
||||||
saml_entity_id = ''
|
this.name = ''
|
||||||
saml_acs_url = ''
|
this.identifier = ''
|
||||||
saml_slo_url = ''
|
this.type = '' // ldap | saml | oauth
|
||||||
|
this.oauth_redirect_uri = ''
|
||||||
|
|
||||||
ldap_username = ''
|
this.saml_entity_id = ''
|
||||||
ldap_password = ''
|
this.saml_acs_url = ''
|
||||||
ldap_password_confirm = ''
|
this.saml_slo_url = ''
|
||||||
ldap_config = {}
|
|
||||||
|
|
||||||
error_message = ''
|
this.ldap_username = ''
|
||||||
|
this.ldap_password = ''
|
||||||
|
this.ldap_password_confirm = ''
|
||||||
|
this.ldap_config = {}
|
||||||
|
|
||||||
app = {}
|
this.error_message = ''
|
||||||
oauth_client = {}
|
|
||||||
saml_provider = {}
|
|
||||||
ldap_client = {}
|
|
||||||
|
|
||||||
app_name = ''
|
this.app = {}
|
||||||
host = ''
|
this.oauth_client = {}
|
||||||
|
this.saml_provider = {}
|
||||||
|
this.ldap_client = {}
|
||||||
|
|
||||||
|
this.app_name = ''
|
||||||
|
this.host = ''
|
||||||
|
}
|
||||||
|
|
||||||
make_url(path) {
|
make_url(path) {
|
||||||
return session.url(path)
|
return session.url(path)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Component } from '../../lib/vues6/vues6.js'
|
import { Component } from '../../lib/vues6/vues6.js'
|
||||||
import { event_bus } from '../service/EventBus.service.js'
|
import { event_bus } from '../service/EventBus.service.js'
|
||||||
import { session } from '../service/Session.service.js'
|
import { session } from '../service/Session.service.js'
|
||||||
import { message_service } from '../service/Message.service.js'
|
|
||||||
|
|
||||||
const template = `
|
const template = `
|
||||||
<nav class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
|
<nav class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
|
||||||
@@ -53,10 +52,10 @@ export default class NavBarComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return [] }
|
static get props() { return [] }
|
||||||
|
|
||||||
can = {}
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
this.can = {}
|
||||||
this.toggle_event = event_bus.event('sidebar.toggle')
|
this.toggle_event = event_bus.event('sidebar.toggle')
|
||||||
this.first_name = session.get('user.first_name')
|
this.first_name = session.get('user.first_name')
|
||||||
this.last_name = session.get('user.last_name')
|
this.last_name = session.get('user.last_name')
|
||||||
|
|||||||
@@ -23,72 +23,75 @@ export default class SideBarComponent extends Component {
|
|||||||
static get props() { return ['app_name'] }
|
static get props() { return ['app_name'] }
|
||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
|
|
||||||
actions = []
|
|
||||||
|
|
||||||
possible_actions = [
|
|
||||||
{
|
|
||||||
text: 'Profile',
|
|
||||||
action: 'redirect',
|
|
||||||
next: '/dash/profile',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Users',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'auth/User',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Groups',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'auth/Group',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Applications',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'App',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'IAM Policy',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'iam/Policy',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'LDAP Clients',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'ldap/Client',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'OAuth2 Clients',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'oauth/Client',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'OpenID Connect Clients',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'openid/Client',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'SAML Service Providers',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'saml/Provider',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Settings',
|
|
||||||
action: 'list',
|
|
||||||
type: 'resource',
|
|
||||||
resource: 'Setting',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
this.actions = []
|
||||||
|
|
||||||
|
this.isCollapsed = false
|
||||||
|
|
||||||
|
this.possible_actions = [
|
||||||
|
{
|
||||||
|
text: 'Profile',
|
||||||
|
action: 'redirect',
|
||||||
|
next: '/dash/profile',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Users',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'auth/User',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Groups',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'auth/Group',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Applications',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'App',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'IAM Policy',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'iam/Policy',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'LDAP Clients',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'ldap/Client',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'OAuth2 Clients',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'oauth/Client',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'OpenID Connect Clients',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'openid/Client',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'SAML Service Providers',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'saml/Provider',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Settings',
|
||||||
|
action: 'list',
|
||||||
|
type: 'resource',
|
||||||
|
resource: 'Setting',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
event_bus.event('sidebar.toggle').subscribe(() => {
|
event_bus.event('sidebar.toggle').subscribe(() => {
|
||||||
this.toggle()
|
this.toggle()
|
||||||
})
|
})
|
||||||
@@ -120,8 +123,6 @@ export default class SideBarComponent extends Component {
|
|||||||
this.actions = new_actions
|
this.actions = new_actions
|
||||||
}
|
}
|
||||||
|
|
||||||
isCollapsed = false
|
|
||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
this.isCollapsed = !this.isCollapsed
|
this.isCollapsed = !this.isCollapsed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,12 @@ export default class MessageContainerComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return [] }
|
static get props() { return [] }
|
||||||
|
|
||||||
messages = []
|
constructor() {
|
||||||
modals = []
|
super()
|
||||||
|
|
||||||
|
this.messages = []
|
||||||
|
this.modals = []
|
||||||
|
}
|
||||||
|
|
||||||
vue_on_create() {
|
vue_on_create() {
|
||||||
this.alert_event = event_bus.event('message.alert')
|
this.alert_event = event_bus.event('message.alert')
|
||||||
|
|||||||
@@ -195,31 +195,35 @@ export default class EditProfileComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return ['user_id'] }
|
static get props() { return ['user_id'] }
|
||||||
|
|
||||||
profile_first = ''
|
constructor() {
|
||||||
profile_last = ''
|
super()
|
||||||
profile_email = ''
|
|
||||||
profile_tagline = ''
|
|
||||||
last_reset = ''
|
|
||||||
mfa_enable_date = ''
|
|
||||||
|
|
||||||
has_mfa_recovery = false
|
this.profile_first = ''
|
||||||
mfa_recovery_date = ''
|
this.profile_last = ''
|
||||||
mfa_recovery_codes = 0
|
this.profile_email = ''
|
||||||
|
this.profile_tagline = ''
|
||||||
|
this.last_reset = ''
|
||||||
|
this.mfa_enable_date = ''
|
||||||
|
|
||||||
form_message = 'No changes.'
|
this.has_mfa_recovery = false
|
||||||
|
this.mfa_recovery_date = ''
|
||||||
|
this.mfa_recovery_codes = 0
|
||||||
|
|
||||||
has_mfa = false
|
this.form_message = 'No changes.'
|
||||||
ready = false
|
|
||||||
|
|
||||||
notify_gateway_url = ''
|
this.has_mfa = false
|
||||||
notify_app_key = ''
|
this.ready = false
|
||||||
notify_enabled = false
|
|
||||||
notify_created_on = ''
|
|
||||||
notify_loaded = false
|
|
||||||
|
|
||||||
app_passwords = []
|
this.notify_gateway_url = ''
|
||||||
app_name = ''
|
this.notify_app_key = ''
|
||||||
t = {}
|
this.notify_enabled = false
|
||||||
|
this.notify_created_on = ''
|
||||||
|
this.notify_loaded = false
|
||||||
|
|
||||||
|
this.app_passwords = []
|
||||||
|
this.app_name = ''
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
on_key_up = ($event) => {}
|
on_key_up = ($event) => {}
|
||||||
|
|
||||||
|
|||||||
@@ -72,12 +72,16 @@ export default class AppPasswordFormComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get props() { return [] }
|
static get props() { return [] }
|
||||||
|
|
||||||
name = ''
|
constructor() {
|
||||||
valid = false
|
super()
|
||||||
uuid = ''
|
|
||||||
enable_form = true
|
this.name = ''
|
||||||
display_password = ''
|
this.valid = false
|
||||||
t = {}
|
this.uuid = ''
|
||||||
|
this.enable_form = true
|
||||||
|
this.display_password = ''
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.t = await T(
|
this.t = await T(
|
||||||
|
|||||||
@@ -29,8 +29,12 @@ export default class ProfilePhotoUploaderComponent extends Component {
|
|||||||
static get template() { return template }
|
static get template() { return template }
|
||||||
static get params() { return [] }
|
static get params() { return [] }
|
||||||
|
|
||||||
ready = false
|
constructor() {
|
||||||
t = {}
|
super()
|
||||||
|
|
||||||
|
this.ready = false
|
||||||
|
this.t = {}
|
||||||
|
}
|
||||||
|
|
||||||
async vue_on_create() {
|
async vue_on_create() {
|
||||||
this.t = await T(
|
this.t = await T(
|
||||||
|
|||||||
@@ -2,126 +2,130 @@ import CRUDBase from './CRUDBase.js'
|
|||||||
import { session } from '../service/Session.service.js'
|
import { session } from '../service/Session.service.js'
|
||||||
|
|
||||||
class AppResource extends CRUDBase {
|
class AppResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/applications'
|
constructor() {
|
||||||
required_fields = ['name', 'identifier']
|
super()
|
||||||
permission_base = 'v1:applications'
|
|
||||||
|
|
||||||
item = 'Application'
|
this.endpoint = '/api/v1/applications'
|
||||||
plural = 'Applications'
|
this.required_fields = ['name', 'identifier']
|
||||||
|
this.permission_base = 'v1:applications'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'Application'
|
||||||
display: `
|
this.plural = 'Applications'
|
||||||
|
|
||||||
|
this.listing_definition = {
|
||||||
|
display: `
|
||||||
An application is anything that can authenticate users against ${session.get('app.name')}. Applications can have any number of associated LDAP clients, SAML service providers, and OAuth2 clients.
|
An application is anything that can authenticate users against ${session.get('app.name')}. Applications can have any number of associated LDAP clients, SAML service providers, and OAuth2 clients.
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
field: 'name',
|
field: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Identifier',
|
name: 'Identifier',
|
||||||
field: 'identifier',
|
field: 'identifier',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Description',
|
name: 'Description',
|
||||||
field: 'description',
|
field: 'description',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'main',
|
position: 'main',
|
||||||
action: 'insert',
|
action: 'insert',
|
||||||
text: 'Manual Setup',
|
text: 'Manual Setup',
|
||||||
color: 'outline-success',
|
color: 'outline-success',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
position: 'main',
|
position: 'main',
|
||||||
action: 'redirect',
|
action: 'redirect',
|
||||||
text: 'Setup Wizard',
|
text: 'Setup Wizard',
|
||||||
color: 'success',
|
color: 'success',
|
||||||
next: '/dash/app/setup',
|
next: '/dash/app/setup',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'update',
|
action: 'update',
|
||||||
icon: 'fa fa-edit',
|
icon: 'fa fa-edit',
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'delete',
|
action: 'delete',
|
||||||
icon: 'fa fa-times',
|
icon: 'fa fa-times',
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
confirm: true,
|
confirm: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
form_definition = {
|
this.form_definition = {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
field: 'name',
|
field: 'name',
|
||||||
placeholder: 'Awesome App',
|
placeholder: 'Awesome App',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Identifier',
|
|
||||||
field: 'identifier',
|
|
||||||
placeholder: 'awesome_app',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Description',
|
|
||||||
field: 'description',
|
|
||||||
type: 'textarea',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Associated LDAP Clients',
|
|
||||||
field: 'ldap_client_ids',
|
|
||||||
type: 'select.dynamic.multiple',
|
|
||||||
options: {
|
|
||||||
resource: 'ldap/Client',
|
|
||||||
display: 'name',
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Identifier',
|
||||||
name: 'Associated OAuth2 Clients',
|
field: 'identifier',
|
||||||
field: 'oauth_client_ids',
|
placeholder: 'awesome_app',
|
||||||
type: 'select.dynamic.multiple',
|
required: true,
|
||||||
options: {
|
type: 'text',
|
||||||
resource: 'oauth/Client',
|
|
||||||
display: 'name',
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Description',
|
||||||
name: 'Associated OpenID Connect Clients',
|
field: 'description',
|
||||||
field: 'openid_client_ids',
|
type: 'textarea',
|
||||||
type: 'select.dynamic.multiple',
|
|
||||||
options: {
|
|
||||||
resource: 'openid/Client',
|
|
||||||
display: 'client_name',
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Associated LDAP Clients',
|
||||||
name: 'Associated SAML Service Providers',
|
field: 'ldap_client_ids',
|
||||||
field: 'saml_service_provider_ids',
|
type: 'select.dynamic.multiple',
|
||||||
type: 'select.dynamic.multiple',
|
options: {
|
||||||
options: {
|
resource: 'ldap/Client',
|
||||||
resource: 'saml/Provider',
|
display: 'name',
|
||||||
display: 'name',
|
value: 'id',
|
||||||
value: 'id',
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
],
|
name: 'Associated OAuth2 Clients',
|
||||||
|
field: 'oauth_client_ids',
|
||||||
|
type: 'select.dynamic.multiple',
|
||||||
|
options: {
|
||||||
|
resource: 'oauth/Client',
|
||||||
|
display: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Associated OpenID Connect Clients',
|
||||||
|
field: 'openid_client_ids',
|
||||||
|
type: 'select.dynamic.multiple',
|
||||||
|
options: {
|
||||||
|
resource: 'openid/Client',
|
||||||
|
display: 'client_name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Associated SAML Service Providers',
|
||||||
|
field: 'saml_service_provider_ids',
|
||||||
|
type: 'select.dynamic.multiple',
|
||||||
|
options: {
|
||||||
|
resource: 'saml/Provider',
|
||||||
|
display: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,17 @@ import APIParseError from './APIParseError.js'
|
|||||||
import { session } from '../service/Session.service.js'
|
import { session } from '../service/Session.service.js'
|
||||||
|
|
||||||
export default class CRUDBase {
|
export default class CRUDBase {
|
||||||
endpoint = '/api/v1'
|
constructor() {
|
||||||
required_fields = []
|
this.endpoint = '/api/v1'
|
||||||
permission_base = ''
|
this.required_fields = []
|
||||||
|
this.permission_base = ''
|
||||||
|
|
||||||
listing_definition = {}
|
this.listing_definition = {}
|
||||||
form_definition = {}
|
this.form_definition = {}
|
||||||
|
|
||||||
item = ''
|
this.item = ''
|
||||||
plural = ''
|
this.plural = ''
|
||||||
|
}
|
||||||
|
|
||||||
async can(action) {
|
async can(action) {
|
||||||
return session.check_permissions(`${this.permission_base}:${action}`)
|
return session.check_permissions(`${this.permission_base}:${action}`)
|
||||||
|
|||||||
@@ -2,53 +2,57 @@ import CRUDBase from './CRUDBase.js'
|
|||||||
import { session } from '../service/Session.service.js'
|
import { session } from '../service/Session.service.js'
|
||||||
|
|
||||||
class SettingResource extends CRUDBase {
|
class SettingResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/settings'
|
constructor() {
|
||||||
required_fields = ['key', 'value']
|
super()
|
||||||
permission_base = 'v1:settings'
|
|
||||||
|
|
||||||
item = 'Setting'
|
this.endpoint = '/api/v1/settings'
|
||||||
plural = 'Settings'
|
this.required_fields = ['key', 'value']
|
||||||
|
this.permission_base = 'v1:settings'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'Setting'
|
||||||
display: `
|
this.plural = 'Settings'
|
||||||
|
|
||||||
|
this.listing_definition = {
|
||||||
|
display: `
|
||||||
<p>These are advanced settings that allow you to tweak the way ${session.get('app.name')} behaves. Tweak them at your own risk.</p>
|
<p>These are advanced settings that allow you to tweak the way ${session.get('app.name')} behaves. Tweak them at your own risk.</p>
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Setting Key',
|
name: 'Setting Key',
|
||||||
field: 'key',
|
field: 'key',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Value',
|
name: 'Value',
|
||||||
field: 'value',
|
field: 'value',
|
||||||
renderer: (v) => JSON.stringify(v),
|
renderer: (v) => JSON.stringify(v),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'update',
|
action: 'update',
|
||||||
icon: 'fa fa-edit',
|
icon: 'fa fa-edit',
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
form_definition = {
|
this.form_definition = {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'Setting Key',
|
name: 'Setting Key',
|
||||||
field: 'key',
|
field: 'key',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
readonly: true,
|
readonly: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Value (JSON)',
|
name: 'Value (JSON)',
|
||||||
field: 'value',
|
field: 'value',
|
||||||
type: 'json',
|
type: 'json',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,74 +2,78 @@ import CRUDBase from '../CRUDBase.js'
|
|||||||
import { session } from '../../service/Session.service.js'
|
import { session } from '../../service/Session.service.js'
|
||||||
|
|
||||||
class GroupResource extends CRUDBase {
|
class GroupResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/auth/groups'
|
constructor() {
|
||||||
required_fields = ['name']
|
super()
|
||||||
permission_base = 'v1:auth:groups'
|
|
||||||
|
|
||||||
item = 'Group'
|
this.endpoint = '/api/v1/auth/groups'
|
||||||
plural = 'Groups'
|
this.required_fields = ['name']
|
||||||
|
this.permission_base = 'v1:auth:groups'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'Group'
|
||||||
display: `
|
this.plural = 'Groups'
|
||||||
In ${session.get('app.name')}, groups are simply a tool for organizing users and assigning permissions and access in bulk. After creating and assigning users to a group, you can manage permissions for that group, and its policies will be applied to all users in that group.
|
|
||||||
`,
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'Name',
|
|
||||||
field: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '# of Users',
|
|
||||||
field: 'user_ids',
|
|
||||||
renderer: (user_ids) => Array.isArray(user_ids) ? user_ids.length : 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'main',
|
|
||||||
action: 'insert',
|
|
||||||
text: 'Create New',
|
|
||||||
color: 'success',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'update',
|
|
||||||
icon: 'fa fa-edit',
|
|
||||||
color: 'primary',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'delete',
|
|
||||||
icon: 'fa fa-times',
|
|
||||||
color: 'danger',
|
|
||||||
confirm: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
form_definition = {
|
this.listing_definition = {
|
||||||
fields: [
|
display: `
|
||||||
{
|
In ${session.get('app.name')}, groups are simply a tool for organizing users and assigning permissions and access in bulk. After creating and assigning users to a group, you can manage permissions for that group, and its policies will be applied to all users in that group.
|
||||||
name: 'Name',
|
`,
|
||||||
field: 'name',
|
columns: [
|
||||||
placeholder: 'Some Cool Users',
|
{
|
||||||
required: true,
|
name: 'Name',
|
||||||
type: 'text',
|
field: 'name',
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Users',
|
|
||||||
field: 'user_ids',
|
|
||||||
type: 'select.dynamic.multiple',
|
|
||||||
options: {
|
|
||||||
resource: 'auth/User',
|
|
||||||
display: (user) => `${user.last_name}, ${user.first_name} (${user.uid})`,
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
],
|
name: '# of Users',
|
||||||
|
field: 'user_ids',
|
||||||
|
renderer: (user_ids) => Array.isArray(user_ids) ? user_ids.length : 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'main',
|
||||||
|
action: 'insert',
|
||||||
|
text: 'Create New',
|
||||||
|
color: 'success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'update',
|
||||||
|
icon: 'fa fa-edit',
|
||||||
|
color: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'delete',
|
||||||
|
icon: 'fa fa-times',
|
||||||
|
color: 'danger',
|
||||||
|
confirm: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form_definition = {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'Name',
|
||||||
|
field: 'name',
|
||||||
|
placeholder: 'Some Cool Users',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Users',
|
||||||
|
field: 'user_ids',
|
||||||
|
type: 'select.dynamic.multiple',
|
||||||
|
options: {
|
||||||
|
resource: 'auth/User',
|
||||||
|
display: (user) => `${user.last_name}, ${user.first_name} (${user.uid})`,
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
import CRUDBase from '../CRUDBase.js'
|
import CRUDBase from '../CRUDBase.js'
|
||||||
|
|
||||||
class RoleResource extends CRUDBase {
|
class RoleResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/auth/roles'
|
|
||||||
required_fields = ['role', 'permissions']
|
|
||||||
permission_base = 'v1:auth:roles'
|
|
||||||
|
|
||||||
item = 'Role'
|
constructor() {
|
||||||
plural = 'Roles'
|
super()
|
||||||
|
|
||||||
|
this.endpoint = '/api/v1/auth/roles'
|
||||||
|
this.required_fields = ['role', 'permissions']
|
||||||
|
this.permission_base = 'v1:auth:roles'
|
||||||
|
|
||||||
|
this.item = 'Role'
|
||||||
|
this.plural = 'Roles'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auth_role = new RoleResource()
|
const auth_role = new RoleResource()
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import CRUDBase from '../CRUDBase.js'
|
import CRUDBase from '../CRUDBase.js'
|
||||||
|
|
||||||
class TrapResource extends CRUDBase {
|
class TrapResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/auth/traps'
|
constructor() {
|
||||||
required_fields = ['name', 'trap', 'redirect_to']
|
super()
|
||||||
permission_base = 'v1:auth:traps'
|
|
||||||
|
|
||||||
item = 'Trap'
|
this.endpoint = '/api/v1/auth/traps'
|
||||||
plural = 'Traps'
|
this.required_fields = ['name', 'trap', 'redirect_to']
|
||||||
|
this.permission_base = 'v1:auth:traps'
|
||||||
|
|
||||||
|
this.item = 'Trap'
|
||||||
|
this.plural = 'Traps'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auth_trap = new TrapResource()
|
const auth_trap = new TrapResource()
|
||||||
|
|||||||
@@ -2,114 +2,118 @@ import CRUDBase from '../CRUDBase.js'
|
|||||||
import { session } from '../../service/Session.service.js'
|
import { session } from '../../service/Session.service.js'
|
||||||
|
|
||||||
class UserResource extends CRUDBase {
|
class UserResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/auth/users'
|
constructor() {
|
||||||
required_fields = ['uid', 'first_name', 'last_name', 'email']
|
super()
|
||||||
permission_base = 'v1:auth:users'
|
|
||||||
|
|
||||||
item = 'User'
|
this.endpoint = '/api/v1/auth/users'
|
||||||
plural = 'Users'
|
this.required_fields = ['uid', 'first_name', 'last_name', 'email']
|
||||||
|
this.permission_base = 'v1:auth:users'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'User'
|
||||||
display: `
|
this.plural = 'Users'
|
||||||
|
|
||||||
|
this.listing_definition = {
|
||||||
|
display: `
|
||||||
Users can be assigned permissions and, if granted, can manage their ${session.get('app.name')} accounts from the Profile page, as well as login to the external applications they've been given access to.
|
Users can be assigned permissions and, if granted, can manage their ${session.get('app.name')} accounts from the Profile page, as well as login to the external applications they've been given access to.
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'UID',
|
name: 'UID',
|
||||||
field: 'uid',
|
field: 'uid',
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Last Name',
|
|
||||||
field: 'last_name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'First Name',
|
|
||||||
field: 'first_name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'E-Mail',
|
|
||||||
field: 'email',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'main',
|
|
||||||
action: 'insert',
|
|
||||||
text: 'Create New',
|
|
||||||
color: 'success',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'update',
|
|
||||||
icon: 'fa fa-edit',
|
|
||||||
color: 'primary',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'delete',
|
|
||||||
icon: 'fa fa-times',
|
|
||||||
color: 'danger',
|
|
||||||
confirm: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
form_definition = {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: 'First Name',
|
|
||||||
field: 'first_name',
|
|
||||||
placeholder: 'John',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Last Name',
|
|
||||||
field: 'last_name',
|
|
||||||
placeholder: 'Doe',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Username',
|
|
||||||
field: 'uid',
|
|
||||||
placeholder: 'john.doe',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'E-Mail',
|
|
||||||
field: 'email',
|
|
||||||
placeholder: 'john@contoso.com',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tagline',
|
|
||||||
field: 'tagline',
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Password',
|
|
||||||
field: 'password',
|
|
||||||
type: 'password',
|
|
||||||
placeholder: 'Password',
|
|
||||||
required: ['insert'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Trap',
|
|
||||||
field: 'trap',
|
|
||||||
type: 'select.dynamic',
|
|
||||||
options: {
|
|
||||||
resource: 'auth/Trap',
|
|
||||||
display: 'name',
|
|
||||||
value: 'trap',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
],
|
name: 'Last Name',
|
||||||
|
field: 'last_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'First Name',
|
||||||
|
field: 'first_name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'E-Mail',
|
||||||
|
field: 'email',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'main',
|
||||||
|
action: 'insert',
|
||||||
|
text: 'Create New',
|
||||||
|
color: 'success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'update',
|
||||||
|
icon: 'fa fa-edit',
|
||||||
|
color: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'delete',
|
||||||
|
icon: 'fa fa-times',
|
||||||
|
color: 'danger',
|
||||||
|
confirm: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form_definition = {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'First Name',
|
||||||
|
field: 'first_name',
|
||||||
|
placeholder: 'John',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Last Name',
|
||||||
|
field: 'last_name',
|
||||||
|
placeholder: 'Doe',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Username',
|
||||||
|
field: 'uid',
|
||||||
|
placeholder: 'john.doe',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'E-Mail',
|
||||||
|
field: 'email',
|
||||||
|
placeholder: 'john@contoso.com',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Tagline',
|
||||||
|
field: 'tagline',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Password',
|
||||||
|
field: 'password',
|
||||||
|
type: 'password',
|
||||||
|
placeholder: 'Password',
|
||||||
|
required: ['insert'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Trap',
|
||||||
|
field: 'trap',
|
||||||
|
type: 'select.dynamic',
|
||||||
|
options: {
|
||||||
|
resource: 'auth/Trap',
|
||||||
|
display: 'name',
|
||||||
|
value: 'trap',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,18 @@ import CRUDBase from '../CRUDBase.js'
|
|||||||
import { session } from '../../service/Session.service.js'
|
import { session } from '../../service/Session.service.js'
|
||||||
|
|
||||||
class PolicyResource extends CRUDBase {
|
class PolicyResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/iam/policy'
|
constructor() {
|
||||||
required_fields = ['entity_id', 'entity_type', 'target_id', 'target_type', 'access_type']
|
super()
|
||||||
permission_base = 'v1:iam:policy'
|
|
||||||
|
|
||||||
item = 'IAM Policy'
|
this.endpoint = '/api/v1/iam/policy'
|
||||||
plural = 'IAM Policies'
|
this.required_fields = ['entity_id', 'entity_type', 'target_id', 'target_type', 'access_type']
|
||||||
|
this.permission_base = 'v1:iam:policy'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'IAM Policy'
|
||||||
display: `
|
this.plural = 'IAM Policies'
|
||||||
|
|
||||||
|
this.listing_definition = {
|
||||||
|
display: `
|
||||||
Identity & Access Management (IAM) policies give you fine grained control over which ${session.get('app.name')} users and groups are allowed to access which applications.
|
Identity & Access Management (IAM) policies give you fine grained control over which ${session.get('app.name')} users and groups are allowed to access which applications.
|
||||||
<br><br>
|
<br><br>
|
||||||
An IAM policy has three parts. First, is the subject. The subject is who the policy applies to and is either a user or a group. The second part is the access type. This is either an allowance or a denial. That is, the policy either grants a subject access to a resource, or explicitly denies them access. The final part of the policy is the target. This is the application that the subject is being granted or denied access to.
|
An IAM policy has three parts. First, is the subject. The subject is who the policy applies to and is either a user or a group. The second part is the access type. This is either an allowance or a denial. That is, the policy either grants a subject access to a resource, or explicitly denies them access. The final part of the policy is the target. This is the application that the subject is being granted or denied access to.
|
||||||
@@ -24,136 +27,137 @@ class PolicyResource extends CRUDBase {
|
|||||||
</ol>
|
</ol>
|
||||||
This means, for example, that if a user's group is allowed access, but a user is denied access, the user will be denied access. Likewise, if there are two policies for a subject, one granting them access and one denying them access, the denial will take precedence.
|
This means, for example, that if a user's group is allowed access, but a user is denied access, the user will be denied access. Likewise, if there are two policies for a subject, one granting them access and one denying them access, the denial will take precedence.
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Subject',
|
name: 'Subject',
|
||||||
field: 'entity_display',
|
field: 'entity_display',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Access Type',
|
name: 'Access Type',
|
||||||
field: 'access_type',
|
field: 'access_type',
|
||||||
renderer: access_type => access_type === 'deny' ? '...is denied access to...' : '...is granted access to...',
|
renderer: access_type => access_type === 'deny' ? '...is denied access to...' : '...is granted access to...',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Target',
|
name: 'Target',
|
||||||
field: 'target_display',
|
field: 'target_display',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'main',
|
position: 'main',
|
||||||
action: 'insert',
|
action: 'insert',
|
||||||
text: 'Create New',
|
text: 'Create New',
|
||||||
color: 'success',
|
color: 'success',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'update',
|
action: 'update',
|
||||||
icon: 'fa fa-edit',
|
icon: 'fa fa-edit',
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'delete',
|
action: 'delete',
|
||||||
icon: 'fa fa-times',
|
icon: 'fa fa-times',
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
confirm: true,
|
confirm: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
form_definition = {
|
this.form_definition = {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'Subject Type',
|
name: 'Subject Type',
|
||||||
field: 'entity_type',
|
field: 'entity_type',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'select',
|
type: 'select',
|
||||||
options: [
|
options: [
|
||||||
{ display: 'User', value: 'user' },
|
{display: 'User', value: 'user'},
|
||||||
{ display: 'Group', value: 'group' },
|
{display: 'Group', value: 'group'},
|
||||||
],
|
],
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Subject',
|
|
||||||
field: 'entity_id',
|
|
||||||
required: true,
|
|
||||||
type: 'select.dynamic',
|
|
||||||
options: {
|
|
||||||
resource: 'auth/User',
|
|
||||||
display: user => `User: ${user.last_name}, ${user.first_name} (${user.uid})`,
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
if: (form_data) => form_data.entity_type === 'user',
|
{
|
||||||
},
|
name: 'Subject',
|
||||||
{
|
field: 'entity_id',
|
||||||
name: 'Subject',
|
required: true,
|
||||||
field: 'entity_id',
|
type: 'select.dynamic',
|
||||||
required: true,
|
options: {
|
||||||
type: 'select.dynamic',
|
resource: 'auth/User',
|
||||||
options: {
|
display: user => `User: ${user.last_name}, ${user.first_name} (${user.uid})`,
|
||||||
resource: 'auth/Group',
|
value: 'id',
|
||||||
display: group => `Group: ${group.name} (${group.user_ids.length} users)`,
|
},
|
||||||
value: 'id',
|
if: (form_data) => form_data.entity_type === 'user',
|
||||||
},
|
},
|
||||||
if: (form_data) => form_data.entity_type === 'group',
|
{
|
||||||
},
|
name: 'Subject',
|
||||||
{
|
field: 'entity_id',
|
||||||
name: 'Access Type',
|
required: true,
|
||||||
field: 'access_type',
|
type: 'select.dynamic',
|
||||||
required: true,
|
options: {
|
||||||
type: 'select',
|
resource: 'auth/Group',
|
||||||
options: [
|
display: group => `Group: ${group.name} (${group.user_ids.length} users)`,
|
||||||
{ display: '...is granted access to...', value: 'allow' },
|
value: 'id',
|
||||||
{ display: '...is denied access to...', value: 'deny' },
|
},
|
||||||
],
|
if: (form_data) => form_data.entity_type === 'group',
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Target Type',
|
|
||||||
field: 'target_type',
|
|
||||||
required: true,
|
|
||||||
type: 'select',
|
|
||||||
options: [
|
|
||||||
{ display: 'Application', value: 'application' },
|
|
||||||
{ display: 'API Scope', value: 'api_scope' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Target',
|
|
||||||
field: 'target_id',
|
|
||||||
required: true,
|
|
||||||
type: 'select.dynamic',
|
|
||||||
options: {
|
|
||||||
resource: 'App',
|
|
||||||
display: 'name',
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
if: (form_data) => form_data.target_type === 'application'
|
{
|
||||||
},
|
name: 'Access Type',
|
||||||
{
|
field: 'access_type',
|
||||||
name: 'Target',
|
required: true,
|
||||||
field: 'target_id',
|
type: 'select',
|
||||||
required: true,
|
options: [
|
||||||
type: 'select.dynamic',
|
{display: '...is granted access to...', value: 'allow'},
|
||||||
options: {
|
{display: '...is denied access to...', value: 'deny'},
|
||||||
resource: 'reflect/Scope',
|
],
|
||||||
display: 'scope',
|
|
||||||
value: 'scope',
|
|
||||||
},
|
},
|
||||||
if: (form_data) => form_data.target_type === 'api_scope'
|
{
|
||||||
},
|
name: 'Target Type',
|
||||||
],
|
field: 'target_type',
|
||||||
/*handlers: {
|
required: true,
|
||||||
insert: {
|
type: 'select',
|
||||||
action: 'back',
|
options: [
|
||||||
},
|
{display: 'Application', value: 'application'},
|
||||||
update: {
|
{display: 'API Scope', value: 'api_scope'},
|
||||||
action: 'back',
|
],
|
||||||
},
|
},
|
||||||
},*/
|
{
|
||||||
|
name: 'Target',
|
||||||
|
field: 'target_id',
|
||||||
|
required: true,
|
||||||
|
type: 'select.dynamic',
|
||||||
|
options: {
|
||||||
|
resource: 'App',
|
||||||
|
display: 'name',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
if: (form_data) => form_data.target_type === 'application'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Target',
|
||||||
|
field: 'target_id',
|
||||||
|
required: true,
|
||||||
|
type: 'select.dynamic',
|
||||||
|
options: {
|
||||||
|
resource: 'reflect/Scope',
|
||||||
|
display: 'scope',
|
||||||
|
value: 'scope',
|
||||||
|
},
|
||||||
|
if: (form_data) => form_data.target_type === 'api_scope'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
/*handlers: {
|
||||||
|
insert: {
|
||||||
|
action: 'back',
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
action: 'back',
|
||||||
|
},
|
||||||
|
},*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,83 +2,88 @@ import CRUDBase from '../CRUDBase.js'
|
|||||||
import { session } from '../../service/Session.service.js'
|
import { session } from '../../service/Session.service.js'
|
||||||
|
|
||||||
class ClientResource extends CRUDBase {
|
class ClientResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/ldap/clients'
|
constructor() {
|
||||||
required_fields = ['name', 'uid', 'password']
|
super()
|
||||||
permission_base = 'v1:ldap:clients'
|
|
||||||
|
|
||||||
item = 'LDAP Client'
|
this.endpoint = '/api/v1/ldap/clients'
|
||||||
plural = 'LDAP Clients'
|
this.required_fields = ['name', 'uid', 'password']
|
||||||
|
this.permission_base = 'v1:ldap:clients'
|
||||||
|
|
||||||
async server_config() {
|
this.item = 'LDAP Client'
|
||||||
const results = await axios.get('/api/v1/ldap/config')
|
this.plural = 'LDAP Clients'
|
||||||
if ( results && results.data && results.data.data ) return results.data.data
|
|
||||||
}
|
|
||||||
|
|
||||||
listing_definition = {
|
|
||||||
display: `
|
this.listing_definition = {
|
||||||
|
display: `
|
||||||
LDAP Clients are special user accounts that external applications can use to bind to ${session.get('app.name')}'s built-in LDAP server to allow these applications to authenticate users.
|
LDAP Clients are special user accounts that external applications can use to bind to ${session.get('app.name')}'s built-in LDAP server to allow these applications to authenticate users.
|
||||||
<br><br>
|
<br><br>
|
||||||
These special accounts are permitted to bind to the LDAP server, but are not allowed to sign-in to ${session.get('app.name')}.
|
These special accounts are permitted to bind to the LDAP server, but are not allowed to sign-in to ${session.get('app.name')}.
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Client Name',
|
name: 'Client Name',
|
||||||
field: 'name',
|
field: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'User ID',
|
name: 'User ID',
|
||||||
field: 'uid',
|
field: 'uid',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'main',
|
position: 'main',
|
||||||
action: 'insert',
|
action: 'insert',
|
||||||
text: 'Create New',
|
text: 'Create New',
|
||||||
color: 'success',
|
color: 'success',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'update',
|
action: 'update',
|
||||||
icon: 'fa fa-edit',
|
icon: 'fa fa-edit',
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'delete',
|
action: 'delete',
|
||||||
icon: 'fa fa-times',
|
icon: 'fa fa-times',
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
confirm: true,
|
confirm: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form_definition = {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'Provider Name',
|
||||||
|
field: 'name',
|
||||||
|
placeholder: 'Awesome External App',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'User ID',
|
||||||
|
field: 'uid',
|
||||||
|
placeholder: 'some_username',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Password',
|
||||||
|
field: 'password',
|
||||||
|
required: ['insert'],
|
||||||
|
type: 'password',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
form_definition = {
|
async server_config() {
|
||||||
fields: [
|
const results = await axios.get('/api/v1/ldap/config')
|
||||||
{
|
if (results && results.data && results.data.data) return results.data.data
|
||||||
name: 'Provider Name',
|
|
||||||
field: 'name',
|
|
||||||
placeholder: 'Awesome External App',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'User ID',
|
|
||||||
field: 'uid',
|
|
||||||
placeholder: 'some_username',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Password',
|
|
||||||
field: 'password',
|
|
||||||
required: ['insert'],
|
|
||||||
type: 'password',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,97 +1,101 @@
|
|||||||
import CRUDBase from '../CRUDBase.js'
|
import CRUDBase from '../CRUDBase.js'
|
||||||
|
|
||||||
class GroupResource extends CRUDBase {
|
class GroupResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/ldap/groups'
|
constructor() {
|
||||||
required_fields = ['name', 'role']
|
super()
|
||||||
permission_base = 'v1:ldap:groups'
|
|
||||||
|
|
||||||
item = 'LDAP Group'
|
this.endpoint = '/api/v1/ldap/groups'
|
||||||
plural = 'LDAP Groups'
|
this.required_fields = ['name', 'role']
|
||||||
|
this.permission_base = 'v1:ldap:groups'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'LDAP Group'
|
||||||
columns: [
|
this.plural = 'LDAP Groups'
|
||||||
{
|
|
||||||
name: 'Group Name',
|
|
||||||
field: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Role',
|
|
||||||
field: 'role',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '# of Users',
|
|
||||||
field: 'user_ids',
|
|
||||||
renderer: (user_ids) => Array.isArray(user_ids) ? user_ids.length : 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'main',
|
|
||||||
action: 'insert',
|
|
||||||
text: 'Create New',
|
|
||||||
color: 'success',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'update',
|
|
||||||
icon: 'fa fa-edit',
|
|
||||||
color: 'primary',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'delete',
|
|
||||||
icon: 'fa fa-times',
|
|
||||||
color: 'danger',
|
|
||||||
confirm: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
form_definition = {
|
this.listing_definition = {
|
||||||
// back_action: {
|
columns: [
|
||||||
// text: 'Back',
|
{
|
||||||
// action: 'back',
|
name: 'Group Name',
|
||||||
// },
|
field: 'name',
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: 'Group Name',
|
|
||||||
field: 'name',
|
|
||||||
placeholder: 'External App Users',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Role',
|
|
||||||
field: 'role',
|
|
||||||
placeholder: 'external_app',
|
|
||||||
required: true,
|
|
||||||
type: 'select.dynamic',
|
|
||||||
options: {
|
|
||||||
resource: 'auth/Role',
|
|
||||||
display: 'role',
|
|
||||||
value: 'role',
|
|
||||||
},
|
},
|
||||||
// options: [
|
{
|
||||||
// { value: 1, display: 'One' },
|
name: 'Role',
|
||||||
// { value: 2, display: 'Two' },
|
field: 'role',
|
||||||
// { value: 3, display: 'Three' },
|
|
||||||
// ],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Users',
|
|
||||||
field: 'user_ids',
|
|
||||||
placeholder: 'John Doe',
|
|
||||||
type: 'select.dynamic.multiple',
|
|
||||||
options: {
|
|
||||||
resource: 'auth/User',
|
|
||||||
display: (user) => `${user.last_name}, ${user.first_name} (${user.uid})`,
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
],
|
name: '# of Users',
|
||||||
|
field: 'user_ids',
|
||||||
|
renderer: (user_ids) => Array.isArray(user_ids) ? user_ids.length : 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'main',
|
||||||
|
action: 'insert',
|
||||||
|
text: 'Create New',
|
||||||
|
color: 'success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'update',
|
||||||
|
icon: 'fa fa-edit',
|
||||||
|
color: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'delete',
|
||||||
|
icon: 'fa fa-times',
|
||||||
|
color: 'danger',
|
||||||
|
confirm: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form_definition = {
|
||||||
|
// back_action: {
|
||||||
|
// text: 'Back',
|
||||||
|
// action: 'back',
|
||||||
|
// },
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'Group Name',
|
||||||
|
field: 'name',
|
||||||
|
placeholder: 'External App Users',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Role',
|
||||||
|
field: 'role',
|
||||||
|
placeholder: 'external_app',
|
||||||
|
required: true,
|
||||||
|
type: 'select.dynamic',
|
||||||
|
options: {
|
||||||
|
resource: 'auth/Role',
|
||||||
|
display: 'role',
|
||||||
|
value: 'role',
|
||||||
|
},
|
||||||
|
// options: [
|
||||||
|
// { value: 1, display: 'One' },
|
||||||
|
// { value: 2, display: 'Two' },
|
||||||
|
// { value: 3, display: 'Three' },
|
||||||
|
// ],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Users',
|
||||||
|
field: 'user_ids',
|
||||||
|
placeholder: 'John Doe',
|
||||||
|
type: 'select.dynamic.multiple',
|
||||||
|
options: {
|
||||||
|
resource: 'auth/User',
|
||||||
|
display: (user) => `${user.last_name}, ${user.first_name} (${user.uid})`,
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,104 +2,108 @@ import CRUDBase from '../CRUDBase.js'
|
|||||||
import { session } from '../../service/Session.service.js';
|
import { session } from '../../service/Session.service.js';
|
||||||
|
|
||||||
class ClientResource extends CRUDBase {
|
class ClientResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/oauth/clients'
|
constructor() {
|
||||||
required_fields = ['name', 'redirect_url', 'api_scopes']
|
super()
|
||||||
permission_base = 'v1:oauth:clients'
|
|
||||||
|
|
||||||
item = 'OAuth2 Client'
|
this.endpoint = '/api/v1/oauth/clients'
|
||||||
plural = 'OAuth2 Clients'
|
this.required_fields = ['name', 'redirect_url', 'api_scopes']
|
||||||
|
this.permission_base = 'v1:oauth:clients'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'OAuth2 Client'
|
||||||
display: `
|
this.plural = 'OAuth2 Clients'
|
||||||
|
|
||||||
|
this.listing_definition = {
|
||||||
|
display: `
|
||||||
OAuth2 clients are applications that support authentication over the OAuth2 protocol. This allows you to add a "Sign-In with XXX" button for ${session.get('app.name')} to the application in question. To do this, you need to create an OAuth2 client for that application, and provide the name, redirect URL, and API scopes.
|
OAuth2 clients are applications that support authentication over the OAuth2 protocol. This allows you to add a "Sign-In with XXX" button for ${session.get('app.name')} to the application in question. To do this, you need to create an OAuth2 client for that application, and provide the name, redirect URL, and API scopes.
|
||||||
<br><br>
|
<br><br>
|
||||||
You must select the API scopes to grant this OAuth2 client. This defines what ${session.get('app.name')} endpoints the application is allowed to access. For most applications, granting the <code>v1:api:users:get</code> and <code>v1:api:groups:get</code> API scopes should be sufficient.
|
You must select the API scopes to grant this OAuth2 client. This defines what ${session.get('app.name')} endpoints the application is allowed to access. For most applications, granting the <code>v1:api:users:get</code> and <code>v1:api:groups:get</code> API scopes should be sufficient.
|
||||||
<br><br>
|
<br><br>
|
||||||
This method can also be used to access the API for other purposes. Hence, the expansive API scopes. ${session.get('app.name')} uses Flitter-Auth's built-in OAuth2 server under the hood, so you can find details on how to configure the OAuth2 clients <a href="https://flitter.garrettmills.dev/tutorial-flitter-auth-oauth2-server.html" target="_blank">here.</a>
|
This method can also be used to access the API for other purposes. Hence, the expansive API scopes. ${session.get('app.name')} uses Flitter-Auth's built-in OAuth2 server under the hood, so you can find details on how to configure the OAuth2 clients <a href="https://flitter.garrettmills.dev/tutorial-flitter-auth-oauth2-server.html" target="_blank">here.</a>
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Client Name',
|
name: 'Client Name',
|
||||||
field: 'name',
|
field: 'name',
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '# of Scopes',
|
|
||||||
field: 'api_scopes',
|
|
||||||
renderer: (api_scopes) => api_scopes.length,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Redirect URL',
|
|
||||||
field: 'redirect_url',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'main',
|
|
||||||
action: 'insert',
|
|
||||||
text: 'Create New',
|
|
||||||
color: 'success',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'update',
|
|
||||||
icon: 'fa fa-edit',
|
|
||||||
color: 'primary',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'delete',
|
|
||||||
icon: 'fa fa-times',
|
|
||||||
color: 'danger',
|
|
||||||
confirm: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
form_definition = {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: 'Client Name',
|
|
||||||
field: 'name',
|
|
||||||
placeholder: 'Awesome External App',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Redirect URL',
|
|
||||||
field: 'redirect_url',
|
|
||||||
placeholder: 'https://awesome.app/oauth2/callback',
|
|
||||||
required: true,
|
|
||||||
type: 'text',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'API Scopes',
|
|
||||||
field: 'api_scopes',
|
|
||||||
type: 'select.dynamic.multiple',
|
|
||||||
options: {
|
|
||||||
resource: 'reflect/Scope',
|
|
||||||
display: 'scope',
|
|
||||||
value: 'scope',
|
|
||||||
},
|
},
|
||||||
required: true,
|
{
|
||||||
},
|
name: '# of Scopes',
|
||||||
{
|
field: 'api_scopes',
|
||||||
name: 'Client ID',
|
renderer: (api_scopes) => api_scopes.length,
|
||||||
field: 'uuid',
|
},
|
||||||
type: 'text',
|
{
|
||||||
readonly: true,
|
name: 'Redirect URL',
|
||||||
hidden: ['insert'],
|
field: 'redirect_url',
|
||||||
},
|
},
|
||||||
{
|
],
|
||||||
name: 'Client Secret',
|
actions: [
|
||||||
field: 'secret',
|
{
|
||||||
type: 'text',
|
type: 'resource',
|
||||||
readonly: true,
|
position: 'main',
|
||||||
hidden: ['insert'],
|
action: 'insert',
|
||||||
},
|
text: 'Create New',
|
||||||
],
|
color: 'success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'update',
|
||||||
|
icon: 'fa fa-edit',
|
||||||
|
color: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'delete',
|
||||||
|
icon: 'fa fa-times',
|
||||||
|
color: 'danger',
|
||||||
|
confirm: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form_definition = {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'Client Name',
|
||||||
|
field: 'name',
|
||||||
|
placeholder: 'Awesome External App',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Redirect URL',
|
||||||
|
field: 'redirect_url',
|
||||||
|
placeholder: 'https://awesome.app/oauth2/callback',
|
||||||
|
required: true,
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'API Scopes',
|
||||||
|
field: 'api_scopes',
|
||||||
|
type: 'select.dynamic.multiple',
|
||||||
|
options: {
|
||||||
|
resource: 'reflect/Scope',
|
||||||
|
display: 'scope',
|
||||||
|
value: 'scope',
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Client ID',
|
||||||
|
field: 'uuid',
|
||||||
|
type: 'text',
|
||||||
|
readonly: true,
|
||||||
|
hidden: ['insert'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Client Secret',
|
||||||
|
field: 'secret',
|
||||||
|
type: 'text',
|
||||||
|
readonly: true,
|
||||||
|
hidden: ['insert'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,94 +2,98 @@ import CRUDBase from '../CRUDBase.js'
|
|||||||
import { session } from '../../service/Session.service.js'
|
import { session } from '../../service/Session.service.js'
|
||||||
|
|
||||||
class ClientResource extends CRUDBase {
|
class ClientResource extends CRUDBase {
|
||||||
endpoint = '/openid/clients'
|
constructor() {
|
||||||
required_fields = ['client_name', 'grant_types', 'redirect_uri']
|
super()
|
||||||
permission_base = 'v1:openid:clients'
|
|
||||||
|
|
||||||
item = 'OpenID Connect Client'
|
this.endpoint = '/openid/clients'
|
||||||
plural = 'OpenID Connect Clients'
|
this.required_fields = ['client_name', 'grant_types', 'redirect_uri']
|
||||||
|
this.permission_base = 'v1:openid:clients'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'OpenID Connect Client'
|
||||||
display: `
|
this.plural = 'OpenID Connect Clients'
|
||||||
|
|
||||||
|
this.listing_definition = {
|
||||||
|
display: `
|
||||||
OpenID Connect clients are applications that support authentication over the OpenID Connect protocol. This allows you to add a "Sign-In with XXX" button for ${session.get('app.name')} to the application in question. To do this, the application need only comply with the OpenID standards.
|
OpenID Connect clients are applications that support authentication over the OpenID Connect protocol. This allows you to add a "Sign-In with XXX" button for ${session.get('app.name')} to the application in question. To do this, the application need only comply with the OpenID standards.
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Client Name',
|
name: 'Client Name',
|
||||||
field: 'client_name',
|
field: 'client_name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Redirect URI',
|
name: 'Redirect URI',
|
||||||
field: 'redirect_uri',
|
field: 'redirect_uri',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'main',
|
position: 'main',
|
||||||
action: 'insert',
|
action: 'insert',
|
||||||
text: 'Create New',
|
text: 'Create New',
|
||||||
color: 'success',
|
color: 'success',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'update',
|
action: 'update',
|
||||||
icon: 'fa fa-edit',
|
icon: 'fa fa-edit',
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'delete',
|
action: 'delete',
|
||||||
icon: 'fa fa-times',
|
icon: 'fa fa-times',
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
confirm: true,
|
confirm: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
form_definition = {
|
this.form_definition = {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'Client Name',
|
name: 'Client Name',
|
||||||
field: 'client_name',
|
field: 'client_name',
|
||||||
placeholder: 'Awesome External App',
|
placeholder: 'Awesome External App',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Redirect URI',
|
name: 'Redirect URI',
|
||||||
field: 'redirect_uri',
|
field: 'redirect_uri',
|
||||||
placeholder: 'https://awesome.app/oauth2/callback',
|
placeholder: 'https://awesome.app/oauth2/callback',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Grant Types',
|
name: 'Grant Types',
|
||||||
field: 'grant_types',
|
field: 'grant_types',
|
||||||
type: 'select.multiple',
|
type: 'select.multiple',
|
||||||
options: [
|
options: [
|
||||||
{ display: 'Refresh Token', value: 'refresh_token' },
|
{display: 'Refresh Token', value: 'refresh_token'},
|
||||||
{ display: 'Authorization Code', value: 'authorization_code' },
|
{display: 'Authorization Code', value: 'authorization_code'},
|
||||||
],
|
],
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Client ID',
|
name: 'Client ID',
|
||||||
field: 'client_id',
|
field: 'client_id',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
readonly: true,
|
readonly: true,
|
||||||
hidden: ['insert'],
|
hidden: ['insert'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Client Secret',
|
name: 'Client Secret',
|
||||||
field: 'client_secret',
|
field: 'client_secret',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
readonly: true,
|
readonly: true,
|
||||||
hidden: ['insert'],
|
hidden: ['insert'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
import CRUDBase from '../CRUDBase.js'
|
import CRUDBase from '../CRUDBase.js'
|
||||||
|
|
||||||
class ScopeResource extends CRUDBase {
|
class ScopeResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/reflect/scopes'
|
constructor() {
|
||||||
required_fields = ['scope']
|
super()
|
||||||
permission_base = 'v1:reflect:scopes'
|
|
||||||
|
|
||||||
item = 'API Scope'
|
this.endpoint = '/api/v1/reflect/scopes'
|
||||||
plural = 'API Scopes'
|
this.required_fields = ['scope']
|
||||||
|
this.permission_base = 'v1:reflect:scopes'
|
||||||
|
|
||||||
|
this.item = 'API Scope'
|
||||||
|
this.plural = 'API Scopes'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const reflect_scope = new ScopeResource()
|
const reflect_scope = new ScopeResource()
|
||||||
|
|||||||
@@ -1,87 +1,90 @@
|
|||||||
import CRUDBase from '../CRUDBase.js'
|
import CRUDBase from '../CRUDBase.js'
|
||||||
|
|
||||||
class TokenResource extends CRUDBase {
|
class TokenResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/reflect/tokens'
|
constructor() {
|
||||||
required_fields = ['client_id']
|
super()
|
||||||
permission_base = 'v1:reflect:tokens'
|
this.endpoint = '/api/v1/reflect/tokens'
|
||||||
|
this.required_fields = ['client_id']
|
||||||
|
this.permission_base = 'v1:reflect:tokens'
|
||||||
|
|
||||||
item = 'API Token'
|
this.item = 'API Token'
|
||||||
plural = 'API Tokens'
|
this.plural = 'API Tokens'
|
||||||
|
|
||||||
listing_definition = {
|
this.listing_definition = {
|
||||||
display: `
|
display: `
|
||||||
This allows you to create bearer tokens manually to allow for easier testing of the API. Notably, this is meant as a measure for testing and development, not for long term use.
|
This allows you to create bearer tokens manually to allow for easier testing of the API. Notably, this is meant as a measure for testing and development, not for long term use.
|
||||||
<br><br>
|
<br><br>
|
||||||
If you have an application that needs to regularly interact with the API, set it up as an <a href="/dash/c/listing/oauth/Client">OAuth2 Client</a>. Manually-created tokens expire 7 days after their creation.
|
If you have an application that needs to regularly interact with the API, set it up as an <a href="/dash/c/listing/oauth/Client">OAuth2 Client</a>. Manually-created tokens expire 7 days after their creation.
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Token',
|
name: 'Token',
|
||||||
field: 'token',
|
field: 'token',
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Client',
|
|
||||||
field: 'client_display',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Expires',
|
|
||||||
field: 'expires',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'main',
|
|
||||||
action: 'insert',
|
|
||||||
text: 'Create New',
|
|
||||||
color: 'success',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'update',
|
|
||||||
icon: 'fa fa-edit',
|
|
||||||
color: 'primary',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'resource',
|
|
||||||
position: 'row',
|
|
||||||
action: 'delete',
|
|
||||||
icon: 'fa fa-times',
|
|
||||||
color: 'danger',
|
|
||||||
confirm: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
form_definition = {
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: 'Client',
|
|
||||||
field: 'client_id',
|
|
||||||
required: true,
|
|
||||||
type: 'select.dynamic',
|
|
||||||
options: {
|
|
||||||
resource: 'oauth/Client',
|
|
||||||
display: 'name',
|
|
||||||
value: 'uuid',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Client',
|
||||||
name: 'Bearer Token',
|
field: 'client_display',
|
||||||
field: 'token',
|
},
|
||||||
type: 'text',
|
{
|
||||||
readonly: true,
|
name: 'Expires',
|
||||||
hidden: ['insert'],
|
field: 'expires',
|
||||||
},
|
},
|
||||||
{
|
],
|
||||||
name: 'Expires',
|
actions: [
|
||||||
field: 'expires',
|
{
|
||||||
type: 'text',
|
type: 'resource',
|
||||||
readonly: true,
|
position: 'main',
|
||||||
hidden: ['insert'],
|
action: 'insert',
|
||||||
},
|
text: 'Create New',
|
||||||
],
|
color: 'success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'update',
|
||||||
|
icon: 'fa fa-edit',
|
||||||
|
color: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'resource',
|
||||||
|
position: 'row',
|
||||||
|
action: 'delete',
|
||||||
|
icon: 'fa fa-times',
|
||||||
|
color: 'danger',
|
||||||
|
confirm: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
this.form_definition = {
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'Client',
|
||||||
|
field: 'client_id',
|
||||||
|
required: true,
|
||||||
|
type: 'select.dynamic',
|
||||||
|
options: {
|
||||||
|
resource: 'oauth/Client',
|
||||||
|
display: 'name',
|
||||||
|
value: 'uuid',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bearer Token',
|
||||||
|
field: 'token',
|
||||||
|
type: 'text',
|
||||||
|
readonly: true,
|
||||||
|
hidden: ['insert'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Expires',
|
||||||
|
field: 'expires',
|
||||||
|
type: 'text',
|
||||||
|
readonly: true,
|
||||||
|
hidden: ['insert'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,92 +2,96 @@ import CRUDBase from '../CRUDBase.js'
|
|||||||
import { session } from '../../service/Session.service.js'
|
import { session } from '../../service/Session.service.js'
|
||||||
|
|
||||||
class ProviderResource extends CRUDBase {
|
class ProviderResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/saml/providers'
|
constructor() {
|
||||||
required_fields = ['name', 'acs_url', 'entity_id']
|
super()
|
||||||
permission_base = 'v1:saml:providers'
|
|
||||||
|
|
||||||
item = 'SAML Service Provider'
|
this.endpoint = '/api/v1/saml/providers'
|
||||||
plural = 'SAML Service Providers'
|
this.required_fields = ['name', 'acs_url', 'entity_id']
|
||||||
|
this.permission_base = 'v1:saml:providers'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'SAML Service Provider'
|
||||||
display: `SAML Service Providers are applications that support external authentication to a SAML Identity Provider. In this case, ${session.get('app.name')} is the identity provider, so these external applications can authenticate against it.
|
this.plural = 'SAML Service Providers'
|
||||||
|
|
||||||
|
this.listing_definition = {
|
||||||
|
display: `SAML Service Providers are applications that support external authentication to a SAML Identity Provider. In this case, ${session.get('app.name')} is the identity provider, so these external applications can authenticate against it.
|
||||||
<br><br>
|
<br><br>
|
||||||
To do this, you need to know the SAML service provider's entity ID, assertion consumer service URL, and single-logout URL (if supported).`,
|
To do this, you need to know the SAML service provider's entity ID, assertion consumer service URL, and single-logout URL (if supported).`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Provider Name',
|
name: 'Provider Name',
|
||||||
field: 'name',
|
field: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Entity ID',
|
name: 'Entity ID',
|
||||||
field: 'entity_id',
|
field: 'entity_id',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Has SLO?',
|
name: 'Has SLO?',
|
||||||
field: 'slo_url',
|
field: 'slo_url',
|
||||||
renderer: 'boolean',
|
renderer: 'boolean',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'ACS URL',
|
name: 'ACS URL',
|
||||||
field: 'acs_url',
|
field: 'acs_url',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'main',
|
position: 'main',
|
||||||
action: 'insert',
|
action: 'insert',
|
||||||
text: 'Create New',
|
text: 'Create New',
|
||||||
color: 'success',
|
color: 'success',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'update',
|
action: 'update',
|
||||||
icon: 'fa fa-edit',
|
icon: 'fa fa-edit',
|
||||||
color: 'primary',
|
color: 'primary',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'delete',
|
action: 'delete',
|
||||||
icon: 'fa fa-times',
|
icon: 'fa fa-times',
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
confirm: true,
|
confirm: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
form_definition = {
|
this.form_definition = {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'Provider Name',
|
name: 'Provider Name',
|
||||||
field: 'name',
|
field: 'name',
|
||||||
placeholder: 'Awesome External App',
|
placeholder: 'Awesome External App',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Entity ID',
|
name: 'Entity ID',
|
||||||
field: 'entity_id',
|
field: 'entity_id',
|
||||||
placeholder: 'https://my.awesome.app/saml/metadata.xml',
|
placeholder: 'https://my.awesome.app/saml/metadata.xml',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Assertion Consumer Service URL',
|
name: 'Assertion Consumer Service URL',
|
||||||
field: 'acs_url',
|
field: 'acs_url',
|
||||||
placeholder: 'https://my.awesome.app/saml/acs',
|
placeholder: 'https://my.awesome.app/saml/acs',
|
||||||
required: true,
|
required: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Single-Logout URL',
|
name: 'Single-Logout URL',
|
||||||
field: 'slo_url',
|
field: 'slo_url',
|
||||||
placeholder: 'https://my.awesome.app/saml/logout',
|
placeholder: 'https://my.awesome.app/saml/logout',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,95 +1,99 @@
|
|||||||
import CRUDBase from '../CRUDBase.js'
|
import CRUDBase from '../CRUDBase.js'
|
||||||
|
|
||||||
class AnnouncementResource extends CRUDBase {
|
class AnnouncementResource extends CRUDBase {
|
||||||
endpoint = '/api/v1/system/announcements'
|
constructor() {
|
||||||
required_fields = ['user_ids', 'group_ids', 'title', 'message', 'type']
|
super()
|
||||||
permission_base = 'v1:system:announcements'
|
|
||||||
|
|
||||||
item = 'System Announcement'
|
this.endpoint = '/api/v1/system/announcements'
|
||||||
plural = 'System Announcements'
|
this.required_fields = ['user_ids', 'group_ids', 'title', 'message', 'type']
|
||||||
|
this.permission_base = 'v1:system:announcements'
|
||||||
|
|
||||||
listing_definition = {
|
this.item = 'System Announcement'
|
||||||
display: `
|
this.plural = 'System Announcements'
|
||||||
|
|
||||||
|
this.listing_definition = {
|
||||||
|
display: `
|
||||||
System announcements are administrative messages that you want all or some of your users to see. These messages can be delivered via e-mail, as a message after login, or as a system banner announcement.
|
System announcements are administrative messages that you want all or some of your users to see. These messages can be delivered via e-mail, as a message after login, or as a system banner announcement.
|
||||||
`,
|
`,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: 'Title',
|
name: 'Title',
|
||||||
field: 'title',
|
field: 'title',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Message',
|
name: 'Message',
|
||||||
field: 'message',
|
field: 'message',
|
||||||
renderer: (message) => String(message).slice(0, 150),
|
renderer: (message) => String(message).slice(0, 150),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'main',
|
position: 'main',
|
||||||
action: 'insert',
|
action: 'insert',
|
||||||
text: 'Create New',
|
text: 'Create New',
|
||||||
color: 'success',
|
color: 'success',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'resource',
|
type: 'resource',
|
||||||
position: 'row',
|
position: 'row',
|
||||||
action: 'delete',
|
action: 'delete',
|
||||||
icon: 'fa fa-times',
|
icon: 'fa fa-times',
|
||||||
color: 'danger',
|
color: 'danger',
|
||||||
confirm: true,
|
confirm: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
form_definition = {
|
this.form_definition = {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'Title',
|
name: 'Title',
|
||||||
field: 'title',
|
field: 'title',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Message',
|
|
||||||
field: 'message',
|
|
||||||
type: 'textarea',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Users',
|
|
||||||
field: 'user_ids',
|
|
||||||
type: 'select.dynamic.multiple',
|
|
||||||
options: {
|
|
||||||
resource: 'auth/User',
|
|
||||||
display: (user) => `${user.last_name}, ${user.first_name} (${user.uid})`,
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Message',
|
||||||
name: 'Groups',
|
field: 'message',
|
||||||
field: 'group_ids',
|
type: 'textarea',
|
||||||
type: 'select.dynamic.multiple',
|
|
||||||
options: {
|
|
||||||
resource: 'auth/Group',
|
|
||||||
display: (group) => `${group.name}`,
|
|
||||||
value: 'id',
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Users',
|
||||||
name: 'Type',
|
field: 'user_ids',
|
||||||
field: 'type',
|
type: 'select.dynamic.multiple',
|
||||||
type: 'select',
|
options: {
|
||||||
options: [
|
resource: 'auth/User',
|
||||||
{ display: 'Login Intercept', value: 'login' },
|
display: (user) => `${user.last_name}, ${user.first_name} (${user.uid})`,
|
||||||
{ display: 'E-Mail', value: 'email' },
|
value: 'id',
|
||||||
{ display: 'System Banner', value: 'banner' },
|
},
|
||||||
],
|
},
|
||||||
},
|
{
|
||||||
],
|
name: 'Groups',
|
||||||
handlers: {
|
field: 'group_ids',
|
||||||
insert: {
|
type: 'select.dynamic.multiple',
|
||||||
action: 'redirect',
|
options: {
|
||||||
next: '/dash/c/listing/system/Announcement',
|
resource: 'auth/Group',
|
||||||
},
|
display: (group) => `${group.name}`,
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Type',
|
||||||
|
field: 'type',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{display: 'Login Intercept', value: 'login'},
|
||||||
|
{display: 'E-Mail', value: 'email'},
|
||||||
|
{display: 'System Banner', value: 'banner'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
handlers: {
|
||||||
|
insert: {
|
||||||
|
action: 'redirect',
|
||||||
|
next: '/dash/c/listing/system/Announcement',
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
class Event {
|
class Event {
|
||||||
firings = []
|
|
||||||
subscriptions = []
|
|
||||||
|
|
||||||
constructor(name) {
|
constructor(name) {
|
||||||
this.name = name
|
this.name = name
|
||||||
|
this.firings = []
|
||||||
|
this.subscriptions = []
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(handler) {
|
subscribe(handler) {
|
||||||
@@ -22,7 +22,9 @@ class Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EventBusService {
|
class EventBusService {
|
||||||
_events = {}
|
constructor() {
|
||||||
|
this._events = {}
|
||||||
|
}
|
||||||
|
|
||||||
event(name) {
|
event(name) {
|
||||||
if ( !this._events[name] ) {
|
if ( !this._events[name] ) {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import { event_bus } from './EventBus.service.js'
|
|||||||
import { auth_api } from './AuthApi.service.js'
|
import { auth_api } from './AuthApi.service.js'
|
||||||
|
|
||||||
class MessageService {
|
class MessageService {
|
||||||
listener_interval = 25000
|
constructor() {
|
||||||
|
this.listener_interval = 25000
|
||||||
|
}
|
||||||
|
|
||||||
alert({type, message, timeout = 0, on_dismiss = () => {} }) {
|
alert({type, message, timeout = 0, on_dismiss = () => {} }) {
|
||||||
event_bus.event('message.alert').fire({ type, message, timeout, on_dismiss })
|
event_bus.event('message.alert').fire({ type, message, timeout, on_dismiss })
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
class Session {
|
class Session {
|
||||||
data = {}
|
constructor() {
|
||||||
|
this.data = {}
|
||||||
|
}
|
||||||
|
|
||||||
init(data) {
|
init(data) {
|
||||||
this.data = data
|
this.data = data
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
class TranslateService {
|
class TranslateService {
|
||||||
_cache = {}
|
constructor() {
|
||||||
|
this._cache = {}
|
||||||
|
}
|
||||||
|
|
||||||
check_cache(...keys) {
|
check_cache(...keys) {
|
||||||
const obj = {}
|
const obj = {}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
class UtilityService {
|
class UtilityService {
|
||||||
_debounce_timeouts = {}
|
constructor() {
|
||||||
|
this._debounce_timeouts = {}
|
||||||
|
}
|
||||||
|
|
||||||
uuid() {
|
uuid() {
|
||||||
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
||||||
|
|||||||
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) {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})()
|
||||||
1
app/assets/lib/axios/axios.min.js
vendored
1
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
1
app/assets/lib/popper/popper-1.16.0.min.js
vendored
1
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] : '',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,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) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,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,6 +8,7 @@ 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
|
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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
@@ -35,7 +35,12 @@ const server_config = {
|
|||||||
* The secret used to encrypt the session.
|
* The secret used to encrypt the session.
|
||||||
* This should be set in the environment.
|
* This should be set in the environment.
|
||||||
*/
|
*/
|
||||||
secret: env("SECRET", "changeme")
|
secret: env("SECRET", "changeme"),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The max age of a session in milliseconds
|
||||||
|
*/
|
||||||
|
max_age: env("SESSION_MAX_AGE", 1000 * 60 * 60 * 24 * 2), // default to 2 days
|
||||||
},
|
},
|
||||||
|
|
||||||
uploads: {
|
uploads: {
|
||||||
|
|||||||
@@ -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.56.1",
|
"libflitter": "^0.57.0",
|
||||||
"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.56.1:
|
libflitter@^0.57.0:
|
||||||
version "0.56.1"
|
version "0.57.0"
|
||||||
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.56.1.tgz#250166027b9cab727c9deb6b1fa1865428b1eafb"
|
resolved "https://registry.yarnpkg.com/libflitter/-/libflitter-0.57.0.tgz#4383d188c4db5b36a5c684874b901ad964f1f721"
|
||||||
integrity sha512-QikFtFRa9okKOjOio5ehpQ6hyacCoMbtOlqcXt4I7uU3lntBeP5qSbz1q3x1wUY/AdBc2k70+Eg8BcpGmBEs4Q==
|
integrity sha512-0yj9tXg5OW7C+sIdRm7ygw+kezaKaYrhvfONCKzqGn9gcUY7HGigALieSIaWuXnj7A+fn6e69gOyFnmwxwuZVQ==
|
||||||
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