jotaelesalinas / laravel-adminless-ldap-auth

Authenticate users in Laravel against an adminless LDAP server
MIT License
210 stars 33 forks source link

Cant login but not show error message anything #27

Closed temmy-alex closed 4 years ago

temmy-alex commented 5 years ago

Hi jota i followed your tutorial laravel simple ldap auth but i cant login but not show messages anything only stay login page

and i found difference config/ldap.php and config/ldap_auth.php

when i install package composer require adldap2/adldap2-laravel the config is config/adldap.php and config/adldap_auth.php

here my code

config\adldap_auth.php

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

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

/*
|--------------------------------------------------------------------------
| 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' => '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' => [

    // 'email' => 'userprincipalname',
    'username' => 'uid',
    'name' => 'cn',
    'phone' => 'telephonenumber'
],

]; `

jotaelesalinas commented 5 years ago

Are you using Laravel 5.7 and Adldap2-Laravel 5.0? I would suggest upgrading. If not possible, have a look at the old tutorial for Laravel 5.5 and Adldap2-Laravel 3.0: https://github.com/jotaelesalinas/laravel-simple-ldap-auth/blob/4fecf4c94317e27315eb47cf27dfb18567dc13db/README.md

temmy-alex commented 5 years ago

I using laravel 5.4 Ok jota i will use this tutorial

https://github.com/jotaelesalinas/laravel-simple-ldap-auth/blob/4fecf4c94317e27315eb47cf27dfb18567dc13db/README.md

jotaelesalinas commented 5 years ago

You should set your configuration (like ADLDAP_CONTROLLERS) in .env, not in the config PHP files. As an example, you are using env('ADLDAP_CONTROLLERS', '172.18.8.10'), which tries to read ADLDAP_CONTROLLERS from the config file and only if it is not found, provides '172.18.8.10' as fallback value.

And, please, first try to get the system to work with the testing server. Only then, make the changes that you need in order to get it to work with your own LDAP server.

jotaelesalinas commented 5 years ago

Hi @temmy-virtuoso , any update on this issue?

chaos520 commented 5 years ago

Hi Jota, I had met the same issues as well.

I had fully followed your guide but seems like the login page does not redirect to any pages or errors.

auth.php

<?php

return [

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

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

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

    'providers' => [

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

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

];
ldap.php

<?php

return [
    'logging' => env('LDAP_LOGGING', true),
    'connections' => [
        'default' => [
            'auto_connect' => env('LDAP_AUTO_CONNECT', false),
            'connection' => Adldap\Connections\Ldap::class,
            'settings' => [

                // replace this line:
                // 'schema' => Adldap\Schemas\ActiveDirectory::class,
                // with this:
                'schema' => env('LDAP_SCHEMA', '') == 'OpenLDAP' ?
                                Adldap\Schemas\OpenLDAP::class :
                                ( env('LDAP_SCHEMA', '') == 'FreeIPA' ?
                                    Adldap\Schemas\FreeIPA::class :
                                    Adldap\Schemas\ActiveDirectory::class ),

                'account_prefix' => env('LDAP_ACCOUNT_PREFIX', ''),
                'account_suffix' => env('LDAP_ACCOUNT_SUFFIX', ''),
                'hosts' => explode(' ', env('LDAP_HOSTS', 'corp-dc1.corp.acme.org corp-dc2.corp.acme.org')),
                'port' => env('LDAP_PORT', 389),
                'timeout' => env('LDAP_TIMEOUT', 5),
                'base_dn' => env('LDAP_BASE_DN', 'dc=corp,dc=acme,dc=org'),
                'username' => env('LDAP_ADMIN_USERNAME', ''),
                'password' => env('LDAP_ADMIN_PASSWORD', ''),
                'follow_referrals' => env('LDAP_FOLLOW_REFERRALS', false),
                'use_ssl' => env('LDAP_USE_SSL', false),
                'use_tls' => env('LDAP_USE_TLS', false),
            ],
        ],
    ],
];
ldap_auth.php

<?php

return [

    'connection' => env('LDAP_CONNECTION', 'default'),

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

    'model' => App\User::class,

    'rules' => [

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

    ],

    'scopes' => [

    ],

    'identifiers' => [

        'ldap' => [

            // 'locate_users_by' => 'userprincipalname',

            // 'bind_users_by' => 'distinguishedname',

            'discover' => env('LDAP_USER_ATTRIBUTE', 'userprincipalname'),
            'authenticate' => env('LDAP_USER_ATTRIBUTE', 'distinguishedname'),
        ],

        'eloquent' => 'username',

        'database' => [

            'guid_column' => 'objectguid',

            'username_column' => 'email',

        ],

        'windows' => [

            'locate_users_by' => 'samaccountname',

            'server_key' => 'AUTH_USER',

        ],

    ],

    'passwords' => [

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

        'column' => 'password',

    ],

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

    'sync_attributes' => [
        // 'email' => 'userprincipalname',

        'username' => 'uid',

        'name' => 'cn',

        'phone' => 'telephonenumber',
    ],

    'logging' => [

        'enabled' => env('LDAP_LOGGING', 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,

        ],
    ],

];
LoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Adldap\Laravel\Facades\Adldap;

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 config('ldap_auth.usernames.eloquent');
    }

    protected function validateLogin(Request $request)
    {
        $this->validate($request, [
            $this->username() => 'required|string|regex:/^\w+$/',
            'password' => 'required|string',
        ]);
    }

    protected function attemptLogin(Request $request)
    {
        $credentials = $request->only($this->username(), 'password');
        $username = $credentials[$this->username()];
        $password = $credentials['password'];

        $user_format = env('LDAP_USER_FORMAT', 'cn=%s,'.env('LDAP_BASE_DN', ''));
        $userdn = sprintf($user_format, $username);

        // you might need this, as reported in
        // [#14](https://github.com/jotaelesalinas/laravel-simple-ldap-auth/issues/14):
        // Adldap::auth()->bind($userdn, $password);

        if(Adldap::auth()->attempt($userdn, $password, $bindAsUser = true)) {
            // the user exists in the LDAP server, with the provided password

            $user = \App\User::where($this->username(), $username)->first();
            if (!$user) {
                // the user doesn't exist in the local database, so we have to create one

                $user = new \App\User();
                $user->username = $username;
                $user->password = '';

                // you can skip this if there are no extra attributes to read from the LDAP server
                // or you can move it below this if(!$user) block if you want to keep the user always
                // in sync with the LDAP server 
                $sync_attrs = $this->retrieveSyncAttributes($username);
                foreach ($sync_attrs as $field => $value) {
                    $user->$field = $value !== null ? $value : '';
                }
            }

            // by logging the user we create the session, so there is no need to login again (in the configured time).
            // pass false as second parameter if you want to force the session to expire when the user closes the browser.
            // have a look at the section 'session lifetime' in `config/session.php` for more options.
            $this->guard()->login($user, true);
            return true;
        }

        // the user doesn't exist in the LDAP server or the password is wrong
        // log error
        return false;
    }

    protected function retrieveSyncAttributes($username)
    {
        $ldapuser = Adldap::search()->where(env('LDAP_USER_ATTRIBUTE'), '=', $username)->first();
        if ( !$ldapuser ) {
            // log error
            return false;
        }
        // if you want to see the list of available attributes in your specific LDAP server:
        // var_dump($ldapuser->attributes); exit;

        // needed if any attribute is not directly accessible via a method call.
        // attributes in \Adldap\Models\User are protected, so we will need
        // to retrieve them using reflection.
        $ldapuser_attrs = null;

        $attrs = [];

        foreach (config('ldap_auth.sync_attributes') as $local_attr => $ldap_attr) {
            if ( $local_attr == 'username' ) {
                continue;
            }

            $method = 'get' . $ldap_attr;
            if (method_exists($ldapuser, $method)) {
                $attrs[$local_attr] = $ldapuser->$method();
                continue;
            }

            if ($ldapuser_attrs === null) {
                $ldapuser_attrs = self::accessProtected($ldapuser, 'attributes');
            }

            if (!isset($ldapuser_attrs[$ldap_attr])) {
                // an exception could be thrown
                $attrs[$local_attr] = null;
                continue;
            }

            if (!is_array($ldapuser_attrs[$ldap_attr])) {
                $attrs[$local_attr] = $ldapuser_attrs[$ldap_attr];
            }

            if (count($ldapuser_attrs[$ldap_attr]) == 0) {
                // an exception could be thrown
                $attrs[$local_attr] = null;
                continue;
            }

            // now it returns the first item, but it could return
            // a comma-separated string or any other thing that suits you better
            $attrs[$local_attr] = $ldapuser_attrs[$ldap_attr][0];
            //$attrs[$local_attr] = implode(',', $ldapuser_attrs[$ldap_attr]);
        }

        return $attrs;
    }

    protected static function accessProtected ($obj, $prop)
    {
        $reflection = new \ReflectionClass($obj);
        $property = $reflection->getProperty($prop);
        $property->setAccessible(true);
        return $property->getValue($obj);
    }    
}
login.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Login') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('login') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="username" class="col-sm-4 col-form-label text-md-right">{{ __('Username') }}</label>
                            <div class="col-md-6">
                                <input id="username" type="username" class="form-control{{ $errors->has('username') ? ' is-invalid' : '' }}" name="username" value="{{ old('username') }}" required autofocus>
                                @if ($errors->has('username'))
                                <span class="invalid-feedback" role="alert">
                                    <strong>{{ $errors->first('username') }}</strong>
                                </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>

                                @if ($errors->has('password'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group row">
                            <div class="col-md-6 offset-md-4">
                                <div class="form-check">
                                    <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                    <label class="form-check-label" for="remember">
                                        {{ __('Remember Me') }}
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Login') }}
                                </button>

                                @if (Route::has('password.request'))
<!--                                     <a class="btn btn-link" href="{{ route('password.request') }}">
                                        {{ __('Forgot Your Password?') }}
                                    </a> -->
                                @endif
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
.env

LDAP_SCHEMA=OpenLDAP
LDAP_HOSTS=ldap.forumsys.com
LDAP_BASE_DN=dc=example,dc=com
LDAP_USER_ATTRIBUTE=uid
LDAP_USER_FORMAT=uid=%s,dc=example,dc=com
LDAP_CONNECTION=default

I am using tesla, gauss, newton, einstein as username and password as password to login, still redirected to login page.

asakre commented 5 years ago

I'm having the same issue as the above folks, I'm stuck at the login screen without any redirection to anywhere. Is this because of some compatibility issues? Please advise what could be the solution.

Thanks

jotaelesalinas commented 5 years ago

I updated the manual to the latest version of Adldap-Laravel, 6.0. Try now.

javiertigre commented 4 years ago

donde puedo ver la ultima version??

jotaelesalinas commented 4 years ago

@javiertigre: the last commit in master https://github.com/jotaelesalinas

javiertigre commented 4 years ago

Disculpe las molestias segui su guia y todo funciona bien pero al modificarlo para mi ldap me sale este mensaje: Estas credenciales no coinciden con nuestros registros., donde o como se si estoy conectado al ldap?? por favor necesito su ayuda

jotaelesalinas commented 4 years ago

@javiertigre Contacta con el administrador del servidor LDAP para que te proporcione los datos de conexión correctos. En los logs del servidor verás si se están produciendo conexiones, y los errores que ocurran.