PMCORE-2351 Advanced LDAP Improvements RM PMCORE-1299

This commit is contained in:
Roly Rudy Gutierrez Pinto
2020-12-11 15:22:55 -04:00
parent 9c1f954cfd
commit 1091a7eddb
27 changed files with 19917 additions and 153 deletions

View File

@@ -100,34 +100,65 @@ try {
global $RBAC;
$co = new Configurations();
$config = $co->getConfiguration( 'authSourcesList', 'pageSize', '', $_SESSION['USER_LOGGED'] );
$limit_size = isset( $config['pageSize'] ) ? $config['pageSize'] : 20;
$config = $co->getConfiguration('authSourcesList', 'pageSize', '', $_SESSION['USER_LOGGED']);
$limit_size = isset($config['pageSize']) ? $config['pageSize'] : 20;
$start = isset( $_REQUEST['start'] ) ? $_REQUEST['start'] : 0;
$limit = isset( $_REQUEST['limit'] ) ? $_REQUEST['limit'] : $limit_size;
$filter = isset( $_REQUEST['textFilter'] ) ? $_REQUEST['textFilter'] : '';
$start = isset($_REQUEST['start']) ? $_REQUEST['start'] : 0;
$limit = isset($_REQUEST['limit']) ? $_REQUEST['limit'] : $limit_size;
$filter = isset($_REQUEST['textFilter']) ? $_REQUEST['textFilter'] : '';
$Criterias = $RBAC->getAuthenticationSources( $start, $limit, $filter );
$criterias = $RBAC->getAuthenticationSources($start, $limit, $filter);
$Dat = AuthenticationSourcePeer::doSelectRS( $Criterias['COUNTER'] );
$Dat->setFetchmode( ResultSet::FETCHMODE_ASSOC );
$Dat->next();
$row = $Dat->getRow();
$dataSourceAuthentication = AuthenticationSourcePeer::doSelectRS($criterias['COUNTER']);
$dataSourceAuthentication->setFetchmode(ResultSet::FETCHMODE_ASSOC);
$dataSourceAuthentication->next();
$row = $dataSourceAuthentication->getRow();
$total_sources = $row['CNT'];
$oDataset = AuthenticationSourcePeer::doSelectRS( $Criterias['LIST'] );
$oDataset->setFetchmode( ResultSet::FETCHMODE_ASSOC );
if (!empty($_REQUEST['orderBy']) && isset($_REQUEST['ascending']) && defined("AuthenticationSourcePeer::" . $_REQUEST['orderBy'])) {
if ($_REQUEST['ascending'] === '1') {
$criterias['LIST']->addAscendingOrderByColumn(constant("AuthenticationSourcePeer::" . $_REQUEST['orderBy']));
}
if ($_REQUEST['ascending'] === '0') {
$criterias['LIST']->addDescendingOrderByColumn(constant("AuthenticationSourcePeer::" . $_REQUEST['orderBy']));
}
} else {
$criterias['LIST']->addAscendingOrderByColumn(AuthenticationSourcePeer::AUTH_SOURCE_NAME);
}
$dataset = AuthenticationSourcePeer::doSelectRS($criterias['LIST']);
$dataset->setFetchmode(ResultSet::FETCHMODE_ASSOC);
global $RBAC;
$auth = $RBAC->getAllUsersByAuthSource();
$aSources = Array ();
while ($oDataset->next()) {
$aSources[] = $oDataset->getRow();
$index = sizeof( $aSources ) - 1;
$aSources[$index]['CURRENT_USERS'] = isset( $auth[$aSources[$index]['AUTH_SOURCE_UID']] ) ? $auth[$aSources[$index]['AUTH_SOURCE_UID']] : 0;
$sources = [];
while ($dataset->next()) {
$row = $dataset->getRow();
$values = explode("_", $row["AUTH_SOURCE_PASSWORD"]);
foreach ($values as $value) {
if ($value == "2NnV3ujj3w") {
$row["AUTH_SOURCE_PASSWORD"] = G::decrypt($values[0], $row["AUTH_SOURCE_SERVER_NAME"]);
}
}
$label = G::LoadTranslation('ID_DISABLE');
if ($row['AUTH_SOURCE_ENABLED_TLS'] === "1") {
$label = G::LoadTranslation('ID_ENABLE');
}
$row['AUTH_SOURCE_ENABLED_TLS_LABEL'] = $label;
//additional information
$authSourceData = unserialize($row['AUTH_SOURCE_DATA']);
if (is_array($authSourceData)) {
$row = array_merge($row, $authSourceData);
}
$sources[] = $row;
$index = sizeof($sources) - 1;
$sources[$index]['CURRENT_USERS'] = isset($auth[$sources[$index]['AUTH_SOURCE_UID']]) ? $auth[$sources[$index]['AUTH_SOURCE_UID']] : 0;
}
echo '{sources: ' . G::json_encode( $aSources ) . ', total_sources: ' . $total_sources . '}';
$response = [
'sources' => $sources,
'total_sources' => $total_sources
];
echo G::json_encode($response);
break;
case 'canDeleteAuthSource':
try {

View File

@@ -1,5 +1,9 @@
<?php
use ProcessMaker\Model\RbacAuthenticationSource;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
$function = $_REQUEST['functionAccion'];
switch ($function) {
@@ -62,10 +66,10 @@ switch ($function) {
//Response
$response["status"] = "OK";
$response["existsRecords"] = ($flagUser || $flagDepartment || $flagGroup)? 1 : 0;
$response["existsRecords"] = ($flagUser || $flagDepartment || $flagGroup) ? 1 : 0;
} catch (Exception $e) {
//Response
$response["status"] = "ERROR";
$response["status"] = "ERROR";
$response["message"] = $e->getMessage();
}
@@ -93,7 +97,44 @@ switch ($function) {
default:
break;
}
echo G::json_encode(array('success'=> true, 'data' => $data, 'message'=>'Created Quote', 'total' => count($data)));
echo G::json_encode(array('success' => true, 'data' => $data, 'message' => 'Created Quote', 'total' => count($data)));
break;
case 'ldapVerifyName':
$authSourceName = empty($_REQUEST['AUTH_SOURCE_NAME']) ? '' : $_REQUEST['AUTH_SOURCE_NAME'];
$authenticationSource = RbacAuthenticationSource::query()
->select(['AUTH_SOURCE_UID', 'AUTH_SOURCE_NAME'])
->where('AUTH_SOURCE_NAME', '=', $authSourceName)
->get()
->first();
$row = false;
$suggestName = "";
if (!empty($authenticationSource)) {
$row = $authenticationSource;
$lastAuthenticationSource = RbacAuthenticationSource::query()
->select(['AUTH_SOURCE_NAME'])
->where('AUTH_SOURCE_NAME', 'LIKE', "%{$authSourceName}%")
->orderBy('AUTH_SOURCE_NAME', 'desc')
->get()
->first();
if (!empty($lastAuthenticationSource)) {
$name = $lastAuthenticationSource->AUTH_SOURCE_NAME;
//get suggest name
$pieces = explode(" ", $name);
$last = array_pop($pieces);
$number = trim($last, "()");
if ("({$number})" === $last) {
$number = intval($number) + 1;
$suggestName = implode("", $pieces) . " ({$number})";
} else {
$suggestName = $name . " (1)";
}
}
}
echo G::json_encode([
'success' => true,
'row' => $row,
'suggestName' => $suggestName
]);
break;
case 'ldapSave':
if (isset($_POST['AUTH_SOURCE_SHOWGRID-checkbox'])) {
@@ -102,7 +143,7 @@ switch ($function) {
$attributes = G::json_decode($_POST['AUTH_SOURCE_GRID_TEXT']);
$con = 1;
foreach ($attributes as $value) {
$_POST['AUTH_SOURCE_GRID_ATTRIBUTE'][$con] = (array)$value;
$_POST['AUTH_SOURCE_GRID_ATTRIBUTE'][$con] = (array) $value;
$con++;
}
}
@@ -133,11 +174,11 @@ switch ($function) {
unset($_POST['AUTH_SOURCE_GRID_TEXT']);
}
$aCommonFields = array ('AUTH_SOURCE_UID','AUTH_SOURCE_NAME','AUTH_SOURCE_PROVIDER','AUTH_SOURCE_SERVER_NAME','AUTH_SOURCE_PORT','AUTH_SOURCE_ENABLED_TLS','AUTH_ANONYMOUS','AUTH_SOURCE_SEARCH_USER','AUTH_SOURCE_PASSWORD','AUTH_SOURCE_VERSION','AUTH_SOURCE_BASE_DN','AUTH_SOURCE_OBJECT_CLASSES','AUTH_SOURCE_ATTRIBUTES');
$aCommonFields = array('AUTH_SOURCE_UID', 'AUTH_SOURCE_NAME', 'AUTH_SOURCE_PROVIDER', 'AUTH_SOURCE_SERVER_NAME', 'AUTH_SOURCE_PORT', 'AUTH_SOURCE_ENABLED_TLS', 'AUTH_ANONYMOUS', 'AUTH_SOURCE_SEARCH_USER', 'AUTH_SOURCE_PASSWORD', 'AUTH_SOURCE_VERSION', 'AUTH_SOURCE_BASE_DN', 'AUTH_SOURCE_OBJECT_CLASSES', 'AUTH_SOURCE_ATTRIBUTES');
$aFields = $aData = array ();
$aFields = $aData = array();
foreach ($_POST as $sField => $sValue) {
if (in_array( $sField, $aCommonFields )) {
if (in_array($sField, $aCommonFields)) {
$aFields[$sField] = $sValue;
} else {
$aData[$sField] = $sValue;
@@ -168,11 +209,11 @@ switch ($function) {
//Save
if ($aFields['AUTH_SOURCE_UID'] == '') {
$RBAC->createAuthSource( $aFields );
$RBAC->createAuthSource($aFields);
} else {
$RBAC->updateAuthSource( $aFields );
$RBAC->updateAuthSource($aFields);
}
echo G::json_encode(array('success'=> true));
echo G::json_encode(array('success' => true));
break;
case "searchUsers":
$response = array();
@@ -182,8 +223,8 @@ switch ($function) {
$authenticationSourceUid = $_POST["sUID"];
$keyword = $_POST["sKeyword"];
$start = (isset($_POST["start"]))? $_POST["start"]: 0;
$limit = (isset($_POST["limit"]))? $_POST["limit"]: $pageSize;
$start = (isset($_POST["start"])) ? $_POST["start"] : 0;
$limit = (isset($_POST["limit"])) ? $_POST["limit"] : $pageSize;
//Get Users from Database
$arrayUser = array();
@@ -217,7 +258,7 @@ switch ($function) {
if (!isset($arrayUser[strtolower($arrayUserData["sUsername"])])) {
$arrayUserData["STATUS"] = G::LoadTranslation("ID_NOT_IMPORTED");
$arrayUserData["IMPORT"] = 1;
} elseif($authenticationSourceUid === $arrayUser[strtolower($arrayUserData["sUsername"])]) {
} elseif ($authenticationSourceUid === $arrayUser[strtolower($arrayUserData["sUsername"])]) {
$arrayUserData["STATUS"] = G::LoadTranslation("ID_IMPORTED");
$arrayUserData["IMPORT"] = 0;
} else {
@@ -229,25 +270,25 @@ switch ($function) {
}
//Response
$response["status"] = "OK";
$response["status"] = "OK";
$response["success"] = true;
$response["resultTotal"] = $result["numRecTotal"];
$response["resultRoot"] = $arrayData;
$response["resultRoot"] = $arrayData;
} catch (Exception $e) {
//Response
$response["status"] = "ERROR";
$response["status"] = "ERROR";
$response["message"] = $e->getMessage();
}
echo G::json_encode($response);
break;
case 'importUsers':
$usersImport = $_REQUEST['UsersImport'];
$usersImport = $_REQUEST['UsersImport'];
$authSourceUid = $_REQUEST['AUTH_SOURCE_UID'];
$aUsers = G::json_decode($usersImport);
global $RBAC;
$aFields = $RBAC->getAuthSource( $authSourceUid );
$aFields = $RBAC->getAuthSource($authSourceUid);
$aAttributes = array();
if (isset($aFields['AUTH_SOURCE_DATA']['AUTH_SOURCE_GRID_ATTRIBUTE'])) {
@@ -258,46 +299,46 @@ switch ($function) {
$countUsers = 0;
//$usersImport
foreach ($aUsers as $sUser) {
$aUser = (array)$sUser;
$aUser = (array) $sUser;
$matches = array();
$aData = array();
$aData['USR_USERNAME'] = str_replace( "*", "'", $aUser['sUsername'] );
$aData = array();
$aData['USR_USERNAME'] = str_replace("*", "'", $aUser['sUsername']);
$aData["USR_PASSWORD"] = "00000000000000000000000000000000";
// note added by gustavo gustavo-at-colosa.com
// asign the FirstName and LastName variables
// add replace to change D*Souza to D'Souza by krlos
$aData['USR_FIRSTNAME'] = str_replace( "*", "'", $aUser['sFirstname'] );
$aData['USR_LASTNAME'] = str_replace( "*", "'", $aUser['sLastname'] );
$aData['USR_FIRSTNAME'] = str_replace("*", "'", $aUser['sFirstname']);
$aData['USR_LASTNAME'] = str_replace("*", "'", $aUser['sLastname']);
$aData['USR_EMAIL'] = $aUser['sEmail'];
$aData['USR_DUE_DATE'] = date( 'Y-m-d', mktime( 0, 0, 0, date( 'm' ), date( 'd' ), date( 'Y' ) + 2 ) );
$aData['USR_CREATE_DATE'] = date( 'Y-m-d H:i:s' );
$aData['USR_UPDATE_DATE'] = date( 'Y-m-d H:i:s' );
$aData['USR_BIRTHDAY'] = date( 'Y-m-d' );
$aData['USR_DUE_DATE'] = date('Y-m-d', mktime(0, 0, 0, date('m'), date('d'), date('Y') + 2));
$aData['USR_CREATE_DATE'] = date('Y-m-d H:i:s');
$aData['USR_UPDATE_DATE'] = date('Y-m-d H:i:s');
$aData['USR_BIRTHDAY'] = date('Y-m-d');
$aData['USR_STATUS'] = (isset($aUser['USR_STATUS'])) ? (($aUser['USR_STATUS'] == 'ACTIVE') ? 1 : 0) : 1;
$aData['USR_AUTH_TYPE'] = strtolower( $aFields['AUTH_SOURCE_PROVIDER'] );
$aData['USR_AUTH_TYPE'] = strtolower($aFields['AUTH_SOURCE_PROVIDER']);
$aData['UID_AUTH_SOURCE'] = $aFields['AUTH_SOURCE_UID'];
// validating with regexp if there are some missing * inside the DN string
// if it's so the is changed to the ' character
preg_match( '/[a-zA-Z]\*[a-zA-Z]/', $aUser['sDN'], $matches );
preg_match('/[a-zA-Z]\*[a-zA-Z]/', $aUser['sDN'], $matches);
foreach ($matches as $key => $match) {
$newMatch = str_replace( '*', '\'', $match );
$aUser['sDN'] = str_replace( $match, $newMatch, $aUser['sDN'] );
$newMatch = str_replace('*', '\'', $match);
$aUser['sDN'] = str_replace($match, $newMatch, $aUser['sDN']);
}
$aData['USR_AUTH_USER_DN'] = $aUser['sDN'];
try {
$sUserUID = $RBAC->createUser( $aData, 'PROCESSMAKER_OPERATOR', $aFields['AUTH_SOURCE_NAME']);
$usersCreated .= $aData['USR_USERNAME'].' ';
$countUsers ++;
$sUserUID = $RBAC->createUser($aData, 'PROCESSMAKER_OPERATOR', $aFields['AUTH_SOURCE_NAME']);
$usersCreated .= $aData['USR_USERNAME'] . ' ';
$countUsers++;
} catch (Exception $oError) {
$G_PUBLISH = new Publisher();
$G_PUBLISH->AddContent( 'xmlform', 'xmlform', 'login/showMessage', '', array ('MESSAGE' => $oError->getMessage()) );
$G_PUBLISH->AddContent('xmlform', 'xmlform', 'login/showMessage', '', array('MESSAGE' => $oError->getMessage()));
G::RenderPage("publish", "blank");
die();
}
$aData['USR_STATUS'] = (isset($aUser['USR_STATUS'])) ? $aUser['USR_STATUS'] :'ACTIVE';
$aData['USR_STATUS'] = (isset($aUser['USR_STATUS'])) ? $aUser['USR_STATUS'] : 'ACTIVE';
$aData['USR_UID'] = $sUserUID;
$aData['USR_ROLE'] = 'PROCESSMAKER_OPERATOR';
@@ -307,7 +348,7 @@ switch ($function) {
if (count($aAttributes)) {
foreach ($aAttributes as $value) {
if (isset($aUser[$value['attributeUser']])) {
$aData[$value['attributeUser']] = str_replace( "*", "'", $aUser[$value['attributeUser']] );
$aData[$value['attributeUser']] = str_replace("*", "'", $aUser[$value['attributeUser']]);
if ($value['attributeUser'] == 'USR_STATUS') {
$evalValue = $aData[$value['attributeUser']];
$statusValue = $aData['USR_STATUS'];
@@ -317,7 +358,7 @@ switch ($function) {
}
}
$oUser = new Users();
$oUser->create( $aData );
$oUser->create($aData);
}
$sClassName = strtolower($aFields['AUTH_SOURCE_PROVIDER']);
@@ -334,7 +375,7 @@ switch ($function) {
$plugin->log($ldapcnn, "Users imported $countUsers: " . $usersCreated);
echo G::json_encode(array('success'=> true));
echo G::json_encode(array('success' => true));
break;
case "ldapTestConnection":
$response = array();
@@ -357,7 +398,7 @@ switch ($function) {
$response["status"] = "OK";
} catch (Exception $e) {
//Response
$response["status"] = "ERROR";
$response["status"] = "ERROR";
$response["message"] = $e->getMessage();
}

View File

@@ -0,0 +1,24 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
/nbproject/private/

View File

@@ -0,0 +1,24 @@
# my-app
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

View File

@@ -0,0 +1,13 @@
<?php
global $G_PUBLISH;
$G_PUBLISH = new Publisher();
try {
echo file_get_contents(PATH_HOME . "public_html/lib/authenticationSources/index.html");
} catch (Exception $e) {
$message = [
'MESSAGE' => $e->getMessage()
];
$G_PUBLISH->AddContent('xmlform', 'xmlform', 'login/showMessage', '', $message);
G::RenderPage('publish', 'blank');
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,51 @@
{
"name": "authenticationSources",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build --dest ../../../public_html/lib/authenticationSources",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@panter/vue-i18next": "^0.15.2",
"@vue/cli": "^4.4.6",
"axios": "^0.19.2",
"bootstrap": "^4.5.0",
"bootstrap-vue": "^2.15.0",
"core-js": "^3.6.5",
"lodash": "^4.17.19",
"save": "^2.4.0",
"vue": "^2.6.11",
"vue-tables-2": "^2.0.27",
"vuelidate": "^0.7.5"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"vue-template-compiler": "^2.6.11"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<script type="text/javascript" src="/js/ext/translation.en.js"></script>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -0,0 +1,155 @@
<template>
<div id="app">
<authenticationSources ref="authenticationSources"
v-show="views.authenticationSources"
@newConnection="newConnection"
@editSettings="editSettings"
@optionSaveButton="optionSaveButton"
@optionUpdateButton="optionUpdateButton"
@optionNewButton="optionNewButton"/>
<newConnection ref="newConnection"
v-show="views.newConnection"
@matchAttributesToSync="matchAttributesToSync"
@save="saveNewConnection"
@cancel="showView('authenticationSources')"/>
<matchAttributes ref="matchAttributes"
v-show="views.matchAttributes"
@connectionSettings="connectionSettings"
@addAttribute="addAttribute"
@editAttribute="editAttribute"/>
<newMatchedAttribute ref="newMatchedAttribute"
v-show="views.newMatchedAttribute"
@save="saveNewMatchedAttribute"
@cancel="cancelNewMatchedAttribute"/>
</div>
</template>
<script>
import authenticationSources from './components/authenticationSources.vue'
import newConnection from './components/newConnection.vue'
import matchAttributes from './components/matchAttributes.vue'
import newMatchedAttribute from "./components/newMatchedAttribute.vue"
import axios from "axios"
export default {
name: 'app',
components: {
authenticationSources,
newConnection,
matchAttributes,
newMatchedAttribute
},
data() {
return {
views: {
authenticationSources: true,
newConnection: false,
matchAttributes: false,
newMatchedAttribute: false
},
selectedRow: null
};
},
methods: {
showView(name) {
for (let view in this.views) {
this.views[view] = false;
}
this.views[name] = true;
},
newConnection() {
this.$refs.newConnection.reset();
this.$refs.newConnection.setTitle(this.$root.translation('ID_NEW_AUTHENTICATION_SOURCES'));
this.showView('newConnection');
},
editSettings(row) {
this.selectedRow = row;
let form = this.$refs.newConnection.rowToForm(row);
this.$refs.newConnection.setTitle(this.$root.translation('ID_EDIT_AUTHENTICATION_SOURCES'));
this.$refs.newConnection.reset();
this.$refs.newConnection.load(form);
this.showView('newConnection');
},
optionSaveButton(row) {
row.AUTH_SOURCE_UID = "";
let form = this.$refs.newConnection.rowToForm(row);
this.$refs.newConnection.setTitle(this.$root.translation('ID_NEW_AUTHENTICATION_SOURCES'));
this.$refs.newConnection.reset();
this.$refs.newConnection.load(form);
this.showView('newConnection');
},
optionUpdateButton(row, rowResult) {
row.AUTH_SOURCE_UID = rowResult.AUTH_SOURCE_UID;
this.selectedRow = row;
let form = this.$refs.newConnection.rowToForm(row);
this.$refs.newConnection.setTitle(this.$root.translation('ID_EDIT_AUTHENTICATION_SOURCES'));
this.$refs.newConnection.reset();
this.$refs.newConnection.load(form);
this.showView('newConnection');
},
optionNewButton(row) {
row.AUTH_SOURCE_UID = "";
let form = this.$refs.newConnection.rowToForm(row);
this.$refs.newConnection.setTitle(this.$root.translation('ID_NEW_AUTHENTICATION_SOURCES'));
this.$refs.newConnection.reset();
this.$refs.newConnection.load(form);
this.showView('newConnection');
},
saveNewConnection(form) {
let formData = this.$refs.newConnection.formToFormData(form);
axios.post(this.$root.baseUrl() + "ldapAdvancedProxy.php?functionAccion=ldapSave", formData)
.then(response => {
response;
this.$refs.authenticationSources.refresh();
})
.catch(error => {
error;
})
.finally(() => {
});
this.showView('authenticationSources');
},
matchAttributesToSync() {
let gridText = this.$refs.newConnection.getGridText();
let rows = JSON.parse(gridText);
this.showView('matchAttributes');
this.$refs.matchAttributes.setRows(rows);
},
addAttribute() {
this.$refs.newMatchedAttribute.reset();
this.showView("newMatchedAttribute");
},
editAttribute(row, index) {
this.$refs.newMatchedAttribute.load(row, index);
this.showView("newMatchedAttribute");
},
saveNewMatchedAttribute(form) {
this.$refs.matchAttributes.saveRow(form);
this.showView('matchAttributes');
},
cancelNewMatchedAttribute() {
this.showView('matchAttributes');
},
connectionSettings(rows) {
let gridText = JSON.stringify(rows);
this.$refs.newConnection.setGridText(gridText);
this.showView('newConnection');
}
}
}
</script>
<style>
#app {
margin: 20px;
}
.custom-tooltip > .tooltip-inner{
max-width: none;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,279 @@
<template>
<div>
<titleSection :title="$root.translation('ID_AUTH_SOURCES')"></titleSection>
<b-form-group class="float-right">
<b-button variant="primary"
@click="$refs['as-b-modal-upload-file'].show();">
<b-icon icon="arrow-up-short" aria-hidden="true"/> {{$root.translation('ID_IMPORT_CONNECTION')}}
</b-button>&nbsp;
<b-button variant="success"
@click="$emit('newConnection')">
<b-icon icon="plus" aria-hidden="true"/> {{$root.translation('ID_NEW_CONNECTION')}}
</b-button>
</b-form-group>
<v-server-table ref="vServerTable1"
:url="baseUrl"
:columns="columns"
:options="options"
:data="tableData">
<div slot="icons"
slot-scope="props">
<b-button :id="'as-b-button-tooltip-'+props.index"
variant="light"
size="sm"
class="mb-2"
@mousedown="$root.$emit('bv::hide::tooltip');"
@mouseup="$root.$emit('bv::show::tooltip','as-b-button-tooltip-'+props.index);">
<b-icon icon="three-dots-vertical" aria-hidden="true"/>
</b-button>
<b-tooltip :target="'as-b-button-tooltip-'+props.index"
triggers="hover click focus"
custom-class="custom-tooltip"
placement="left"
variant="light">
<b-button-group>
<b-button @click="importUsers(props.row)"
v-b-tooltip.hover
:title="$root.translation('ID_IMPORT_USERS')"
variant="light">
<b-icon icon="arrow-repeat" aria-hidden="true" variant="success"/>
</b-button>
<b-button @click="downloadRow(props.row)"
v-b-tooltip.hover
:title="$root.translation('ID_DOWNLOAD_SETTINGS')"
variant="light">
<b-icon icon="arrow-down" aria-hidden="true" variant="info"/>
</b-button>
<b-button @click="syncGroups(props.row)"
v-b-tooltip.hover
:title="$root.translation('ID_GROUPS_SYNCHRONIZE')"
variant="light">
<b-icon icon="people-fill" aria-hidden="true" variant="warning"/>
</b-button>
<b-button @click="syncDepartments(props.row)"
v-b-tooltip.hover
:title="$root.translation('ID_DEPARTMENTS_SYNCHRONIZE')"
variant="light">
<b-icon icon="diagram3-fill" aria-hidden="true" variant="warning"/>
</b-button>
<b-button @click="$emit('editSettings',props.row)"
v-b-tooltip.hover
:title="$root.translation('ID_EDIT_SETTINGS')"
variant="light">
<b-icon icon="pencil-fill" aria-hidden="true" variant="info"/>
</b-button>
<b-button @click="deleteRow(props.row)"
v-b-tooltip.hover
:title="$root.translation('ID_DELETE_SETTINGS')"
variant="light">
<b-icon icon="trash" aria-hidden="true" variant="danger"/>
</b-button>
</b-button-group>
</b-tooltip>
</div>
</v-server-table>
<b-modal ref="as-b-modal-upload-file"
:title="$root.translation('ID_UPLOAD_CONNECTION_SETTINGS')"
hide-footer
size="lg">
<formUploadSource ref="formUploadSource"
@cancel="$refs['as-b-modal-upload-file'].hide();$refs.formUploadSource.reset();"
@optionSaveButton="optionSaveButton"
@optionUpdateButton="optionUpdateButton"
@optionNewButton="optionNewButton">
</formUploadSource>
</b-modal>
</div>
</template>
<script>
import titleSection from "./titleSection.vue"
import formUploadSource from "./formUploadSource.vue"
import axios from "axios"
export default {
components: {
titleSection,
formUploadSource
},
data() {
return {
baseUrl: this.$root.baseUrl() + "/authSources_Ajax?action=authSourcesList",
columns: [
"AUTH_SOURCE_NAME",
"AUTH_SOURCE_PROVIDER",
"AUTH_SOURCE_SERVER_NAME",
"AUTH_SOURCE_PORT",
"AUTH_SOURCE_ENABLED_TLS_LABEL",
"CURRENT_USERS",
"icons"
],
options: {
headings: {
AUTH_SOURCE_NAME: this.$root.translation("ID_NAME"),
AUTH_SOURCE_PROVIDER: this.$root.translation("ID_PROVIDER"),
AUTH_SOURCE_SERVER_NAME: this.$root.translation("ID_SERVER_NAME"),
AUTH_SOURCE_PORT: this.$root.translation("ID_PORT"),
AUTH_SOURCE_ENABLED_TLS_LABEL: this.$root.translation("ID_ENABLED_TLS"),
CURRENT_USERS: this.$root.translation("ID_ACTIVE_USERS"),
icons: ""
},
sortable: [
"AUTH_SOURCE_NAME",
"AUTH_SOURCE_PROVIDER",
"AUTH_SOURCE_SERVER_NAME",
"AUTH_SOURCE_PORT",
"AUTH_SOURCE_ENABLED_TLS_LABEL",
"CURRENT_USERS"
],
filterable: [
"AUTH_SOURCE_NAME",
"AUTH_SOURCE_PROVIDER",
"AUTH_SOURCE_SERVER_NAME",
"AUTH_SOURCE_PORT",
"AUTH_SOURCE_ENABLED_TLS_LABEL",
"CURRENT_USERS"
],
texts: {
filter: "",
filterPlaceholder: this.$root.translation("ID_EMPTY_SEARCH"),
count: this.$root.translation("ID_SHOWING_FROM_RECORDS_COUNT"),
noResults: this.$root.translation("ID_NO_MATCHING_RECORDS"),
loading: this.$root.translation("ID_LOADING_GRID")
},
perPage: 5,
perPageValues: [],
sortIcon: {
is: "glyphicon-sort",
base: "glyphicon",
up: "glyphicon-chevron-up",
down: "glyphicon-chevron-down"
},
requestKeys: {
query: "textFilter"
},
requestFunction(data) {
data.start = (data.page - 1) * data.limit;
return axios.get(this.url, {params: data}, {}).catch(function (e) {
this.dispatch("error", e);
});
},
responseAdapter(data) {
if (!("sources" in data.data)) {
data.data.sources = [];
}
if (!("total_sources" in data.data)) {
data.data.total_sources = 0;
}
return {
data: data.data.sources,
count: data.data.total_sources
};
}
},
tableData: []
};
},
methods: {
refresh() {
this.$refs.vServerTable1.refresh();
},
deleteRow(row) {
this.$root.$emit('bv::hide::tooltip');
this.$bvModal.msgBoxConfirm(this.$root.translation('ID_ARE_YOU_SURE_TO_DELETE_CONNECTION_PLEASE_CONFIRM', [row.AUTH_SOURCE_NAME]), {
title: " ", //is important because title disappear
hideHeaderClose: false,
okTitle: this.$root.translation('ID_YES'),
okVariant: "success",
cancelTitle: this.$root.translation('ID_NO'),
cancelVariant: "danger"
}).then(value => {
if (value === false) {
return;
}
let formData = new FormData();
formData.append("action", "deleteAuthSource");
formData.append("auth_uid", row.AUTH_SOURCE_UID);
axios.post(this.$root.baseUrl() + "authSources_Ajax", formData)
.then(response => {
response;
this.refresh();
})
.catch(error => {
error;
})
.finally(() => {
});
}).catch(err => {
err;
});
},
downloadRow(row) {
this.$root.$emit('bv::hide::tooltip');
let obj = JSON.parse(JSON.stringify(row)); //is need a object copy
//compatibility for complement ppsellucianldap
obj.AUTH_SOURCE_UID = "";
delete obj.AUTH_SOURCE_PASSWORD;
delete obj.CURRENT_USERS;
delete obj["UPPER(RBAC_AUTHENTICATION_SOURCE.AUTH_SOURCE_NAME)"];
delete obj.AUTH_SOURCE_VERSION;
delete obj.AUTH_SOURCE_ATTRIBUTES;
delete obj.AUTH_SOURCE_OBJECT_CLASSES;
delete obj.AUTH_SOURCE_DATA;
delete obj.AUTH_SOURCE_ENABLED_TLS_LABEL;
delete obj.LDAP_PAGE_SIZE_LIMIT;
if ("AUTH_SOURCE_GRID_ATTRIBUTE" in obj) {
let convert = [];
for (let i in obj.AUTH_SOURCE_GRID_ATTRIBUTE) {
let data = obj.AUTH_SOURCE_GRID_ATTRIBUTE[i] || {};
convert.push({
attributeLdap: data.attributeLdap || '',
attributeUser: data.attributeUser || '',
attributeRole: data.attributeRole || ''
});
}
obj.AUTH_SOURCE_GRID_ATTRIBUTE = convert;
}
//creation file
let name = obj.AUTH_SOURCE_NAME + ".json";
if (window.navigator.msSaveBlob) {
window.navigator.msSaveBlob(new Blob([JSON.stringify(obj)], {type: 'application/octet-stream'}), name);
return;
}
let a = document.createElement('a');
document.body.appendChild(a);
a.href = window.URL.createObjectURL(new Blob([JSON.stringify(obj)], {type: 'application/octet-stream'}));
a.download = name;
a.click();
document.body.removeChild(a);
},
importUsers(row) {
//the return action is in: processmaker/workflow/engine/templates/ldapAdvanced/ldapAdvancedSearch.js
location.href = this.$root.baseUrl() + 'authSources_SearchUsers?sUID=' + row.AUTH_SOURCE_UID;
},
syncGroups(row) {
//the return action is in: processmaker/workflow/engine/templates/authSources/authSourcesSynchronize.js
location.href = this.$root.baseUrl() + "authSourcesSynchronize?authUid=" + row.AUTH_SOURCE_UID + "&tab=synchronizeGroups";
},
syncDepartments(row) {
//the return action is in: processmaker/workflow/engine/templates/authSources/authSourcesSynchronize.js
location.href = this.$root.baseUrl() + "authSourcesSynchronize?authUid=" + row.AUTH_SOURCE_UID + "&tab=synchronizeDepartments";
},
optionSaveButton(fileContent) {
this.$refs['as-b-modal-upload-file'].hide();
this.$emit('optionSaveButton', fileContent);
},
optionUpdateButton(fileContent, row) {
this.$refs['as-b-modal-upload-file'].hide();
this.$emit('optionUpdateButton', fileContent, row);
},
optionNewButton(fileContent) {
this.$refs['as-b-modal-upload-file'].hide();
this.$emit('optionNewButton', fileContent);
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,444 @@
<template>
<div>
<b-form @submit.stop.prevent="onSave">
<b-container fluid>
<b-row>
<b-col>
<b-form-group :label="$root.translation('ID_AVAILABLE_AUTHENTICATION_SOURCES')" description="">
<b-form-select v-model="form.availableAuthenticationSource"
:options="availableAuthenticationSources"/>
</b-form-group>
<b-form-group :label="$root.translation('ID_NAME')">
<b-form-input v-model="form.name"
:state="validateState('name')"
placeholder=""/>
<b-form-invalid-feedback>{{$root.translation('ID_IS_REQUIRED')}}</b-form-invalid-feedback>
</b-form-group>
<b-form-group :label="$root.translation('ID_TYPE')">
<b-form-select v-model="form.type"
:options="types"
@change="changeTypeForm"/>
</b-form-group>
<b-form-group v-if="form.type==='ad'"
:label="$root.translation('ID_REQUIRE_SIGN_IN_POLICY_FOR_LDAP')">
<b-form-checkbox v-model="form.signInPolicyForLDAP"
value="1"
unchecked-value="0"/>
</b-form-group>
<b-form-group :label="$root.translation('ID_SERVER_ADDRESS')">
<b-form-input v-model="form.serverAddress"
:state="validateState('serverAddress')"
placeholder=""/>
<b-form-invalid-feedback>{{$root.translation('ID_IS_REQUIRED')}}</b-form-invalid-feedback>
</b-form-group>
<b-form-group :label="$root.translation('ID_PORT')">
<b-form-input v-model="form.port"
:state="validateState('port')"
placeholder=""/>
<b-form-invalid-feedback>{{$root.translation('ID_IS_REQUIRED')}}</b-form-invalid-feedback>
</b-form-group>
<b-form-group :label="$root.translation('ID_ENABLE_AUTOMATIC_REGISTER')"
label-cols-lg="8">
<b-form-checkbox v-model="form.enableAutomaticRegister"
value="1"
unchecked-value="0"
switch/>
</b-form-group>
<b-form-group :label="$root.translation('ID_ANONYMOUS')"
label-cols-lg="8">
<b-form-checkbox v-model="form.anonymous"
value="1"
unchecked-value="0"
switch/>
</b-form-group>
<b-form-group :label="$root.translation('ID_ENABLED_TLS')"
label-cols-lg="8">
<b-form-checkbox v-model="form.enableTLS"
value="1"
unchecked-value="0"
switch/>
</b-form-group>
<b-form-group :label="$root.translation('ID_BASE_DN')">
<b-form-input v-model="form.baseDN"
placeholder="dc=business,dc=net"/>
</b-form-group>
<b-form-group :label="$root.translation('ID_INACTIVE_USERS')">
<b-form-input v-model="form.inactiveUsers"
placeholder=""/>
</b-form-group>
<b-form-group :label="$root.translation('ID_ROLE')">
<b-form-select v-model="form.role"
:options="roles"/>
</b-form-group>
</b-col>
<b-col>
<b-form-group class="text-right">
<b-button variant="success" @click="$refs['fas-b-modal-upload-file'].show();">{{$root.translation('ID_IMPORT_SETTINGS')}}</b-button>
</b-form-group>
<b-form-group class="text-right">
<b-link href="#" @click="matchAttributesToSync" v-show="showMathAttributes || testStatus">{{$root.translation('ID_MATCH_ATTRIBUTES_TO_SYNC')}} &gt;&gt;</b-link>
</b-form-group>
<b-form-group :label="$root.translation('ID_USERNAME')">
<b-form-input v-model="form.userName"
:state="validateState('userName')"
placeholder=""/>
<b-form-invalid-feedback>{{$root.translation('ID_IS_REQUIRED')}}</b-form-invalid-feedback>
</b-form-group>
<b-form-group :label="$root.translation('ID_PASSWORD')">
<b-form-input v-model="form.password"
:state="validateState('password')"
type="password"/>
<b-form-invalid-feedback>{{$root.translation('ID_IS_REQUIRED')}}</b-form-invalid-feedback>
</b-form-group>
<b-form-group :label="$root.translation('ID_USER_IDENTIFIER')">
<b-form-input v-model="form.userIdentifier"
placeholder=""
readonly/>
</b-form-group>
<b-form-group :label="$root.translation('ID_GROUP_IDENTIFIER')">
<b-form-input v-model="form.groupIdentifier"
placeholder=""
readonly/>
</b-form-group>
<b-form-group :label="$root.translation('ID_FILTER_TO_SEARCH_USERS')">
<b-form-input v-model="form.filterToSearchUsers"
placeholder=""/>
</b-form-group>
<b-form-group :label="$root.translation('ID_USER_CLASS_IDENTIFIER')">
<b-form-input v-model="form.userClassIdentifier"
placeholder=""/>
</b-form-group>
<b-form-group :label="$root.translation('ID_GROUP_CLASS_IDENTIFIER')">
<b-form-input v-model="form.groupClassIdentifier"
placeholder=""/>
</b-form-group>
<b-form-group :label="$root.translation('ID_DEPARTMENT_CLASS_IDENTIFIER')">
<b-form-input v-model="form.departmentClassIdentifier"
placeholder=""/>
</b-form-group>
</b-col>
</b-row>
<b-row class="text-right">
<b-col>
<b-form-group>
<b-button variant="danger" @click="$emit('cancel')">{{$root.translation('ID_CANCEL')}}</b-button>&nbsp;
<b-button type="submit" variant="success">{{buttonLabel}}</b-button>
</b-form-group>
</b-col>
</b-row>
</b-container>
</b-form>
<b-modal id="messageForFailedTest"
ok-variant="success"
ok-only>
{{testMessage}}
</b-modal>
<b-modal ref="fas-b-modal-upload-file"
:title="$root.translation('ID_IMPORT_SETTINGS')"
hide-footer
size="lg">
<formUploadSource ref="formUploadSource"
@cancel="$refs['fas-b-modal-upload-file'].hide();$refs.formUploadSource.reset();"
@optionSaveButton="optionSaveButton"
skipNameValidation>
</formUploadSource>
</b-modal>
</div>
</template>
<script>
import formUploadSource from "./formUploadSource.vue"
import { validationMixin } from "vuelidate"
import { required } from "vuelidate/lib/validators"
import axios from "axios"
export default {
mixins: [validationMixin],
components: {
formUploadSource
},
validations: {
form: {
name: {
required
},
serverAddress: {
required
},
port: {
required
},
userName: {
required
},
password: {
required
}
}
},
data() {
return {
buttonLabel: this.$root.translation("ID_TEST"),
testStatus: false,
testMessage: "",
showMathAttributes: false,
form: {
uid: "",
availableAuthenticationSource: "ldapAdvanced",
name: "",
type: "ad",
serverAddress: "",
port: "389",
enableAutomaticRegister: "0",
anonymous: "0",
enableTLS: "0",
baseDN: "",
userName: "",
password: "",
userIdentifier: "samaccountname",
filterToSearchUsers: "",
gridText: "[]",
signInPolicyForLDAP: "1",
inactiveUsers: "",
role: "PROCESSMAKER_OPERATOR",
groupIdentifier: "member",
userClassIdentifier: "",
groupClassIdentifier: "(objectclass=posixgroup)(objectclass=group)(objectclass=groupofuniquenames)",
departmentClassIdentifier: "(objectclass=organizationalunit)"
},
availableAuthenticationSources: [
{value: "ldapAdvanced", text: "LDAP Advanced"},
{value: "ldap", text: "LDAP"}
],
types: [
{value: "ad", text: "Active Directory"},
{value: "ldap", text: "Open LDAP"},
{value: "ds", text: "389 DS"}
],
roles: [
{value: "PROCESSMAKER_ADMIN", text: this.$root.translation("ID_SYSTEM_ADMINISTRATOR")},
{value: "PROCESSMAKER_MANAGER", text: this.$root.translation("ID_MANAGER")},
{value: "PROCESSMAKER_OPERATOR", text: this.$root.translation("ID_OPERATOR")}
],
show: true
};
},
methods: {
validateState(name) {
const {$dirty, $error} = this.$v.form[name];
return $dirty ? !$error : null;
},
reset() {
this.form = {
uid: "",
availableAuthenticationSource: "ldapAdvanced",
name: "",
type: "ad",
serverAddress: "",
port: "389",
enableAutomaticRegister: "0",
anonymous: "0",
enableTLS: "0",
baseDN: "",
userName: "",
password: "",
userIdentifier: "samaccountname",
filterToSearchUsers: "",
gridText: "[]",
signInPolicyForLDAP: "1",
inactiveUsers: "",
role: "PROCESSMAKER_OPERATOR",
groupIdentifier: "member",
userClassIdentifier: "",
groupClassIdentifier: "(objectclass=posixgroup)(objectclass=group)(objectclass=groupofuniquenames)",
departmentClassIdentifier: "(objectclass=organizationalunit)"
};
},
onSave() {
this.$v.form.$touch();
if (this.$v.form.$anyError) {
return;
}
if (this.testStatus) {
this.$emit("save", this.form);
} else {
this.test(this.form);
}
},
load(obj) {
this.form = obj;
},
test(form) {
let formDataForName = new FormData();
formDataForName.append("AUTH_SOURCE_NAME", form.name);
axios.post(this.$root.baseUrl() + "ldapAdvancedProxy.php?functionAccion=ldapVerifyName", formDataForName)
.then(response => {
//the name is valid
if (response.data.row === false || (this.form.uid !== "" && typeof this.form.uid === "string")) {
let formData = this.formToFormData(form);
axios.post(this.$root.baseUrl() + "ldapAdvancedProxy.php?functionAccion=ldapTestConnection", formData)
.then(response => {
//test is successful
if (response.data.status === "OK") {
this.testStatus = true;
this.buttonLabel = this.$root.translation("ID_SAVE");
return;
}
//test fail
this.testMessage = response.data.message;
this.testStatus = false;
this.buttonLabel = this.$root.translation("ID_TEST");
this.$bvModal.show("messageForFailedTest");
})
.catch(error => {
error;
})
.finally(() => {
});
return;
}
//the name exist
this.$bvModal.msgBoxOk(this.$root.translation('ID_NAME_EXISTS'), {
title: " ", //is important because title disappear
hideHeaderClose: false,
okTitle: this.$root.translation('ID_OK'),
okVariant: "success",
okOnly: true
}).then(value => {
if (value === false) {
return;
}
}).catch(err => {
err;
});
})
.catch(error => {
error;
})
.finally(() => {
});
},
matchAttributesToSync() {
this.$emit('matchAttributesToSync');
},
setGridText(gridText) {
this.form.gridText = gridText;
},
getGridText() {
return this.form.gridText;
},
optionSaveButton(row) {
this.$refs['fas-b-modal-upload-file'].hide();
row.AUTH_SOURCE_UID = "";
let form = this.rowToForm(row);
this.load(form);
},
rowToForm(row) {
let gridText = [];
if ("AUTH_SOURCE_GRID_ATTRIBUTE" in row) {
for (let i in row.AUTH_SOURCE_GRID_ATTRIBUTE) {
let data = row.AUTH_SOURCE_GRID_ATTRIBUTE[i] || {};
gridText.push({
attributeRole: data.attributeRole || '',
attributeUser: data.attributeUser || '',
attributeLdap: data.attributeLdap || ''
});
}
}
var obj = {
uid: row.AUTH_SOURCE_UID,
availableAuthenticationSource: row.AUTH_SOURCE_PROVIDER,
name: row.AUTH_SOURCE_NAME,
type: row.LDAP_TYPE,
serverAddress: row.AUTH_SOURCE_SERVER_NAME,
port: row.AUTH_SOURCE_PORT,
enableAutomaticRegister: row.AUTH_SOURCE_AUTO_REGISTER,
anonymous: row.AUTH_ANONYMOUS,
enableTLS: row.AUTH_SOURCE_ENABLED_TLS,
baseDN: row.AUTH_SOURCE_BASE_DN,
userName: row.AUTH_SOURCE_SEARCH_USER,
password: row.AUTH_SOURCE_PASSWORD,
userIdentifier: row.AUTH_SOURCE_IDENTIFIER_FOR_USER,
filterToSearchUsers: row.AUTH_SOURCE_USERS_FILTER,
gridText: JSON.stringify(gridText),
signInPolicyForLDAP: row.AUTH_SOURCE_SIGNIN_POLICY_FOR_LDAP,
inactiveUsers: row.AUTH_SOURCE_RETIRED_OU,
role: row.USR_ROLE,
groupIdentifier: row.AUTH_SOURCE_IDENTIFIER_FOR_USER_GROUP,
userClassIdentifier: row.AUTH_SOURCE_IDENTIFIER_FOR_USER_CLASS,
groupClassIdentifier: row.GROUP_CLASS_IDENTIFIER,
departmentClassIdentifier: row.DEPARTMENT_CLASS_IDENTIFIER
};
return obj;
},
formToFormData(form) {
let formData = new FormData();
formData.append("AUTH_SOURCE_UID", form.uid);
formData.append("AUTH_SOURCE_NAME", form.name);
formData.append("AUTH_SOURCE_PROVIDER", form.availableAuthenticationSource);
formData.append("LDAP_TYPE", form.type);
formData.append("AUTH_SOURCE_AUTO_REGISTER", form.enableAutomaticRegister);
formData.append("AUTH_SOURCE_SERVER_NAME", form.serverAddress);
formData.append("AUTH_SOURCE_PORT", form.port);
formData.append("AUTH_SOURCE_ENABLED_TLS", form.enableTLS);
formData.append("AUTH_SOURCE_BASE_DN", form.baseDN);
formData.append("AUTH_ANONYMOUS", form.anonymous);
formData.append("AUTH_SOURCE_SEARCH_USER", form.userName);
formData.append("AUTH_SOURCE_PASSWORD", form.password);
formData.append("AUTH_SOURCE_IDENTIFIER_FOR_USER", form.userIdentifier);
formData.append("AUTH_SOURCE_USERS_FILTER", form.filterToSearchUsers);
formData.append("AUTH_SOURCE_RETIRED_OU", form.inactiveUsers);
formData.append("AUTH_SOURCE_ATTRIBUTE_IDS", "USR_FIRSTNAME|USR_LASTNAME|USR_EMAIL|USR_DUE_DATE|USR_STATUS|USR_STATUS_ID|USR_ADDRESS|USR_PHONE|USR_FAX|USR_CELLULAR|USR_ZIP_CODE|USR_POSITION|USR_BIRTHDAY|USR_COST_BY_HOUR|USR_UNIT_COST|USR_PMDRIVE_FOLDER_UID|USR_BOOKMARK_START_CASES|USR_TIME_ZONE|USR_DEFAULT_LANG|USR_LAST_LOGIN|");
formData.append("AUTH_SOURCE_SHOWGRID", "");
formData.append("AUTH_SOURCE_GRID_TEXT", form.gridText);
formData.append("AUTH_SOURCE_SHOWGRID-checkbox", "on");
//additional
formData.append("AUTH_SOURCE_SIGNIN_POLICY_FOR_LDAP", form.signInPolicyForLDAP);
formData.append("USR_ROLE", form.role);
formData.append("AUTH_SOURCE_IDENTIFIER_FOR_USER_GROUP", form.groupIdentifier);
formData.append("AUTH_SOURCE_IDENTIFIER_FOR_USER_CLASS", form.userClassIdentifier);
formData.append("GROUP_CLASS_IDENTIFIER", form.groupClassIdentifier);
formData.append("DEPARTMENT_CLASS_IDENTIFIER", form.departmentClassIdentifier);
//compatibility for complement ppsellucianldap
formData.append("CUSTOM_CHECK_AUTH_SOURCE_IDENTIFIER_FOR_USER", 0);
formData.append("CUSTOM_CHECK_AUTH_SOURCE_IDENTIFIER_FOR_USER_GROUP", 0);
formData.append("CUSTOM_CHECK_DEPARTMENT_CLASS_IDENTIFIER", 0);
formData.append("CUSTOM_CHECK_GROUP_CLASS_IDENTIFIER", 0);
formData.append("CUSTOM_AUTH_SOURCE_IDENTIFIER_FOR_USER", "");
formData.append("CUSTOM_AUTH_SOURCE_IDENTIFIER_FOR_USER_GROUP", "");
formData.append("CUSTOM_DEPARTMENT_CLASS_IDENTIFIER", "");
formData.append("CUSTOM_GROUP_CLASS_IDENTIFIER", "");
return formData;
},
changeTypeForm(value) {
if (value === "ad") {
this.form.userIdentifier = "samaccountname";
this.form.groupIdentifier = "member";
this.form.signInPolicyForLDAP = "1";
}
if (value === "ldap") {
this.form.userIdentifier = "uid";
this.form.groupIdentifier = "memberuid";
this.form.signInPolicyForLDAP = "0";
}
if (value === "ds") {
this.form.userIdentifier = "uid";
this.form.groupIdentifier = "uniquemember";
this.form.signInPolicyForLDAP = "0";
}
}
},
watch: {
form: {
handler() {
this.testStatus = false;
this.buttonLabel = this.$root.translation("ID_TEST");
this.showMathAttributes = !(this.form.uid === "");
},
deep: true
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,166 @@
<template>
<div>
<b-form @submit.stop.prevent="onSave">
<b-container fluid>
<b-row>
<b-col>
<b-form-group :label="$root.translation('ID_PLEASE_ADD_THE_FILE_SETTINGS_TO_BE_UPLOADED')" v-if="newName==true">
<b-form-file v-model="form.connectionSettings"
@change="change"
:state="validateState('connectionSettings')"
:placeholder="$root.translation('ID_CHOOSE_A_FILE_OR_DROP_IT_HERE')"
:drop-placeholder="$root.translation('ID_DROP_FILE_HERE')">
</b-form-file>
<b-form-invalid-feedback>{{$root.translation('ID_IS_REQUIRED')}}</b-form-invalid-feedback>
</b-form-group>
<b-form-group :label="$root.translation('ID_CONNECTION_WITH_THE_SAME_NAME_PLEASE_SELECT_AN_OPTION')" v-else>
<b-form-file v-model="form.connectionSettings"
@change="change"
:state="validateState('connectionSettings')"
:placeholder="$root.translation('ID_CHOOSE_A_FILE_OR_DROP_IT_HERE')"
:drop-placeholder="$root.translation('ID_DROP_FILE_HERE')">
</b-form-file>
<b-form-invalid-feedback>{{$root.translation('ID_IS_REQUIRED')}}</b-form-invalid-feedback>
</b-form-group>
</b-col>
</b-row>
<b-row class="text-center">
<b-col>
<b-form-group v-if="newName==true">
<b-button variant="danger"
@click="$emit('cancel')">{{$root.translation('ID_CANCEL')}}</b-button>&nbsp;
<b-button type="submit"
variant="success"
:disabled='isDisabled'
id="save">{{$root.translation('ID_SAVE')}}</b-button>
</b-form-group>
<b-form-group v-else>
<b-button variant="danger"
@click="$emit('cancel')">{{$root.translation('ID_CANCEL')}}</b-button>&nbsp;
<b-button type="submit"
variant="primary"
:disabled='isDisabled'
id="update">{{$root.translation('ID_UPDATE_SETTINGS')}}</b-button>&nbsp;
<b-button type="submit"
variant="success"
:disabled='isDisabled'
id="new">{{$root.translation('ID_NEW_CONNECTION')}}</b-button>
</b-form-group>
</b-col>
</b-row>
</b-container>
</b-form>
<b-modal id="messageForInvalidFileExtension" ok-only static>{{$root.translation('ID_PMG_SELECT_FILE')}}</b-modal>
<b-modal id="messageForInvalidFileFormat" ok-only static>{{$root.translation('ID_INVALID_DATA')}}</b-modal>
</div>
</template>
<script>
import { validationMixin } from "vuelidate"
import { required } from "vuelidate/lib/validators"
import axios from "axios"
export default {
mixins: [validationMixin],
props: {
skipNameValidation: Boolean
},
components: {
},
validations: {
form: {
connectionSettings: {
required
}
}
},
data() {
return {
form: {
connectionSettings: []
},
fileContent: {},
isDisabled: true,
validationResult: {},
newName: true
};
},
methods: {
validateState(name) {
const {$dirty, $error} = this.$v.form[name];
return $dirty ? !$error : null;
},
onSave(e) {
this.$v.form.$touch();
if (this.$v.form.$anyError) {
return;
}
//validation
if (e.submitter.id === "save") {
this.$emit('optionSaveButton', this.fileContent);
}
if (e.submitter.id === "update") {
this.$emit('optionUpdateButton', this.fileContent, this.validationResult.row);
}
if (e.submitter.id === "new") {
this.fileContent.AUTH_SOURCE_NAME = this.validationResult.suggestName;
this.$emit('optionNewButton', this.fileContent);
}
},
reset() {
this.newName = true;
this.validationResult = {};
this.form.connectionSettings = [];
},
change(e) {
let input = e.target;
if (input.files.length <= 0) {
return;
}
let file = input.files[0];
if (file.name.indexOf(".json") < 0) {
this.$bvModal.show("messageForInvalidFileExtension");
this.reset();
this.isDisabled = true;
return;
}
let reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = (e) => {
this.fileContent = JSON.parse(e.target.result);
//validation content
if (!("AUTH_SOURCE_NAME" in this.fileContent)) {
this.$bvModal.show("messageForInvalidFileFormat");
this.reset();
this.isDisabled = true;
return;
}
if (this.skipNameValidation === true) {
this.isDisabled = false;
return;
}
//validation name
let formData = new FormData();
formData.append("AUTH_SOURCE_NAME", this.fileContent.AUTH_SOURCE_NAME);
axios.post(this.$root.baseUrl() + "ldapAdvancedProxy.php?functionAccion=ldapVerifyName", formData)
.then(response => {
this.newName = response.data.row === false;
this.validationResult = response.data;
this.isDisabled = false;
})
.catch(error => {
error;
this.isDisabled = true;
})
.finally(() => {
});
};
reader.onerror = () => {
};
return;
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,142 @@
<template>
<div>
<titleSection :title="$root.translation('ID_MATCH_ATTRIBUTES')"></titleSection>
<b-form-group class="text-right">
<b-link href="#" @click="connectionSettings"> &lt;&lt; {{$root.translation('ID_CONNECTION_SETTINGS')}}</b-link>
</b-form-group>
<b-form-group class="float-right">
<b-button variant="success" @click="addAttribute">{{$root.translation('ID_ADD_ATTRIBUTE')}}</b-button>
</b-form-group>
<v-client-table :columns="columns"
:options="options"
:data="rows">
<div slot="icons"
slot-scope="props">
<b-button :id="'ma-b-button-tooltip-'+props.index"
variant="light"
size="sm"
class="mb-2">
<b-icon icon="three-dots-vertical" aria-hidden="true"/>
</b-button>
<b-tooltip :target="'ma-b-button-tooltip-'+props.index"
triggers="hover focus click"
custom-class="custom-tooltip"
placement="left"
variant="light">
<b-button-group>
<b-button @click="editAttribute(props.row,props.index)"
v-b-tooltip.hover
:title="$root.translation('ID_EDIT_ATTRIBUTE')"
variant="light">
<b-icon icon="pencil-fill" aria-hidden="true" variant="info"/>
</b-button>
<b-button @click="deleteAttribute(props.index,props.row)"
v-b-tooltip.hover
:title="$root.translation('ID_DELETE_ATTRIBUTE')"
variant="light">
<b-icon icon="trash" aria-hidden="true" variant="danger"/>
</b-button>
</b-button-group>
</b-tooltip>
</div>
</v-client-table>
<b-modal id="messageForDeleteAttribute"
@ok="deleteAttributeProcess"
:ok-title="$root.translation('ID_YES')"
ok-variant="success"
:cancel-title="$root.translation('ID_NO')"
cancel-variant="danger">
{{$root.translation('ID_ARE_YOU_SURE_TO_DELETE_ATTRIBUTE_PLEASE_CONFIRM',[selectedRowName])}}
</b-modal>
</div>
</template>
<script>
import titleSection from "./titleSection.vue"
export default {
components: {
titleSection
},
data() {
return {
selectedRowIndex: 0,
selectedRowName: "",
columns: [
"attributeRole",
"attributeUser",
"attributeLdap",
"icons"
],
options: {
headings: {
attributeRole: this.$root.translation('ID_ROLE'),
attributeUser: this.$root.translation('ID_USER_FIELD'),
attributeLdap: this.$root.translation('ID_LDAP_FIELD'),
icons: ""
},
sortable: [
"attributeLdap",
"attributeRole",
"attributeUser"
],
filterable: [
"attributeLdap",
"attributeRole",
"attributeUser"
],
texts: {
filter: "",
filterPlaceholder: this.$root.translation("ID_EMPTY_SEARCH"),
count: this.$root.translation("ID_SHOWING_FROM_RECORDS_COUNT"),
noResults: this.$root.translation("ID_NO_MATCHING_RECORDS"),
loading: this.$root.translation("ID_LOADING_GRID")
},
perPage: 5,
perPageValues: [],
sortIcon: {
is: "glyphicon-sort",
base: "glyphicon",
up: "glyphicon-chevron-up",
down: "glyphicon-chevron-down"
}
},
rows: []
};
},
methods: {
setRows(rows) {
this.rows = rows;
},
addAttribute() {
this.$emit("addAttribute");
},
editAttribute(row, index) {
this.$emit("editAttribute", row, index);
},
deleteAttribute(index, row) {
this.selectedRowName = row.attributeLdap;
this.selectedRowIndex = index;
this.$bvModal.show("messageForDeleteAttribute");
},
deleteAttributeProcess() {
this.rows.splice(this.selectedRowIndex - 1, 1);
},
saveRow(obj) {
if (obj.index === null) {
delete obj.index;
this.rows.push(obj);
} else {
let i = obj.index;
delete obj.index;
this.rows[i - 1] = obj;
}
},
connectionSettings() {
this.$emit('connectionSettings', this.rows);
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,55 @@
<template>
<div>
<titleSection :title="title"></titleSection>
<formAuthenticationSources ref="formAuthenticationSources"
@matchAttributesToSync="$emit('matchAttributesToSync',$event)"
@cancel="cancel"
@save="$emit('save',$event)"/>
</div>
</template>
<script>
import titleSection from "./titleSection.vue"
import formAuthenticationSources from "./formAuthenticationSources.vue"
export default {
data() {
return {
title: "#"
};
},
components: {
titleSection,
formAuthenticationSources
},
methods: {
setTitle(value) {
this.title = value;
},
reset() {
this.$refs.formAuthenticationSources.reset();
},
load(obj) {
this.$refs.formAuthenticationSources.load(obj);
},
cancel() {
this.reset();
this.$emit('cancel');
},
rowToForm(row) {
return this.$refs.formAuthenticationSources.rowToForm(row);
},
formToFormData(form) {
return this.$refs.formAuthenticationSources.formToFormData(form);
},
setGridText(data) {
this.$refs.formAuthenticationSources.setGridText(data);
},
getGridText() {
return this.$refs.formAuthenticationSources.getGridText();
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,122 @@
<template>
<div>
<titleSection :title="$root.translation('ID_NEW_MATCHED_ATTRIBUTE')"></titleSection>
<b-form @submit.stop.prevent="onSave">
<b-container fluid>
<b-row>
<b-col>
<b-form-group :label="$root.translation('ID_ROLE')">
<b-form-select v-model="form.attributeRole"
:options="roles"/>
</b-form-group>
<b-form-group :label="$root.translation('ID_PROCESSMAKER_USER_FIELD')" description="">
<b-form-select v-model="form.attributeUser"
:options="userAttributes"/>
</b-form-group>
<b-form-group :label="$root.translation('ID_LDAP_ATTRIBUTE')">
<b-form-input v-model="form.attributeLdap"
:state="validateState('attributeLdap')"
placeholder=""/>
<b-form-invalid-feedback>{{$root.translation('ID_IS_REQUIRED')}}</b-form-invalid-feedback>
</b-form-group>
</b-col>
</b-row>
<b-row class="text-right">
<b-col>
<b-form-group>
<b-button variant="danger" @click="$emit('cancel')">{{$root.translation('ID_CANCEL')}}</b-button>&nbsp;
<b-button type="submit" variant="success">{{$root.translation('ID_SAVE')}}</b-button>
</b-form-group>
</b-col>
</b-row>
</b-container>
</b-form>
</div>
</template>
<script>
import { validationMixin } from "vuelidate"
import { required } from "vuelidate/lib/validators"
import titleSection from "./titleSection.vue"
export default {
mixins: [validationMixin],
components: {
titleSection
},
validations: {
form: {
attributeLdap: {
required
}
}
},
data() {
return {
form: {
index: null,
attributeLdap: "",
attributeRole: "",
attributeUser: "USR_FIRSTNAME"
},
roles: [
{value: "", text: "All"},
{value: "PROCESSMAKER_ADMIN", text: this.$root.translation("ID_SYSTEM_ADMINISTRATOR")},
{value: "PROCESSMAKER_MANAGER", text: this.$root.translation("ID_MANAGER")},
{value: "PROCESSMAKER_OPERATOR", text: this.$root.translation("ID_OPERATOR")}
],
userAttributes: [
{value: "USR_FIRSTNAME", text: "USR_FIRSTNAME"},
{value: "USR_LASTNAME", text: "USR_LASTNAME"},
{value: "USR_EMAIL", text: "USR_EMAIL"},
{value: "USR_DUE_DATE", text: "USR_DUE_DATE"},
{value: "USR_STATUS", text: "USR_STATUS"},
{value: "USR_STATUS_ID", text: "USR_STATUS_ID"},
{value: "USR_ADDRESS", text: "USR_ADDRESS"},
{value: "USR_PHONE", text: "USR_PHONE"},
{value: "USR_FAX", text: "USR_FAX"},
{value: "USR_CELLULAR", text: "USR_CELLULAR"},
{value: "USR_ZIP_CODE", text: "USR_ZIP_CODE"},
{value: "USR_POSITION", text: "USR_POSITION"},
{value: "USR_BIRTHDAY", text: "USR_BIRTHDAY"},
{value: "USR_COST_BY_HOUR", text: "USR_COST_BY_HOUR"},
{value: "USR_UNIT_COST", text: "USR_UNIT_COST"},
{value: "USR_PMDRIVE_FOLDER_UID", text: "USR_PMDRIVE_FOLDER_UID"},
{value: "USR_BOOKMARK_START_CASES", text: "USR_BOOKMARK_START_CASES"},
{value: "USR_TIME_ZONE", text: "USR_TIME_ZONE"},
{value: "USR_DEFAULT_LANG", text: "USR_DEFAULT_LANG"},
{value: "USR_LAST_LOGIN", text: "USR_LAST_LOGIN"}
]
};
},
methods: {
validateState(name) {
const {$dirty, $error} = this.$v.form[name];
return $dirty ? !$error : null;
},
onSave() {
this.$v.form.$touch();
if (this.$v.form.$anyError) {
return;
}
this.$emit("save", this.form);
},
load(row, index) {
this.form.index = index;
this.form.attributeLdap = row.attributeLdap;
this.form.attributeRole = row.attributeRole;
this.form.attributeUser = row.attributeUser;
},
reset() {
this.form = {
index: null,
attributeLdap: "",
attributeRole: "",
attributeUser: "USR_FIRSTNAME"
};
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,18 @@
<template>
<div>
<h3 class="text-primary">
{{title}}
</h3>
</div>
</template>
<script>
export default{
props: {
title: String
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,33 @@
import Vue from 'vue'
import {BootstrapVue, IconsPlugin} from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import {ClientTable} from 'vue-tables-2'
import {ServerTable} from 'vue-tables-2'
import App from './App.vue';
Vue.config.productionTip = false
Vue.use(BootstrapVue)
Vue.use(IconsPlugin)
Vue.use(ClientTable, {}, false, 'bootstrap4', {});
Vue.use(ServerTable, {}, false, 'bootstrap4', {});
new Vue({
render: h => h(App),
methods: {
translation(text, params) {
if ("TRANSLATIONS" in window && text in window.TRANSLATIONS) {
text = window.TRANSLATIONS[text];
if (params != undefined && "length" in params) {
for (let i = 0; i < params.length; i++) {
text = text.replace("{" + i + "}", params[i]);
}
}
}
return text;
},
baseUrl() {
return "../authSources/";
}
}
}).$mount('#app');

View File

@@ -0,0 +1,3 @@
module.exports = {
publicPath: '/lib/authenticationSources/'
};