+5
-3
@@ -54,9 +54,11 @@ app.use(function(req, res, next) {
|
|||||||
// Error handler. This is where `next()` will go on error
|
// Error handler. This is where `next()` will go on error
|
||||||
app.use(function(err, req, res, next) {
|
app.use(function(err, req, res, next) {
|
||||||
console.error(err.status || res.status, err.name, req.method, req.url);
|
console.error(err.status || res.status, err.name, req.method, req.url);
|
||||||
console.error(err.message);
|
if(![401, 404].includes(err.status || res.status)){
|
||||||
console.error(err.stack);
|
console.error(err.message);
|
||||||
console.error('=========================================');
|
console.error(err.stack);
|
||||||
|
console.error('=========================================');
|
||||||
|
}
|
||||||
|
|
||||||
res.status(err.status || 500);
|
res.status(err.status || 500);
|
||||||
res.json({name: err.name, message: err.message});
|
res.json({name: err.name, message: err.message});
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ async function getGroups(client, member){
|
|||||||
|
|
||||||
return groups.map(function(group){
|
return groups.map(function(group){
|
||||||
if(!Array.isArray(group.member)) group.member = [group.member];
|
if(!Array.isArray(group.member)) group.member = [group.member];
|
||||||
|
if(!Array.isArray(group.owner)) group.owner = [group.owner];
|
||||||
return group
|
return group
|
||||||
});
|
});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
@@ -81,6 +82,41 @@ async function removeMember(client, group, user){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function addOwner(client, group, user){
|
||||||
|
try{
|
||||||
|
await client.modify(group.dn, [
|
||||||
|
new Change({
|
||||||
|
operation: 'add',
|
||||||
|
modification: new Attribute({
|
||||||
|
type: 'owner',
|
||||||
|
values: [user.dn]
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}catch(error){
|
||||||
|
// if(error = "TypeOrValueExistsError"){
|
||||||
|
// console.error('addMember error skipped', error)
|
||||||
|
// return ;
|
||||||
|
// }
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeOwner(client, group, user){
|
||||||
|
try{
|
||||||
|
await client.modify(group.dn, [
|
||||||
|
new Change({
|
||||||
|
operation: 'delete',
|
||||||
|
modification: new Attribute({
|
||||||
|
type: 'owner',
|
||||||
|
values: [user.dn]
|
||||||
|
})}),
|
||||||
|
]);
|
||||||
|
}catch(error){
|
||||||
|
if(error = "TypeOrValueExistsError")return ;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var Group = {};
|
var Group = {};
|
||||||
|
|
||||||
@@ -133,6 +169,7 @@ Group.get = async function(data){
|
|||||||
await client.unbind();
|
await client.unbind();
|
||||||
|
|
||||||
if(!Array.isArray(group.member)) group.member = [group.member];
|
if(!Array.isArray(group.member)) group.member = [group.member];
|
||||||
|
if(!Array.isArray(group.owner)) group.owner = [group.owner];
|
||||||
|
|
||||||
if(group){
|
if(group){
|
||||||
let obj = Object.create(this);
|
let obj = Object.create(this);
|
||||||
@@ -196,6 +233,37 @@ Group.removeMember = async function(user){
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Group.addOwner = async function(user){
|
||||||
|
try{
|
||||||
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
|
await addOwner(client, this, user);
|
||||||
|
|
||||||
|
await client.unbind();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Group.removeOwner = async function(user){
|
||||||
|
try{
|
||||||
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|
||||||
|
await removeOwner(client, this, user);
|
||||||
|
|
||||||
|
await client.unbind();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}catch(error){
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Group.remove = async function(){
|
Group.remove = async function(){
|
||||||
try{
|
try{
|
||||||
await client.bind(conf.bindDN, conf.bindPassword);
|
await client.bind(conf.bindDN, conf.bindPassword);
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ async function addLdapUser(client, data){
|
|||||||
var group;
|
var group;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
data.uid = `${data.givenName[0]}${data.sn}`;
|
data.uid = `${data.givenName[0]}${data.sn}`.toLowerCase();
|
||||||
data.cn = data.uid;
|
data.cn = data.uid;
|
||||||
data.loginShell = '/bin/bash';
|
data.loginShell = '/bin/bash';
|
||||||
data.homeDirectory= `/home/${data.uid}`;
|
data.homeDirectory= `/home/${data.uid}`;
|
||||||
@@ -324,6 +324,7 @@ User.verifyEmail = async function(data){
|
|||||||
|
|
||||||
let token = await InviteToken.get(data.token);
|
let token = await InviteToken.get(data.token);
|
||||||
await token.update({mail: data.mail})
|
await token.update({mail: data.mail})
|
||||||
|
|
||||||
await Mail.sendTemplate(
|
await Mail.sendTemplate(
|
||||||
data.mail,
|
data.mail,
|
||||||
'validate_link',
|
'validate_link',
|
||||||
|
|||||||
Generated
+268
-158
File diff suppressed because it is too large
Load Diff
+7
-5
@@ -12,14 +12,13 @@
|
|||||||
"start": "node ./bin/www"
|
"start": "node ./bin/www"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sendgrid/mail": "^7.2.6",
|
"@sendgrid/mail": "^7.4.0",
|
||||||
"ejs": "^3.1.5",
|
"ejs": "^3.1.5",
|
||||||
"express": "~4.16.1",
|
"express": "~4.16.1",
|
||||||
"extend": "^3.0.2",
|
"extend": "^3.0.2",
|
||||||
"ldapts": "^2.7.0",
|
"ldapts": "^2.10.1",
|
||||||
"moment": "^2.29.0",
|
"moment": "^2.29.1",
|
||||||
"mustache": "^4.0.1",
|
"mustache": "^4.1.0",
|
||||||
"nodemon": "^2.0.4",
|
|
||||||
"redis": "^2.8.0",
|
"redis": "^2.8.0",
|
||||||
"smtpc": "^0.1.2"
|
"smtpc": "^0.1.2"
|
||||||
},
|
},
|
||||||
@@ -27,5 +26,8 @@
|
|||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.theta42.com/wmantly/proxy.git"
|
"url": "https://git.theta42.com/wmantly/proxy.git"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"nodemon": "^2.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
transition: all .4s ease;
|
transition: all .4s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover, button:hover, div.form-group:hover{
|
a:hover, button:hover, div.form-group:hover, header nav a{
|
||||||
color: inherit;
|
color: inherit;
|
||||||
transition: all .4s ease;
|
transition: all .4s ease;
|
||||||
background-color: inherit;
|
background-color: inherit;
|
||||||
@@ -22,3 +22,7 @@ div.card-body{
|
|||||||
.my-2 > a {
|
.my-2 > a {
|
||||||
padding-right: .5em;
|
padding-right: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
header nav svg{
|
||||||
|
margin-right: .4em
|
||||||
|
}
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ app.util = (function(app){
|
|||||||
|
|
||||||
function actionMessage(message, $target, type){
|
function actionMessage(message, $target, type){
|
||||||
message = message || '';
|
message = message || '';
|
||||||
$target = $target.closest('div.card').find('.actionMessage');
|
$target = $($target.closest('div.card').find('.actionMessage')[0]);
|
||||||
type = type || 'info';
|
type = type || 'info';
|
||||||
|
|
||||||
if($target.html() === message) return;
|
if($target.html() === message) return;
|
||||||
|
|||||||
+54
-11
@@ -3,13 +3,12 @@
|
|||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
const {User} = require('../models/user_ldap');
|
const {User} = require('../models/user_ldap');
|
||||||
const {Group} = require('../models/group_ldap');
|
const {Group} = require('../models/group_ldap');
|
||||||
|
const permission = require('../utils/permission');
|
||||||
|
|
||||||
router.get('/', async function(req, res, next){
|
router.get('/', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
let member = req.query.member ? await User.get(req.query.member) : {}
|
let member = req.query.member ? await User.get(req.query.member) : {}
|
||||||
|
|
||||||
console.log('member', member)
|
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
results: await Group[req.query.detail ? "listDetail" : "list"](member.dn)
|
results: await Group[req.query.detail ? "listDetail" : "list"](member.dn)
|
||||||
});
|
});
|
||||||
@@ -20,6 +19,9 @@ router.get('/', async function(req, res, next){
|
|||||||
|
|
||||||
router.post('/', async function(req, res, next){
|
router.post('/', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
|
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin']);
|
||||||
|
|
||||||
req.body.owner = req.user.dn;
|
req.body.owner = req.user.dn;
|
||||||
return res.json({
|
return res.json({
|
||||||
results: await Group.add(req.body),
|
results: await Group.add(req.body),
|
||||||
@@ -40,39 +42,80 @@ router.get('/:name', async function(req, res, next){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put('/:name/:uid', async function(req, res, next){
|
router.put('/owner/:group/:uid', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
var group = await Group.get(req.params.name);
|
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'], [req.params.group]);
|
||||||
|
|
||||||
|
var group = await Group.get(req.params.group);
|
||||||
|
var user = await User.get(req.params.uid);
|
||||||
|
return res.json({
|
||||||
|
results: group.addOwner(user),
|
||||||
|
message: `Added owner ${req.params.uid} to ${req.params.group} group.`
|
||||||
|
});
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.delete('/owner/:group/:uid', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'], [req.params.group]);
|
||||||
|
|
||||||
|
var group = await Group.get(req.params.group);
|
||||||
|
var user = await User.get(req.params.uid);
|
||||||
|
return res.json({
|
||||||
|
results: group.removeOwner(user),
|
||||||
|
message: `Removed Owner ${req.params.uid} from ${req.params.group} group.`
|
||||||
|
});
|
||||||
|
}catch(error){
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.put('/:group/:uid', async function(req, res, next){
|
||||||
|
try{
|
||||||
|
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'], [req.params.group]);
|
||||||
|
|
||||||
|
var group = await Group.get(req.params.group);
|
||||||
var user = await User.get(req.params.uid);
|
var user = await User.get(req.params.uid);
|
||||||
return res.json({
|
return res.json({
|
||||||
results: group.addMember(user),
|
results: group.addMember(user),
|
||||||
message: `Added user ${req.params.uid} to ${req.params.name} group.`
|
message: `Added user ${req.params.uid} to ${req.params.group} group.`
|
||||||
});
|
});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.delete('/:name/:uid', async function(req, res, next){
|
router.delete('/:group/:uid', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
var group = await Group.get(req.params.name);
|
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'], [req.params.group]);
|
||||||
|
|
||||||
|
var group = await Group.get(req.params.group);
|
||||||
var user = await User.get(req.params.uid);
|
var user = await User.get(req.params.uid);
|
||||||
return res.json({
|
return res.json({
|
||||||
results: group.removeMember(user),
|
results: group.removeMember(user),
|
||||||
message: `Removed user ${req.params.uid} from ${req.params.name} group.`
|
message: `Removed user ${req.params.uid} from ${req.params.group} group.`
|
||||||
});
|
});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.delete('/:name', async function(req, res, next){
|
router.delete('/:group', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
var group = await Group.get(req.params.name);
|
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'], [req.params.group]);
|
||||||
|
|
||||||
|
var group = await Group.get(req.params.group);
|
||||||
return res.json({
|
return res.json({
|
||||||
removed: await group.remove(),
|
removed: await group.remove(),
|
||||||
results: group,
|
results: group,
|
||||||
message: `Group ${req.params.name} Deleted`
|
message: `Group ${req.params.group} Deleted`
|
||||||
});
|
});
|
||||||
}catch(error){
|
}catch(error){
|
||||||
next(error);
|
next(error);
|
||||||
|
|||||||
+27
-4
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
const {User} = require('../models/user');
|
const {User} = require('../models/user');
|
||||||
|
const permission = require('../utils/permission');
|
||||||
|
|
||||||
router.get('/', async function(req, res, next){
|
router.get('/', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
@@ -15,6 +16,8 @@ router.get('/', async function(req, res, next){
|
|||||||
|
|
||||||
router.post('/', async function(req, res, next){
|
router.post('/', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'])
|
||||||
|
|
||||||
req.body.created_by = req.user.uid
|
req.body.created_by = req.user.uid
|
||||||
|
|
||||||
return res.json({results: await User.add(req.body)});
|
return res.json({results: await User.add(req.body)});
|
||||||
@@ -25,7 +28,14 @@ router.post('/', async function(req, res, next){
|
|||||||
|
|
||||||
router.delete('/:uid', async function(req, res, next){
|
router.delete('/:uid', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
let user = await User.get(req.params.uid);
|
let user;
|
||||||
|
|
||||||
|
if(req.params.uid.toLowerCase() === req.user.uid.toLowerCase()){
|
||||||
|
user = req.user;
|
||||||
|
}else{
|
||||||
|
user = await User.get(req.params.uid);
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'])
|
||||||
|
}
|
||||||
|
|
||||||
return res.json({uid: req.params.uid, results: await user.remove()})
|
return res.json({uid: req.params.uid, results: await user.remove()})
|
||||||
}catch(error){
|
}catch(error){
|
||||||
@@ -35,9 +45,14 @@ router.delete('/:uid', async function(req, res, next){
|
|||||||
|
|
||||||
router.put('/:uid', async function(req, res, next){
|
router.put('/:uid', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
let user = await User.get(req.params.uid);
|
let user;
|
||||||
|
|
||||||
// console.log('update user', user);
|
if(req.params.uid.toLowerCase() === req.user.uid.toLowerCase()){
|
||||||
|
user = req.user;
|
||||||
|
}else{
|
||||||
|
user = await User.get(req.params.uid);
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'])
|
||||||
|
}
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
results: await user.update(req.body),
|
results: await user.update(req.body),
|
||||||
@@ -68,7 +83,15 @@ router.put('/password', async function(req, res, next){
|
|||||||
|
|
||||||
router.put('/:uid/password', async function(req, res, next){
|
router.put('/:uid/password', async function(req, res, next){
|
||||||
try{
|
try{
|
||||||
let user = await User.get(req.params.uid);
|
let user;
|
||||||
|
|
||||||
|
if(req.params.uid.toLowerCase() === req.user.uid.toLowerCase()){
|
||||||
|
user = req.user;
|
||||||
|
}else{
|
||||||
|
user = await User.get(req.params.uid);
|
||||||
|
await permission.byGroup(req.user, ['app_sso_admin'])
|
||||||
|
}
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
results: await user.setPassword(req.body),
|
results: await user.setPassword(req.body),
|
||||||
message: `User ${user.uid} password changed.`
|
message: `User ${user.uid} password changed.`
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
'use static';
|
||||||
|
|
||||||
|
const {Group} = require('../models/group_ldap');
|
||||||
|
|
||||||
|
let byGroup = async function(user, groups, ownerOf){
|
||||||
|
for(let group of groups){
|
||||||
|
try{
|
||||||
|
console.log('checking group', group, 'for access', groups, ownerOf)
|
||||||
|
group = await Group.get(group);
|
||||||
|
if(group.member.includes(user.dn)) return true
|
||||||
|
}catch(error){
|
||||||
|
console.error('Error byGroup', groups, ownerOf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let group of ownerOf || []){
|
||||||
|
try{
|
||||||
|
console.log('checking group owners', group, 'for access', groups, ownerOf)
|
||||||
|
|
||||||
|
group = await Group.get(group);
|
||||||
|
if(group.owner.includes(user.dn)) return true
|
||||||
|
}catch(error){
|
||||||
|
console.error('Error byGroup', groups, ownerOf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let error = new Error('Insufficient Permission');
|
||||||
|
error.name = 'Insufficient Permission';
|
||||||
|
error.message = `You do not have permission to perform this action.`;
|
||||||
|
error.status = 401;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {byGroup};
|
||||||
+133
-50
@@ -1,46 +1,111 @@
|
|||||||
<%- include('top') %>
|
<%- include('top') %>
|
||||||
<script id="rowTemplate" type="text/html">
|
<script id="rowTemplate" type="text/html">
|
||||||
<p>
|
<div id="group-card-{{cn}}" class="card shadow">
|
||||||
<div class="card shadow">
|
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<i class="fad fa-users-class"></i>
|
<h5>
|
||||||
Group: {{ cn }}
|
<i class="fad fa-users-class"></i>
|
||||||
|
Group: {{ cn }}
|
||||||
|
</h5>
|
||||||
|
<ul class="nav nav-tabs card-header-tabs" id="myTab" role="tablist">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" id="group-members-tab-{{cn}}" data-toggle="tab" href="#group-memmbers-{{cn}}" role="tab" aria-controls="member" aria-selected="true">
|
||||||
|
<i class="fad fa-users"></i>
|
||||||
|
Members
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" id="group-admins-tab-{{cn}}" data-toggle="tab" href="#group-admins-{{cn}}" role="tab" aria-controls="admin" aria-selected="false">
|
||||||
|
<i class="fad fa-users-crown"></i>
|
||||||
|
Owners
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item float-right">
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-header actionMessage" style="display:none"></div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p>
|
<p>
|
||||||
{{ description }}
|
{{ description }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<div class="tab-content" id="myTabContent">
|
||||||
<ul class="list-group">
|
<div class="tab-pane fade show active" id="group-memmbers-{{cn}}" role="tabpanel" aria-labelledby="member-tab">
|
||||||
{{ #member }}
|
<p>
|
||||||
<li class="list-group-item shadow">
|
<ul class="list-group">
|
||||||
<i class="fad fa-user"></i> {{ uid }}
|
{{ #member }}
|
||||||
<button type="button" action="group/{{groupCN}}/{{uid}}" method="delete" onclick="formAJAX(this)" evalAJAX="tableAJAX(data.message)" class="btn btn-sm btn-danger float-right">
|
<li id="group-card-{{cn}}-{{uid}}" class="list-group-item shadow">
|
||||||
<i class="fad fa-user-slash"></i>
|
<i class="fad fa-user"></i> {{ uid }}
|
||||||
|
<button type="button" action="group/{{groupCN}}/{{uid}}" method="delete" onclick="formAJAX(this)" evalAJAX="addedUser(data.message, '{{groupCN}}', '{{uid}}', $form)" class="btn btn-sm btn-danger float-right">
|
||||||
|
<i class="fad fa-user-slash"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{{ /member }}
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="group_add_member" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<i class="fad fa-user-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
<div class="dropdown-menu shadow-lg" aria-labelledby="group_add_member">
|
||||||
{{ /member }}
|
{{ #toAdd }}{{#.}}
|
||||||
</ul>
|
<a class="dropdown-item" action="group/{{groupCN}}/{{uid}}" method="put" onclick="formAJAX(this)" evalAJAX="addedUser(data.message, '{{groupCN}}', '{{uid}}', $form);">
|
||||||
</p>
|
<i class="fad fa-user"></i> {{uid}}
|
||||||
|
</a>
|
||||||
|
{{/.}}{{ /toAdd }}
|
||||||
|
|
||||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
</div>
|
||||||
<i class="fad fa-user-plus"></i>
|
</div>
|
||||||
</button>
|
</div>
|
||||||
<div class="dropdown-menu shadow-lg" aria-labelledby="dropdownMenuButton">
|
|
||||||
{{ #toAdd }}{{#.}}
|
|
||||||
<a class="dropdown-item" action="group/{{groupCN}}/{{uid}}" method="put" onclick="formAJAX(this)" evalAJAX="tableAJAX(data.message)">
|
|
||||||
<i class="fad fa-user"></i> {{uid}}
|
|
||||||
</a>
|
|
||||||
{{/.}}{{ /toAdd }}
|
|
||||||
|
|
||||||
|
<div class="tab-pane fade" id="group-admins-{{cn}}" role="tabpanel" aria-labelledby="admin-tab">
|
||||||
|
<p>
|
||||||
|
<ul class="list-group">
|
||||||
|
{{ #owner }}
|
||||||
|
<li class="list-group-item shadow">
|
||||||
|
<i class="fad fa-user"></i> {{ uid }}
|
||||||
|
<button type="button" action="group/owner/{{groupCN}}/{{uid}}" method="delete" onclick="formAJAX(this)" evalAJAX="addedUser(data.message, '{{groupCN}}', '{{uid}}', $form)" class="btn btn-sm btn-danger float-right">
|
||||||
|
<i class="fad fa-user-slash"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
{{ /owner }}
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="dropdown float-left">
|
||||||
|
<button class="btn btn-secondary dropdown-toggle" type="button" id="group_add_admin" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<i class="fad fa-user-crown"></i>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu shadow-lg" aria-labelledby="group_add_admin">
|
||||||
|
{{ #toAddOwner }}{{#.}}
|
||||||
|
<a class="dropdown-item" action="group/owner/{{groupCN}}/{{uid}}" method="put" onclick="formAJAX(this)" evalAJAX="addedUser(data.message, '{{groupCN}}', '{{uid}}', $form)">
|
||||||
|
<i class="fad fa-user"></i> {{uid}}
|
||||||
|
</a>
|
||||||
|
{{/.}}{{ /toAddOwner }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<div class="float-left">
|
||||||
|
Created: {{createTimestamp}}<br />
|
||||||
|
Last Mortified: {{modifyTimestamp}}
|
||||||
|
</div>
|
||||||
|
<div class="float-right">
|
||||||
|
<button type="button" onclick="" class="btn btn-warning btn-lg shadow">
|
||||||
|
<i class="fad fa-edit"></i>
|
||||||
|
</button>
|
||||||
|
<button type="button" onclick="app.group.remove({cn: '{{cn}}'}, function(){tableAJAX('Group {{cn}} deleted.')})" class="btn btn-danger btn-lg">
|
||||||
|
<i class="fad fa-trash"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" onclick="app.group.remove({cn: '{{cn}}'}, function(){tableAJAX('Group {{cn}} deleted.')})" class="btn btn-danger float-right">
|
|
||||||
<i class="fad fa-trash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
<br/>
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
@@ -50,11 +115,24 @@
|
|||||||
app.user.list(function(error, data){
|
app.user.list(function(error, data){
|
||||||
userlist = data.results;
|
userlist = data.results;
|
||||||
callback()
|
callback()
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addedUser(message, group, user, $form){
|
||||||
|
tableAJAX(null, function(){
|
||||||
|
app.util.actionMessage(message, $("#group-card-"+group), 'success');
|
||||||
|
|
||||||
function tableAJAX(actionMessage){
|
|
||||||
|
$('a[href="#'+$form.closest('.tab-pane').attr('id')+'"]').tab('show');
|
||||||
|
setTimeout(function(group){
|
||||||
|
$("body,html").animate({
|
||||||
|
scrollTop: $("#group-card-" + group).offset().top
|
||||||
|
}, 0);
|
||||||
|
}, 400, group);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function tableAJAX(actionMessage, callback){
|
||||||
var rowTemplate = $('#rowTemplate').html();
|
var rowTemplate = $('#rowTemplate').html();
|
||||||
var $target = $('#tableAJAX');
|
var $target = $('#tableAJAX');
|
||||||
|
|
||||||
@@ -62,25 +140,42 @@
|
|||||||
app.util.actionMessage('Refreshing user list...', $target);
|
app.util.actionMessage('Refreshing user list...', $target);
|
||||||
|
|
||||||
app.group.list(function(error, data){
|
app.group.list(function(error, data){
|
||||||
$.each( data.results, function(key, value) {
|
var out = ''
|
||||||
|
$.each(data.results, function(key, value) {
|
||||||
// console.log(value.member)
|
|
||||||
|
|
||||||
value.toAdd = userlist.map(function(user){
|
value.toAdd = userlist.map(function(user){
|
||||||
if(!value.member.includes(user.dn)) return user;
|
if(!value.member.includes(user.dn)) return user;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
value.toAddOwner = userlist.map(function(user){
|
||||||
|
if(!value.owner.includes(user.dn)) return user;
|
||||||
|
})
|
||||||
|
|
||||||
value.member = value.member.map(function(user){
|
value.member = value.member.map(function(user){
|
||||||
return {
|
return {
|
||||||
dn: user,
|
dn: user,
|
||||||
uid: user.match(/cn=[a-zA-Z0-9\_\-\@\.]+/)[0].replace('cn=', '')
|
uid: user.match(/cn=[a-zA-Z0-9\_\-\@\.]+/)[0].replace('cn=', '')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
value.owner = value.owner.map(function(user){
|
||||||
|
return {
|
||||||
|
dn: user,
|
||||||
|
uid: user.match(/cn=[a-zA-Z0-9\_\-\@\.]+/)[0].replace('cn=', '')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
value.createTimestamp = moment(value.createTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
||||||
|
value.modifyTimestamp = moment(value.modifyTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
||||||
|
|
||||||
|
|
||||||
value.groupCN = value.cn;
|
value.groupCN = value.cn;
|
||||||
user_row = Mustache.render(rowTemplate, value);
|
out += Mustache.render(rowTemplate, value);
|
||||||
$target.append(user_row);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$target.fadeIn('slow');
|
$target.html(out);
|
||||||
|
|
||||||
|
$target.fadeIn('slow', ($.isFunction(callback) ? callback: function(){})());
|
||||||
|
|
||||||
app.util.actionMessage(actionMessage || '', $target, 'info');
|
app.util.actionMessage(actionMessage || '', $target, 'info');
|
||||||
|
|
||||||
@@ -116,19 +211,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8" id="tableAJAX">
|
||||||
<div class="card shadow-lg">
|
|
||||||
<div class="card-header">
|
|
||||||
<i class="fad fa-users-class"></i>
|
|
||||||
Group list
|
|
||||||
</div>
|
|
||||||
<div class="card-header actionMessage" style="display:none">
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="" id="tableAJAX">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%- include('bottom') %>
|
<%- include('bottom') %>
|
||||||
|
|||||||
+55
-39
@@ -1,23 +1,40 @@
|
|||||||
<%- include('top') %>
|
<%- include('top') %>
|
||||||
<script id="profileTemplate" type="text/html">
|
<script id="profileTemplate" type="text/html">
|
||||||
<h2><i>User Name:</i> <b>{{uid}}</b></h2>
|
<div class="card-body profile-body-{{uid}}">
|
||||||
<i>Name:</i> <b>{{givenName}} {{sn}}</b><br />
|
<h2><i>User Name:</i> <b>{{uid}}</b></h2>
|
||||||
<i>Email:</i> <b>{{mail}} </b><br />
|
<i>Name:</i> <b>{{givenName}} {{sn}}</b><br />
|
||||||
<i>Joined:</i> <b>{{createTimestamp}} </b>, <i>Edited:</i> <b>{{modifyTimestamp}} </b><br />
|
<i>Email:</i> <b>{{mail}} </b><br />
|
||||||
<i>Phone:</i> <b>{{mobile}} </b><br />
|
<i>Phone:</i> <b>{{mobile}} </b><br />
|
||||||
<i>LDAP DN:</i> <b>{{dn}} </b><br />
|
<i>LDAP DN:</i> <b>{{dn}} </b><br />
|
||||||
<i>Home Directory:</i> <b>{{homeDirectory}} </b><br />
|
<i>Home Directory:</i> <b>{{homeDirectory}} </b><br />
|
||||||
<i>Login Shell:</i> <b>{{loginShell}} </b><br />
|
<i>Login Shell:</i> <b>{{loginShell}} </b><br />
|
||||||
<i>SSH Public Key:</i> <b>{{sshPublicKey}}</b><br />
|
<i>SSH Public Key:</i> <b>{{sshPublicKey}}</b><br />
|
||||||
<i>Unix User ID:</i> <b>{{uidNumber}} </b><br />
|
<i>Unix User ID:</i> <b>{{uidNumber}} </b><br />
|
||||||
<i>Unix Group ID:</i> <b>{{gidNumber}} </b><br />
|
<i>Unix Group ID:</i> <b>{{gidNumber}} </b><br />
|
||||||
<i>Description:</i><br>
|
<i>Description:</i><br>
|
||||||
<p>
|
<p>
|
||||||
{{description}}
|
{{description}}
|
||||||
</p>
|
</p>
|
||||||
<img id="profile_photo" >
|
<!-- <img id="profile_photo" /> -->
|
||||||
|
</div>
|
||||||
|
<div class="card-footer profile-body-{{uid}}">
|
||||||
|
<div class="float-left">
|
||||||
|
<i>Joined:</i> <b>{{createTimestamp}} </b> <br/>
|
||||||
|
<i>Edited:</i> <b>{{modifyTimestamp}} </b>
|
||||||
|
</div>
|
||||||
|
<div class="float-right">
|
||||||
|
<button type="button" onclick="editUser()" class="btn btn-warning btn shadow ">
|
||||||
|
<i class="fad fa-user-edit"></i>
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn btn-danger" action="user/{{uid}}" method="delete" onsubmit="formAJAX(this)" evalAJAX="window.location.href = '/users'">
|
||||||
|
<i class="fad fa-user-slash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<script id="groupRowTemplate" type="text/html">
|
<script id="groupRowTemplate" type="text/html">
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{cn}}</td>
|
<td>{{cn}}</td>
|
||||||
@@ -27,7 +44,7 @@
|
|||||||
|
|
||||||
<script id="userEditTemplate" type="text/html">
|
<script id="userEditTemplate" type="text/html">
|
||||||
<h3>Editing {{uid}}</h3>
|
<h3>Editing {{uid}}</h3>
|
||||||
<form action="user/{{uid}}" method="put" onsubmit="formAJAX(this)" evalAJAX="editUserSeccess()">
|
<form action="user/{{uid}}" method="put" onsubmit="formAJAX(this)" evalAJAX="editUserSeccess(data.message)">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label">SSH Public Key</label>
|
<label class="control-label">SSH Public Key</label>
|
||||||
<input type="text" class="form-control" name="sshPublicKey" placeholder="ssh-rsa AAAAB3NzaC1yc2EAAAADAQ..." value="{{sshPublicKey}}" />
|
<input type="text" class="form-control" name="sshPublicKey" placeholder="ssh-rsa AAAAB3NzaC1yc2EAAAADAQ..." value="{{sshPublicKey}}" />
|
||||||
@@ -82,16 +99,20 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderProfile(user){
|
function renderProfile(user, message){
|
||||||
var profileTemplate = $('#profileTemplate').html();
|
var profileTemplate = $('#profileTemplate').html();
|
||||||
var paswordResetTemplate = $('#paswordResetTemplate').html();
|
var paswordResetTemplate = $('#paswordResetTemplate').html();
|
||||||
var $target = $('#userProfile div.card-body');
|
var $target = $('#userProfile div.actionMessage');
|
||||||
|
|
||||||
|
$('.profile-body-'+user.uid).remove();
|
||||||
|
|
||||||
|
app.util.actionMessage(message, $target, 'success')
|
||||||
|
|
||||||
// data.photo = unescape(encodeURIComponent(data.jpegPhoto));
|
// data.photo = unescape(encodeURIComponent(data.jpegPhoto));
|
||||||
user.createTimestamp = moment(user.createTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
user.createTimestamp = moment(user.createTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
||||||
user.modifyTimestamp = moment(user.modifyTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
user.modifyTimestamp = moment(user.modifyTimestamp, "YYYYMMDDHHmmssZ").fromNow();
|
||||||
|
|
||||||
$target.html(Mustache.render(profileTemplate, user));
|
$target.after(Mustache.render(profileTemplate, user));
|
||||||
|
|
||||||
$('#passwordReset').html(Mustache.render(paswordResetTemplate, user))
|
$('#passwordReset').html(Mustache.render(paswordResetTemplate, user))
|
||||||
};
|
};
|
||||||
@@ -103,7 +124,7 @@
|
|||||||
|
|
||||||
$target.html('')
|
$target.html('')
|
||||||
if(error){
|
if(error){
|
||||||
app.utils.actionMessage(data.message, $target, 'danger');
|
app.util.actionMessage(data.message, $target, 'danger');
|
||||||
}else{
|
}else{
|
||||||
for(var group of data.results){
|
for(var group of data.results){
|
||||||
$target.append(Mustache.render(groupRowTemplate, group));
|
$target.append(Mustache.render(groupRowTemplate, group));
|
||||||
@@ -137,15 +158,17 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function editUserSeccess(){
|
function editUserSeccess(message){
|
||||||
console.log('edit done')
|
console.log('edit done')
|
||||||
$('#editProfile').slideUp();
|
$('#editProfile').slideUp();
|
||||||
determinUser(function(user){
|
app.auth.isLoggedIn(function(){
|
||||||
currentUser = user;
|
determinUser(function(user){
|
||||||
app.auth.user = user;
|
currentUser = user;
|
||||||
renderProfile(user);
|
app.auth.user = user;
|
||||||
renderUserGroups(user);
|
renderProfile(user, message);
|
||||||
$('#userProfile').slideDown();
|
renderUserGroups(user);
|
||||||
|
$('#userProfile').slideDown();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +180,8 @@
|
|||||||
renderProfile(user);
|
renderProfile(user);
|
||||||
renderUserGroups(user);
|
renderUserGroups(user);
|
||||||
$('#username').text(user.uid);
|
$('#username').text(user.uid);
|
||||||
|
$('form[action="user/{{uid}}"]').attr('action', 'user/'+user.uid)
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -218,7 +243,7 @@
|
|||||||
<a href="https://rdp.vm42.us" target="_blank" class="text-dark">
|
<a href="https://rdp.vm42.us" target="_blank" class="text-dark">
|
||||||
<li class="list-group-item text-dark">
|
<li class="list-group-item text-dark">
|
||||||
<i class="fad fa-desktop"></i>
|
<i class="fad fa-desktop"></i>
|
||||||
Virtual Desk Top
|
Virtual Desktops
|
||||||
</li>
|
</li>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://pve.admin.vm42.us" target="_blank" class="text-dark">
|
<a href="https://pve.admin.vm42.us" target="_blank" class="text-dark">
|
||||||
@@ -256,16 +281,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-header shadow actionMessage" style="display:none">
|
<div class="card-header shadow actionMessage" style="display:none">
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="profile-body">
|
||||||
<!-- User profile inserted by JS -->
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<button type="button" onclick="editUser()" class="btn btn-warning btn-lg shadow ">
|
|
||||||
<i class="fad fa-user-edit"></i>
|
|
||||||
</button>
|
|
||||||
<button type="button" onclick="app.user.remove({uid: currentUser.uid}, function(){app.util.actionMessage('username {{uid}} delete.', $(this), 'danger')})" class="shadow btn btn-danger btn-lg float-right">
|
|
||||||
<i class="fad fa-user-slash"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,9 @@
|
|||||||
<header class="shadow d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
|
<header class="shadow d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
|
||||||
<h5 class="hover-effect my-0 mr-md-auto font-weight-normal">SSO Manager - Theta 42</h5>
|
<h5 class="hover-effect my-0 mr-md-auto font-weight-normal">SSO Manager - Theta 42</h5>
|
||||||
<nav class="my-2 my-md-0 mr-md-3">
|
<nav class="my-2 my-md-0 mr-md-3">
|
||||||
<a class="text-dark hover-effect" href="/"><i class="fad fa-tachometer-alt-fastest"></i> Home</a>
|
<a class="text-dark hover-effect" href="/"><i class="fad fa-tachometer-alt-fastest"></i>Home</a>
|
||||||
<a class="text-dark hover-effect" href="/users"><i class="fad fa-users"></i> Users</a>
|
<a class="text-dark hover-effect" href="/users"><i class="fad fa-users"></i>Users</a>
|
||||||
<a class="text-dark hover-effect" href="/groups"><i class="fad fa-users-class"></i> Groups</a>
|
<a class="text-dark hover-effect" href="/groups"><i class="fad fa-users-class"></i>Groups</a>
|
||||||
</nav>
|
</nav>
|
||||||
<a class="hover-effect btn btn-outline-primary" onclick="app.auth.logOut(e => window.location.href='/')"><i class="fas fa-sign-out"></i> Log Out</a>
|
<a class="hover-effect btn btn-outline-primary" onclick="app.auth.logOut(e => window.location.href='/')"><i class="fas fa-sign-out"></i> Log Out</a>
|
||||||
|
|
||||||
|
|||||||
@@ -20,15 +20,17 @@
|
|||||||
{{#sshPublicKey}}<i class="fad fa-check-square"></i>{{/sshPublicKey}}
|
{{#sshPublicKey}}<i class="fad fa-check-square"></i>{{/sshPublicKey}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button type="button" onclick="app.user.remove({uid: '{{uid}}'}, function(){renderUsers('username {{uid}} delete.')})" class="btn btn-sm btn-danger">
|
<form action="user/{{uid}}" method="delete" onsubmit="formAJAX(this)" evalAJAX="renderUsers('Deleted {{uid}}', 'success')">
|
||||||
<i class="fad fa-user-slash"></i>
|
<button type="submit" class="btn btn-sm btn-danger">
|
||||||
</button>
|
<i class="fad fa-user-slash"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
function renderUsers(actionMessage){
|
function renderUsers(actionMessage, type){
|
||||||
var rowTemplate = $('#rowTemplate').html();
|
var rowTemplate = $('#rowTemplate').html();
|
||||||
var $target = $('#tableAJAX');
|
var $target = $('#tableAJAX');
|
||||||
|
|
||||||
@@ -44,14 +46,14 @@
|
|||||||
|
|
||||||
$target.fadeIn('slow');
|
$target.fadeIn('slow');
|
||||||
|
|
||||||
app.util.actionMessage(actionMessage || '', $target, 'info');
|
app.util.actionMessage(actionMessage || '', $target, type || 'info');
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
renderUsers(); //populate the table
|
renderUsers(); //populate the table
|
||||||
$('form[action="user/"]').attr('evalAJAX', 'renderUsers()')
|
$('form[action="user/"]').attr('evalAJAX', 'renderUsers("User added", "success")')
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<div class="row" style="display:none">
|
<div class="row" style="display:none">
|
||||||
|
|||||||
Reference in New Issue
Block a user