Adldap2 / Adldap2-Laravel

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

Can't login on server but can locally with same config #300

Closed 2Foot closed 7 years ago

2Foot commented 7 years ago

Description:

I have ADLDAP working on my local dev environment and talking to my AD server just fine. When I try to login from my site on my dev server however it fails with: "BindException in Guard.php line 80: Can't contact LDAP server". I can successfully ping from the dev server to the AD server just fine. I can also run "php artisan adldap:import" from the dev server and it will import all the users. Any ideas?

stevebauman commented 7 years ago

Hi @2Foot,

That exception will only appear if your admin_username and admin_password is incorrect. Check your configuration (config/adldap.php) file.

EDIT: Apologies, misread the exception.

This sounds like a basic connectivity issue. Are you sure you server IP addresses / host names are correct in your configuration?

2Foot commented 7 years ago

Definitely. I've git pushed all my code to the dev server and verified that it worked. The config files are identical, my local machine and the dev server are on the same network and trying to contact the same AD server. I cleared my config cache in laravel just in case as well. The part baffling me is that it successfully imports all the users into the dev server DB, it just won't login via the web login...

stevebauman commented 7 years ago

Strange... Can you try locating a user during an auth login request to see if there's something going on with how you've configured the auth driver?

$user = Adldap::search()->users()->first();

dd($user);
2Foot commented 7 years ago

Steve,

Sorry for the long delay... long weekend.

I did as you suggested by putting the code you gave me into the login function of the AuthenticatesUsers.php. When I dump it out I DO NOT get valid data for a user. So now I'me even more confused. Lol.

So yeah, that still fails. Again, using that code from my local dev environment works and shows valid data - just tested it to make sure. Using that same code to dump out on the login fails on my dev server however with the same message... "BindException in Guard.php line 80: Can't contact LDAP server". Ideas?

PS. Talking to my network guy as well over here. The dev server is on the same subnet as my workstation so no firewall touches the login request. I can ping the AD server when ssh'd into the dev server. The real kicker though is that I can import from the command line when I ssh into the dev server and that works fine as well. That last part really baffles me.

Craig

2Foot commented 7 years ago

Steve,

Still having this issue. Just wondering if it has something to do with the following scenario:

My local development system is a Windows based workstation running WAMP. My dev server is a Linux based server. They both run very similar versions of PHP, MySQL, etc. I am wondering however if the fact that I am signed in already to the domain on my Windows workstation has any bearing on whether or not the authentication process is working locally (but not when trying to log into the site hosted on the Linux server)?

My databases for both the local and development environments have the same user names and passwords, everything is configured very similarly between the two environments. I have verified those credentials all work etc as well. As I've said, the console based import for the DB works fine on the Linux server environment when I am ssh'd into the system. It just won't authenticate from the site when I try to sign in from there.

stevebauman commented 7 years ago

Are you using SSL or TLS to connect to your LDAP server?

2Foot commented 7 years ago

No. Both are set to false. Here is my adldap config file:

'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 using: Adldap::connect();
        |
        */

        'auto_connect' => true,

        /*
        |--------------------------------------------------------------------------
        | Connection
        |--------------------------------------------------------------------------
        |
        | The connection class to use to run raw LDAP operations on.
        |
        | 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' => '',//env('ADLDAP_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' => env('ADLDAP_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' => explode(' ', env('ADLDAP_CONTROLLERS', '###.###.###.### ###.###.###.###')),

            /*
            |--------------------------------------------------------------------------
            | Port
            |--------------------------------------------------------------------------
            |
            | The port option is used for authenticating and binding to your AD 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', 'ou=######,dc=######,dc=####'),

            /*
            |--------------------------------------------------------------------------
            | 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' => env('ADLDAP_ADMIN_ACCOUNT_SUFFIX', '##########'),

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

        ],

    ],

],

And here is my adldap_auth.php file:

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

/*
|--------------------------------------------------------------------------
| Resolver
|--------------------------------------------------------------------------
|
| The resolver that locates users from your LDAP server.
|
| Custom resolvers must implement the following interface:
|
|   Adldap\Laravel\Auth\ResolverInterface
|
*/

'resolver' => Adldap\Laravel\Auth\Resolver::class,

/*
|--------------------------------------------------------------------------
| Importer
|--------------------------------------------------------------------------
|
| The importer that imports LDAP users into your local database.
|
| Custom importers must implement the following interface:
|
|   Adldap\Laravel\Auth\ImporterInterface
|
*/

'importer' => Adldap\Laravel\Auth\Importer::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.

    Adldap\Laravel\Scopes\UpnScope::class,

],

'usernames' => [

    /*
    |--------------------------------------------------------------------------
    | LDAP
    |--------------------------------------------------------------------------
    |
    | This is the LDAP users attribute that you use to authenticate
    | against your LDAP server. This is usually the users
    |'sAMAccountName' / 'userprincipalname' attribute.
    |
    | If you'd like to use their username to login instead, insert `samaccountname`.
    |
    */

    'ldap' => 'samaccountname',//userprincipalname

    /*
    |--------------------------------------------------------------------------
    | Eloquent
    |--------------------------------------------------------------------------
    |
    | This is the attribute that is used for locating
    | and storing the LDAP username above.
    |
    | If you're using a `username` field instead, change this to `username`.
    |
    | This option is only applicable to the DatabaseUserProvider.
    |
    */

    'eloquent' => 'username',

],

/*
|--------------------------------------------------------------------------
| 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', true),

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

'password_sync' => env('ADLDAP_PASSWORD_SYNC', true),

/*
|--------------------------------------------------------------------------
| 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 value of
|     $_SERVER['AUTH_USER'].
|
|     If a user is found, they are imported (if using the DatabaseUserProvider)
|     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' => 'PHP_AUTH_USER'],//'AUTH_USER'

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

'sync_attributes' => [

    'username' => 'samaccountname',//userprincipalname
    'name' => 'cn',

],
stevebauman commented 7 years ago

Hmmm, this is bizarre. I've experienced this with TLS / SSL connections, but not with regular connections. Your configuration looks fine as well.

I'm not sure to be honest, there's a lot of variables here. Unfortunately it's just a basic connectivity exception, I don't think PHP is lying to you here.

Are you able to ping / access the LDAP server from your ubuntu dev server? I'd take PHP out of the question and use a completely different tool to make sure you can absolutely contact your server.

2Foot commented 7 years ago

When I ssh into the dev server I can ping the AD server fine. While logged into the dev server through ssh I can also run the "php artisan adldap:import" and it works! So it can definitely talk to the AD server. It just can't talk to it web I try to sign in using the web page.

The AD server is also ok as I can do all tasks fine when logging in from my WAMP setup on my local workstation.

So as a quick summary:

Local development workstation to the AD server: "php artisan adldap:import" - Works Logging into website - Works

Linux web server to AD server: "php artisan adldap:import" - Works Logging into website - FAILS with "BindException in Guard.php line 80: Can't contact LDAP server"

It's so strange.

stevebauman commented 7 years ago

Ok, hmm... Can you post the stack trace on the dev server with your sensitive details omitted?

2Foot commented 7 years ago

Hi Steven,

Before I include the stack trace I also realized that I did not mention that my server OS is CentOS and not a windows based server. Are there additional requirements to get this to run from a Linux server that perhaps are already present in my local windows development setup?

stevebauman commented 7 years ago

Unfortunately I'm not sure. I've never installed a production laravel application using Adldap2 running under Linux.

All the servers I deploy on are Windows.

2Foot commented 7 years ago

Alright. Let me get back to you then. I will try a couple of ideas over here to see if I can get it to work. If I can I will provide the solution here.

2Foot commented 7 years ago

The strange part is that if I ssh into the server and run the adldap:import command it works. It imports all the users into the DB. So why can't it reach the LDAP server when trying to login via the webpage? Does this hint to anything you can think of in your code? While I am trying different things, here is my stack trace in case it helps:

BindException in Guard.php line 80:
Can't contact LDAP server
in Guard.php line 80
at Guard->bind('#####@######.#####', '#########', '', '@######.#####') in Guard.php line 93
at Guard->bindAsAdministrator() in Provider.php line 210
at Provider->connect() in AdldapServiceProvider.php line 95
at AdldapServiceProvider->Adldap\Laravel\{closure}(array('auto_connect' => true, 'connection' => 'Adldap\\Connections\\Ldap', 'schema' => 'Adldap\\Schemas\\ActiveDirectory', 'connection_settings' => array('account_suffix' => '@######.#####', 'domain_controllers' => array('###.###.###.###', '###.###.###.###'), 'port' => 389, 'timeout' => 5, 'base_dn' => 'ou=XXXXXXXX,dc=XXXXXX,dc=XXXXX', 'admin_account_suffix' => '@######.#####', 'admin_username' => 'XXXXXX', 'admin_password' => 'XXXXXX', 'follow_referrals' => false, 'use_ssl' => false, 'use_tls' => false)), 'default') in Collection.php line 260
at Collection->each(object(Closure)) in AdldapServiceProvider.php line 100
at AdldapServiceProvider->addProviders(object(Adldap), array('default' => array('auto_connect' => true, 'connection' => 'Adldap\\Connections\\Ldap', 'schema' => 'Adldap\\Schemas\\ActiveDirectory', 'connection_settings' => array('account_suffix' => '@######.#####', 'domain_controllers' => array('###.###.###.###', '###.###.###.###'), 'port' => 389, 'timeout' => 5, 'base_dn' => 'ou=XXXXXXXX,dc=XXXXXXXX,dc=XXXXXXXX', 'admin_account_suffix' => '@######.#####', 'admin_username' => 'XXXXXXXX', 'admin_password' => 'XXXXXXXX', 'follow_referrals' => false, 'use_ssl' => false, 'use_tls' => false)))) in AdldapServiceProvider.php line 54
at AdldapServiceProvider->Adldap\Laravel\{closure}(object(Application), array()) in Container.php line 716
at Container->build(object(Closure)) in Container.php line 598
at Container->resolve('adldap') in Container.php line 567
at Container->make('adldap') in Application.php line 708
at Application->make('adldap') in Container.php line 1139
at Container->offsetGet('adldap') in Facade.php line 159
at Facade::resolveFacadeInstance('adldap') in Facade.php line 128
at Facade::getFacadeRoot() in Facade.php line 215
at Facade::__callStatic('getProvider', array('default')) in UsesAdldap.php line 85
at Provider->getLdapProvider() in UsesAdldap.php line 59
at Provider->getResolver() in DatabaseUserProvider.php line 105
at DatabaseUserProvider->retrieveByCredentials(array('username' => 'XXXXXXXX', 'password' => 'XXXXXXXX')) in SessionGuard.php line 351
at SessionGuard->attempt(array('username' => 'XXXXXXXX', 'password' => 'XXXXXXXX'), false) in AuthenticatesUsers.php line 76
at LoginController->attemptLogin(object(Request)) in AuthenticatesUsers.php line 41
at LoginController->login(object(Request))
at call_user_func_array(array(object(LoginController), 'login'), array(object(Request))) in Controller.php line 55
at Controller->callAction('login', array(object(Request))) in ControllerDispatcher.php line 44
at ControllerDispatcher->dispatch(object(Route), object(LoginController), 'login') in Route.php line 203
at Route->runController() in Route.php line 160
at Route->run() in Router.php line 559
at Router->Illuminate\Routing\{closure}(object(Request)) in Pipeline.php line 30
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in RedirectIfAuthenticated.php line 24
at RedirectIfAuthenticated->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in SubstituteBindings.php line 41
at SubstituteBindings->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in VerifyCsrfToken.php line 65
at VerifyCsrfToken->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in ShareErrorsFromSession.php line 49
at ShareErrorsFromSession->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in StartSession.php line 64
at StartSession->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in AddQueuedCookiesToResponse.php line 37
at AddQueuedCookiesToResponse->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in EncryptCookies.php line 59
at EncryptCookies->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in Router.php line 561
at Router->runRouteWithinStack(object(Route), object(Request)) in Router.php line 520
at Router->dispatchToRoute(object(Request)) in Router.php line 498
at Router->dispatch(object(Request)) in Kernel.php line 174
at Kernel->Illuminate\Foundation\Http\{closure}(object(Request)) in Pipeline.php line 30
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in TransformsRequest.php line 30
at TransformsRequest->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in TransformsRequest.php line 30
at TransformsRequest->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in ValidatePostSize.php line 27
at ValidatePostSize->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in CheckForMaintenanceMode.php line 46
at CheckForMaintenanceMode->handle(object(Request), object(Closure)) in Pipeline.php line 148
at Pipeline->Illuminate\Pipeline\{closure}(object(Request)) in Pipeline.php line 53
at Pipeline->Illuminate\Routing\{closure}(object(Request)) in Pipeline.php line 102
at Pipeline->then(object(Closure)) in Kernel.php line 149
at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 116
at Kernel->handle(object(Request)) in index.php line 53
stevebauman commented 7 years ago

Hmm, everything looks fine in the stack trace, it's literally just giving a generic connection error when trying to connect to your server as your configured administrator account... Bizarre...

Since you can import users on the production server, this makes it even more strange...

Are you able to run php artisan tinker commands on your server? If so, we can begin troubleshooting there.

If you can run php artisan tinker, try resolving Adldap out of the container and see if it throws the same exception:

php artisan tinker

> app('adldap');

This should fail, according to your stack trace above.

2Foot commented 7 years ago

Admittedly I don't utilize tinker normally. I know it's purpose but rarely have ever needed it for anything. This is the result of the tinker command if it helps...

app('adldap'); => Adldap\Adldap {#766}

stevebauman commented 7 years ago

That's fine, we can begin troubleshooting here.

Okay, since it's resolving normally, try:

$ldap = app('adldap');

$ldap->auth()->bindAsAdministrator();

See if that returns true.

2Foot commented 7 years ago

$ldap = app('adldap'); => Adldap\Adldap {#764} $ldap->auth()->bindAsAdministrator(); => null

stevebauman commented 7 years ago

Okay, so that works as well.

Now try:

Auth::attempt(['username' => 'yourusername', 'password' => 'mypassword']);

Replace the credentials above with valid ones.

2Foot commented 7 years ago

it returned false

2Foot commented 7 years ago

Sorry, had a typo. It returned true.

2Foot commented 7 years ago

Auth::attempt(['username' => 'XXXXXX', 'password' => 'XXXXXXXX']); PHP warning: unlink(/var/www/html/deathreg/storage/framework/sessions/K1Lwei8naxbmn2yksidhg3923e0olAh2hajSclOp): No such file or directory in /var/www/html/deathreg/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php on line 172 => true

stevebauman commented 7 years ago

Wow this is strange... Are you using the default LoginController.php that ships with Laravel 5.4? Or have you modified it at all? If so, please post.

2Foot commented 7 years ago

I did override the authenticated function (which is empty anyway) from the AuthenticatesUsers Trait. See below:

 protected function authenticated(Request $request, $user)
    {
        //This function is typically empty. There code below grabs the Active Directory Groups the user belongs too and verifies which "role"
        //value they should have stored in their profile on the local DB - admin(2) or user(1). If the user is no longer found in the AD
        //but is found locally then their account was either disabled or deleted from AD and we will mimic that by deleting their local account
        //and redirecting them.

        if($user->ldap != null)
        {
            $userGroups = $user->ldap->getGroups();

            $isMemberOfAdminGroup = false;
            $isMemberOfUserGroup = false;

            foreach($userGroups as $group)
            {
                if(($group->cn[0] == "InformationSystems") || ($group->cn[0] == env('APP_ADMIN_GROUP')))
                {
                    $isMemberOfAdminGroup = true;
                }

                if($group->cn[0] == env('APP_USER_GROUP'))
                {
                    $isMemberOfUserGroup = true;
                }
            }

            if($isMemberOfUserGroup == true)
            {
                $user->role = 1;
                $user->save();
            }

            if($isMemberOfAdminGroup == true)
            {
                $user->role = 2;
                $user->save();
            }

        }
        elseif($user->ldap==null)
        {
            User::where('username','=',$request->username)->delete();
            return redirect('/');
        }
    }

This is simply just to record into the local Users Model whether the user is an admin or not. Users from the Information Services group or APP_ADMIN_GROUP then have their "role" set as admins. Otherwise it looks for users of the "APP_USER_GROUP" and sets them to a regular user. If they are not a member of any of these groups it just redirects. This should be done after authentication though. Otherwise I haven't modified anything.

2Foot commented 7 years ago

Alternatively... since the import will work I could add a cron job that runs every couple of hours to import the latest user set and then if it's possible somehow disable the adldap web authentication part and just login using the local DB since it'd have all the user information anyway... ? It'd be a bit hackish but do you think that is possible?

stevebauman commented 7 years ago

Alternatively... since the import will work I could add a cron job that runs every couple of hours to import the latest user set and then if it's possible somehow disable the adldap web authentication part and just login using the local DB since it'd have all the user information anyway... ? It'd be a bit hackish but do you think that is possible?

You can definitely do this if you'd like, I don't see an issue with this.

I just think this is bizarre, unfortunately you'll need to debug this further yourself through testing since I don't have hands on access to your server.

You could also try calling raw ldap_bind() and ldap_connect() methods during the login attempt request to see if it's Adldap2, or your server / application.

2Foot commented 7 years ago

Steve,

Finally figured it out. I am not sure someone else will find this solution given the issue heading I posted so maybe you will want to note it elsewhere...

Basically on a newer Linux distribution (such as CentOS 7) it utilizes a security utility called "selinux" which acts as a sort of security for the OS, allowing or denying certain behaviours by the server itself. By default it's turned on as well. There is a debate among Linux admins about how useful it is but mostly that it because: 1. It's new and people are lazy and don't want to learn it. 2. It's easier just to disable it entirely and not have to configure anything. I don't disable it because ultimately I know it's something I will have to adopt in the future so I may as well just learn it now. I've had my share of struggles with it but... it's all new to me and I will adapt. Bottom line, you need to run these commands from your Linux command line (which are pretty self explanatory) to allow it to connect to the remote LDAP server:

setsebool -P httpd_can_connect_ldap 1

setsebool -P httpd_can_network_connect_db 1 (may not be necessary for ldap - not sure so I just included it)

as a rule I tend to enable this one too so my sites can send out email as this has caused problems for me in the past as well:

setsebool -P httpd_can_sendmail 1

Quick breakdown explanation: "setsebool" = Set selinux boolean "-P" = makes the setting permanent on reboot "httpd_"... = httpd is the apache web service and so each command starting with that is related to it.

This explains why the command line would work but not the website login, we were not trying to access the LDAP through the httpd service. Now with that setting enabled login is working great!

Hope this helps future users!

Craig

stevebauman commented 7 years ago

@2Foot, thanks so much for posting this detailed response! Really glad you've resolved your issue.

This information will be massively useful for anyone running Adldap2 on linux.

Thanks again :smile:

nathan-lochala commented 6 years ago

@2Foot @stevebauman This is a pretty big gotcha. Given in my case, I could use tinker and authenticate, but my application failed with such a deceptive error (Failed to connect to LDAP server), I think the application could use some additional guards.

For instance, if bind fails and getenforce != disabled, throw exception "can't connect to LDAP server, possibly due to selinux enforcement, see .... blah blah for details".

stevebauman commented 6 years ago

Hi @nathan-lochala, definitely agree!

I'm going to add this into the root repository.

See issue https://github.com/Adldap2/Adldap2/issues/597

Once v5.0 is released (will be soon, finishing up docs), this fix will be included.