Adldap2 / Adldap2-Laravel

LDAP Authentication & Management for Laravel
MIT License
911 stars 184 forks source link

adldap2 integration with laravel 5.3 binding to Auth driver #190

Closed gitRpm closed 8 years ago

gitRpm commented 8 years ago

Ok, so there is some documentation on this, which I've followed (https://github.com/Adldap2/Adldap2-Laravel), but I cannot seem to get this working. I'm also using laravel 5.3 so I don't know if that has something to do with it. And please bear with me as I'm new to laravel.

I cannot authenticate using the Auth::attempt($creds) method.

I can, however authenticate with Adldap::user()->attempt($user,$pass)

I want to use the Auth facade so I can verify logins and such. If there is another way to do it without using Auth I'm all ears.

I also want to bind to the User model once that user has logged in, but I haven't gotten far enough to see if that works.

I've been working on this for a few days and I think it's time I reach out. Please help!

Here's what I'm working with...

adldap.php:

'auto_connect' => false,

adldap_auth.php:

'bind_user_to_model' => env('ADLDAP_BIND_USER_TO_MODEL', true)

auth.php:

'providers' => [
    'users' => [
        'driver' => 'adldap',
        'model' => App\Models\User::class,
    ],

    // 'users' => [
    //     'driver' => 'database',
    //     'table' => 'users',
    // ],
],

app.php:

'aliases' => [
    'Adldap' => Adldap\Laravel\Facades\Adldap::class,
]

'providers' => [

    Adldap\Laravel\AdldapServiceProvider::class,
]

controller:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

use App\Http\Requests;
use Illuminate\Support\Facades\Input;

class LoginController extends Controller
{
    public function login()
    {
        $input = Input::all();
        if(Auth::attempt([$input['username'],$input['password']])
        {
            return 'Authenticated';
        }
    }
}

User model: namespace App\Models;

use Adldap\Laravel\Traits\AdldapUserModelTrait;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;

class User extends Model implements AuthenticatableContract
{
    use Authenticatable, AdldapUserModelTrait;
    use Authenticatable, AdldapUserModelTrait;

}
stevebauman commented 8 years ago

Can you post your entire adldap_auth.php file?

gitRpm commented 8 years ago
<?php

return [
    /*
    |--------------------------------------------------------------------------
    | Connection
    |--------------------------------------------------------------------------
    |
    | The LDAP connection to use for laravel authentication.
    |
    | You must specify connections in your `config/adldap.php` configuration file.
    |
    | This must be a string.
    |
    */
    'connection' => env('ADLDAP_CONNECTION', 'default'),
    /*
    |--------------------------------------------------------------------------
    | Username Attribute
    |--------------------------------------------------------------------------
    |
    | The username attribute is an array of the html input name and the LDAP
    | attribute to discover the user by. The reason for this is to hide
    | the attribute that you're using to login users.
    |
    | For example, if your HTML input name is `email` and you'd like users to login
    | by their LDAP `mail` attribute, then keep the configuration below. However,
    | if you'd like to login users by their usernames, then change `mail`
    | to `samaccountname`. and `email` to `username`.
    |
    | This must be an array with a key - value pair.
    |
    */
    'username_attribute' => ['username' => 'samaccountname'],
    /*
    |--------------------------------------------------------------------------
    | Limitation Filter
    |--------------------------------------------------------------------------
    |
    | The limitation filter allows you to enter a raw filter to only allow
    | specific users / groups / ous to authenticate.
    |
    | For an example, to only allow users inside of a group
    | named 'Accounting', you would insert the Accounting
    | groups full distinguished name inside the filter:
    |
    | '(memberof=cn=Accounting,dc=corp,dc=acme,dc=org)'
    |
    | This value must be a standard LDAP filter.
    |
    */
    'limitation_filter' => env('ADLDAP_LIMITATION_FILTER', ''),
    /*
    |--------------------------------------------------------------------------
    | Login Fallback
    |--------------------------------------------------------------------------
    |
    | The login fallback option allows you to login as a user located on the
    | local database if active directory authentication fails.
    |
    | Set this to true if you would like to enable it.
    |
    | This option must be true or false.
    |
    */
    'login_fallback' => env('ADLDAP_LOGIN_FALLBACK', false),
    /*
    |--------------------------------------------------------------------------
    | Password Key
    |--------------------------------------------------------------------------
    |
    | The password key is the name of the input array key located inside
    | the user input array given to the auth driver.
    |
    | Change this if you change your password fields input name.
    |
    | This option must be a string.
    |
    */
    'password_key' => env('ADLDAP_PASSWORD_KEY', 'password'),
    /*
    |--------------------------------------------------------------------------
    | Password Sync
    |--------------------------------------------------------------------------
    |
    | The password sync option allows you to automatically synchronize
    | users AD passwords to your local database. These passwords are
    | hashed natively by laravel using the bcrypt() method.
    |
    | Enabling this option would also allow users to login to their
    | accounts using the password last used when an AD connection
    | was present.
    |
    | If this option is disabled, the local user account is applied
    | a random 16 character hashed password, and will lose access
    | to this account upon loss of AD connectivity.
    |
    | This option must be true or false.
    |
    */
    'password_sync' => env('ADLDAP_PASSWORD_SYNC', true),
    /*
    |--------------------------------------------------------------------------
    | Login Attribute
    |--------------------------------------------------------------------------
    |
    | The login attribute is the name of the active directory user property
    | that you use to log users in. For example, if your company uses
    | email, then insert `mail`.
    |
    | This option must be a string.
    |
    */
    'login_attribute' => env('ADLDAP_LOGIN_ATTRIBUTE', 'samaccountname'),
    /*
    |--------------------------------------------------------------------------
    | Windows Auth Attribute
    |--------------------------------------------------------------------------
    |
    | This array represents how a user is found when
    | utilizing the Adldap Windows Auth Middleware.
    |
    | The key of the array represents the attribute that the user is located by.
    |
    |     For example, if 'samaccountname' is the key, then your LDAP server is
    |     queried for a user with the 'samaccountname' equal to the
    |     $_SERVER['AUTH_USER'] variable.
    |
    |     If a user is found, they are imported into your
    |     local database, then logged in.
    |
    | The value of the array represents the 'key' of the $_SERVER
    | array to pull the users username from.
    |
    |    For example, $_SERVER['AUTH_USER'].
    |
    | This must be an array with a key - value pair.
    |
    */
    'windows_auth_attribute' => ['samaccountname' => 'AUTH_USER'],
    /*
    |--------------------------------------------------------------------------
    | Bind User to Model
    |--------------------------------------------------------------------------
    |
    | The 'bind user to model' option allows you to access the authenticated
    | Adldap user model instance on your laravel User model.
    |
    | If this option is true, you must insert the trait:
    |
    |   `Adldap\Laravel\Traits\AdldapUserModelTrait`
    |
    | Onto your User model that is configured in `config/auth.php`.
    |
    | Then use `Auth::user()->adldapUser` to access.
    |
    | This option must be true or false.
    |
    */
    'bind_user_to_model' => env('ADLDAP_BIND_USER_TO_MODEL', true),
    /*
    |--------------------------------------------------------------------------
    | Sync Attributes
    |--------------------------------------------------------------------------
    |
    | Attributes specified here will be added / replaced on the user model
    | upon login, automatically synchronizing and keeping the attributes
    | up to date.
    |
    | The array key represents the Laravel model key, and the value
    | represents the Active Directory attribute to set it to.
    |
    | Your login attribute (configured above) is already synchronized
    | and does not need to be added to this array.
    |
    */
    'sync_attributes' => [
        'name' => 'cn',
    ],
    /*
    |--------------------------------------------------------------------------
    | Select Attributes
    |--------------------------------------------------------------------------
    |
    | Attributes to select upon the user on authentication and binding.
    |
    | If no attributes are given inside the array, all attributes on the
    | user are selected.
    |
    | This is configurable to allow for faster LDAP queries, rather
    | than retrieving all attributes on every login.
    |
    | ** Note ** : Keep in mind you must include attributes that you would
    | like to synchronize, as well as your login attribute.
    |
    */
    'select_attributes' => [
        //
    ],
];
stevebauman commented 8 years ago

Oh hang on, you're not passing in a correct key=>value array to the Auth::attempt() method here:

if (Auth::attempt([$input['username'], $input['password']])

Switch this to:

if (Auth::attempt(request()->only('username', 'password')) {
    //
}
gitRpm commented 8 years ago

That did not fix it:

if(Auth::attempt(request()->all()))
{
   var_dump(Auth::check());
}

dd(Auth::user());

returns null - as a result of the dd(Auth::user());

stevebauman commented 8 years ago

Try running the command php artisan adldap:import {username} - without brackets, and see if the user you're trying to authenticate to is successfully imported.

gitRpm commented 8 years ago

[Adldap\Exceptions\ModelNotFoundException] No LDAP query results for filter: [(&(objectclass=person)(objectcategory=pe rson)(anr=rmorris))] in: [dc=corp,dc=acme,dc=org]

stevebauman commented 8 years ago

Looks like you haven't changed your base_dn configuration option in config/adldap.php. This needs to equal your base_dn in your server.

gitRpm commented 8 years ago

I changed it, but I'm still not getting any results. Same message, just a different base_dn

stevebauman commented 8 years ago

Are you absolutely sure it's the correct base DN of your domain? Just need to verify before we move on.

gitRpm commented 8 years ago

Yes, we have another app that uses an old adlap plugin and I'm using the same settings from that.

stevebauman commented 8 years ago

Ok, can you posts your adldap.php configuration file (with your credentials and other confidential information omitted)?

gitRpm commented 8 years ago
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | 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, anytime Adldap is instantiated it will automatically
            | connect to your AD server. If this is set to false, you must connect manually
            | using: Adldap::connect().
            |
            */

            'auto_connect' => false,

            /*
            |--------------------------------------------------------------------------
            | Connection
            |--------------------------------------------------------------------------
            |
            | The connection class to use to run operations on.
            |
            | You can also set this option to `null` to use the default connection class.
            |
            | Custom connection classes must implement \Adldap\Contracts\Connections\ConnectionInterface
            |
            */

            'connection' => Adldap\Connections\Ldap::class,

            /*
            |--------------------------------------------------------------------------
            | 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.
            |
            | Custom schema classes must implement \Adldap\Contracts\Schemas\SchemaInterface
            |
            */

            'schema' => Adldap\Schemas\ActiveDirectory::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.
            |
            */

            'connection_settings' => [

                /*
                |--------------------------------------------------------------------------
                | Account Prefix
                |--------------------------------------------------------------------------
                |
                | The account prefix option is the prefix of your user accounts in AD.
                |
                | For example, if you'd prefer your users to use only their username instead
                | of specifying a domain ('ACME\jdoe'), enter your domain name.
                |
                */

                'account_prefix' => '',

                /*
                |--------------------------------------------------------------------------
                | Account Suffix
                |--------------------------------------------------------------------------
                |
                | The account suffix option is the suffix of your user accounts in AD.
                |
                | For example, if your domain DN is DC=corp,DC=acme,DC=org, then your
                | account suffix would be @corp.acme.org. This is then appended to
                | then end of your user accounts on authentication.
                |
                */

                '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.
                |
                */

                'domain_controllers' => [],

                /*
                |--------------------------------------------------------------------------
                | Port
                |--------------------------------------------------------------------------
                |
                | The port option is used for authenticating and binding to your AD server.
                |
                */

                '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' => 5,

                /*
                |--------------------------------------------------------------------------
                | Base Distinguished Name
                |--------------------------------------------------------------------------
                |
                | The base distinguished name is the base distinguished name you'd like
                | to perform operations on. An example base DN would be DC=corp,DC=acme,DC=org.
                |
                | If one is not defined, then Adldap will try to find it automatically
                | by querying your server. It's recommended to include it to
                | limit queries executed per request.
                |
                */

                'base_dn' => '',

                /*
                |--------------------------------------------------------------------------
                | Administrator Account Suffix
                |--------------------------------------------------------------------------
                |
                | This option allows you to set a different account suffix for your
                | configured administrator account upon binding.
                |
                | If left empty, your `account_suffix` option will be used.
                |
                */

                //'admin_account_suffix' => '@acme.org',

                /*
                |--------------------------------------------------------------------------
                | Administrator Username & Password
                |--------------------------------------------------------------------------
                |
                | When connecting to your AD 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.
                |
                */

                'admin_username' => env('ADLDAP_ADMIN_USERNAME'),
                'admin_password' => env('ADLDAP_ADMIN_PASSWORD'),

                /*
                |--------------------------------------------------------------------------
                | 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' => false,
                'use_tls' => false,

            ],

        ],

    ],

];
gitRpm commented 8 years ago

I was able to perform Adlap::search()->all() after authenticating and it returned results. Just an fyi...

gitRpm commented 8 years ago

One more thing... what should my User class look like?

I don't want a users table as everything will be managed through adldap.

stevebauman commented 8 years ago

If you're still not receiving any results from the adldap:import command, you're either searching for a user that doesn't exist, or your configuration is wrong (the base_dn would be the culprit in this situtation).

One more thing... what should my User class look like?

I don't want a users table as everything will be managed through adldap.

Unfortunately your users table is a requirement. This is the whole purpose of the Adldap auth driver. It creates an AD user a local account so you can attach data to them as you would a regular user.

Can you post your users migration file as well as your User model?

gitRpm commented 8 years ago

User model:

<?php

    namespace App\Models;

    use Adldap\Laravel\Traits\AdldapUserModelTrait;
    use Illuminate\Auth\Authenticatable;
    use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
    use Illuminate\Database\Eloquent\Model;

    class User extends Model implements AuthenticatableContract
    {
        use Authenticatable, AdldapUserModelTrait;

        protected $table = 'users';

        /**
         * The attributes that are mass assignable.
         *
         * @var array
         */
        protected $fillable = ['name', 'email', 'password', 'logon_name'];

        /**
         * The attributes excluded from the model's JSON form.
         *
         * @var array
         */
        protected $hidden = ['password', 'remember_token'];

        protected $connection = 'auth';

        public $timestamps = false;

    }

I'm not using migrations so here is the table so far:

create table dbo.Users (
    username varchar(30) not null,
    password varchar(60) not null,
    email varchar(50)
)
gitRpm commented 8 years ago

Going to use the Adldap2 base instead... closing this.

stevebauman commented 8 years ago

You don't need to utilize the Adldap2 base instead of the laravel version. The Adldap2 base is installed automatically with Adldap2-Laravel. You can access it through the facade:

if (Adldap::auth()->attempt('username', 'password')) {
    //
}
itguy614 commented 8 years ago

This has me stumped. Auth::attempt([...]) returns false however Adldap::auth()->attempt(...) returns true...

itguy614 commented 8 years ago

I should add that I also have the user imported into my user model...

itguy614 commented 8 years ago

Figured out... in my cast the LoginAttribute was set to samaccountname instead of mail.

stevebauman commented 8 years ago

Thanks for following up @itguy614.

Configuration is usually always the issue when you just get an Auth::attempt() failure with the Adldap driver.