Site icon PlusMagi's Blog By Pitt Phunsanit

Laravel 5: LDAP.Active Directory (AD)

ตัวอย่างการ login โดยใช้ Active Directory (AD) หรือ LDAP version ของ microsoft ทำการ authentication แทนข้อมูลผู้ใช้ในตาราง users

  1. ติดตั้ง Adldap2/Adldap2-Laravel โดยใช้ command
    cd D:\xampp\htdocs\laravel_dev
    composer require adldap2/adldap2-laravel
  2. ลงทะเบียน Adldap facade โดยเปิดไฟล์ config/app.php
        'aliases' => [
    
            'Adldap' => Adldap\Laravel\Facades\Adldap::class,
    
    ],
  3. Publish Adldap service providers โดยใช้ command
    php artisan vendor:publish --provider="Adldap\Laravel\AdldapServiceProvider"
    php artisan vendor:publish --provider="Adldap\Laravel\AdldapAuthServiceProvider"
  4. เปลี่ยน driver ของ user provider ในไฟล์ config/auth.php จาก eloquent เป็น ldap
        'providers' => [
            'users' => [
                'driver' => 'ldap', // eloquent
                'model' => App\User::class,
            ],
  5. เพิ่ม config .env ถ้าใช้ synology จะได้ LDAP Server ประมาณ
    IP
    192.168.1.101
    Base DN:
    dc=phunsanit
    Bind DN:
    uid=root,cn=users,dc=phunsanit

    ก็จะเพิ่มไปประมาณ

    LDAP_SCHEMA=ActiveDirectory
    LDAP_HOSTS=192.168.1.101
    LDAP_LOGGING=true
    LDAP_BASE_DN=dc=phunsanit
    LDAP_USER_ATTRIBUTE=uid
    LDAP_USER_FORMAT=uid=%s,cn=users,dc=phunsanit
    LDAP_CONNECTION=default

    โดยหลักการคือ

    LDAP_BASE_DN
    คือจุดเริ่มต้นข้อมูลที่เราสนใจ
    LDAP_USER_FORMAT
    จะโดน replace กับ user ที่ผู้ใช้กรอกข้อมูลเข้ามาเช่น user: pitt.p แทนที่ uid=%s,cn=users,dc=phunsanit จะได้ uid=pitt.p,cn=users,dc=phunsanit

    โดยมีที่มาจาการทดลอง login ได้โดยใช้โปรแกรม Apache Directory Studio โดยชั้นของข้อมูลจะเป็น dc=phunsanit > cn=users > uid=pitt.p > ข้อมูลของ user นี้

  6. แก้ ตาราง user อาจจะใช้ database/migrations/2014_10_12_000000_create_users_table.php
    public function up()
        {
            Schema::create('users', function (Blueprint $table) {
                $table->bigIncrements('id');
                $table->string('name');
    
                /* remove
                $table->string('email')->unique();
                $table->timestamp('email_verified_at')->nullable();
                 */
                //add
                $table->string('phone');
    
                $table->string('password');
                $table->rememberToken();
                $table->timestamps();
            });
        }

    และใช้ command

    php artisan migrate

    (ถ้าไม่ได้เช็คให้ดีว่า connect database ถูกต้อง)

  7. แก้ config/ldap.php ประมาณ
    <?php
    
    return [
    
        /*
        |--------------------------------------------------------------------------
        | Logging
        |--------------------------------------------------------------------------
        |
        | This option enables logging all LDAP operations on all configured
        | connections such as bind requests and CRUD operations.
        |
        | Log entries will be created in your default logging stack.
        |
        | This option is extremely helpful for debugging connectivity issues.
        |
         */
    
        'logging' => env('LDAP_LOGGING', false),
    
        /*
        |--------------------------------------------------------------------------
        | Connections
        |--------------------------------------------------------------------------
        |
        | This array stores the connections that are added to Adldap. You can add
        | as many connections as you like.
        |
        | The key is the name of the connection you wish to use and the value is
        | an array of configuration settings.
        |
         */
    
        'connections' => [
    
            'default' => [
    
                /*
                |--------------------------------------------------------------------------
                | Auto Connect
                |--------------------------------------------------------------------------
                |
                | If auto connect is true, Adldap will try to automatically connect to
                | your LDAP server in your configuration. This allows you to assume
                | connectivity rather than having to connect manually
                | in your application.
                |
                | If this is set to false, you **must** connect manually before running
                | LDAP operations. Otherwise, you will receive exceptions.
                |
                 */
    
                'auto_connect' => env('LDAP_AUTO_CONNECT', true),
    
                /*
                |--------------------------------------------------------------------------
                | Connection
                |--------------------------------------------------------------------------
                |
                | The connection class to use to run raw LDAP operations on.
                |
                | Custom connection classes must implement:
                |
                |  Adldap\Connections\ConnectionInterface
                |
                 */
    
                'connection' => Adldap\Connections\Ldap::class,
    
                /*
                |--------------------------------------------------------------------------
                | Connection Settings
                |--------------------------------------------------------------------------
                |
                | This connection settings array is directly passed into the Adldap constructor.
                |
                | Feel free to add or remove settings you don't need.
                |
                 */
    
                'settings' => [
    
                    /*
                    |--------------------------------------------------------------------------
                    | Schema
                    |--------------------------------------------------------------------------
                    |
                    | The schema class to use for retrieving attributes and generating models.
                    |
                    | You can also set this option to `null` to use the default schema class.
                    |
                    | For OpenLDAP, you must use the schema:
                    |
                    |   Adldap\Schemas\OpenLDAP::class
                    |
                    | For FreeIPA, you must use the schema:
                    |
                    |   Adldap\Schemas\FreeIPA::class
                    |
                    | Custom schema classes must implement Adldap\Schemas\SchemaInterface
                    |
                     */
    
                    'schema' => Adldap\Schemas\ActiveDirectory::class,
    
                    /*
                    |--------------------------------------------------------------------------
                    | Account Prefix
                    |--------------------------------------------------------------------------
                    |
                    | The account prefix option is the prefix of your user accounts in LDAP directory.
                    |
                    | This string is prepended to all authenticating users usernames.
                    |
                     */
    
                    'account_prefix' => env('LDAP_ACCOUNT_PREFIX', ''),
    
                    /*
                    |--------------------------------------------------------------------------
                    | Account Suffix
                    |--------------------------------------------------------------------------
                    |
                    | The account suffix option is the suffix of your user accounts in your LDAP directory.
                    |
                    | This string is appended to all authenticating users usernames.
                    |
                     */
    
                    'account_suffix' => env('LDAP_ACCOUNT_SUFFIX', ''),
    
                    /*
                    |--------------------------------------------------------------------------
                    | Domain Controllers
                    |--------------------------------------------------------------------------
                    |
                    | The domain controllers option is an array of servers located on your
                    | network that serve Active Directory. You can insert as many servers or
                    | as little as you'd like depending on your forest (with the
                    | minimum of one of course).
                    |
                    | These can be IP addresses of your server(s), or the host name.
                    |
                     */
    
                    'hosts' => explode(' ', env('LDAP_HOSTS', 'corp-dc1.corp.acme.org corp-dc2.corp.acme.org')),
    
                    /*
                    |--------------------------------------------------------------------------
                    | Port
                    |--------------------------------------------------------------------------
                    |
                    | The port option is used for authenticating and binding to your LDAP server.
                    |
                     */
    
                    'port' => env('LDAP_PORT', 389),
    
                    /*
                    |--------------------------------------------------------------------------
                    | Timeout
                    |--------------------------------------------------------------------------
                    |
                    | The timeout option allows you to configure the amount of time in
                    | seconds that your application waits until a response
                    | is received from your LDAP server.
                    |
                     */
    
                    'timeout' => env('LDAP_TIMEOUT', 5),
    
                    /*
                    |--------------------------------------------------------------------------
                    | Base Distinguished Name
                    |--------------------------------------------------------------------------
                    |
                    | The base distinguished name is the base distinguished name you'd
                    | like to perform query operations on. An example base DN would be:
                    |
                    |        dc=corp,dc=acme,dc=org
                    |
                    | A correct base DN is required for any query results to be returned.
                    |
                     */
    
                    'base_dn' => env('LDAP_BASE_DN', 'dc=corp,dc=acme,dc=org'),
    
                    /*
                    |--------------------------------------------------------------------------
                    | LDAP Username & Password
                    |--------------------------------------------------------------------------
                    |
                    | When connecting to your LDAP server, a username and password is required
                    | to be able to query and run operations on your server(s). You can
                    | use any user account that has these permissions. This account
                    | does not need to be a domain administrator unless you
                    | require changing and resetting user passwords.
                    |
                     */
    
                    'username' => env('LDAP_USERNAME'),
                    'password' => env('LDAP_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('LDAP_USE_SSL', false),
                    'use_tls' => env('LDAP_USE_TLS', false),
    
                ],
    
            ],
    
        ],
    
    ];

    จุดสำคัญคือ

    schema
    จะบอกว่าใช้ protocal อะไร เช่นถ้าใช้ AD จะต้องเลือก Adldap\Schemas\ActiveDirectory::class, ถ้าใช้ LDAP ชนิดอื่นต้องเปลี่ยนจุดนี้
    username
    user ที่มีสิทธิแก้ข้อมูลใน LDAP server ถ้าไม่มีหรือไม่ต้องการแก้ข้อมูลเข้าไป (ห้ามใช้เด็ดขาด) เพราะจะทำให้ login ไม่สำเร็จ
    password
    password ของ user ที่มีสิทธิแก้ข้อมูลใน LDAP server ถ้าไม่มีหรือไม่ต้องการแก้ข้อมูลเข้าไป (ห้ามใช้เด็ดขาด) เพราะจะทำให้ login ไม่สำเร็จ
  8. แก้ config/ldap_auth.php ประมาณ
    <?php
    
    return [
    
        /*
        |--------------------------------------------------------------------------
        | Connection
        |--------------------------------------------------------------------------
        |
        | The LDAP connection to use for Laravel authentication.
        |
        | You must specify connections in your `config/ldap.php` configuration file.
        |
         */
    
        'connection' => env('LDAP_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,
    
        /*
        |--------------------------------------------------------------------------
        | Model
        |--------------------------------------------------------------------------
        |
        | The model to utilize for authentication and importing.
        |
        | This option is only applicable to the DatabaseUserProvider.
        |
         */
    
        'model' => App\User::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.
            // Suitable when using ActiveDirectory.
            // Adldap\Laravel\Scopes\UpnScope::class,
    
            // Only allows users with a uid to authenticate.
            // Suitable when using OpenLDAP.
            // Adldap\Laravel\Scopes\UidScope::class,
    
        ],
    
        'identifiers' => [
    
            /*
            |--------------------------------------------------------------------------
            | LDAP
            |--------------------------------------------------------------------------
            |
            | Locate Users By:
            |
            |   This 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.
            |
            | Bind Users By:
            |
            |   This 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 attribute,
            |   the users attribute you specify below will be used as
            |   the 'username' to bind to your LDAP server.
            |
            |   This is usually their distinguished name.
            |
             */
    
            'ldap' => [
    
                'locate_users_by' => 'userprincipalname',
    
                'bind_users_by' => 'distinguishedname',
    
            ],
    
            'database' => [
    
                /*
                |--------------------------------------------------------------------------
                | GUID Column
                |--------------------------------------------------------------------------
                |
                | The value of this option is the database column that will contain the
                | LDAP users global identifier. This column does not need to be added
                | to the sync attributes below. It is synchronized automatically.
                |
                | This option is only applicable to the DatabaseUserProvider.
                |
                 */
    
                'guid_column' => 'objectguid',
    
                /*
                |--------------------------------------------------------------------------
                | Username Column
                |--------------------------------------------------------------------------
                |
                | The value of this option is the database column that contains your
                | users login username.
                |
                | This column must be added to your sync attributes below to be
                | properly synchronized.
                |
                | This option is only applicable to the DatabaseUserProvider.
                |
                 */
    
                'username_column' => 'email',
    
            ],
    
            /*
            |--------------------------------------------------------------------------
            | Windows Authentication Middleware (SSO)
            |--------------------------------------------------------------------------
            |
            | Local Users By:
            |
            |   This 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.
            |
            | Server Key:
            |
            |    This value represents the 'key' of the $_SERVER
            |    array to pull the users account name from.
            |
            |    For example, $_SERVER['AUTH_USER'].
            |
             */
    
            'windows' => [
    
                'locate_users_by' => 'samaccountname',
    
                'server_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 Hash::make() 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 first login, and will
            | lose access to this account upon loss of LDAP connectivity.
            |
            | This option is only applicable to the DatabaseUserProvider.
            |
             */
    
            'sync' => env('LDAP_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 in the
        | local database if active directory authentication fails.
        |
        | Set this to true if you would like to enable it.
        |
        | This option is only applicable to the DatabaseUserProvider.
        |
         */
    
        'login_fallback' => env('LDAP_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.
        |
        | You **must** include the users login attribute here.
        |
        | This option is only applicable to the DatabaseUserProvider.
        |
         */
    
        'sync_attributes' => [
            // 'field_in_local_db' => 'attribute_in_ldap_server',
            'username' => 'uid',
            'email' => 'userprincipalname',
            'name' => 'cn',
            'phone' => 'telephonenumber',
        ],
    
        /*
        |--------------------------------------------------------------------------
        | 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' => 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,
    
            ],
        ],
    
        'usernames' => [
    
            'ldap' => [
    
                // replace this line:
                // 'discover' => 'userprincipalname',
                // with this one:
                'discover' => env('LDAP_USER_ATTRIBUTE', 'userprincipalname'),
    
                // replace this line:
                // 'authenticate' => 'distinguishedname',
                // with this one:
                'authenticate' => env('LDAP_USER_ATTRIBUTE', 'distinguishedname'),
    
            ],
    
            // replace this line:
            // 'eloquent' => 'email',
            // with this one:
            'eloquent' => 'username',
    
        ],
    
    ];

    จุดสำคัญคือ

    sync_attributes
    บอกให้ copy ค่าจาก attribute อะไรไปเก็บในตาราง users
    usernames
    คือการผูก username ในระบบ login ในตาราง ใน LDAP เข้าไว้ด้วยกัน
  9. สร้างระบบ login โดย command
    php artisan make:auth
  10. แก้ login template ให้ใช้ username แทน email เปิด resources/views/auth/login.blade.php จาก
    <div class="form-group row">
    <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
    
    <div class="col-md-6">
        <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
    
        @error('email')
            <span class="invalid-feedback" role="alert">
                <strong>{{ $message }}</strong>
            </span>
        @enderror
    </div>
    </div>

    เป็น

    <div class="form-group row">
    <label for="username" class="col-md-4 col-form-label text-md-right">{{ __('Username') }}</label>
    
    <div class="col-md-6">
        <input id="username" type="text" class="form-control @error('username') is-invalid @enderror" name="username" value="{{ old('username') }}" required autocomplete="username" autofocus>
    
        @error('username')
            <span class="invalid-feedback" role="alert">
                <strong>{{ $message }}</strong>
            </span>
        @enderror
    </div>
    </div>

    หลักๆ คือ replace email แทนที่โดย username นั่นละ ลบ link เกี่ยวกับการ reset password ใน

    <a class="btn btn-link" href="">
    
    </a>
  11. แก้ app/Http/Controllers/Auth/LoginController.php โดยจะเป็นส่วนที่ทำการ login และทำหน้าที่ insert / update ข้อมูลกลับไปให้ตาราง users แก้ประมาณ
    <?php
    
    namespace App\Http\Controllers\Auth;
    
    use Adldap\Laravel\Facades\Adldap;
    use App\Http\Controllers\Controller;
    use Illuminate\Foundation\Auth\AuthenticatesUsers;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    
    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');
        }
    
        /* cusstom */
    
        /**
         * Handle a login request to the application.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
         *
         * @throws \Illuminate\Validation\ValidationException
         */
        public function login(Request $request)
        {
            $this->validateLogin($request);
    
            // If the class is using the ThrottlesLogins trait, we can automatically throttle
            // the login attempts for this application. We'll key this by the username and
            // the IP address of the client making these requests into this application.
            if ($this->hasTooManyLoginAttempts($request)) {
                $this->fireLockoutEvent($request);
    
                return $this->sendLockoutResponse($request);
            }
    
            if ($this->attemptLogin($request)) {
                return $this->sendLoginResponse($request);
            }
    
            // If the login attempt was unsuccessful we will increment the number of attempts
            // to login and redirect the user back to the login form. Of course, when this
            // user surpasses their maximum number of attempts they will get locked out.
            $this->incrementLoginAttempts($request);
    
            return $this->sendFailedLoginResponse($request);
        }
    
        /**
         * Attempt to log the user into the application.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return bool
         */
        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);
        }
    
        /**
         * Get the login username to be used by the controller.
         *
         * @return string
         */
        public function username()
        {
            return 'username';
        }
    
    }

    จุดสำคัญคือ

    use AuthenticatesUsers
    ต้นแบบของระบบ login ที่เอามา overwrite ถ้าทำตามทั้งหมดแล้วใช้ไม่ได้ จะเป็นผู้ต้องสงสัยอันดับหนึ่งว่า แกเปลี่ยนไปใช่มั๋ยสาด
    public function login
    function ที่เขียนมา overwrite function login ใน AuthenticatesUsers เป็นแกนกลางของระบบ login ที่ข้อมูลของฟอร์ม login จะถูกส่งเข้ามาที่ function นี้เป็นที่แรก
    protected function attemptLogin
    เป็น function ที่จะใช้ตรวจสอบว่า username และ password ถูกต้องจริงรึเปล่า ถ้าถูกจะ return ค่าจากตาราง users กลับไปโดย code ตัวนี้จะอ่านค่าจาก LDAP จากกนั้นจะ insert / update ไปที่ตาราง users ด้วย
    public function username()
    เป็น function ที่บอกใช้ laravel ใช้ username แทน email ในการ login ที่แก้ใน login template
  12. ทดลอง login ถ้าไม่ได้กลับไปทำขั้นตอนแรกใหม่
  13. แก้ routes ให้ router ที่ต้องการจำเป็นต้องมีการ login ก่อนจึงใช้ได้ เปิดไฟล์ routes/web.php ลบ Auth::routes(); ออกแทนที่ด้วย
    // Auth::routes();
    Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
    Route::post('login', 'Auth\LoginController@login');
    Route::post('logout', 'Auth\LoginController@logout')->name('logout');

    และครอบ routes ที่ต้องการให้ต้อง login ถึงจะใช้ได้โดย

    Route::middleware('auth')->group(function () {
    ...
        Route::get('/home', 'HomeController@index')->name('home');
    ...
    });
  14. ลบส่วนที่ไม่จำเป็นออกเพื่อความปลอดภัย
    • app/Http/Controllers/Auth/ForgotPasswordController.php
    • app/Http/Controllers/Auth/RegisterController.php
    • app/Http/Controllers/Auth/ResetPasswordController.php
    • app/Http/Controllers/Auth/VerificationController.php
    • database/migrations/2014_10_12_100000_create_password_resets_table.php
    • resources/views/auth/passwords
    • resources/views/auth/register.blade.php
    • resources/views/auth/verify.blade.php

ขอบคุณ José Luis Salinas ที่เขียน laravel-simple-ldap-auth Howto: adminless LDAP authentification in Laravel ที่ช่วยไขความกระจ่างให้ config ครั้งนี้สำเร็จ

Exit mobile version