In an AD server we have an attribute called directreports. I want to be able to go top to bottom in the chain. CEO his direct reports are A,B,C. As direct reports are D,E,F while Bs direct report is G,H,I. Then Ds direct reports are X,Y,Z, etc all the way down.
I've looked at this as a nested group kind of thing, but it's not. I'm lost as how to tackle this all together. I'm trying to do this in PHP. My php code right now just searches a user and gives me the direct reports.
<?php
function aduserlookup ($UserName)
{
include_once 'config.php';
$ldapconn = ldap_connect("ldap://<IP>:389") or die("Could not connect to the ldap server");
if($ldapconn) {
$r = #ldap_bind($ldapconn, $ldapuser."#test.com", $ldappass);
$sr=ldap_search($ldapconn, "OU=Employees,OU=Users,DC=test,DC=com",
"cn=" . $UserName);
$info = ldap_get_entries($ldapconn, $sr);
ldap_close($ldapconn);
return $info;
} else {
echo "<h4>Unable to connect to LDAP server</h4>";
}
}
$user = aduserlookup('test');
$directreports = $user[0]['directreports'];
echo '<pre>';
var_dump($directreports);
echo '</pre>';
foreach ($directreports as $key => $value)
{
$directreports = substr($value, 0, strpos($value, ","));
$directreports = strstr($directreports, '=');
$directreports = str_replace('=', '', $directreports);
$directreports1 = aduserlookup('\'' . $directreports . '\'');
echo $directreports1 . "<br>";
}
?>
IF you are using Microsoft Active Directory and If I understood what you are looking for,
You can Query All users that report to a department manager or their subordinates by using this query
(manager:1.2.840.113556.1.4.1941:=CN=manager,OU=users,DC=willeke,DC=com)
DirectReports is a server generated list of users that directly report to the "manager". The users that are listed as reports are those that have the property manager property set to this user. Each item in the list is a Linked Attribute to the object that represents the user.
Related
I found some cases where the error was the same, but the situation was not.
This is intended as custom workflow function in vTiger, code is the following:
function perform_query($entity) {
/*$entityArray = get_object_vars($entity); //array
echo "<pre>";
print_r($entityArray);
echo "</pre>";
break;*/
include_once 'include/Webservices/Query.php';
include_once 'modules/Users/Users.php';
$user = new Users();
$current_user = $user->retrieveCurrentUserInfoFromFile(Users::getActiveAdminId());
try {
$q = "SELECT * FROM vtiger_seactivityrel WHERE crmid = ".substr($entity->id, strpos($entity->id, "x") + 1);
$q = $q . ';';
$records = vtws_query($q, $current_user);
print_r($records);
} catch (WebServiceException $ex) {
echo $ex->getMessage();
}
break;
}
?>
This should give me the results: if there are, i want to take further actions. This gives me the following error:
Permission to perform the operation is denied for name.
I don't know what's happening, does anyone have any idea? Thank you.
I solved this myself. The fact is that vtws_query does NOT query the database directly. It has some kind of abstraction, so if you put database table and columns it just denies access. Although strange, right form is this one:
SELECT * FROM <ModuleName> WHERE <Property> = '<your_search>'
To list the modules, you should use vtws_listtypes; to know which properties you could search, use vtws_describe. More info here.
Similar issues -
INVALID_SESSION_ID using partner/enterprise wsdl for two different SF users - Tried solution but didn't work.
I was trying to use Salesforce PHP toolkit with ZF 2. I have added namespace to php files in salesforce soap client and used it in zend controller.
Added follwing line to all php files in Salesforce SOAP client library.
namespace Salesforce\Soapclient;
Then included it in ZF controller.
use Salesforce\Soapclient;
Here is the connetion code -
$empid = 'e1234567';
$sf_WSDL = 'C:\wamp\www\myapp\app\vendor\salesforce\wsdl\enterprise.wsdl.xml';
$sf_username = $config['salesforce']['username'];
$sf_password = $config['salesforce']['password'];
$sf_token = $config['salesforce']['token'];
/***********/
try {
// Create SOAP client instance
$sfSoapClient = new Soapclient\SforceEnterpriseClient();
// Create connection
$sfSoapClient->createConnection($sf_WSDL);
var_dump($_SESSION['enterpriseSessionId']);
if (isset($_SESSION['enterpriseSessionId'])) {
$location = $_SESSION['enterpriseLocation'];
$sessionId = $_SESSION['enterpriseSessionId'];
$sfSoapClient->setEndpoint($location);
$sfSoapClient->setSessionHeader($sessionId);
} else {
// Login to SF
$sfSoapClient->login($sf_username,$sf_password . $sf_token);
$_SESSION['enterpriseLocation'] = $sfSoapClient->getLocation();
$_SESSION['enterpriseSessionId'] = $sfSoapClient->getSessionId();
}
var_dump($_SESSION['enterpriseSessionId']);
// Get candidate profile by employee id
$candidate_profile = $this->getCandidateTable()->getCandidateByEmpId($empid);
$ids = array();
array_push($ids, $empid);
// If no profile for logged internal employee
if (!$candidate_profile){
$query = "SELECT Id, First_Name__c from Employee__c";
$response = $sfSoapClient->query($query);
echo "Results of query '$query'<br/><br/>\n";
foreach ($response->records as $record) {
echo $record->Id . ": " . $record->First_Name__c . "<br/>\n";
}
}
} catch (Exception $exc) {
//TODO Handle error login exception
die('Connection could not established.');
}
But I'm getting following error -
INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal
Session
Note that "Lock sessions to the IP address from which they originated" setting is turned off.
I have managed to create a mysql database with itemIDs and Item types. so far all I have managed to do is generate a button that opens a url to eve api that grabs the prices from eve central. I can't currently post images.
The php code then generates an api url to show the prices which eventually my plan is to grab the Max Buy Prices and Min sell prices and perform on of the following on them:
if the corp needs the item it will be (maxbuyprice + Minsellprice)/2
if the corp doesn't need the item the calculation will be ((maxbuyprice + Minsellprice)/2) * 0.9
My problem is getting php to parse the xml instead of showing the xml document - I did this for debugging or seeing the data that is available.
for an example the url that I generated with Veldspar is:
generated url using Veldspar is the item name
index.php file:
<?php
include_once $_SERVER['DOCUMENT_ROOT'] .'/includes/db.inc.php';
$pagetitle = 'HoMs Asset Management System - Create Contract';
$pagedescription = 'HoMs Asset Management System for managing Corporation Contracts and Pricing';
include_once $_SERVER['DOCUMENT_ROOT'] .'/includes/access.inc.php';
include_once $_SERVER['DOCUMENT_ROOT'] .'/includes/ObjectClasses.inc.php';
include_once $_SERVER['DOCUMENT_ROOT'] .'/includes/helpers.inc.php';
include_once $_SERVER['DOCUMENT_ROOT'] .'/includes/EveCentral.inc.php';
if (isset($_POST['action']) and $_POST['action']=='View Eve Central Prices')
{
$itemname = html($_POST['ItemName']);
calculateAskingPrice($itemname);
}
include 'createcontract.html.php';
?>
db.inc.php file:
<?php
//local dbstrings
//production dbstrings
$dbhost='localhost';
$dbusername='homedata1';
$dbpassword='EzPKfmxcTKAeSnDs';
$dbname='homdata';
Function connect2db()
{
Global $dbhost;
Global $pagetitle;
Global $pagedescription;
Global $mysqlport;
Global $dbname;
Global $dbusername;
Global $dbpassword;
Global $pdo;
Global $error;
Global $curNewsMessage;
Global $logged;
Global $ItemList;
try
{
$pdo = new PDO('mysql:host=' .$dbhost .';dbname=' .$dbname .';port=' .$mysqlport, $dbusername, $dbpassword);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec('SET NAMES "utf8"');
return TRUE;
}
catch (PDOException $dbconerr)
{
$pagetitle = 'Hom Asset Management - Database Connection Error';
$pagedescription = 'There was a problem connecting to the database';
$error = 'Unable to connect to the database server:' ."\n\n"
.'The database in which this pages content relies on is unavailable or, for other reasons is not contactable' ."\n"
.'I am liasing with my website host to get this resolved as quickly as possible. Please check later.' ."\n"
.'sorry for any inconvenience' ."\n\n" .'This information may help to diagnose the problem: <br>' .$dbconerr;
$logged = 'Sorry. The interactive areas are unavailable because the database is unavailable';
$curNewsMessage = 'News message unavailable. ' ."\n" .' Database connection error';
return FALSE;
}
return TRUE;
}
EveCentral.inc.php file:
<?php
include_once $_SERVER['DOCUMENT_ROOT'] .'/includes/helpers.inc.php';
function calculateAskingPrice($Item)
{
// Connect to the database and search for the item posted
include_once $_SERVER['DOCUMENT_ROOT'] .'/includes/db.inc.php';
Global $pdo;
Global $itemname;
if (connect2db())
{
$sql = "SELECT * FROM `itemtypes` WHERE ItemName=:itemname";
$s = $pdo->Prepare($sql);
$s->bindValue(':itemname',$Item);
$s->execute();
$row = $s->fetch();
if ($row > 0)
{
$itemid = html($row['ID']);
$evecurl = 'http://api.eve-central.com/api/marketstat?typeid=' .$itemid .'&usesystem=30000142';
header('Location: ' .$evecurl);
}
else
htmlout('Item not found: ' . $itemname);
}
else
{
echo 'problem connecting to database';
}
}
?>
here i got some version how can help us both:
$xml = simplexml_load_file('http://api.eve-central.com/api/marketstat?usesystem=30000142&hours=24&typeid=3683&minQ=10000');
echo $xml->marketstat->type->sell->min; // 257.99
Im a little comfused, are you wanting help parsing the EVE API xml or the mineral pull XML from eve central?
If it is the price XML, here is what i use, this is on my main page...
// Get Mineral Prices
GetCurrentMineralPrice();
$TritPrice = $ItemPrice[1];
$PyerPrice = $ItemPrice[2];
$MexPrice = $ItemPrice[3];
$IsoPrice = $ItemPrice[4];
$NocxPrice = $ItemPrice[5];
$ZydPrice = $ItemPrice[6];
$MegaPrice = $ItemPrice[7];
$MorPrice = $ItemPrice[8];
and this is the function it calls.
function GetCurrentMineralPrice() {
global $ItemPrice;
$xml = simplexml_load_file("http://api.eve-central.com/api/marketstat?typeid=34&typeid=35&typeid=36&typeid=37&typeid=38&typeid=39&typeid=40&typeid=11399&usesystem=30000142");
$i = 1;
foreach ($xml->marketstat->type as $child) {
$ItemPrice[$i] = $child->buy->max;
$i++;
}
return $ItemPrice;
}
For the sell max price change this line...$ItemPrice[$i] = $child->sell->min;
if you are wanting to parse the EVE API, thats an entirely different story, that I havent mastered yet since each API XML is different...
ArangoDB is a flexible multi-model database server which has very nice features and lots of good documentation. It's a young, very promising open source project with a growing community but not many real world examples to get started.
A common real-world example, is user registration and authentication. It's needed in most applications out there.
So, how to do user registration and authentication in PHP with ArangoDB?
You can run the following example code directly and it will run through a user registration and authentication by providing some fictional user data.
It will display each step that it's doing. From collection-creation, to user-registration, authentication and finally cleaning up the collection again.
There are also lots of comments that explain what is being done, in order to make it easier to understand.
Just put this code in a file, configure the path to autoload.php according to your environment and visit its link with a browser.
This code requires ArangoDB 1.2 and up as well as the ArangoDB-PHP client version 1.2 and up.
It expects ArangoDB to be running on localhost and listening on port 8529.
Note1: The script automatically creates the 'users' collection and a unique skip-list index on 'username'. It also will drop the collection in the end.
If you want to create the collection by hand instead of automatically, you need to comment out the parts where the collection and index are created as well as the part where the collection is dropped.
After that open up a shell to ArangoDB (arangosh) and run the following commands in it:
arangosh> db._createDocumentCollection('users');
arangosh> db.users.ensureUniqueSkiplist("username");
if you want to drop the collection, type:
arangosh> db.users.drop();
Note2: I have intentionally avoided introducing more OO style, like user objects, address objects, etc.. in order to keep it simple.
So, finally here's the script.
<?php
namespace triagens\ArangoDb;
// use this and change it to the path to autoload.php of the arangodb-php client if you're using the client standalone...
// require __DIR__ . '/../vendor/triagens/ArangoDb/autoload.php';
// ...or use this and change it to the path to autoload.php in the vendor directory if you're using Composer/Packagist
require __DIR__ . '/../vendor/autoload.php';
// This function will provide us with our pre-configured connection options.
function getConnectionOptions()
{
$traceFunc = function ($type, $data) {
print "TRACE FOR " . $type . PHP_EOL;
};
return array(
ConnectionOptions::OPTION_ENDPOINT => 'tcp://localhost:8529/',
// endpoint to connect to
ConnectionOptions::OPTION_CONNECTION => 'Close',
// can use either 'Close' (one-time connections) or 'Keep-Alive' (re-used connections)
ConnectionOptions::OPTION_AUTH_TYPE => 'Basic',
// use basic authorization
/*
ConnectionOptions::OPTION_AUTH_USER => '', // user for basic authorization
ConnectionOptions::OPTION_AUTH_PASSWD => '', // password for basic authorization
ConnectionOptions::OPTION_PORT => 8529, // port to connect to (deprecated, should use endpoint instead)
ConnectionOptions::OPTION_HOST => "localhost", // host to connect to (deprecated, should use endpoint instead)
*/
ConnectionOptions::OPTION_TIMEOUT => 5,
// timeout in seconds
//ConnectionOptions::OPTION_TRACE => $traceFunc, // tracer function, can be used for debugging
ConnectionOptions::OPTION_CREATE => false,
// do not create unknown collections automatically
ConnectionOptions::OPTION_UPDATE_POLICY => UpdatePolicy::LAST,
// last update wins
);
}
// This function tries to persist the user data into the database upon registration
// it will fail if a user with the same username already exists.
function register($connection, $username, $password, $registrationData)
{
// This would be where you call the function that encrypts your password like you did for storage earlier
$hashedPassword = md5($password);
// assign the collection to a var (or type it directly into the methods parameters)
$collectionId = 'users';
//create an example document or an array in order to pass to the following byExample method
$document = Document::createFromArray(
array('username' => $username, 'password' => $hashedPassword, 'data' => $registrationData)
);
// Get an instance of the collection handler
$documentHandler = new DocumentHandler($connection);
try {
// query the given $collectionId by example using the previously declared $exampleDocument array
$result = $documentHandler->add($collectionId, $document);
// return the result;
return $result;
} catch (Exception $e) {
if ($e->getCode()) {
echo ('User already exists... ');
} else {
// any other error
echo ('An error occured. Exception: ' . $e);
}
}
}
// This function tries to authenticate the user and will return an array with its data
function authenticate($connection, $username, $password)
{
// This would be where you call the function that encrypts your password like you did for storage earlier
$hashedPassword = md5($password);
// assign the collection to a var (or type it directly into the methods parameters)
$collectionId = 'users';
//create an example document or an array in order to pass to the following byExample method
$exampleDocumentArray = array('username' => $username, 'password' => $hashedPassword);
// Get an instance of the collection handler
$documentHandler = new CollectionHandler($connection);
try {
// query the given $collectionId by example using the previously declared $exampleDocument array
$cursor = $documentHandler->byExample($collectionId, $exampleDocumentArray);
// check if the count of the cursor is one or not.
if ($cursor->getCount() == 1) {
// do some fancy login stuff here...
// get the current document from the cursor
$userDocument = $cursor->current();
// set session uid to the document key that was set automatically by ArangoDB,
// since we didn't provide our own on registration
$_SESSION['uid'] = $userDocument->getKey();
// extract and return the document in form of an array
return $userDocument->getAll();
} else {
return false;
}
} catch (Exception $e) {
echo ('An error occured. Exception: ' . $e . '<br>');
}
}
// register the connection to ArangoDB
$connection = new Connection(getConnectionOptions());
// register a collection handler to work with the 'users' collection
$collectionHandler = new CollectionHandler($connection);
// create the 'users' collection...
// remark those lines if you want to create the collection by hand.
echo "creating 'users' collection...";
try {
$collection = new Collection();
$collection->setName('users');
$collectionHandler->create($collection);
echo "created.<br>";
} catch (Exception $e) {
echo ('Could not create collection. Exception: ' . $e . '<br>');
}
// create unique skip list index in 'users' collection on field ''username'...
// remark those lines if you want to create the index by hand.
echo "creating unique skip list index in 'users' collection on field ''username'... ";
try {
$collection = new Collection();
$collection->setName('users');
$collectionHandler->index('users', 'skiplist', array('username'), true);
echo "created.<br>";
} catch (Exception $e) {
echo ('Could not create skip list index. Exception: ' . $e . '<br>');
}
// let's assume those variables hold your username / password
$userNameProvided = 'jane';
$passwordProvided = 'mysecretpassword';
// here we pass some structured registration data
$registrationData = array(
'name' => 'Jane',
'surname' => 'Doe',
'addresses' => array(
'email' => array('jane#doe.com', 'jane2#doe.com'),
'home' => array(
array('street' => 'Brooklyn Ave.', 'number' => 10),
array('street' => '54th Street', 'number' => 340, 'is_primary' => true)
)
)
);
// First register
echo "trying to register user for the first time... ";
$result = register($connection, $userNameProvided, $passwordProvided, $registrationData);
if ($result) {
echo " " . $userNameProvided . " registered<br>";
} else {
echo "failed<br>";
}
// Trying to register user with same username a second time
echo "trying to register user with same username a second time... ";
$result = register($connection, $userNameProvided, $passwordProvided, $registrationData);
if ($result) {
echo "registered<br>";
} else {
echo "failed<br>";
}
// now authenticate with the correct username/password combination
echo "trying to authenticate with the correct username/password combination... ";
if ($userArray = authenticate($connection, $userNameProvided, $passwordProvided)) {
echo "login successful. ";
echo '<br>';
// do some fancy after-login stuff here...
echo "<br>Welcome back " . $userArray['username'] . '!<br>';
if (count($userArray['data']['addresses']['email']) > 0) {
echo "Your primary mail address is " . $userArray['data']['addresses']['email'][0] . '<br>';
}
foreach ($userArray['data']['addresses']['home'] as $key => $value) {
if (array_key_exists('is_primary', $value)) {
$homeAddress = $userArray['data']['addresses']['home'][$key];
echo "Your primary home address is " . $homeAddress['number'] . ', ' . $homeAddress['street'] . '<br>';
// if found, break out of the loop. There can be only one... primary address!
break;
}
}
} else {
// re-display login form. +1 the wrong-login counter...
echo "wrong username or password<br>";
}
echo '<br>';
// now authenticate with the wrong username/password combination
echo "trying to authenticate with the wrong username/password combination... ";
if (authenticate($connection, $userNameProvided, 'I am a wrong password')) {
// do some fancy after-login stuff here...
echo "login successful<br>";
} else {
// re-display login form. +1 the wrong-login counter...
echo "wrong username or password<br>";
}
// truncate the collection... not needed if dropping, but only here to empty the collection of its tests
// in case you decide to not create and drop the collection through this script, but by hand.
echo "truncating collection...";
try {
$collectionHandler->truncate('users');
echo "truncated.<br>";
} catch (Exception $e) {
die ('Could not truncate collection. Exception: ' . $e . '<br>');
}
// finally drop the collection...
// remark those lines if you want to drop the collection by hand.
echo "dropping collection...";
try {
$collectionHandler->drop('users');
echo "dropped.<br>";
} catch (Exception $e) {
die ('Could not drop collection. Exception: ' . $e . '<br>');
}
In some situations ldap_get_entries returns array with element count=zero, so I have an array like array('count'=>0) without any further entries.
What are the conditions for this to happen?
PS:
if the OU I am searching in is empty I am getting a different error (Invalid Base DN)
if the user doesn't have permissions to an OU I am getting the same error as above
EDIT:
the PHP code is irrelevant, since I can do all kind of searches with it and the above mentioned problem happens only in some strange Active Directory configurations
if you still insists... $entries = ldap_get_entries($this->ldap_connection, $search_result);
ldap_get_entries returns in most of the cases what I expect it to return with proper errors
So, to restate my question, what are the conditions for ldap_get_entries to return an array with count=0, without any errors. By condition I mean:
Active Directory rights and permissions
user permissions
OU permissions (aka Security tab)
any PHP related information on when this can happen
Thanks
EDIT2 - as requested, here is the rest of the code:
public function connect() {
// connect to the server
$this->ldap_connection = ldap_connect($this->ldap_server);
if (!$this->ldap_connection){
$error_message= "LDAP-Connect-Error: " . ldap_error($this->ldap_connection) . ".";
throw new RuntimeErrorException($error_message);
}
// set protocol version
if (!ldap_set_option($this->ldap_connection, LDAP_OPT_PROTOCOL_VERSION, $this->ldap_protocol_version)){
$error_message= "LDAP-SetProtocolVersion-Error: " . ldap_error($this->ldap_connection) . ".";
throw new RuntimeErrorException($error_message);
}
// set with/without referrals (limit/do not limit search on current server)
if (!ldap_set_option($this->ldap_connection, LDAP_OPT_REFERRALS, $this->ldap_protocol_referrals)){
$error_message= "LDAP-SetReferrals-Error: " . ldap_error($this->ldap_connection) . ".";
throw new RuntimeErrorException($error_message);
}
// binding to ldap server
if (!#ldap_bind($this->ldap_connection, $this->ldap_auth_rdn, $this->ldap_auth_pass)){
$error_message= "LDAP-Bind-Error: " . ldap_error($this->ldap_connection) . ".";
throw new RuntimeErrorException($error_message);
}
}
public function search($filter,$fields){
if (!$this->ldap_connection) {
$this->connect();
}
// search the ldap
$search_result = #ldap_search($this->ldap_connection, $this->ldap_base_distinguished_name, $filter,$fields);
if ($search_result===false){
$error_message= "LDAP-Error: " . ldap_error($this->ldap_connection) . ".";
throw new RuntimeErrorException($error_message);
}
//Create result set
$entries = ldap_get_entries($this->ldap_connection, $search_result);
if ($entries === false ){
$error_message= "LDAP-Error: " . ldap_error($this->ldap_connection) . ".";
throw new RuntimeErrorException($error_message);
}
return (is_null($entries) ? array() : $entries); // http://bugs.php.net/48469
}
It seems like ldap_connect is successfully connecting to your server.
I think the problem is with the ldap_base_distinguished_name param from ldap_search, make sure that it's correct and you have that base distinguished name in you AD tree.
It means what you are searching for didn't return results either because it isn't there or you aren't searching correctly for it.
$ldap = new stdclass;
$ldap->host = 'YOUR_HOST';
$ldap->port = 'PORT';
$ldap->user = 'YOUR_USER';
$ldap->pass = 'YOUR_PASS';
$ldap->dn = "CN=Users,DC=DOMAIN,DC=COM,DC=br";
$ldap->filter = '(sAMAccountName=YOUR_USER_NAME)';
try {
$ldap->conn = ldap_connect($ldap->host,$ldap->port);
$ldap->bind = ldap_bind($ldap->conn, $ldap->user, $ldap->pass);
$ldap->option[] = ldap_set_option($ldap->conn, LDAP_OPT_PROTOCOL_VERSION,3);
$ldap->option[] = ldap_set_option($ldap->conn, LDAP_OPT_REFERRALS,0);
$ldap->seach=ldap_search($ldap->conn, $ldap->dn, $ldap->filter);
$ldap->info = ldap_get_entries($ldap->conn, $ldap->seach);
var_dump($ldap);
} catch (Exception $error_message) {
throw new RuntimeErrorException($error_message);
}