Commit d71b3ecb authored by jiangbowen's avatar jiangbowen

'test'

parent 3352ad38
File added
<?php
return [
/*
|--------------------------------------------------------------------------
| Logging
|--------------------------------------------------------------------------
|
| This option enables logging all LDAP operations on all configured
| connections such as bind requests and CRUD operations.
|
| Log entries will be created in your default logging stack.
|
| This option is extremely helpful for debugging connectivity issues.
|
*/
'logging' => env('LDAP_LOGGING', false),
/*
|--------------------------------------------------------------------------
| Connections
|--------------------------------------------------------------------------
|
| This array stores the connections that are added to Adldap. You can add
| as many connections as you like.
|
| The key is the name of the connection you wish to use and the value is
| an array of configuration settings.
|
*/
'connections' => [
'default' => [
/*
|--------------------------------------------------------------------------
| Auto Connect
|--------------------------------------------------------------------------
|
| If auto connect is true, Adldap will try to automatically connect to
| your LDAP server in your configuration. This allows you to assume
| connectivity rather than having to connect manually
| in your application.
|
| If this is set to false, you **must** connect manually before running
| LDAP operations. Otherwise, you will receive exceptions.
|
*/
'auto_connect' => env('LDAP_AUTO_CONNECT', true),
/*
|--------------------------------------------------------------------------
| Connection
|--------------------------------------------------------------------------
|
| The connection class to use to run raw LDAP operations on.
|
| Custom connection classes must implement:
|
| Adldap\Connections\ConnectionInterface
|
*/
'connection' => Adldap\Connections\Ldap::class,
/*
|--------------------------------------------------------------------------
| Connection Settings
|--------------------------------------------------------------------------
|
| This connection settings array is directly passed into the Adldap constructor.
|
| Feel free to add or remove settings you don't need.
|
*/
'settings' => [
/*
|--------------------------------------------------------------------------
| Schema
|--------------------------------------------------------------------------
|
| The schema class to use for retrieving attributes and generating models.
|
| You can also set this option to `null` to use the default schema class.
|
| For OpenLDAP, you must use the schema:
|
| Adldap\Schemas\OpenLDAP::class
|
| For FreeIPA, you must use the schema:
|
| Adldap\Schemas\FreeIPA::class
|
| Custom schema classes must implement Adldap\Schemas\SchemaInterface
|
*/
'schema' => Adldap\Schemas\ActiveDirectory::class,
/*
|--------------------------------------------------------------------------
| Account Prefix
|--------------------------------------------------------------------------
|
| The account prefix option is the prefix of your user accounts in LDAP directory.
|
| This string is prepended to all authenticating users usernames.
|
*/
'account_prefix' => env('LDAP_ACCOUNT_PREFIX', ''),
/*
|--------------------------------------------------------------------------
| Account Suffix
|--------------------------------------------------------------------------
|
| The account suffix option is the suffix of your user accounts in your LDAP directory.
|
| This string is appended to all authenticating users usernames.
|
*/
'account_suffix' => env('LDAP_ACCOUNT_SUFFIX', ''),
/*
|--------------------------------------------------------------------------
| Domain Controllers
|--------------------------------------------------------------------------
|
| The domain controllers option is an array of servers located on your
| network that serve Active Directory. You can insert as many servers or
| as little as you'd like depending on your forest (with the
| minimum of one of course).
|
| These can be IP addresses of your server(s), or the host name.
|
*/
'hosts' => explode(' ', env('LDAP_HOSTS', 'corp-dc1.corp.acme.org corp-dc2.corp.acme.org')),
/*
|--------------------------------------------------------------------------
| Port
|--------------------------------------------------------------------------
|
| The port option is used for authenticating and binding to your LDAP server.
|
*/
'port' => env('LDAP_PORT', 389),
/*
|--------------------------------------------------------------------------
| Timeout
|--------------------------------------------------------------------------
|
| The timeout option allows you to configure the amount of time in
| seconds that your application waits until a response
| is received from your LDAP server.
|
*/
'timeout' => env('LDAP_TIMEOUT', 5),
/*
|--------------------------------------------------------------------------
| Base Distinguished Name
|--------------------------------------------------------------------------
|
| The base distinguished name is the base distinguished name you'd
| like to perform query operations on. An example base DN would be:
|
| dc=corp,dc=acme,dc=org
|
| A correct base DN is required for any query results to be returned.
|
*/
'base_dn' => env('LDAP_BASE_DN', 'dc=corp,dc=acme,dc=org'),
/*
|--------------------------------------------------------------------------
| LDAP Username & Password
|--------------------------------------------------------------------------
|
| When connecting to your LDAP server, a username and password is required
| to be able to query and run operations on your server(s). You can
| use any user account that has these permissions. This account
| does not need to be a domain administrator unless you
| require changing and resetting user passwords.
|
*/
'username' => env('LDAP_USERNAME', 'username'),
'password' => env('LDAP_PASSWORD', 'secret'),
/*
|--------------------------------------------------------------------------
| Follow Referrals
|--------------------------------------------------------------------------
|
| The follow referrals option is a boolean to tell active directory
| to follow a referral to another server on your network if the
| server queried knows the information your asking for exists,
| but does not yet contain a copy of it locally.
|
| This option is defaulted to false.
|
*/
'follow_referrals' => false,
/*
|--------------------------------------------------------------------------
| SSL & TLS
|--------------------------------------------------------------------------
|
| If you need to be able to change user passwords on your server, then an
| SSL or TLS connection is required. All other operations are allowed
| on unsecured protocols.
|
| One of these options are definitely recommended if you
| have the ability to connect to your server securely.
|
*/
'use_ssl' => env('LDAP_USE_SSL', false),
'use_tls' => env('LDAP_USE_TLS', false),
],
],
],
];
* Getting Started
* [Introduction & Quick Start](/)
* [Installation](installation.md)
* [Setup](setup.md)
* [Usage](usage.md)
* [Upgrade Guide](upgrading.md)
* Authentication Driver
* [Introduction & Quick Start](auth/introduction.md)
* [Installation](auth/installation.md)
* [Setup](auth/setup.md)
* [Middleware (Single Sign On)](auth/middleware.md)
* [Events](auth/events.md)
* [Model Binding](auth/model-binding.md)
* [Importing](auth/importing.md)
* [Testing](auth/testing.md)
# Events
Adldap2-Laravel raises a variety of events throughout authentication attempts.
You may attach listeners to these events in your `EventServiceProvider`:
```php
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Adldap\Laravel\Events\Authenticating' => [
'App\Listeners\LogAuthenticating',
],
'Adldap\Laravel\Events\Authenticated' => [
'App\Listeners\LogLdapAuthSuccessful',
],
'Adldap\Laravel\Events\AuthenticationSuccessful' => [
'App\Listeners\LogAuthSuccessful'
],
'Adldap\Laravel\Events\AuthenticationFailed' => [
'App\Listeners\LogAuthFailure',
],
'Adldap\Laravel\Events\AuthenticationRejected' => [
'App\Listeners\LogAuthRejected',
],
'Adldap\Laravel\Events\AuthenticatedModelTrashed' => [
'App\Listeners\LogUserModelIsTrashed',
],
'Adldap\Laravel\Events\AuthenticatedWithCredentials' => [
'App\Listeners\LogAuthWithCredentials',
],
'Adldap\Laravel\Events\AuthenticatedWithWindows' => [
'App\Listeners\LogSSOAuth',
],
'Adldap\Laravel\Events\DiscoveredWithCredentials' => [
'App\Listeners\LogAuthUserLocated',
],
'Adldap\Laravel\Events\Importing' => [
'App\Listeners\LogImportingUser',
],
'Adldap\Laravel\Events\Synchronized' => [
'App\Listeners\LogSynchronizedUser',
],
'Adldap\Laravel\Events\Synchronizing' => [
'App\Listeners\LogSynchronizingUser',
],
];
```
> **Note:** For some real examples, you can browse the listeners located
> in: `vendor/adldap2/adldap2-laravel/src/Listeners` and see their usage.
\ No newline at end of file
# Importing
Adldap2-Laravel comes with a command that allows you to import users from your LDAP server automatically.
> **Note**: Make sure you're able to connect to your LDAP server and have configured
> the `ldap` auth driver correctly before running the command.
## Running the Command
To import all users from your LDAP connection simply run `php artisan adldap:import`.
> **Note**: The import command will utilize all scopes and sync all attributes you
> have configured in your `config/ldap_auth.php` configuration file.
Example:
```bash
php artisan adldap:import
Found 2 user(s).
```
You will then be asked:
```bash
Would you like to display the user(s) to be imported / synchronized? (yes/no) [no]:
> y
```
Confirming the display of users to will show a table of users that will be imported:
```bash
+------------------------------+----------------------+----------------------------------------------+
| Name | Account Name | UPN |
+------------------------------+----------------------+----------------------------------------------+
| John Doe | johndoe | johndoe@email.com |
| Jane Doe | janedoe | janedoe@email.com |
+------------------------------+----------------------+----------------------------------------------+
```
After it has displayed all users, you will then be asked:
```bash
Would you like these users to be imported / synchronized? (yes/no) [no]:
> y
2/2 [============================] 100%
Successfully imported / synchronized 2 user(s).
```
## Scheduling the Command
To run the import as a scheduled job, place the following in your `app/Console/Kernel.php` in the command scheduler:
```php
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*
* @return void
*/
protected function schedule(Schedule $schedule)
{
// Import LDAP users hourly.
$schedule->command('adldap:import', [
'--no-interaction',
'--restore',
'--delete',
'--filter' => '(objectclass=user)',
])->hourly();
}
```
The above scheduled import command will:
- Run without interaction and import new users as well as synchronize already imported users
- Restore user models who have been re-activated in your LDAP directory (if you're using [SoftDeletes](https://laravel.com/docs/5.7/eloquent#soft-deleting))
- Soft-Delete user models who have been deactived in your LDAP directory (if you're using [SoftDeletes](https://laravel.com/docs/5.7/eloquent#soft-deleting))
- Only import users that have an `objectclass` equal to `user`
### Importing a Single User
To import a single user, insert one of their attributes and Adldap2 will try to locate the user for you:
```bash
php artisan adldap:import jdoe@email.com
Found user 'John Doe'.
```
## Import Scope
> **Note**: This feature was added in v6.0.2.
To customize the query that locates the LDAP users local database model, you may
use the `useScope` method on the `Import` command in your `AppServiceProvider`:
```php
use App\Scopes\LdapUserImportScope;
use Adldap\Laravel\Commands\Import;
public function boot()
{
Import::useScope(LdapUserImportScope::class);
}
```
The custom scope:
> **Note**: It's recommended that your custom scope extend the default `UserImportScope`.
> Otherwise, it must implement the `Illuminate\Database\Eloquent\Scope` interface.
```php
namespace App\Scopes;
use Adldap\Laravel\Facades\Resolver;
use Adldap\Laravel\Commands\UserImportScope as BaseScope;
class LdapUserImportScope extends BaseScope
{
/**
* Apply the scope to a given Eloquent query builder.
*
* @param Builder $query
* @param Model $model
*
* @return void
*/
public function apply(Builder $query, Model $model)
{
$query
->where(Resolver::getDatabaseIdColumn(), '=', $this->getGuid())
->orWhere(Resolver::getDatabaseUsernameColumn(), '=', $this->getUsername());
}
}
```
## Command Options
### Filter
The `--filter` (or `-f`) option allows you to enter in a raw filter in combination with your scopes inside your `config/ldap_auth.php` file:
```bash
php artisan adldap:import --filter "(cn=John Doe)"
Found user 'John Doe'.
```
### Model
The `--model` (or `-m`) option allows you to change the model to use for importing users.
By default your configured model from your `ldap_auth.php` file will be used.
```bash
php artisan adldap:import --model "\App\Models\User"
```
### No Logging
The `--no-log` option allows you to disable logging during the command.
By default, this is enabled.
```bash
php artisan adldap:import --no-log
```
### Delete
The `--delete` (or `-d`) option allows you to soft-delete deactivated LDAP users. No users will
be deleted if your User model does not have soft-deletes enabled.
```bash
php artisan adldap:import --delete
```
### Restore
The `--restore` (or `-r`) option allows you to restore soft-deleted re-activated LDAP users.
```bash
php artisan adldap:import --restore
```
> **Note**: Usually the `--restore` and `--delete` options are used in tandem to allow full synchronization.
### No Interaction
To run the import command via a schedule, use the `--no-interaction` flag:
```php
php artisan adldap:import --no-interaction
```
Users will be imported automatically with no prompts.
You can also call the command from the Laravel Scheduler, or other commands:
```php
// Importing one user
$schedule->command('adldap:import sbauman', ['--no-interaction'])
->everyMinute();
```
```php
// Importing all users
$schedule->command('adldap:import', ['--no-interaction'])
->everyMinute();
```
```php
// Importing users with a filter
$dn = 'CN=Accounting,OU=SecurityGroups,DC=Acme,DC=Org';
$filter = sprintf('(memberof:1.2.840.113556.1.4.1941:=%s)', $dn);
$schedule->command('adldap:import', ['--no-interaction', '--filter' => $filter])
->everyMinute();
```
## Tips
- Users who already exist inside your database will be updated with your configured `sync_attributes`
- Users are never deleted from the import command, you will need to delete users regularly through your model
- Successfully imported (new) users are reported in your log files with:
- `[2016-06-29 14:51:51] local.INFO: Imported user johndoe`
- Unsuccessful imported users are also reported in your log files, with the message of the exception:
- `[2016-06-29 14:51:51] local.ERROR: Unable to import user janedoe. SQLSTATE[23000]: Integrity constraint violation: 1048`
- Specifying a username uses ambiguous naming resolution, so you're able to specify attributes other than their username, such as their email (`php artisan adldap:import jdoe@mail.com`).
- If you have a password mutator (setter) on your User model, it will not override it. This way, you can hash the random 16 characters any way you please.
# Installation
> **Note**: If you're using Laravel 6, you must publish Laravel's auth
> scaffolding by running the following commands before continuing on:
>
> ```bash
> composer require laravel/ui --dev
>
> php artisan ui vue --auth
> ```
To start configuring the authentication driver, you will need
to publish the configuration file using the command below:
```bash
php artisan vendor:publish --provider "Adldap\Laravel\AdldapAuthServiceProvider"
```
Then, open your `config/auth.php` configuration file and change the `driver`
value inside the `users` authentication provider to `ldap`:
```php
'providers' => [
'users' => [
'driver' => 'ldap', // Changed from 'eloquent'
'model' => App\User::class,
],
],
```
> **Tip**: Now that you've enabled LDAP authentication, you may want to turn off some of
> Laravel's authorization routes such as password resets, registration, and email
> verification.
>
> You can do so in your `routes/web.php` file via:
>
> ```php
> Auth::routes([
> 'reset' => false,
> 'verify' => false,
> 'register' => false,
> ]);
> ```
Now that you've completed the basic installation, let's move along to the [setup guide](auth/setup.md).
# Introduction
The Adldap2 Laravel auth driver allows you to seamlessly authenticate LDAP users into your Laravel application.
There are two primary ways of authenticating LDAP users:
- Authenticate and synchronize LDAP users into your local applications database:
This allows you to attach data to users as you would in a traditional application.
Calling `Auth::user()` returns your configured Eloquent model (ex. `App\User`) of the LDAP user.
- Authenticate without keeping a database record for users
This allows you to have temporary users.
Calling `Auth::user()` returns the actual LDAP users model (ex. `Adldap\Models\User`).
We'll get into each of these methods and how to implement them, but first, lets go through the [installation guide](auth/installation.md).
## Quick Start - From Scratch
Here is a step by step guide for configuring Adldap2-Laravel (and its auth driver) with a fresh new laravel project. This guide assumes you have knowledge working with:
- Laravel
- The LDAP Protocol
- Your LDAP distro (ActiveDirectory, OpenLDAP, FreeIPA)
- Command line tools (such as Composer and Laravel's Artisan).
This guide was created with the help of [@st-claude](https://github.com/st-claude) and other awesome contributors.
1. Create a new laravel project by running the command:
- `laravel new my-ldap-app`
Or (if you don't have the [Laravel Installer](https://laravel.com/docs/5.7#installation))
- `composer create-project --prefer-dist laravel/laravel my-app`.
2. Run the following command to install Adldap2-Laravel:
- `composer require adldap2/adldap2-laravel`
3. Create a new database in your desired database interface (such as PhpMyAdmin, MySQL Workbench, command line etc.)
4. Enter your database details and credentials inside the `.env` file located in your project root directory (if there is not one there, rename the `.env.example` to `.env`).
5. If you're using username's to login users **instead** of their emails, you will need to change
the default `email` column in `database/migrations/2014_10_12_000000_create_users_table.php`.
```php
// database/migrations/2014_10_12_000000_create_users_table.php
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
// From:
$table->string('email')->unique();
// To:
$table->string('username')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
```
6. Now run `php artisan migrate`.
7. Insert the following service providers in your `config/app.php` file (in the `providers` array):
> **Note**: This step is only required for Laravel 5.0 - 5.4.
> They are registered automatically in Laravel 5.5.
```php
Adldap\Laravel\AdldapServiceProvider::class,
Adldap\Laravel\AdldapAuthServiceProvider::class,
```
8. Now, insert the facade into your `config/app.php` file (in the `aliases` array):
```php
'Adldap' => Adldap\Laravel\Facades\Adldap::class,
```
> **Note**: Insertion of this alias in your `app.php` file isn't necessary unless you're planning on utilizing it.
9. Now run `php artisan vendor:publish` in your root project directory to publish Adldap2's configuration files.
* Two files will be published inside your `config` folder, `ldap.php` and `ldap_auth.php`.
10. Modify the `config/ldap.php` and `config/ldap_auth.php` files for your LDAP server configuration.
11. Run the command `php artisan make:auth` to scaffold login controllers and routes.
12. If you require logging in by another attribute, such as a username instead of email follow
the process below for your Laravel version. Otherwise ignore this step.
**Laravel <= 5.2**
Inside the generated `app/Http/Controllers/Auth/AuthController.php`, you'll need to add the `protected $username` property if you're logging in users by username.
```php
class AuthController extends Controller
{
protected $username = 'username';
```
**Laravel > 5.3**
Inside the generated `app/Http/Controllers/Auth/LoginController.php`, you'll need to add the public method `username()`:
```php
public function username()
{
return 'username';
}
```
13. Now insert a new auth driver inside your `config/auth.php` file:
```php
'providers' => [
'users' => [
'driver' => 'ldap', // Was 'eloquent'.
'model' => App\User::class,
],
],
```
14. Inside your `resources/views/auth/login.blade.php` file, if you're requiring the user logging in by username, you'll
need to modify the HTML input to `username` instead of `email`. Ignore this step otherwise.
From:
```html
<input type="email" class="form-control" name="email" value="{{ old('email') }}">
```
To:
```html
<input type="text" class="form-control" name="username" value="{{ old('username') }}">
```
15. You should now be able to login to your Laravel application using LDAP authentication!
If you check out your database in your `users` table, you'll see that your LDAP account was synchronized to a local user account.
This means that you can attach data regularly to this user as you would with standard Laravel authentication.
If you're having issues, and you're unable to authenticate LDAP users, please check your configuration settings inside the `ldap.php` and `ldap_auth.php` files as these directly impact your applications ability to authenticate.
16. Congratulations, you're awesome.
# Middleware
SSO authentication allows you to authenticate your domain users automatically in your application by
the pre-populated `$_SERVER['AUTH_USER']` (or `$_SERVER['REMOTE_USER']`) that is filled when
users visit your site when SSO is enabled on your server. This is
configurable in your `ldap_auth.php`configuration file in the `identifiers` array.
> **Requirements**: This feature assumes that you have enabled `Windows Authentication` in IIS, or have enabled it
> in some other means with Apache. Adldap2 does not set this up for you. To enable Windows Authentication, visit:
> https://www.iis.net/configreference/system.webserver/security/authentication/windowsauthentication/providers/add
> **Note**: The WindowsAuthenticate middleware utilizes the `scopes` inside your `config/ldap.php` file.
> A user may successfully authenticate against your LDAP server when visiting your site, but
> depending on your scopes, may not be imported or logged in.
To use the middleware, insert it on your middleware stack inside your `app/Http/Kernel.php` file:
```php
protected $middlewareGroups = [
'web' => [
Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
Middleware\VerifyCsrfToken::class,
\Adldap\Laravel\Middleware\WindowsAuthenticate::class, // Inserted here.
],
];
```
Now when you visit your site, a user account will be created (if one does not exist already)
with a random 16 character string password and then automatically logged in. Neat huh?
## Configuration
You can configure the attributes users are logged in by in your configuration:
```php
'usernames' => [
//..//
'windows' => [
'locate_users_by' => 'samaccountname',
'server_key' => 'AUTH_USER',
],
],
```
If a user is logged into a domain joined computer and is visiting your website with windows
authentication enabled, IIS will set the PHP server variable `AUTH_USER`. This variable
is usually equal to the currently logged in users `samaccountname`.
The configuration array represents this mapping. The WindowsAuthenticate middleware will
check if the server variable is set, and try to locate the user in your LDAP server
by their `samaccountname`.
# Model Binding
Model binding allows you to attach the users LDAP model to their Eloquent
model so their LDAP data is available on every request automatically.
> **Note**: Before we begin, enabling this option will perform a single query on your LDAP server for a logged
> in user **per request**. Eloquent already does this for authentication, however
> this could lead to slightly longer load times (depending on your LDAP
> server and network speed of course).
To begin, insert the `Adldap\Laravel\Traits\HasLdapUser` trait onto your `User` model:
```php
namespace App;
use Adldap\Laravel\Traits\HasLdapUser;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use SoftDeletes, HasLdapUser;
```
Now, after you've authenticated a user (with the `ldap` auth driver),
their LDAP model will be available on their `User` model:
```php
if (Auth::attempt($credentials)) {
$user = Auth::user();
var_dump($user); // Returns instance of App\User;
var_dump($user->ldap); // Returns instance of Adldap\Models\User;
// Examples:
$user->ldap->getGroups();
$user->ldap->getCommonName();
$user->ldap->getConvertedSid();
}
```
\ No newline at end of file
This diff is collapsed.
# Testing
To test that your configured LDAP connection is being authenticated against, you can utilize the `Adldap\Laravel\Facades\Resolver` facade.
Using the facade, you can mock certain methods to return mock LDAP users
and pass or deny authentication to test different scenarios.
```php
<?php
namespace Tests\Feature;
use App\User;
use Tests\TestCase;
use Adldap\Laravel\Facades\Adldap;
use Adldap\Laravel\Facades\Resolver;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Testing\WithFaker;
class AuthTest extends TestCase
{
use WithFaker;
/**
* Returns a new LDAP user model.
*
* @param array $attributes
*
* @return \Adldap\Models\User
*/
protected function makeLdapUser(array $attributes = [])
{
$provider = config('ldap_auth.connection');
return Adldap::getProvider($provider)->make()->user($attributes);
}
/**
* A basic test example.
*
* @return void
*/
public function test_ldap_authentication_works()
{
$credentials = ['email' => 'jdoe@email.com', 'password' => '12345'];
$user = $this->makeLdapUser([
'objectguid' => [$this->faker->uuid],
'cn' => ['John Doe'],
'userprincipalname' => ['jdoe@email.com'],
]);
Resolver::shouldReceive('byCredentials')->once()->with($credentials)->andReturn($user)
->shouldReceive('getDatabaseIdColumn')->twice()->andReturn('objectguid')
->shouldReceive('getDatabaseUsernameColumn')->once()->andReturn('email')
->shouldReceive('getLdapDiscoveryAttribute')->once()->andReturn('userprincipalname')
->shouldReceive('authenticate')->once()->andReturn(true);
$this->post(route('login'), $credentials)->assertRedirect('/dashboard');
$this->assertInstanceOf(User::class, Auth::user());
}
}
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Adldap2-Laravel Documentation</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="Adldap2-Laravel Documentation">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'Adldap2-Laravel',
repo: 'https://github.com/Adldap2/Adldap2-Laravel',
autoHeader: true,
auto2top: true,
homepage: 'readme.md',
search: 'auto',
loadSidebar: true,
maxLevel: 3,
subMaxLevel: 2
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-php.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
</body>
</html>
# Requirements
Adldap2-Laravel requires the following:
- Laravel 5.5
- PHP 7.1 or greater
- PHP LDAP extension enabled
- An LDAP Server
# Composer
Run the following command in the root of your project:
```bash
composer require adldap2/adldap2-laravel
```
> **Note**: If you are using laravel 5.5 or higher you can skip the service provider
> and facade registration and continue with publishing the configuration file.
Once finished, insert the service provider in your `config/app.php` file:
```php
Adldap\Laravel\AdldapServiceProvider::class,
```
Then insert the facade alias (if you're going to use it):
```php
'Adldap' => Adldap\Laravel\Facades\Adldap::class
```
Finally, publish the `ldap.php` configuration file by running:
```bash
php artisan vendor:publish --provider "Adldap\Laravel\AdldapServiceProvider"
```
Now you're all set! You're ready to move onto [setup](setup.md).
\ No newline at end of file
# Introduction
## What is Adldap2-Laravel?
Adldap2-Laravel is an extension to the core [Adldap2](https://github.com/Adldap2/Adldap2) package.
This package allows you to:
1. Easily configure and manage multiple LDAP connections at once
2. Authenticate LDAP users into your Laravel application
3. Import / Synchronize LDAP users into your database and easily keep them up to date with changes in your directory
4. Search your LDAP directory with a fluent and easy to use query builder
5. Create / Update / Delete LDAP entities with ease
6. And more
## Quick Start
Install Adldap2-Laravel via [composer](https://getcomposer.org/) using the command:
```bash
composer require adldap2/adldap2-laravel
```
Publish the configuration file using:
```bash
php artisan vendor:publish --provider="Adldap\Laravel\AdldapServiceProvider"
```
Configure your LDAP connection in the published `ldap.php` file.
Then, use the `Adldap\Laravel\Facades\Adldap` facade:
```php
use Adldap\Laravel\Facades\Adldap;
// Finding a user:
$user = Adldap::search()->users()->find('john doe');
// Searching for a user:
$search = Adldap::search()->where('cn', '=', 'John Doe')->get();
// Running an operation under a different connection:
$users = Adldap::getProvider('other-connection')->search()->users()->get();
// Creating a user:
$user = Adldap::make()->user([
'cn' => 'John Doe',
]);
// Modifying Attributes:
$user->cn = 'Jane Doe';
// Saving a user:
$user->save();
```
**Or** inject the `Adldap\AdldapInterface`:
```php
use Adldap\AdldapInterface;
class UserController extends Controller
{
/**
* @var Adldap
*/
protected $ldap;
/**
* Constructor.
*
* @param AdldapInterface $adldap
*/
public function __construct(AdldapInterface $ldap)
{
$this->ldap = $ldap;
}
/**
* Displays the all LDAP users.
*
* @return \Illuminate\View\View
*/
public function index()
{
$users = $this->ldap->search()->users()->get();
return view('users.index', compact('users'));
}
/**
* Displays the specified LDAP user.
*
* @return \Illuminate\View\View
*/
public function show($id)
{
$user = $this->ldap->search()->findByGuid($id);
return view('users.show', compact('user'));
}
}
```
## Versioning
Adldap2-Laravel is versioned under the [Semantic Versioning](http://semver.org/) guidelines as much as possible.
Releases will be numbered with the following format:
`<major>.<minor>.<patch>`
And constructed with the following guidelines:
* Breaking backward compatibility bumps the major and resets the minor and patch.
* New additions without breaking backward compatibility bumps the minor and resets the patch.
* Bug fixes and misc changes bumps the patch.
Minor versions are not maintained individually, and you're encouraged to upgrade through to the next minor version.
Major versions are maintained individually through separate branches.
# Setup
## Configuration
Upon publishing your `ldap.php` configuration, you'll see an array named `connections`. This
array contains a key value pair for each LDAP connection you're looking to configure.
Each connection you configure should be separate domains. Only one connection is necessary
when using multiple LDAP servers on the same domain.
### Connection Name
The `default` key is your LDAP connections name. This is used as an identifier when connecting.
Usually this is set to your domain name. For example:
```php
'connections' => [
'corp.acme.org' => [
'...',
],
],
```
You may change this to whatever name you prefer.
### Auto Connect
The `auto_connect` configuration option determines whether Adldap2-Laravel will try to bind to your
LDAP server automatically using your configured credentials when calling the `Adldap`
facade or injecting the `AdldapInterface` interface.
For the example below, notice how we don't have to connect manually and we can assume connectivity:
```php
use Adldap\AdldapInterface;
public class UserController extends Controller
{
public function index(AdldapInterface $ldap)
{
return view('users.index', [
'users' => $ldap->search()->users()->get();
]);
}
}
```
If this is set to `false`, you **must** connect manually before running operations on your server.
Otherwise, you will receive an exception upon performing operations.
### Settings
The `settings` option contains a configuration array of your LDAP server connection.
Please view the core [Aldap2 Configuration Guide](https://adldap2.github.io/Adldap2/#/setup?id=options)
for definitions on each option and its meaning.
Once you've done so, you're ready to move to the [usage guide](usage.md).
# The Basics
Lets get down to the basics. This guide will help you get a quick understanding of
using Adldap2 and cover some use cases you might want to learn how to
perform before trying to work it out on your own.
## Searching
### Querying for your Base DN
If you're not sure what your base distinguished name should be, you can use the query
builder to locate it for you if you're making a successful connection to the server:
```php
$base = Adldap::search()->findBaseDn();
echo $base; // Returns 'dc=corp,dc=acme,dc=org'
```
### Querying for Enabled / Disabled Users
To locate enabled / disabled users in your directory, call the `whereEnabled()`
and `whereDisabled()` methods on a query:
```php
$enabledUsers = Adldap:search()->users()->whereEnabled()->get();
$disabledUsers = Adldap:search()->users()->whereDisabled()->get();
```
### Querying for Group Membership
To locate records in your directory that are apart of a group, use the `whereMemberOf()` query method:
```php
// First, locate the group we want to retrieve the members for:
$accounting = Adldap::search()->groups()->find('Accounting');
// Retrieve the members that belong to the above group.
$results = Adldap::search()->whereMemberOf($accounting)->get();
// Iterate through the results:
foreach ($results as $model) {
$model->getCommonName(); // etc.
}
```
### Escaping Input Manually
If you'd like to execute raw filters, it's best practice to escape any input you receive from a user.
You can do this in a couple ways, so use whichever feels best to you.
Each escape method below will escape all characters inputted unless an **ignore** parameter or **flag**
parameter have been given (such as `LDAP_ESCAPE_FITLER` or `LDAP_ESCAPE_DN`).
```php
// Escaping using the query builder:
$escaped = Adldap::search()->escape($input, $ignore = '', $flags = 0);
// Escaping using the `Utilities` class:
$escaped = \Adldap\Utilities::escape($input, $ignore = '', $flags = 0);
// Escaping with the native PHP:
$escaped = ldap_escape($input, $ignore = '', $flags = 0);
$rawFilter = `(samaccountname=$escaped)`
$results = Adldap::search()->rawFilter($rawFilter)->get();
```
## Models
### Creating
### Updating
### Deleting
### Moving
### Renaming
# User Tutorials
> **Notice**: These tutorials have been created using ActiveDirectory.
> Some tutorials may not relate to your LDAP distribution.
> **Note**: You cannot create or modify user passwords without
> connecting to your LDAP server via SSL or TLS.
## Creating Users
To begin, creating a user is actually quite simple, as it only requires a Common Name:
```php
$user = Adldap::make()->user([
'cn' => 'John Doe',
]);
$user->save();
```
If you'd like to provide more attributes, simply add more:
```php
$user = Adldap::make()->user([
'cn' => 'John Doe',
'sn' => 'Doe',
'givenname' => 'John',
'department' => 'Accounting'
]);
$user->save();
```
If you don't provide a Distinguished Name to the user during creation, one will be set for you automatically
by taking your configured `base_dn` and using the users Common Name you give them:
```php
$user = Adldap::make()->user([
'cn' => 'John Doe',
]);
$user->save(); // Creates a user with the DN: 'cn=John Doe,dc=acme,dc=org'
```
You can provide a `dn` attribute to set the users Distinguished Name you would like to use for creation:
```php
$user = Adldap::make()->user([
'cn' => 'John Doe',
'dn' => 'cn=John Doe,ou=Users,dc=acme,dc=com'
]);
$user->save();
```
All users created in your directory will be disabled by default. How do we enable these users upon creation and set thier password?
What we can use is the `Adldap\Models\Attributes\AccountControl` attribute class and the `userPassword` attribute.
```php
// Encode the users password.
$password = Adldap\Utilies::encodePassword('super-secret');
// Create a new AccountControl object.
$uac = new Adldap\Models\Attributes\AccountControl();
// Set the UAC value to '512'.
$uac->accountIsNormal();
$user = Adldap::make()->user([
'cn' => 'John Doe',
'dn' => 'cn=John Doe,ou=Users,dc=acme,dc=com'
'userPassword' => $password,
'userAccountControl' => $uac->getValue(),
]);
$user->save();
```
You can also fluently create accounts using setter methods if you'd prefer:
> **Note**: There are some conveniences that come with using the setter methods.
> Notice how you don't have to encode the password using the `setPassword()`
> method or call `getValue()` when setting the users account control.
```php
// Create a new AccountControl object.
$uac = new Adldap\Models\Attributes\AccountControl();
$uac->accountIsNormal();
$user = Adldap::make()->user();
$user
->setCommonName('John Doe')
->setDn('cn=John Doe,ou=Users,dc=acme,dc=com')
->setPassword('super-secret')
->setUserAccountControl($uac);
$user->save();
```
## Modifying Users
You can modify users in a variety of ways. Each way will be shown below.
Use whichever ways you prefer readable and most clear to you.
To modify users, you simply modify their attributes using dynamic properties and `save()` them:
```php
$jdoe = Adldap::search()->users()->find('jdoe');
$uac = new Adldap\Models\Attributes\AccountControl();
$uac->accountIsNormal();
$jdoe->deparment = 'Accounting';
$jdoe->telephoneNumber = '555 555-5555';
$jdoe->mobile = '555 444-4444';
$jdoe->userAccountControl = $uac->getValue();
$jdoe->save();
```
You can also use 'setter' methods to perform the same task.
```php
$jdoe = Adldap::search()->users()->find('jdoe');
$uac = new Adldap\Models\Attributes\AccountControl();
$uac->accountIsNormal();
$jdoe
->setDepartment('Accounting');
->setTelephoneNumber('555 555-5555')
->setMobileNumber('555 555-5555')
->setUserAccountControl($uac);
$jdoe->save();
```
Using setter methods offer a little bit of benefit, for example you can see above that
`$uac->getValue()` does not need to be called as the `setUserAccountControl()` method
will automatically convert an `AccountControl` object to its integer value.
Setter methods are also chainable (if you prefer that syntax).
## Deleting Users
As any other returned model in Adldap2, you can call the `delete()` method
to delete a user from your directory:
```php
$user = Adldap::search()->find('jdoe');
$user->delete();
```
Once you `delete()` a user (successfully), the `exists` property on their model is set to `false`:
```php
$user = Adldap::search()->find('jdoe');
$user->delete();
var_dump($user->exists); // Returns 'bool(false)'
```
# Upgrade Guide
## Upgrading from 5.* to 6.*
**Estimated Upgrade Time: 1 hour**
### Minimum Requirements
Adldap2-Laravel now requires a minimum of Laravel 5.5, as all previous versions are now out of their respective support windows.
If you require using an earlier version of Laravel, please use Adldap2-Laravel v5.0.
### Configuration
It is recommended to re-publish both of your `ldap.php` and `ldap_auth.php`
files to ensure you have all of the updated configuration keys.
You can do so by deleting your `ldap.php` and `ldap_auth.php` files and then running:
- `php artisan vendor:publish --provider=Adldap\Laravel\AdldapServiceProvider`
- `php artisan vendor:publish --provider=Adldap\Laravel\AdldapAuthServiceProvider`
#### Quick Changes View
Here's a quick overview of the configuration changes made in their respective files:
```php
// ldap.php
// v5.0
// Non-existent
// v6.0
'logging' => env('LDAP_LOGGING', true),
```
```php
// ldap_auth.php
// v5.0
'usernames' => [
'ldap' => [
'discover' => 'userprincipalname',
'authenticate' => 'distinguishedname',
],
'eloquent' => 'email',
'windows' => [
'discover' => 'samaccountname',
'key' => 'AUTH_USER',
],
],
// v6.0
'model' => App\User::class,
'identifiers' => [
'ldap' => [
'locate_users_by' => 'userprincipalname',
'bind_users_by' => 'distinguishedname',
],
'database' => [
'guid_column' => 'objectguid',
'username_column' => 'email',
],
'windows' => [
'locate_users_by' => 'samaccountname',
'server_key' => 'AUTH_USER',
],
]
```
#### Authentication
##### Object GUID Database Column
When using the `DatabaseUserProvider`, you must now create a database column to
store users `objectguid`. This allows usernames to change in your directory
and synchronize properly in your database. This also allows you to use
multiple LDAP directories / domains in your application.
This column is configurable via the `guid_column` located in the `database` configuration array:
```php
'database' => [
'guid_column' => 'objectguid',
//
```
If you're starting from scratch, simply add the `objectguid` column (or whichever column you've configured) to your `users` migration file:
```php
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('objectguid')->unique()->nullable(); // Added here.
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
```
Otherwise if you're upgrading from v5, make another migration and add the column to your `users` table.
Ex. `php artisan make:migration add_objectguid_column`
```php
Schema::table('users', function (Blueprint $table) {
$table->string('objectguid')->unique()->nullable()->after('id');
});
```
You can learn more about this configuration option [here](auth/setup.md#guid-column).
##### Username Database Column
The `database.username_column` option was renamed from `eloquent` to more directly indicate what it is used for.
Set this option to your users database username column so users are correctly located from your database.
##### LDAP Discover and Authenticate
The `ldap.discover` and `ldap.authenticate` options have been renamed to `ldap.locate_users_by` and `ldap.bind_user_by` respectively.
They were renamed to more directly indicate what they are used for.
##### Windows Discover and Key
The `windows.discover` and `windows.key` options were renamed to `windows.locate_users_by` and `windows.server_key` to follow suit with the above change and to directly indicate what it is used for.
#### LDAP
##### Logging
The `logging` option has been added to automatically enable LDAP operation logging that was added in [Adldap2 v10.0](https://adldap2.github.io/Adldap2/#/logging).
Simply set this to `false` if you would not like operation logging enabled. Any connections you specify in your `connections` configuration will be logged.
## Upgrading from 4.* to 5.*
**Estimated Upgrade Time: 30 minutes**
Functionally, you should not need to change the way you use Adldap2-Laravel. There have been no major API changes that will impact your current usage.
However, there have been API changes to the core [Adldap2](https://github.com/Adldap2/Adldap2/releases/tag/v9.0.0) package.
It is heavily recommended to read the release notes to see if you may be impacted.
### Requirements
Adldap2-Laravel's PHP requirements has been changed. It now requires a minimum of PHP 7.1.
However, Adldap2's Laravel requirements **have not** changed. You can still use all versions of Laravel 5.
### Configuration
Both Adldap2's configuration files have been renamed to `ldap.php` and `ldap_auth.php` for simplicity.
Simply rename `adldap.php` to `ldap.php` and `adldap_auth.php` to `ldap_auth.php`.
If you'd prefer to re-publish them from scratch, here's a quick guide:
1. Delete your `config/adldap.php` file
2. Run `php artisan vendor:publish --provider="Adldap\Laravel\AdldapServiceProvider"`
If you're using the Adldap2 authentication driver, repeat the same steps for its configuration:
1. Delete your `config/adldap_auth.php` file
2. Run `php artisan vendor:publish --provider="Adldap\Laravel\AdldapAuthServiceProvider"`
#### Prefix and Suffix Changes
The configuration options `admin_account_prefix` and `admin_account_suffix` have been removed. Simply
apply a prefix and suffix to the username of the administrator account in your configuration.
The `account_prefix` and `account_suffix` options now only apply to user accounts that are
authenticated, not your configured administrator account.
This means you will need to add your suffix or prefix onto your configured administrators username if you require it.
#### Connection Settings
The configuration option named `connection_settings` inside each of your configured connections in the `adldap.php` (now `ldap.php`) configuration file has been renamed to `settings` for simplicity.
### Authentication Driver
The authentication driver name has been *renamed* to **ldap** instead of **adldap**. This is for the sake of simplicity.
Open your `auth.php` file and rename your authentication driver to `ldap`:
```php
'users' => [
'driver' => 'ldap', // Renamed from 'adldap'
'model' => App\User::class,
],
```
## Upgrading From 3.* to 4.*
**Estimated Upgrade Time: 1 hour**
With `v4.0`, there are some significant changes to the code base.
This new version utilizes the newest `v8.0` release of the underlying Adldap2 repository.
Please visit the [Adldap2](https://github.com/Adldap2/Adldap2/releases/tag/v8.0.0)
repository for the release notes and changes.
However for this package you should only have to change your `adldap_auth.php` configuration.
### Authentication Driver
LDAP connection exceptions are now caught when authentication attempts occur.
These exceptions are logged to your configured logging driver so you can view the stack trace and discover issues easier.
### Configuration
1. Delete your `config/adldap_auth.php`
2. Run `php artisan vendor:publish --tag="adldap"`
3. Reconfigure auth driver in `config/adldap_auth.php`
#### Usernames Array
The `usernames` array has been updated with more options.
You can now configure the attribute you utilize for discovering the LDAP user as well as authenticating.
This will help users who use OpenLDAP and other distributions of directory servers.
Each configuration option is extensively documented in the published
file, so please take a moment to review it once published.
This array now also contains the `windows_auth_attribute` array (shown below).
```php
// v3.0
'usernames' => [
'ldap' => 'userprincipalname',
'eloquent' => 'email',
],
// v4.0
'usernames' => [
'ldap' => [
'discover' => 'userprincipalname',
'authenticate' => 'distinguishedname',
],
'eloquent' => 'email',
'windows' => [
'discover' => 'samaccountname',
'key' => 'AUTH_USER',
],
],
```
#### Logging
Logging has been added for authentication requests to your server.
Which events are logged can be configured in your `adldap_auth.php` file.
Here's an example of the information logged:
```
[2017-11-14 22:19:45] local.INFO: User 'Steve Bauman' has been successfully found for authentication.
[2017-11-14 22:19:45] local.INFO: User 'Steve Bauman' is being imported.
[2017-11-14 22:19:45] local.INFO: User 'Steve Bauman' is being synchronized.
[2017-11-14 22:19:45] local.INFO: User 'Steve Bauman' has been successfully synchronized.
[2017-11-14 22:19:45] local.INFO: User 'Steve Bauman' is authenticating with username: 'sbauman@company.org'
[2017-11-14 22:19:45] local.INFO: User 'Steve Bauman' has successfully passed LDAP authentication.
[2017-11-14 22:19:46] local.INFO: User 'Steve Bauman' has been successfully logged in.
```
#### Resolver
The resolver configuration option has now been removed.
It has been modified to utilize Laravel's Facades so you can now swap the implementation at runtime if you wish.
The complete namespace for this facade is below:
```
Adldap\Laravel\Facades\Resolver
```
Usage:
```php
use Adldap\Laravel\Facades\Resolver;
Resolver::swap(new MyResolver());
```
#### Importer
The importer configuration option has now been removed.
The importer command is bound to Laravel's IoC and can be swapped out with your own implementation if you wish.
#### NoDatabaseUserProvider
The `NoDatabaseUserProvider` will now locate users by their ObjectGUID instead of their ObjectSID.
# Usage
Adldap2-Laravel leverages the core [Adldap2](https://github.com/Adldap2/Adldap2) package.
When you insert the `Adldap\Laravel\AdldapServiceProvider` into your `config/app.php`, an instance of the [Adldap\Adldap](https://adldap2.github.io/Adldap2/#/setup?id=getting-started) class is created and bound as a singleton into your application.
This means, upon calling the included facade (`Adldap\Laravel\Facades\Adldap`) or interface (`Adldap\AdldapInterface`), the same instance will be returned.
This is extremely useful to know, because the `Adldap\Adldap` class is a container that stores each of your LDAP connections.
For example:
```php
use Adldap\Laravel\Facades\Adldap;
// Returns instance of `Adldap\Adldap`
$adldap = Adldap::getFacadeRoot();
```
For brevity, please take a look at the core [Adldap2 documentation](https://adldap2.github.io/Adldap2/#/setup?id=getting-started) for usage.
<?php
namespace Adldap\Laravel\Auth;
use BadMethodCallException;
use Error;
trait ForwardsCalls
{
/**
* Forward a method call to the given object.
*
* @param mixed $object
* @param string $method
* @param array $parameters
*
* @throws BadMethodCallException
*
* @return mixed
*/
protected function forwardCallTo($object, $method, $parameters)
{
try {
return $object->{$method}(...$parameters);
} catch (Error | BadMethodCallException $e) {
$pattern = '~^Call to undefined method (?P<class>[^:]+)::(?P<method>[^\(]+)\(\)$~';
if (! preg_match($pattern, $e->getMessage(), $matches)) {
throw $e;
}
if ($matches['class'] != get_class($object) ||
$matches['method'] != $method) {
throw $e;
}
static::throwBadMethodCallException($method);
}
}
/**
* Throw a bad method call exception for the given method.
*
* @param string $method
*
* @throws BadMethodCallException
*
* @return void
*/
protected static function throwBadMethodCallException($method)
{
throw new BadMethodCallException(sprintf(
'Call to undefined method %s::%s()', static::class, $method
));
}
}
<?php
namespace Adldap\Laravel\Auth;
use Adldap\Laravel\Traits\ValidatesUsers;
use Illuminate\Contracts\Auth\UserProvider as UserProviderContract;
abstract class UserProvider implements UserProviderContract
{
use ValidatesUsers;
}
<?php
namespace Adldap\Laravel\Commands;
use Adldap\Laravel\Facades\Resolver;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class UserImportScope implements Scope
{
/**
* The LDAP users object guid.
*
* @var string
*/
protected $guid;
/**
* The LDAP users username.
*
* @var string
*/
protected $username;
/**
* Constructor.
*
* @param string $guid
* @param string $username
*/
public function __construct($guid, $username)
{
$this->guid = $guid;
$this->username = $username;
}
/**
* Apply the scope to a given Eloquent query builder.
*
* @param Builder $query
* @param Model $model
*
* @return void
*/
public function apply(Builder $query, Model $model)
{
$this->user($query);
}
/**
* Applies the user scope to the given Eloquent query builder.
*
* @param Builder $query
*/
protected function user(Builder $query)
{
// We'll try to locate the user by their object guid,
// otherwise we'll locate them by their username.
$query
->where(Resolver::getDatabaseIdColumn(), '=', $this->getGuid())
->orWhere(Resolver::getDatabaseUsernameColumn(), '=', $this->getUsername());
}
/**
* Returns the LDAP users object guid.
*
* @return string
*/
protected function getGuid()
{
return $this->guid;
}
/**
* Returns the LDAP users username.
*
* @return string
*/
protected function getUsername()
{
return $this->username;
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\Authenticated;
use Adldap\Laravel\Listeners\LogAuthenticated;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogAuthenticatedTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogAuthenticated();
$user = m::mock(User::class);
$user->shouldReceive('getCommonName')->andReturn('jdoe');
$e = new Authenticated($user);
$logged = "User 'jdoe' has successfully passed LDAP authentication.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\AuthenticationFailed;
use Adldap\Laravel\Listeners\LogAuthenticationFailure;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogAuthenticationFailureTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogAuthenticationFailure();
$user = m::mock(User::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new AuthenticationFailed($user);
$logged = "User '{$name}' has failed LDAP authentication.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\AuthenticationRejected;
use Adldap\Laravel\Listeners\LogAuthenticationRejection;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogAuthenticationRejectionTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogAuthenticationRejection();
$user = m::mock(User::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new AuthenticationRejected($user);
$logged = "User '{$name}' has failed validation. They have been denied authentication.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\AuthenticationSuccessful;
use Adldap\Laravel\Listeners\LogAuthenticationSuccess;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogAuthenticationSuccessTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogAuthenticationSuccess();
$user = m::mock(User::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new AuthenticationSuccessful($user);
$logged = "User '{$name}' has been successfully logged in.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\Authenticating;
use Adldap\Laravel\Listeners\LogAuthentication;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogAuthenticationTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogAuthentication();
$user = m::mock(User::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$username = 'jdoe';
$prefix = 'prefix.';
$suffix = '.suffix';
$authUsername = $prefix.$username.$suffix;
$e = new Authenticating($user, $username);
$logged = "User '{$name}' is authenticating with username: '{$authUsername}'";
Log::shouldReceive('info')->once()->with($logged);
Config::shouldReceive('get')->with('ldap_auth.connection')->andReturn('default')
->shouldReceive('get')->with('ldap.connections.default.settings.account_prefix')->andReturn($prefix)
->shouldReceive('get')->with('ldap.connections.default.settings.account_suffix')->andReturn($suffix);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\DiscoveredWithCredentials;
use Adldap\Laravel\Listeners\LogDiscovery;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogDiscoveryTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogDiscovery();
$user = m::mock(User::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new DiscoveredWithCredentials($user);
$logged = "User '{$name}' has been successfully found for authentication.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\Importing;
use Adldap\Laravel\Listeners\LogImport;
use Adldap\Laravel\Tests\Models\TestUser;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogImportTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogImport();
$user = m::mock(User::class);
$model = m::mock(TestUser::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new Importing($user, $model);
$logged = "User '{$name}' is being imported.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\Synchronized;
use Adldap\Laravel\Listeners\LogSynchronized;
use Adldap\Laravel\Tests\Models\TestUser;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogSynchronizedTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogSynchronized();
$user = m::mock(User::class);
$model = m::mock(TestUser::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new Synchronized($user, $model);
$logged = "User '{$name}' has been successfully synchronized.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\Synchronizing;
use Adldap\Laravel\Listeners\LogSynchronizing;
use Adldap\Laravel\Tests\Models\TestUser;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogSynchronizingTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogSynchronizing();
$user = m::mock(User::class);
$model = m::mock(TestUser::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new Synchronizing($user, $model);
$logged = "User '{$name}' is being synchronized.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\AuthenticatedModelTrashed;
use Adldap\Laravel\Listeners\LogTrashedModel;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogTrashedModelTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogTrashedModel();
$user = m::mock(User::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new AuthenticatedModelTrashed($user, m::mock(Authenticatable::class));
$logged = "User '{$name}' was denied authentication because their model has been soft-deleted.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Listeners;
use Adldap\Laravel\Events\AuthenticatedWithWindows;
use Adldap\Laravel\Listeners\LogWindowsAuth;
use Adldap\Laravel\Tests\TestCase;
use Adldap\Models\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\Log;
use Mockery as m;
class LogWindowsAuthTest extends TestCase
{
/** @test */
public function logged()
{
$l = new LogWindowsAuth();
$user = m::mock(User::class);
$name = 'John Doe';
$user->shouldReceive('getCommonName')->andReturn($name);
$e = new AuthenticatedWithWindows($user, m::mock(Authenticatable::class));
$logged = "User '{$name}' has successfully authenticated via NTLM.";
Log::shouldReceive('info')->once()->with($logged);
$l->handle($e);
}
}
<?php
namespace Adldap\Laravel\Tests\Models;
use Adldap\Laravel\Traits\HasLdapUser;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
class TestUser extends Authenticatable
{
use SoftDeletes, HasLdapUser;
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'objectguid',
];
}
name: Tests
on:
push:
branches:
- master
- v9.0
- v8.0
paths-ignore:
- '**.md'
pull_request:
branches:
- master
- v9.0
- v8.0
paths-ignore:
- '**.md'
# Allow manually triggering the workflow
workflow_dispatch:
jobs:
test:
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.0"
- "7.1"
- "7.2"
- "7.3"
- "7.4"
- "8.0"
- "8.1"
name: PHP ${{ matrix.php-version }} tests
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: ldap
coverage: none
- uses: "ramsey/composer-install@v1"
- name: "Run PHPUnit"
run: ./vendor/bin/simple-phpunit
preset: recommended
enabled:
- length_ordered_imports
disabled:
- alpha_ordered_imports
\ No newline at end of file
# Security Policy
## Reporting a Vulnerability
Please report security issues to `steven_bauman@outlook.com`
<!-- _coverpage.md -->
# Adldap2
<p align="center">
<a href="https://travis-ci.org/Adldap2/Adldap2"><img src="https://img.shields.io/travis/Adldap2/Adldap2.svg?style=flat-square"/></a>
<a href="https://scrutinizer-ci.com/g/Adldap2/Adldap2/?branch=master"><img src="https://img.shields.io/scrutinizer/g/adLDAP2/adLDAP2/master.svg?style=flat-square"/></a>
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/dt/adldap2/adldap2.svg?style=flat-square"/></a>
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/v/adldap2/adldap2.svg?style=flat-square"/></a>
<a href="https://packagist.org/packages/adldap2/adldap2"><img src="https://img.shields.io/packagist/l/adldap2/adldap2.svg?style=flat-square"/></a>
</p>
> Working with LDAP doesn't need to be hard.
<!-- background image -->
![](media/bg.svg)
<!-- _sidebar.md -->
* Getting Started
* [Introduction](/)
* [Installation](installation.md)
* [Setup](setup.md)
* Usage
* [Searching](searching.md)
* [Creating & Updating](models/model.md)
* [Events](events.md)
* [Logging](logging.md)
* [Working With Distiguished Names](distinguished-names.md)
* [Troubleshooting](troubleshooting.md)
* Models
* [Model (Base)](models/model.md)
* [Computer](models/computer.md)
* [Contact](models/contact.md)
* [Container](models/container.md)
* [Group](models/group.md)
* [Organizational Unit](models/ou.md)
* [Printer](models/printer.md)
* [RootDse](models/root-dse.md)
* [User](models/user.md)
# Events
Adldap2 events provide a method of listening for certain LDAP actions
that are called and execute tasks for that specific event.
> **Note**: The Adldap2 event dispatcher was actually derived from the
> [Laravel Framework](https://github.com/laravel/framework) with
> Broadcasting & Queuing omitted to remove extra dependencies
> that would be required with implementing those features.
>
> If you've utilized Laravel's events before, this will feel very familiar.
## Registering Listeners
> **Note**: Before we get to registering listeners, it's crucial to know that events throughout
> Adldap2 are fired irrespective of the current connection or provider in use.
>
> This means that when using multiple LDAP connections, the same events will be fired.
>
> This allows you to set listeners on events that occur for all LDAP connections you utilize.
>
> If you are required to determine which events are fired from alternate connections, see [below](#determining-the-connection).
To register a listener on an event, retrieve the event dispatcher and call the `listen()` method:
```php
use Adldap\Auth\Events\Binding;
$dispatcher = \Adldap\Adldap::getEventDispatcher();
$dispatcher->listen(Binding::class, function (Binding $event) {
// Do something with the Binding event information:
$event->connection; // Adldap\Connections\Ldap instance
$event->username; // 'jdoe@acme.org'
$event->password; // 'super-secret'
});
```
The first argument is the event name you would like to listen for, and the
second is either a closure or class name that should handle the event:
Using a class:
> **Note**: When using just a class name, the class must contain a public `handle()` method that will handle the event.
```php
use Adldap\Adldap;
use Adldap\Auth\Events\Binding;
$dispatcher = Adldap::getEventDispatcher();
$dispatcher->listen(Binding::class, MyApp\BindingEventHandler::class);
```
```php
namespace MyApp;
use Adldap\Auth\Events\Binding;
class BindingEventHandler
{
public function handle(Binding $event)
{
// Handle the event...
}
}
```
## Model Events
Model events are handled the same way as authentication events.
Simply call the event dispatcher `listen()` method with the model event you are wanting to listen for:
```php
use Adldap\Models\Events\Saving;
$dispatcher = \Adldap\Adldap::getEventDispatcher();
$dispatcher->listen(Saving::class, function (Saving $event) {
// Do something with the Saving event information:
// Returns the model instance being saved eg. `Adldap\Models\Entry`
$event->getModel();
});
```
## Wildcard Event Listeners
You can register listeners using the `*` as a wildcard parameter to catch multiple events with the same listener.
Wildcard listeners will receive the event name as their first argument, and the entire event data array as their second argument:
```php
$dispatcher = Adldap::getEventDispatcher();
// Listen for all model events.
$dispatcher->listen('Adldap\Models\Events\*', function ($eventName, array $data) {
echo $eventName; // Returns 'Adldap\Models\Events\Updating'
var_dump($data); // Returns [0] => (object) Adldap\Models\Events\Updating;
});
$user = $provider->search()->users()->find('jdoe');
$user->setTelephoneNumber('555 555-5555');
$user->save();
```
## Determining the Connection
If you're using multiple LDAP connections and you require the ability to determine which events belong
to a certain connection, you can do so by verifying the host of the LDAP connection.
Here's an example:
```php
$dispatcher = Adldap::getEventDispatcher();
$dispatcher->listen(\Adldap\Models\Events\Creating::class, function ($event) {
$connection = $event->model->getConnection();
$host = $connection->getHost();
echo $host; // Displays 'ldap://192.168.1.1:386'
});
```
Another example with auth events:
```php
$dispatcher = Adldap::getEventDispatcher();
$dispatcher->listen(\Adldap\Auth\Events\Binding::class, function ($event) {
$connection = $event->connection;
$host = $connection->getHost();
echo $host; // Displays 'ldap://192.168.1.1:386'
});
```
## List of Events
### Authentication Events
There are several events that are fired during initial and subsequent binds to your configured LDAP server.
Here is a list of all events that are fired:
| Event| Description |
|---|---|
| Adldap\Auth\Events\Attempting | When any authentication attempt is called via: `$provider->auth()->attempt()` |
| Adldap\Auth\Events\Passed | When any authentication attempts pass via: `$provider->auth()->attempt()` |
| Adldap\Auth\Events\Failed | When any authentication attempts fail via: `$provider->auth()->attempt()` *Or* `$provider->auth()->bind()` |
| Adldap\Auth\Events\Binding | When any LDAP bind attempts occur via: `$provider->auth()->attempt()` *Or* `$provider->auth()->bind()` |
| Adldap\Auth\Events\Bound | When any LDAP bind attempts are successful via: `$provider->auth()->attempt()` *Or* `$provider->auth()->bind()` |
### Model Events
There are several events that are fired during the creation, updating and deleting of all models.
Here is a list of all events that are fired:
| Event | Description |
|---|---|
| Adldap\Models\Events\Saving | When a model is in the process of being saved via: `$model->save()` |
| Adldap\Models\Events\Saved | When a model has been successfully saved via: `$model->save()` |
| Adldap\Models\Events\Creating | When a model is being created via: `$model->save()` *Or* `$model->create()` |
| Adldap\Models\Events\Created | When a model has been successfully created via: `$model->save()` *Or* `$model->create()` |
| Adldap\Models\Events\Updating | When a model is being updated via: `$model->save()` *Or* `$model->update()` |
| Adldap\Models\Events\Updated | When a model has been successfully updated via: `$model->save()` *Or* `$model->update()` |
| Adldap\Models\Events\Deleting | When a model is being deleted via: `$model->delete()` |
| Adldap\Models\Events\Deleted | When a model has been successfully deleted via: `$model->delete()` |
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Adldap2 Documentation</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="Adldap2 Documentation">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/docsify/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'Adldap2',
repo: 'https://github.com/Adldap2/Adldap2',
autoHeader: true,
auto2top: true,
homepage: 'readme.md',
coverpage: true,
search: 'auto',
loadSidebar: true,
subMaxLevel: 3
}
</script>
<script src="https://unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="https://unpkg.com/prismjs/components/prism-php.min.js"></script>
<script src="https://unpkg.com/docsify/lib/plugins/search.min.js"></script>
</body>
</html>
# Requirements
Adldap2 requires the following:
- PHP 7.0 or greater
- LDAP extension enabled in PHP
- An LDAP server (ActiveDirectory, OpenLDAP, FreeIPA etc.)
# Composer
Adldap2 uses [Composer](https://getcomposer.org) for installation.
Once you have composer installed, run the following command in the root directory of your project:
```bash
composer require adldap2/adldap2
```
Then, if your application doesn't already require Composer's autoload, you will need to do it manually.
Insert this line at the top of your projects PHP script (usually `index.php`):
```php
require __DIR__ . '/vendor/autoload.php';
```
You're all set!
Now, head over to the [setup guide](setup.md) to get up and running.
# Logging
Adldap2 includes an implementation of PSR's widely supported [Logger](https://github.com/php-fig/log) interface.
By default, all of Adldap2's [events](events.md) will call the logger you have set to utilize.
> **Note**: Adldap2 does not include a file / text logger. You must implement your own.
## Registering & Enabling a Logger
To register a logger call `Adldap::setLogger()`. The logger must implement the `Psr\Log\LoggerInterface`.
>**Note**: Be sure to set the logger prior to creating a new `Adldap` instance. This
> ensures all events throughout the lifecycle of the request use your logger.
```php
use Adldap\Adldap;
Adldap::setLogger($myLogger);
$config = ['...'];
$ad = new Adldap();
$ad->addProvider($config);
```
## Disabling Logging
If you need to disable the event logger after a certain set of operations, simply pass in `null` and logging will be disabled:
```php
use Adldap\Adldap;
Adldap::setLogger($myLogger);
$config = ['...'];
$ad = new Adldap();
$ad->addProvider($config);
try {
$ad->connect();
// Disable logging anything else.
Adldap::setLogger(null);
} catch (\Adldap\Connections\BindException $e) {
//
}
```
## Logged Information
Here is a list of events that are logged along with the information included:
| Authentication Events | Logged |
|---|---|
| `Adldap\Auth\Events\Attempting` | `LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Attempting - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org` |
| `Adldap\Auth\Events\Binding` |` LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Binding - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org` |
| `Adldap\Auth\Events\Bound` | `LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Bound - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org` |
| `Adldap\Auth\Events\Passed` | `LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Passed - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org` |
| `Adldap\Auth\Events\Failed` | `LDAP (ldap://192.168.1.1:389) - Operation: Adldap\Auth\Events\Failed - Username: CN=Steve Bauman,OU=Users,DC=corp,DC=acme,DC=org - Result: Invalid Credentials` |
| Model Events | Logged |
|---|---|
| `Adldap\Models\Events\Saving` | `LDAP (ldap://192.168.1.1:389) - Operation: Saving - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
| `Adldap\Models\Events\Saved` | `LDAP (ldap://192.168.1.1:389) - Operation: Saved - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
| `Adldap\Models\Events\Creating` | `LDAP (ldap://192.168.1.1:389) - Operation: Creating - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
| `Adldap\Models\Events\Created` | `LDAP (ldap://192.168.1.1:389) - Operation: Created - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
| `Adldap\Models\Events\Updating` | `LDAP (ldap://192.168.1.1:389) - Operation: Updating - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
| `Adldap\Models\Events\Updated` | `LDAP (ldap://192.168.1.1:389) - Operation: Updated - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
| `Adldap\Models\Events\Deleting` | `LDAP (ldap://192.168.1.1:389) - Operation: Deleting - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
| `Adldap\Models\Events\Deleted` | `LDAP (ldap://192.168.1.1:389) - Operation: Deleted - On: Adldap\Models\User - Distinguished Name: cn=John Doe,dc=acme,dc=org` |
<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%' viewBox='0 0 1600 800'><rect fill='#46ff55' width='1600' height='800'/><g ><path fill='#51ff76' d='M486 705.8c-109.3-21.8-223.4-32.2-335.3-19.4C99.5 692.1 49 703 0 719.8V800h843.8c-115.9-33.2-230.8-68.1-347.6-92.2C492.8 707.1 489.4 706.5 486 705.8z'/><path fill='#57ff94' d='M1600 0H0v719.8c49-16.8 99.5-27.8 150.7-33.5c111.9-12.7 226-2.4 335.3 19.4c3.4 0.7 6.8 1.4 10.2 2c116.8 24 231.7 59 347.6 92.2H1600V0z'/><path fill='#5affb1' d='M478.4 581c3.2 0.8 6.4 1.7 9.5 2.5c196.2 52.5 388.7 133.5 593.5 176.6c174.2 36.6 349.5 29.2 518.6-10.2V0H0v574.9c52.3-17.6 106.5-27.7 161.1-30.9C268.4 537.4 375.7 554.2 478.4 581z'/><path fill='#57ffcd' d='M0 0v429.4c55.6-18.4 113.5-27.3 171.4-27.7c102.8-0.8 203.2 22.7 299.3 54.5c3 1 5.9 2 8.9 3c183.6 62 365.7 146.1 562.4 192.1c186.7 43.7 376.3 34.4 557.9-12.6V0H0z'/><path fill='#50ffe8' d='M181.8 259.4c98.2 6 191.9 35.2 281.3 72.1c2.8 1.1 5.5 2.3 8.3 3.4c171 71.6 342.7 158.5 531.3 207.7c198.8 51.8 403.4 40.8 597.3-14.8V0H0v283.2C59 263.6 120.6 255.7 181.8 259.4z'/><path fill='#7dffe9' d='M1600 0H0v136.3c62.3-20.9 127.7-27.5 192.2-19.2c93.6 12.1 180.5 47.7 263.3 89.6c2.6 1.3 5.1 2.6 7.7 3.9c158.4 81.1 319.7 170.9 500.3 223.2c210.5 61 430.8 49 636.6-16.6V0z'/><path fill='#9effe9' d='M454.9 86.3C600.7 177 751.6 269.3 924.1 325c208.6 67.4 431.3 60.8 637.9-5.3c12.8-4.1 25.4-8.4 38.1-12.9V0H288.1c56 21.3 108.7 50.6 159.7 82C450.2 83.4 452.5 84.9 454.9 86.3z'/><path fill='#baffea' d='M1600 0H498c118.1 85.8 243.5 164.5 386.8 216.2c191.8 69.2 400 74.7 595 21.1c40.8-11.2 81.1-25.2 120.3-41.7V0z'/><path fill='#d2ffea' d='M1397.5 154.8c47.2-10.6 93.6-25.3 138.6-43.8c21.7-8.9 43-18.8 63.9-29.5V0H643.4c62.9 41.7 129.7 78.2 202.1 107.4C1020.4 178.1 1214.2 196.1 1397.5 154.8z'/><path fill='#e9ffeb' d='M1315.3 72.4c75.3-12.6 148.9-37.1 216.8-72.4h-723C966.8 71 1144.7 101 1315.3 72.4z'/></g></svg>
\ No newline at end of file
# The Organization Model
The Organization model extends from the base `Adldap\Models\Model` class and contains
no specific methods / attributes that are limited to it.
## Creation
```php
// Adldap\Models\Organization
$org = $provider->make()->organization([
'o' => 'Some Company',
]);
// Set the DN manually:
$org->setDn('o=Some Company,dc=test,dc=local,dc=com');
$org->save();
```
# Introduction
## What is Adldap2?
Adldap2 is a PHP LDAP package that allows you to:
1. Easily manage multiple LDAP connections at once
2. Perform authentication
3. Search your LDAP directory with a fluent and easy to use query builder
4. Create / Update / Delete LDAP entities with ease
5. And more
## History of Adldap2
Adldap2 was originally created as a fork of the original LDAP library [adLDAP](https://github.com/adldap/adLDAP) due to bugs, and it being completely abandoned.
Adldap2 contains absolutely no similarities to the original repository, and was built to be as easily accessible as possible, with great documentation, and easily understandable syntax.
Much of the API was constructed with Ruby's ActiveRecord and Laravel's Eloquent in mind, and to be an answer to the question:
> _Why can't we use LDAP like we use a database?_
## Why should you use Adldap2?
Working with LDAP in PHP can be a messy and confusing endeavor, especially when using multiple connections, creating and managing entities, performing moves, resetting passwords, and performing ACL modifications to user accounts.
Wrapper classes for LDAP are usually always created in PHP applications.
Adldap2 allows you to easily manage the above problems without reinventing the wheel for every project.
## Implementations
- [Laravel](https://github.com/Adldap2/Adldap2-Laravel)
## Quick Start
Install the package via `composer`:
```
composer require adldap2/adldap2
```
Use Adldap2:
```php
// Construct new Adldap instance.
$ad = new \Adldap\Adldap();
// Create a configuration array.
$config = [
// An array of your LDAP hosts. You can use either
// the host name or the IP address of your host.
'hosts' => ['ACME-DC01.corp.acme.org', '192.168.1.1'],
// The base distinguished name of your domain to perform searches upon.
'base_dn' => 'dc=corp,dc=acme,dc=org',
// The account to use for querying / modifying LDAP records. This
// does not need to be an admin account. This can also
// be a full distinguished name of the user account.
'username' => 'admin@corp.acme.org',
'password' => 'password',
];
// Add a connection provider to Adldap.
$ad->addProvider($config);
try {
// If a successful connection is made to your server, the provider will be returned.
$provider = $ad->connect();
// Performing a query.
$results = $provider->search()->where('cn', '=', 'John Doe')->get();
// Finding a record.
$user = $provider->search()->find('jdoe');
// Creating a new LDAP entry. You can pass in attributes into the make methods.
$user = $provider->make()->user([
'cn' => 'John Doe',
'title' => 'Accountant',
'description' => 'User Account',
]);
// Setting a model's attribute.
$user->cn = 'John Doe';
// Saving the changes to your LDAP server.
if ($user->save()) {
// User was saved!
}
} catch (\Adldap\Auth\BindException $e) {
// There was an issue binding / connecting to the server.
}
```
## Versioning
Adldap2 is versioned under the [Semantic Versioning](http://semver.org/) guidelines as much as possible.
Releases will be numbered with the following format:
`<major>.<minor>.<patch>`
And constructed with the following guidelines:
* Breaking backward compatibility bumps the major and resets the minor and patch.
* New additions without breaking backward compatibility bumps the minor and resets the patch.
* Bug fixes and misc changes bumps the patch.
Minor versions are not maintained individually, and you're encouraged to upgrade through to the next minor version.
Major versions are maintained individually through separate branches.
This diff is collapsed.
This diff is collapsed.
<?php
namespace Adldap\Auth\Events;
class Attempting extends Event
{
//
}
<?php
namespace Adldap\Auth\Events;
class Binding extends Event
{
//
}
<?php
namespace Adldap\Auth\Events;
class Bound extends Event
{
//
}
<?php
namespace Adldap\Auth\Events;
use Adldap\Connections\ConnectionInterface;
abstract class Event
{
/**
* The connection that the username and password is being bound on.
*
* @var ConnectionInterface
*/
protected $connection;
/**
* The username that is being used for binding.
*
* @var string
*/
protected $username;
/**
* The password that is being used for binding.
*
* @var string
*/
protected $password;
/**
* Constructor.
*
* @param ConnectionInterface $connection
* @param string $username
* @param string $password
*/
public function __construct(ConnectionInterface $connection, $username, $password)
{
$this->connection = $connection;
$this->username = $username;
$this->password = $password;
}
/**
* Returns the events connection.
*
* @return ConnectionInterface
*/
public function getConnection()
{
return $this->connection;
}
/**
* Returns the authentication events username.
*
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Returns the authentication events password.
*
* @return string
*/
public function getPassword()
{
return $this->password;
}
}
<?php
namespace Adldap\Auth\Events;
class Failed extends Event
{
//
}
<?php
namespace Adldap\Auth\Events;
class Passed extends Event
{
//
}
<?php
namespace Adldap\Configuration\Validators;
use Adldap\Configuration\ConfigurationException;
class ClassValidator extends Validator
{
/**
* Validates the configuration value.
*
* @throws ConfigurationException When the value given fails validation.
*
* @return bool
*/
public function validate()
{
if (!is_string($this->value) || !class_exists($this->value)) {
throw new ConfigurationException("Option {$this->key} must be a valid class.");
}
return true;
}
}
<?php
namespace Adldap\Connections;
class DetailedError
{
/**
* The error code from ldap_errno.
*
* @var int|null
*/
protected $errorCode;
/**
* The error message from ldap_error.
*
* @var string|null
*/
protected $errorMessage;
/**
* The diagnostic message when retrieved after an ldap_error.
*
* @var string|null
*/
protected $diagnosticMessage;
/**
* Constructor.
*
* @param int $errorCode
* @param string $errorMessage
* @param string $diagnosticMessage
*/
public function __construct($errorCode, $errorMessage, $diagnosticMessage)
{
$this->errorCode = $errorCode;
$this->errorMessage = $errorMessage;
$this->diagnosticMessage = $diagnosticMessage;
}
/**
* Returns the LDAP error code.
*
* @return int
*/
public function getErrorCode()
{
return $this->errorCode;
}
/**
* Returns the LDAP error message.
*
* @return string
*/
public function getErrorMessage()
{
return $this->errorMessage;
}
/**
* Returns the LDAP diagnostic message.
*
* @return string
*/
public function getDiagnosticMessage()
{
return $this->diagnosticMessage;
}
}
This diff is collapsed.
<?php
namespace Adldap\Events;
interface DispatcherInterface
{
/**
* Register an event listener with the dispatcher.
*
* @param string|array $events
* @param mixed $listener
*
* @return void
*/
public function listen($events, $listener);
/**
* Determine if a given event has listeners.
*
* @param string $eventName
*
* @return bool
*/
public function hasListeners($eventName);
/**
* Fire an event until the first non-null response is returned.
*
* @param string|object $event
* @param mixed $payload
*
* @return array|null
*/
public function until($event, $payload = []);
/**
* Fire an event and call the listeners.
*
* @param string|object $event
* @param mixed $payload
* @param bool $halt
*
* @return mixed
*/
public function fire($event, $payload = [], $halt = false);
/**
* Fire an event and call the listeners.
*
* @param string|object $event
* @param mixed $payload
* @param bool $halt
*
* @return array|null
*/
public function dispatch($event, $payload = [], $halt = false);
/**
* Get all of the listeners for a given event name.
*
* @param string $eventName
*
* @return array
*/
public function getListeners($eventName);
/**
* Remove a set of listeners from the dispatcher.
*
* @param string $event
*
* @return void
*/
public function forget($event);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
namespace Adldap\Models\Events;
class Created extends Event
{
//
}
<?php
namespace Adldap\Models\Events;
class Creating extends Event
{
//
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment