Forums: LDAP authentication II - The questions - Forums

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • This topic is locked

LDAP authentication II - The questions Rate Topic: -----

#1 User is offline   thesofa 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 650
  • Joined: 24-February 06
  • Gender:Male
  • Location:NE England

Post icon  Posted 06 October 2006 - 10:35 PM

Hi
Here we go again.
I have 4 applications on the intranet here, all are set up to authenticate with LDAP.
All 4 use totally different ways of doing what seems to be a simple thing.
So I have to have a go at writing it for myself for my PHPR applications ;)
I was planning to base it on the code generated from PHPR with autherentication using a table in the database.
Sergey or others, can you please tell me what I have to return from LDAP query and feed into PHPR?
"Make something fool-proof and they will make a bigger fool"
0

#2 User is offline   Alexey 

  • Advanced Member
  • PipPipPip
  • Group: Admin
  • Posts: 1288
  • Joined: 11-May 05

Posted 09 October 2006 - 06:27 AM

Hi,

all you need is to save a username in $_SESSION["UserID"] variable.
best regards,
Alexey Kornilov
E-Mail: support@xlinesoft.com
0

#3 User is offline   thesofa 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 650
  • Joined: 24-February 06
  • Gender:Male
  • Location:NE England

Posted 10 October 2006 - 05:55 PM

well , its working, still in the testing stage tho, I may have a solution if you want it.
:rolleyes:
"Make something fool-proof and they will make a bigger fool"
0

#4 User is offline   admin 

  • Administrator
  • PipPipPip
  • Group: Admin
  • Posts: 8096
  • Joined: 03-February 03

Posted 11 October 2006 - 05:31 AM

Sure, when you have it ready feel free to share this code.

We can add this as a feature to PHPRunner or just write an article on this subject so everyone can benefit from this.
Best regards,
Sergey Kornilov
0

#5 User is offline   thesofa 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 650
  • Joined: 24-February 06
  • Gender:Male
  • Location:NE England

Posted 11 October 2006 - 11:40 PM

OK, here we go.
LDAP authentication uses a class file called adLDAP.php from sourceforge written by Scott Barnett.
All Hail Scott Barnett.
This file is stored in the LDAP directory in the root of the project, but you can put it in the includes folder if you wish, as long as you change the path in the code section below.
this has loads of documentation in it and there is a good FAQ mentioned in the file.
Then you need to build the project in PHPRunner, selecting authenticate from a table in a database and set up all the tables so it will authenticate the users in the table.
Once you have built the project and tested it and you are happy, you need to add a section into the login.php file as follows.

before the section

Quote

if(function_exists("BeforeLogin"))
if(!BeforeLogin(@$_POST["username"],@$_POST["password"]))
$strSQL="select * from ".AddTableWrappers($cLoginTable)." where 1<0";

insert this lot

Quote

################################################################################
##
# LDAP AUTHENTICATION MODIFICATION #
################################################################################
##

//include the class
include ("ldap/adLDAP.php");

//create the LDAP connection
$adldap = new adLDAP();
$ldap_auth = 0;
$ldap_group ="usergroup"; # Specified group for group authentication

// Authenticate
if (($adldap -> authenticate($strlUsername,$strlPassword))){
#if ($adldap -> user_ingroup($strlUsername,$ldap_group)){ # Group Authentication Only
$ldap_auth = 1;

// Check if user exists
$sql = "Select * from ".AddTableWrappers($cLoginTable)." Where ".AddFieldWrappers($cUserNameField)." = \"$strlUsername\"";
$rs = mysql_query($sql,$conn) or die("USER QUERY FAILED.");

// Update DB for new users
if (mysql_num_rows($rs) < 1) {
$info=$adldap->user_info($strlUsername,array("givenname","sn"));
$strldapfirstname = $info[0][givenname][0]; #sets firstname value from AD
$strldaplastname = $info[0][sn][0]; #sets lastname value from AD
$sql = "INSERT INTO ".AddTableWrappers($cLoginTable)." ( ".AddFieldWrappers($cUserNameField).", firstname, lastname, level)";
$sql .= " SELECT ";
$sql .= "\"$strlUsername\" AS Expr1, "; #adds username to database
$sql .= "\"$strldapfirstname\" AS Expr2, "; #adds firstname to database
$sql .= "\"$strldaplastname\" AS Expr3, "; #adds lastname to database
$sql .= "1 AS Expr4;"; #adds level to database
$result = mysql_query($sql,$conn);
}

// Generate Query
$strSQL = "select * from ".AddTableWrappers($cLoginTable)." where ".AddFieldWrappers($cUserNameField).
"=\"".$strlUsername."\"";

#} #Group Authentication Only
}

// Catch failed logins
if ($ldap_auth == 0) $strSQL = "select * from ".AddTableWrappers($cLoginTable)." where ".AddFieldWrappers($cUserNameField)."=\"xxxxx\"";

################################################################################
##
# END OF MODIFICATION #
################################################################################
##


The line

Quote

$ldap_group ="usergroup"; # Specified group for group authentication
holds the group for group membership checking.
the code pulls the first name and last name of the user from ad and inserts it into the table you selected for authentication, you do not need a pasword field in the user table

If you go for group authentication as well, you have 2 lines to uncomment.

All of the coding for the addition to the login.php file was written and kindly given to me by a colleague, Mark Hall, here. He has written some rather nice applications here, the code for this page came from his helpdesk application and he hacked it to work with this project of mine.

I reckon I owe him loads of beer.


and many thanks too.



All Hail Mark Hall
All Hail Mark HallAll Hail Mark Hall
All Hail Mark Hall
All Hail Mark Hall
All Hail Mark Hall
OK, its late and I am silly.
But this works.

In addition you may need to install and configure the MOd_auth_ldap module for PHP, available from Muhammad A Muquit here.
All Hail Muhammad A Muquit
All Hail Muhammad A Muquit
All Hail Muhammad A Muquit
All Hail Muhammad A Muquit
OK, I am old and tired, I shall go to bed.
Plese tell me if you have got it to work, , a line to Mark via his web site might be cool as well as any thanks to Muhammad A Muquit.
Honestly, all I did was a load of reading and then I pestered people to do it for me.
"Make something fool-proof and they will make a bigger fool"
0

#6 User is offline   Graeme Forrester 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 98
  • Joined: 14-July 06
  • Location:Australia

Posted 18 October 2006 - 09:13 PM

Great.
So where do you add the bind and the dn? Does this work with active dirctory? Willing to test.
0

#7 User is offline   thesofa 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 650
  • Joined: 24-February 06
  • Gender:Male
  • Location:NE England

Posted 18 October 2006 - 10:24 PM

View PostGraeme Forrester, on Oct 18 2006, 10:13 PM, said:

Great.
So where do you add the bind and the dn? Does this work with active dirctory? Willing to test.

Follow the link near the top of the lon post to sourceforge and download the LDAP class. There are instructions in the file and the bind is done from there when you call authenticate.

I have it working with AD on win2000 server as the root forest server!
We have around 60 staff members using the web based detention system all day, with a school of around 900 pupils.

here is the whole class from sourceforge

Quote

<?php
/*
PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
Version 1.5

Written by Scott Barnett
email: scott@wiggumworld.com
http://adldap.sourceforge.net/

Copyright © 2006 Scott Barnett

I'd appreciate any improvements or additions to be submitted back
to benefit the entire community :)

Works with both PHP 4 and PHP 5

The examples should be pretty self explanatory. If you require more
information, please visit http://adldap.sourceforge.net/


This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

********************************************************************
Something to keep in mind is that Active Directory is a permissions
based directory. If you bind as a domain user, you can't fetch as
much information on other users as you could as a domain admin.
********************************************************************

FUNCTIONS:

authenticate($username,$password)
Authenticate to the directory with a specific username and password

user_info($user,$fields=NULL)
Returns an array of information for a specific user

user_groups($user,$recursive=NULL)
Returns an array of groups that a user is a member off

user_ingroup($user,$group,$recursive=NULL)
Returns true if the user is a member of the group

group_info($group)
Returns an array of information for a specific group

all_users($include_desc = false, $search = "*", $sorted = true)
Returns all AD users (expensive on resources)

all_groups($include_desc = false, $search = "*", $sorted = true)
Returns all AD groups (expensive on resources)

*/

// Different type of accounts in AD
define ('ADLDAP_NORMAL_ACCOUNT', 805306368);
define ('ADLDAP_WORKSTATION_TRUST', 805306369);
define ('ADLDAP_INTERDOMAIN_TRUST', 805306370);
define ('ADLDAP_SECURITY_GLOBAL_GROUP', 268435456);
define ('ADLDAP_DISTRIBUTION_GROUP', 268435457);
define ('ADLDAP_SECURITY_LOCAL_GROUP', 536870912);
define ('ADLDAP_DISTRIBUTION_LOCAL_GROUP', 536870913);

class adLDAP {
// BEFORE YOU ASK A QUESTION, PLEASE READ THE FAQ
// http://adldap.sourceforge.net/faq.php

// You will need to edit these variables to suit your installation
var $_account_suffix="@yourdomain.com";
var $_base_dn ="DC=domain,DC=coml";

// An array of domain controllers. Specify multiple controllers if you
// would like the class to balance the LDAP queries amongst multiple servers
var $_domain_controllers = array ("server1.domain.com");

// optional account with higher privileges for searching
var $_ad_username="topnotchbloke";
var $_ad_password="putarealpasswordinhere";

// AD does not return the primary group. http://support.micro...om/?kbid=321360
// This tweak will resolve the real primary group, but may be resource intensive.
// Setting to false will fudge "Domain Users" and is much faster. Keep in mind though that if
// someone's primary group is NOT domain users, this is obviously going to bollocks the results
var $_real_primarygroup=true;

// When querying group memberships, do it recursively
// eg. User Fred is a member of Group A, which is a member of Group B, which is a member of Group C
// user_ingroup("Fred","C") will returns true with this option turned on, false if turned off
var $_recursive_groups=true;

// You should not need to edit anything below this line
//********************************************************************************
**********

//other variables
var $_user_dn;
var $_user_pass;
var $_conn;
var $_bind;

// default constructor
function adLDAP(){
//connect to the LDAP server as the username/password
$this->_conn = ldap_connect($this->random_controller());
ldap_set_option($this->_conn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($this->_conn, LDAP_OPT_REFERRALS, 0); //disable plain text passwords
return true;
}

// default destructor
function __destruct(){ ldap_close ($this->_conn); }

function random_controller(){
//select a random domain controller
mt_srand(doubleval(microtime()) * 100000000);
return ($this->_domain_controllers[array_rand($this->_domain_controllers)]);
}

// authenticate($username,$password)
// Authenticate to the directory with a specific username and password
// Extremely useful for validating login credentials
function authenticate($username,$password){
//validate a users login credentials
$returnval=false;

if ($username!=NULL && $password!=NULL){ //prevent null bind
$this->_user_dn=$username.$this->_account_suffix;
$this->_user_pass=$password;

$this->_bind = @ldap_bind($this->_conn,$this->_user_dn,$this->_user_pass);
if ($this->_bind){ $returnval=true; }
}
return ($returnval);
}

// rebind()
// Binds to the directory with the default search username and password
// specified above.
function rebind(){
//connect with another account to search with if necessary
$ad_dn=$this->_ad_username.$this->_account_suffix;
$this->_bind = @ldap_bind($this->_conn,$ad_dn,$this->_ad_password);
if ($this->_bind){ return (true); }
return (false);
}

// user_info($user,$fields)
// Returns an array of information for a specific user
function user_info($user,$fields=NULL){
if ($user!=NULL){
if ($this->_ad_username!=NULL){ $this->rebind(); } //bind as a another account if necessary

if ($this->_bind){ //perform the search and grab all their details
$filter="samaccountname=".$user;
if ($fields==NULL){
$fields=array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid");
//$fields=array("*");
}
$sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
$entries = ldap_get_entries($this->_conn, $sr);

// AD does not return the primary group in the ldap query, we may need to fudge it
if ($this->_real_primarygroup){
$entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
} else {
$entries[0]["memberof"][]="CN=Domain Users,CN=Users,".$this->_base_dn;
}

//echo ("<pre>"); print_r($entries);

$entries[0]["memberof"]["count"]++;
return ($entries);
}
}

return (false);
}

// user_groups($user)
// Returns an array of groups that a user is a member off
function user_groups($user,$recursive=NULL){
if ($this->_ad_username!=NULL){ $this->rebind(); } //bind as a another account if necessary
if ($recursive==NULL){ $recursive=$this->_recursive_groups; }

if ($this->_bind){
//search the directory for their information
$info=@$this->user_info($user,array("memberof"));
//echo ("<pre>"); print_r($info);
$groups=$info[0]["memberof"]; //presuming the entry returned is our guy (unique usernames)

$group_array=$this->nice_names($groups);

if ($recursive){
foreach ($group_array as $id => $group_name){
$extra_groups=$this->recursive_groups($group_name);
$group_array=array_merge($group_array,$extra_groups);
}
}

return ($group_array);
}
return (false);
}

// user_ingroup($user,$group)
// Returns true if the user is a member of the group
function user_ingroup($user,$group,$recursive=NULL){
if ($recursive==NULL){ $recursive=$this->_recursive_groups; }

if (($user!=NULL) && ($group!=NULL)){
if ($this->_ad_username!=NULL){ $this->rebind(); } //bind as a another account if necessary

if ($this->_bind){
$groups=$this->user_groups($user,array("memberof"),$recursive);
if (in_array($group,$groups)){ return (true); }
}
}
return (false);
}

function recursive_groups($group){
$ret_groups=array();

$groups=$this->group_info($group,array("memberof"));
$groups=$groups[0]["memberof"];

if ($groups){
$group_names=$this->nice_names($groups);
$ret_groups=array_merge($ret_groups,$group_names); //final groups to return

foreach ($group_names as $id => $group_name){
$child_groups=$this->recursive_groups($group_name);
$ret_groups=array_merge($ret_groups,$child_groups);
}

}

return ($ret_groups);
}

// take an ldap query and return the nice names, without all the LDAP prefixes (eg. CN, DN)
function nice_names($groups){

$group_array=array();
for ($i=0; $i<$groups["count"]; $i++){ //for each group
$line=$groups[$i];

if (strlen($line)>0){
//more presumptions, they're all prefixed with CN=
//so we ditch the first three characters and the group
//name goes up to the first comma
$bits=explode(",",$line);
$group_array[]=substr($bits[0],3,(strlen($bits[0])-3));
}
}
return ($group_array);
}




function group_cn($gid){
if ($this->_ad_username!=NULL){ $this->rebind(); } //bind as a another account if necessary

// coping with AD not returning the primary group
// http://support.micro...om/?kbid=321360
// for some reason it's not possible to search on primarygrouptoken=XXX
// if someone can show otherwise, I'd like to know about it :)
// this way is resource intensive and generally a pain in the @#%^

$r=false;

if ($this->_bind){
$filter="(&(objectCategory=group)(samaccounttype=". ADLDAP_SECURITY_GLOBAL_GROUP ."))";
$fields=array("primarygrouptoken","samaccountname","distinguishedname");
$sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
$entries = ldap_get_entries($this->_conn, $sr);

for ($i=0; $i<$entries["count"]; $i++){
if ($entries[$i]["primarygrouptoken"][0]==$gid){
$r=$entries[$i]["distinguishedname"][0];
$i=$entries["count"];
}
}
}
return ($r);
}

// group_info($group_name,$fields=NULL)
// Returns an array of information for a specified group
function group_info($group_name,$fields=NULL){
if ($this->_ad_username!=NULL){ $this->rebind(); } //bind as a another account if necessary

if ($this->_bind){
//escape brackets
$group_name=str_replace("(","\(",$group_name);
$group_name=str_replace(")","\)",$group_name);

$filter="(&(objectCategory=group)(name=".$group_name."))";
//echo ($filter."<br>");
if ($fields==NULL){ $fields=array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); }
$sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
$entries = ldap_get_entries($this->_conn, $sr);
//print_r($entries);
return ($entries);
}
return (false);
}

function all_users($include_desc = false, $search = "*", $sorted = true){
// Returns all AD users
if ($this->_ad_username!=NULL){ $this->rebind(); } //bind as a another account if necessary

if ($this->_bind){
$users_array = array();

//perform the search and grab all their details
$filter = "(&(objectClass=user)(samaccounttype=". ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=$search))";
$fields=array("samaccountname","displayname");
$sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
$entries = ldap_get_entries($this->_conn, $sr);

for ($i=0; $i<$entries["count"]; $i++){
if( $include_desc && strlen($entries[$i]["displayname"][0]) > 0 )
$users_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["displayname"][0];
else if( $include_desc )
$users_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["samaccountname"][0];
else
array_push($users_array, $entries[$i]["samaccountname"][0]);
}
if( $sorted ){ asort($users_array); }
return ($users_array);
}
return (false);
}

function all_groups($include_desc = false, $search = "*", $sorted = true){
// Returns all AD groups
if ($this->_ad_username!=NULL){ $this->rebind(); } //bind as a another account if necessary

if ($this->_bind){
$groups_array = array();

//perform the search and grab all their details
$filter = "(&(objectCategory=group)(samaccounttype=". ADLDAP_SECURITY_GLOBAL_GROUP .")(cn=$search))";
$fields=array("samaccountname","description");
$sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
$entries = ldap_get_entries($this->_conn, $sr);

for ($i=0; $i<$entries["count"]; $i++){
if( $include_desc && strlen($entries[$i]["description"][0]) > 0 )
$groups_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["description"][0];
else if( $include_desc )
$groups_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["samaccountname"][0];
else

array_push($groups_array, $entries[$i]["samaccountname"][0]);
}
if( $sorted ){ asort($groups_array); }
return ($groups_array);
}
return (false);
}
} // End class

?>


I must point out that this is not my code, it is a direct blag from sourceforge and I must say
All Hail Scott Barnett.
All Hail Scott Barnett.
All Hail Scott Barnett.
All Hail Scott Barnett..
HTH and have fun
"Make something fool-proof and they will make a bigger fool"
0

#8 User is offline   Graeme Forrester 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 98
  • Joined: 14-July 06
  • Location:Australia

Posted 20 October 2006 - 04:27 AM

Many, many thanks. Great job.

BTW I work in a school as well.
Have you built a project for reporting behaviour / conduct problems? This is what I am working on now.
0

#9 User is offline   Graeme Forrester 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 98
  • Joined: 14-July 06
  • Location:Australia

Post icon  Posted 03 November 2006 - 10:52 PM

Update to LDAP

Thanks Sofa for the support and work on this. There needs to be a change to the login.php file as follows

Add two lines of code to the login.php file from

Quote

// username and password are stored in the database
$conn=db_connect();
$strUsername = (string)@$_POST["username"];
$strPassword = (string)@$_POST["password"];

to this

Quote

// username and password are stored in the database
$conn=db_connect();
$strUsername = (string)@$_POST["username"];
$strPassword = (string)@$_POST["password"];
$strlUsername = $_POST["username"];]
$strlPassword = $_POST["password"];

as well as making the other changes in Sofas post.
Works well and is very quick.
Great work again Sofa
0

#10 User is offline   thesofa 

  • Advanced Member
  • PipPipPip
  • Group: Members
  • Posts: 650
  • Joined: 24-February 06
  • Gender:Male
  • Location:NE England

Posted 03 November 2006 - 11:55 PM

Thanks for pointing out my omission, I hope no-one has given up with LDAP due to my laxness?
:D
"Make something fool-proof and they will make a bigger fool"
0

Page 1 of 1
  • You cannot start a new topic
  • This topic is locked

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users