Adldap2 / Adldap2-Laravel

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

These credentials do not match our records - No Log Trace #551

Closed petay87 closed 6 years ago

petay87 commented 6 years ago

Description:

I have implemented Adldap2-Laravel and configured the Auth Driver to enable login validation via ActiveDirectory LDAP but also keep users in the local DB so that I can implement Permissions and Roles with laravel-permission.

So far, as far as I can tell, everything is working but I'm not sure if the user LDAP validation is actually happening.

If I intentionally put in incorrect details in the config files, I can see that the laravel.log files populates with information do to with the error I forced (In my case, incorrect admin credentials) and I can see clear as day that the issue is invalid credentials.

However, as soon as I remove this issue and put all settings back to "LIVE", I am unable to log in with an active account and all I get in return is "These credentials do not match our records". If I check the laravel.log file, nothing is populated at all.

Am I correct in assuming that the logging is automatically configured? Or should I be enabling this somehow?

It almost appears as though the validation of the user attempting to log in via the webpage is not taking place.

I have attempted to use "username" as the field to check again LDAP for.

_EDIT -_ When added a dd($credentials) in the NoDatabaseUserProvider.php under retrieveByCredentials() I can see the correct credentials being passed which are inputted in the login page. However, a dd($user) later, returns null which would indicate that the search is not able to find the user in LDAP.

When I attempt to do the same for DatabaseUserProvider.php I don't get that far and the dd doesn't trigger which means I must have an issue with looking for the user in the local database. However, this doesn't explain why it doesn't find the user in LDAP when we disable the local database.

My adlap_auth.php file:

`<?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'),

/*
|--------------------------------------------------------------------------
| Provider
|--------------------------------------------------------------------------
|
| The LDAP authentication provider to use depending
| if you require database synchronization.
|
| For synchronizing LDAP users to your local applications database, use the provider:
|
| Adldap\Laravel\Auth\DatabaseUserProvider::class
|
| Otherwise, if you just require LDAP authentication, use the provider:
|
| Adldap\Laravel\Auth\NoDatabaseUserProvider::class
|
*/

'provider' => Adldap\Laravel\Auth\DatabaseUserProvider::class,

/*
|--------------------------------------------------------------------------
| Rules
|--------------------------------------------------------------------------
|
| Rules allow you to control user authentication requests depending on scenarios.
|
| You can create your own rules and insert them here.
|
| All rules must extend from the following class:
|
|   Adldap\Laravel\Validation\Rules\Rule
|
*/

'rules' => [

    // Denys deleted users from authenticating.

    Adldap\Laravel\Validation\Rules\DenyTrashed::class,

    // Allows only manually imported users to authenticate.

    // Adldap\Laravel\Validation\Rules\OnlyImported::class,

],

/*
|--------------------------------------------------------------------------
| Scopes
|--------------------------------------------------------------------------
|
| Scopes allow you to restrict the LDAP query that locates
| users upon import and authentication.
|
| All scopes must implement the following interface:
|
|   Adldap\Laravel\Scopes\ScopeInterface
|
*/

'scopes' => [

    // Only allows users with a user principal name to authenticate.
    // Remove this if you're using OpenLDAP.
    Adldap\Laravel\Scopes\UpnScope::class,

    // Only allows users with a uid to authenticate.
    // Uncomment if you're using OpenLDAP.
    // Adldap\Laravel\Scopes\UidScope::class,

],

'usernames' => [

    /*
    |--------------------------------------------------------------------------
    | LDAP
    |--------------------------------------------------------------------------
    |
    | Discover:
    |
    |   The discover value is the users attribute you would
    |   like to locate LDAP users by in your directory.
    |
    |   For example, using the default configuration below, if you're
    |   authenticating users with an email address, your LDAP server
    |   will be queried for a user with the a `userprincipalname`
    |   equal to the entered email address.
    |
    | Authenticate:
    |
    |   The authenticate value is the users attribute you would
    |   like to use to bind to your LDAP server.
    |
    |   For example, when a user is located by the above 'discover'
    |   attribute, the users attribute you specify below will
    |   be used as the username to bind to your LDAP server.
    |
    */

    'ldap' => [

        'discover' => 'samaccountname',

        'authenticate' => 'distinguishedname',

    ],

    /*
    |--------------------------------------------------------------------------
    | Eloquent
    |--------------------------------------------------------------------------
    |
    | The value you enter is the database column name used for locating
    | the local database record of the authenticating user.
    |
    | If you're using a `username` column instead, change this to `username`.
    |
    | This option is only applicable to the DatabaseUserProvider.
    |
    */

    'eloquent' => 'username',

    /*
    |--------------------------------------------------------------------------
    | Windows Authentication Middleware (SSO)
    |--------------------------------------------------------------------------
    |
    | Discover:
    |
    |   The 'discover' value is the users attribute you would
    |   like to locate LDAP users by in your directory.
    |
    |   For example, if 'samaccountname' is the value, then your LDAP server is
    |   queried for a user with the 'samaccountname' equal to the value of
    |   $_SERVER['AUTH_USER'].
    |
    |   If a user is found, they are imported (if using the DatabaseUserProvider)
    |   into your local database, then logged in.
    |
    | Key:
    |
    |    The 'key' value represents the 'key' of the $_SERVER
    |    array to pull the users account name from.
    |
    |    For example, $_SERVER['AUTH_USER'].
    |
    */

    'windows' => [

        'discover' => 'samaccountname',

        'key' => 'AUTH_USER',

    ],

],

'passwords' => [

    /*
    |--------------------------------------------------------------------------
    | Password Sync
    |--------------------------------------------------------------------------
    |
    | The password sync option allows you to automatically synchronize users
    | LDAP 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 LDAP connection was present.
    |
    | If this option is disabled, the local database account is applied a
    | random 16 character hashed password upon every login, and will
    | lose access to this account upon loss of LDAP connectivity.
    |
    | This option must be true or false and is only applicable
    | to the DatabaseUserProvider.
    |
    */

    'sync' => env('ADLDAP_PASSWORD_SYNC', false),

    /*
    |--------------------------------------------------------------------------
    | Column
    |--------------------------------------------------------------------------
    |
    | This is the column of your users database table
    | that is used to store passwords.
    |
    | Set this to `null` if you do not have a password column.
    |
    | This option is only applicable to the DatabaseUserProvider.
    |
    */

    'column' => 'password',

],

/*
|--------------------------------------------------------------------------
| 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 and is only
| applicable to the DatabaseUserProvider.
|
*/

'login_fallback' => env('ADLDAP_LOGIN_FALLBACK', false),

/*
|--------------------------------------------------------------------------
| 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 users Laravel model key, and
| the value represents the users LDAP attribute.
|
| This option must be an array and is only applicable
| to the DatabaseUserProvider.
|
*/

'sync_attributes' => [

    'username' => 'samaccountname',

    'name' => 'cn',

],

/*
|--------------------------------------------------------------------------
| Logging
|--------------------------------------------------------------------------
|
| User authentication attempts will be logged using Laravel's
| default logger if this setting is enabled.
|
| No credentials are logged, only usernames.
|
| This is usually stored in the '/storage/logs' directory
| in the root of your application.
|
| This option is useful for debugging as well as auditing.
|
| You can freely remove any events you would not like to log below,
| as well as use your own listeners if you would prefer.
|
*/

'logging' => [

    'enabled' => true,

    'events' => [

        \Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class,
        \Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class,
        \Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class,
        \Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class,
        \Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class,
        \Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class,
        \Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class,
        \Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class,
        \Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class,
        \Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class,
        \Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class,

    ],
],

]; `

My adldap.php file:

`<?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, 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.
        |
        */

        'auto_connect' => env('ADLDAP_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,

        /*
        |--------------------------------------------------------------------------
        | 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,

        /*
        |--------------------------------------------------------------------------
        | 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 LDAP directory.
            |
            | This string is prepended to authenticating users usernames.
            |
            */

            'account_prefix' => env('ADLDAP_ACCOUNT_PREFIX', ''),

            /*
            |--------------------------------------------------------------------------
            | Account Suffix
            |--------------------------------------------------------------------------
            |
            | The account suffix option is the suffix of your user accounts in your LDAP directory.
            |
            | This string is appended to authenticating users usernames.
            |
            */

            'account_suffix' => env('ADLDAP_ACCOUNT_SUFFIX', '@domain.internal'),

            /*
            |--------------------------------------------------------------------------
            | 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' => explode(' ', env('ADLDAP_CONTROLLERS', 'SERVER_IP_ADDRESS')),

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

            'port' => env('ADLDAP_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('ADLDAP_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('ADLDAP_BASEDN', 'dc=Users,dc=Resources,dc=domain,dc=internal'),

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

            'admin_account_prefix' => env('ADLDAP_ADMIN_ACCOUNT_PREFIX', ''),
            'admin_account_suffix' => env('ADLDAP_ADMIN_ACCOUNT_SUFFIX', '@domain.internal'),

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

            'admin_username' => env('ADLDAP_ADMIN_USERNAME', 'username'),
            'admin_password' => env('ADLDAP_ADMIN_PASSWORD', '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' => env('ADLDAP_USE_SSL', false),
            'use_tls' => env('ADLDAP_USE_TLS', false),

        ],

    ],

],

]; `

My auth.php file:

`<?php

return [

/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/

'defaults' => [
    'guard' => 'web',
    'passwords' => 'users',
],

/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'token',
        'provider' => 'users',
    ],
],

/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/

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

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

/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/

'passwords' => [
    'users' => [
        'provider' => 'users',
        'table' => 'password_resets',
        'expire' => 60,
    ],
],

]; `

My User.php model:

`<?php

namespace App;

use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable { use Notifiable; use HasRoles;

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

/**
 * The attributes that should be hidden for arrays.
 *
 * @var array
 */
protected $hidden = [
    'password', 'remember_token',
];

} `

My LoginController.php controller file:

`<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller { /* -------------------------------------------------------------------------- Login Controller
This controller handles authenticating users for the application and
redirecting them to your home screen. The controller uses a trait
to conveniently provide its functionality to your applications.
*/

use AuthenticatesUsers;

/**
 * Where to redirect users after login.
 *
 * @var string
 */
protected $redirectTo = '/home';

/**
 * Create a new controller instance.
 *
 * @return void
 */
public function __construct()
{
    $this->middleware('guest')->except('logout');
}

public function username()
{
  return 'username';
}

} `

I feel like I must be missing something.

Some assistance in getting this working would be greatly appreciated.

petay87 commented 6 years ago

This was me being stupid and putting the OU containers as DC and appending the domain name to the user to be authenticated when using distinguishedName

stevebauman commented 6 years ago

Thanks for posting your solution @petay87! Much appreciated :smile: