Warning: ldap_add(): Add: Object class violation - php

Over the past few days I've been trying to learn more about ldap, and I would now like to be able to create a new account on my phpldapadmin server from a webform. I have the values being passed back through php correctly, but I keep getting an objectclass violation error. I've scoured many different resources (including this one) and basically all that I can find is that the objectclass needs to match exactly how the dictionary is setup. I ran an export for some of the manually created users I already have working in there successfully, and this is an example of the output:
# LDIF Export for cn=api user,cn=students,ou=users,dc=myhost,dc=com
# Server: LDAP (ip)
# Search Scope: sub
# Search Filter: (objectClass=*)
# Total Entries: 1
#
# Generated by phpLDAPadmin (http://phpldapadmin.sourceforge.net) on June 4, 2016 3:15 pm
# Version: 1.2.2
version: 1
# Entry 1: cn=api user,cn=students,ou=users,dc=myhost,dc=co...
dn: cn=test user,cn=students,ou=users,dc=myhost,dc=com
cn: test
gidnumber: 502
givenname: test
homedirectory: /home/users/testuser
loginshell: /bin/sh
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: top
sn: tuser
uid: testuser
uidnumber: 1003
userpassword: {MD5}pass==
and I have tried mimicking it as closely as possible in my script (below), but I am still getting the violation error. No problems connecting or with any of the other fields, only the objectclass problem.
$ds = ldap_connect($AD_server);
if ($ds) {
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
$r = ldap_bind($ds, $AD_Auth_User, $AD_Auth_PWD);
$info["cn"] = $user_full_name;
$info["sn"] = $user_username;
$info['objectclass'][0] = "top";
$info['objectclass'][1] = "posixAccount";
$info['objectclass'][2] = "inetOrgPerson";
$info['uid'] = $user_username;
$info['userpassword'] = $newPassw;
$info['loginshell'] = '/bin/sh';
$info['homedirectory'] = "/home/users/$user_username";
// add data to directory
$r = ldap_add($ds, $dn, $info);
ldap_close($ds);
} else {
echo "Unable to connect to LDAP server";
}
I've played around with the objectclasses and tried switching their positions or using only inetOrgPerson, and still no luck. Any thoughts?

When creating entries within LDAP you need to know which Attributes are "MUST" (required) for the ObjectClasses used when creating the entry.
In your example:
person MUST ( sn $ cn )
posixAccount MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
So to create the entry in LDAP you MUST have values for all of these:
sn
cn
uid
uidNumber
gidNumber
homeDirectory
You can tell which is required by a LDAP Query For Schema and reading each ObjectClass to determine which Attributes are "MUST" (required).

It looks like you need to make sure to pass every value back through. I was missing the uidnumber givenname and gidnumber fields. But now it works! :)

Related

How to process large data from database using PHP? [duplicate]

In one of my project, I am planning to use ElasticSearch with MySQL.
I have successfully installed ElasticSearch. I am able to manage index in ES separately. but I don't know how to implement the same with MySQL.
I have read a couple of documents but I am a bit confused and not having a clear idea.
As of ES 5.x , they have given this feature out of the box with logstash plugin.
This will periodically import data from database and push to ES server.
One has to create a simple import file given below (which is also described here) and use logstash to run the script. Logstash supports running this script on a schedule.
# file: contacts-index-logstash.conf
input {
jdbc {
jdbc_connection_string => "jdbc:mysql://localhost:3306/mydb"
jdbc_user => "user"
jdbc_password => "pswd"
schedule => "* * * * *"
jdbc_validate_connection => true
jdbc_driver_library => "/path/to/latest/mysql-connector-java-jar"
jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
statement => "SELECT * from contacts where updatedAt > :sql_last_value"
}
}
output {
elasticsearch {
protocol => http
index => "contacts"
document_type => "contact"
document_id => "%{id}"
host => "ES_NODE_HOST"
}
}
# "* * * * *" -> run every minute
# sql_last_value is a built in parameter whose value is set to Thursday, 1 January 1970,
# or 0 if use_column_value is true and tracking_column is set
You can download the mysql jar from maven here.
In case indexes do not exist in ES when this script is executed, they will be created automatically. Just like a normal post call to elasticsearch
Finally i was able to find the answer. sharing my findings.
To use ElasticSearch with Mysql you will require The Java Database Connection (JDBC) importer. with JDBC drivers you can sync your mysql data into elasticsearch.
I am using ubuntu 14.04 LTS and you will require to install Java8 to run elasticsearch as it is written in Java
following are steps to install ElasticSearch 2.2.0 and ElasticSearch-jdbc 2.2.0 and please note both the versions has to be same
after installing Java8 ..... install elasticsearch 2.2.0 as follows
# cd /opt
# wget https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/2.2.0/elasticsearch-2.2.0.deb
# sudo dpkg -i elasticsearch-2.2.0.deb
This installation procedure will install Elasticsearch in /usr/share/elasticsearch/ whose configuration files will be placed in /etc/elasticsearch .
Now lets do some basic configuration in config file. here /etc/elasticsearch/elasticsearch.yml is our config file
you can open file to change by
nano /etc/elasticsearch/elasticsearch.yml
and change cluster name and node name
For example :
# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
#
cluster.name: servercluster
#
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
#
node.name: vps.server.com
#
# Add custom attributes to the node:
#
# node.rack: r1
Now save the file and start elasticsearch
/etc/init.d/elasticsearch start
to test ES installed or not run following
curl -XGET 'http://localhost:9200/?pretty'
If you get following then your elasticsearch is installed now :)
{
"name" : "vps.server.com",
"cluster_name" : "servercluster",
"version" : {
"number" : "2.2.0",
"build_hash" : "8ff36d139e16f8720f2947ef62c8167a888992fe",
"build_timestamp" : "2016-01-27T13:32:39Z",
"build_snapshot" : false,
"lucene_version" : "5.4.1"
},
"tagline" : "You Know, for Search"
}
Now let's install elasticsearch-JDBC
download it from http://xbib.org/repository/org/xbib/elasticsearch/importer/elasticsearch-jdbc/2.3.3.1/elasticsearch-jdbc-2.3.3.1-dist.zip and extract the same in /etc/elasticsearch/ and create "logs" folder also there ( path of logs should be /etc/elasticsearch/logs)
I have one database created in mysql having name "ElasticSearchDatabase" and inside that table named "test" with fields id,name and email
cd /etc/elasticsearch
and run following
echo '{
"type":"jdbc",
"jdbc":{
"url":"jdbc:mysql://localhost:3306/ElasticSearchDatabase",
"user":"root",
"password":"",
"sql":"SELECT id as _id, id, name,email FROM test",
"index":"users",
"type":"users",
"autocommit":"true",
"metrics": {
"enabled" : true
},
"elasticsearch" : {
"cluster" : "servercluster",
"host" : "localhost",
"port" : 9300
}
}
}' | java -cp "/etc/elasticsearch/elasticsearch-jdbc-2.2.0.0/lib/*" -"Dlog4j.configurationFile=file:////etc/elasticsearch/elasticsearch-jdbc-2.2.0.0/bin/log4j2.xml" "org.xbib.tools.Runner" "org.xbib.tools.JDBCImporter"
now check if mysql data imported in ES or not
curl -XGET http://localhost:9200/users/_search/?pretty
If all goes well, you will be able to see all your mysql data in json format
and if any error is there you will be able to see them in /etc/elasticsearch/logs/jdbc.log file
Caution :
In older versions of ES ... plugin Elasticsearch-river-jdbc was used which is completely deprecated in latest version so do not use it.
I hope i could save your time :)
Any further thoughts are appreciated
Reference url : https://github.com/jprante/elasticsearch-jdbc
The logstash JDBC plugin will do the job:
input {
jdbc {
jdbc_connection_string => "jdbc:mysql://localhost:3306/testdb"
jdbc_user => "root"
jdbc_password => "factweavers"
# The path to our downloaded jdbc driver
jdbc_driver_library => "/home/comp/Downloads/mysql-connector-java-5.1.38.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
# our query
schedule => "* * * *"
statement => "SELECT" * FROM testtable where Date > :sql_last_value order by Date"
use_column_value => true
tracking_column => Date
}
output {
stdout { codec => json_lines }
elasticsearch {
"hosts" => "localhost:9200"
"index" => "test-migrate"
"document_type" => "data"
"document_id" => "%{personid}"
}
}
To make it more simple I have created a PHP class to Setup MySQL with Elasticsearch. Using my Class you can sync your MySQL data in elasticsearch and also perform full-text search. You just need to set your SQL query and class will do the rest for you.

How to retrieve Active Directory group policy maximum password age using LDAP

I would like to retrieve the group policy regarding to passwords from the company Active Directory, but I cannot find any info, how to filter my search to find the attributes.
At first I like to get the maximum password age, which should be the msDS-MaximumPasswordAge attribute.
The search term I've been trying:
ldap_search($ldap, 'CN=Policies,CN=System,DC=company,DC=com', '(objectClass=*)', array('msDS-MaximumPasswordAge'));
This is the widest filter I've tried, but it returns no object where the count is not zero. Of course I replaced the DC name for the purpose of this example.
Did I missed something? Should I search under a different container?
Are you sure you have implemented a Group Policy with msDS-PasswordSettings enabled?
You should use a filter like (&(objectClass=msDS-PasswordSettings))
And return an attribute "msDS-MaximumPasswordAge".
A msDS-PasswordSettings entry appears in an LDIF like:
dn: CN=PS??,CN=Password Settings Container,CN=System,DC=dc1,DC=contoso,DC=com
objectClass: msDS-PasswordSettings
msDS-MaximumPasswordAge:-1728000000000
msDS-MinimumPasswordAge:-864000000000
msDS-MinimumPasswordLength:8
msDS-PasswordHistoryLength:24
msDS-PasswordComplexityEnabled:TRUE
msDS-PasswordReversibleEncryptionEnabled:FALSE
msDS-LockoutObservationWindow:-18000000000
msDS-LockoutDuration:-18000000000
msDS-LockoutThreshold:0
msDS-PasswordSettingsPrecedence:20
msDS-PSOAppliesTo:CN=user1,CN=Users,DC=dc1,DC=contoso,DC=com
-jim

How to generate openvpn client key dynamically with php and pass variables to shell command?

I want to generate clients key with PHP. When a client key generated it should give me the expiry date of the key.
root#zohaib-VirtualBox:/etc/openvpn/easy-rsa# ./build-key client1
Generating a 2048 bit RSA private key .............................................................+++ ............................+++
writing new private key to 'client1.key'
You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [GB]:
State or Province Name (full name) [London]:
Locality Name (eg, city) [London]:
Organization Name (eg, company) [Org]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) [client1]:
Name [OrgServer]:
Email Address [admin#org.com]:
Please enter the following 'extra' attributes to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /etc/openvpn/easy-rsa/openssl-1.0.0.cnf
Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'GB'
stateOrProvinceName :PRINTABLE:'London'
localityName :PRINTABLE:'London'
organizationName :PRINTABLE:'Org'
commonName :PRINTABLE:'client1'
name :PRINTABLE:'OrgServer'
emailAddress :IA5STRING:'admin#gamban.com'
Certificate is to be certified until Apr 21 15:43:47 2026 GMT (3650 days) Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
root#zohaib-VirtualBox:/etc/openvpn/easy-rsa#
You can use shell_exec and get the result to use, for example, with a regex to match expiry the date of key etc, i.e.:
$ovpnKey = shell_exec("your command here");
The result of the command will held on var $ovpnKey.
Update:
To automatize the creation of new OpenVPN client certificates, use the following script. Make sure you edit, at least, the following variables OPENVPN_RSA_DIR OPENVPN_KEYS KEY_DOWNLOAD_PATH
#! /bin/bash
# Script to automate creating new OpenVPN clients
# The client cert and key, along with the CA cert is
# zipped up and placed somewhere to download securely
#
# H Cooper - 05/02/11
#
# Usage: new-openvpn-client.sh <common-name>
# Set where we're working from
OPENVPN_RSA_DIR=/etc/openvpn/easy-rsa/2.0
OPENVPN_KEYS=$OPENVPN_RSA_DIR/keys
KEY_DOWNLOAD_PATH=/var/www/secure
# Either read the CN from $1 or prompt for it
if [ -z "$1" ]
then echo -n "Enter new client common name (CN): "
read -e CN
else
CN=$1
fi
# Ensure CN isn't blank
if [ -z "$CN" ]
then echo "You must provide a CN."
exit
fi
# Check the CN doesn't already exist
if [ -f $OPENVPN_KEYS/$CN.crt ]
then echo "Error: certificate with the CN $CN alread exists!"
echo " $OPENVPN_KEYS/$CN.crt"
exit
fi
# Enter the easy-rsa directory and establish the default variables
cd $OPENVPN_RSA_DIR
source ./vars > /dev/null
# Copied from build-key script (to ensure it works!)
export EASY_RSA="${EASY_RSA:-.}"
"$EASY_RSA/pkitool" --batch $CN
# Take the new cert and place it somewhere it can be downloaded securely
zip -q $KEY_DOWNLOAD_PATH/$CN-`date +%d%m%y`.zip keys/$CN.crt keys/$CN.key keys/ca.crt
# Celebrate!
echo ""
echo "#############################################################"
echo "COMPLETE! Download the new certificate here:"
echo "https://domain.com/secure/$CN-`date +%d%m%y`.zip"
echo "#############################################################"
Save the above bash script as new-openvpn-client.sh and give it execute permissions.
Then use php shell_exec to generate the keys:
$ovpnKey = shell_exec("sh /full/path/to/new-openvpn-client.sh <common-name>");
Sources:
https://gist.github.com/hcooper/814247

Sphinx returns wrong document ids

My sphinx search returns wrong results, if I search for a keyword, the document ids returned do not contain that keyword.
Here is how I created conf settings:
source source_name
{
type = mysql
sql_host = ******
sql_user = ******
sql_pass = ******
sql_db = ******
sql_port = # optional, default is 3306
sql_query_pre = SET CHARACTER_SET_RESULTS=utf8
sql_query_pre = SET NAMES utf8
sql_query = \
SELECT \
P.ID AS ID, P.TITLE AS TITLE, P.TITLE AS TITLE_SORT \
FROM \
PRODUCT P \
WHERE \
P.ISVALID='Y'
sql_attr_string = TITLE_SORT
sql_query_info = SELECT * FROM PRODUCT WHERE ID=$id
}
index index_name
{
source = source_name
path = /path/to/data/file_name
docinfo = extern
min_word_len = 1
charset_type = utf-8
}
indexer
{
mem_limit = 128M
}
searchd
{
listen = 3312 # port is deprecated from 2.1+
log = /path/to/log/searchd.log
query_log = /path/to/log/query.log
read_timeout = 5
max_children = 30
pid_file = /path/to/log/searchd.pid
max_matches = 1000
seamless_rotate = 0
preopen_indexes = 0
unlink_old = 1
compat_sphinxql_magics = 0
}
One important thing is that If I search with the test.php tool, I can see that the attribute value shows products with searched keywords, but document ids are still wrong, which makes me thing why it is returning wrong document ids
Another important thing is that on the same machine and same conf file, I created an index for another mysql database and it works fine.
Thanks
EDIT:
Here is an example:
I search for "professional" and I get this result
1. doc_id=33285, weight=102, title_sort=Wella Professional Bezoplachový kondicionér pro objem vlasï SP Volumize 150 ml, manufacturer_id=217, category_id=4648, min_price=0, product_rating=4294967295, filter_userid=(2714222508,3149373076)
2. doc_id=33286, weight=102, title_sort=Wella Professional àampon pro lesk vlasï SP Shine Define 250 ml, manufacturer_id=217, category_id=3046113, min_price=0, product_rating=4294967295, filter_userid=(2714222508,3149373076)
3. doc_id=33287, weight=102, title_sort=Wella Professional àampon pro barvené vlasy SP Color Save 250 ml, manufacturer_id=217, category_id=3046113, min_price=0, product_rating=4294967295, filter_userid=(2714222508,3149373076)
.. and so on ..
You can see that the title_sort field has the word professional in it, but the doc_ids returned (33285, 33286, 33287) are not these records.
This below is the id - title data from database
33285 Avon Čisticí tonikum na tělo proti akné ve spreji Blemish Clearing 100 ml
33286 Biotherm Pleťový krém a sérum 2v1 pro navrácení pružnosti normální až smíšené pleti Age Fitness Elastic 30 ml AKCE
33287 Avon Dětský šampon Barbie® 200 ml
While the results you see in the title_sort above are tied to these ids:
32854 Wella Professional Bezoplachový kondicionér pro objem vlasů SP Volumize 150 ml
32855 Wella Professional Šampon pro lesk vlasů SP Shine Define 250 ml
32856 Wella Professional Šampon pro barvené vlasy SP Color Save 250 ml
Sorry guys, issue is solved! It was a stupid mistake by our hosting support.
They created a new database and transferred old db data into it. The old database was corrupted.
I found this out when I created a duplicate table of the original and then tried to index it, sphinx gave me error that table does not exist, and that clicked my mind and I compared the database settings on site and sphinx.conf
I did not find an issue like mine on any forums and google, apart from one that had a similar configuration problem. So if you are reading this answer to find a solution for a similar problem, then you must check your configuration and confirm that your conf file is pointing to the correct database and table. This will save you days, may be weeks of pain :).

PHP LDAP to change Active Directory samAccountName?

Our policy for people who are terminated/separated or who go on leave of absence involves a handful of changes to their AD account for record keeping purposes and security. One of these changes is renaming the account (login name, display name and dn) to a value that includes the original name with the help desk ticket number appended.
I have been able to use ldap_rename() to change the active directory "name" attribute, thus changing the DN. I can change the displayName attribute using either ldap_modify() or ldap_mod_replace(). What I cannot seem to do is change the samAccountName using any of these. Below is the core of the code I'm using. The errors I get are dependent upon which function I use, and are listed below.
I know there are some nuances to using PHP LDAP with Active Directory, but I find it hard to believe that I have been able to do everything up to and including changing passwords and I can't change the samAccountName... help?
<?php
$connection=ldap_connect(domain.local,389);
ldap_set_option($connection,LDAP_OPT_PROTOCOL_VERSION,3);
ldap_set_option($connection,LDAP_OPT_REFERRALS,0);
ldap_start_tls($connection);
ldap_bind($connection,$username,$password);
$accountName=$_POST["accountName"];
$ticketNumber=$_POST["ticketNumber"];
$baseDn="dc=domain,dc=local";
$attribs=array("samaccountname","dn","name","displayname","description","info","memberof");
$search=ldap_search($connection,$baseDn,"(samaccountname=".$accountName.")",$attribs);
$result=ldap_get_entries($connection,$search);
// ldap_modify returns error 80: Internal (implementation specific) error.
foreach ($result as $account) {
$newValues=array("samaccountname"=>$account["samaccountname"][0]."-".$ticketNumber)
ldap_modify($connection,$account["dn"],$newValues);
}
// ldap_mod_replace returns error 80: Internal (implementation specific) error.)
foreach ($result as $account) {
$newValues=array("samaccountname"=>$account["samaccountname"][0]."-".$ticketNumber)
ldap_mod_replace($connection,$account["dn"],$newValues);
}
?>
So yeah, what is it I'm supposed to be doing to make this happen?
The "implementation specific" error message you're receiving means that your sAMAccountName is invalid because it doesn't meet specific AD restrictions on it. The sAMAccountName attribute cannot be more than 20 characters and cannot contain any of the following: " [ ] : ; | = + * ? < > / \ ,. It might be helpful to see an example username with the ticket number appended.

Categories