]> BookStack Code Mirror - bookstack/commitdiff
Aligned SAML2 system with LDAP implementation in terms of guards and UI
authorDan Brown <redacted>
Sat, 1 Feb 2020 16:11:56 +0000 (16:11 +0000)
committerDan Brown <redacted>
Sat, 1 Feb 2020 16:11:56 +0000 (16:11 +0000)
app/Auth/Access/Guards/Saml2SessionGuard.php [new file with mode: 0644]
resources/views/auth/forms/login/saml2.blade.php [new file with mode: 0644]

diff --git a/app/Auth/Access/Guards/Saml2SessionGuard.php b/app/Auth/Access/Guards/Saml2SessionGuard.php
new file mode 100644 (file)
index 0000000..1bdb59d
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+
+namespace BookStack\Auth\Access\Guards;
+
+use BookStack\Auth\Access\LdapService;
+use BookStack\Auth\User;
+use BookStack\Auth\UserRepo;
+use BookStack\Exceptions\LdapException;
+use BookStack\Exceptions\LoginAttemptException;
+use BookStack\Exceptions\LoginAttemptEmailNeededException;
+use Illuminate\Contracts\Auth\UserProvider;
+use Illuminate\Contracts\Session\Session;
+
+class LdapSessionGuard extends ExternalBaseSessionGuard
+{
+
+    protected $ldapService;
+
+    /**
+     * LdapSessionGuard constructor.
+     */
+    public function __construct($name,
+        UserProvider $provider,
+        Session $session,
+        LdapService $ldapService,
+        UserRepo $userRepo
+    )
+    {
+        $this->ldapService = $ldapService;
+        parent::__construct($name, $provider, $session, $userRepo);
+    }
+
+    /**
+     * Validate a user's credentials.
+     *
+     * @param array $credentials
+     * @return bool
+     * @throws LdapException
+     */
+    public function validate(array $credentials = [])
+    {
+        $userDetails = $this->ldapService->getUserDetails($credentials['username']);
+        $this->lastAttempted = $this->provider->retrieveByCredentials([
+            'external_auth_id' => $userDetails['uid']
+        ]);
+
+        return $this->ldapService->validateUserCredentials($userDetails, $credentials['username'], $credentials['password']);
+    }
+
+    /**
+     * Attempt to authenticate a user using the given credentials.
+     *
+     * @param array $credentials
+     * @param bool $remember
+     * @return bool
+     * @throws LoginAttemptEmailNeededException
+     * @throws LoginAttemptException
+     * @throws LdapException
+     */
+    public function attempt(array $credentials = [], $remember = false)
+    {
+        $username = $credentials['username'];
+        $userDetails = $this->ldapService->getUserDetails($username);
+        $this->lastAttempted = $user = $this->provider->retrieveByCredentials([
+            'external_auth_id' => $userDetails['uid']
+        ]);
+
+        if (!$this->ldapService->validateUserCredentials($userDetails, $username, $credentials['password'])) {
+            return false;
+        }
+
+        if (is_null($user)) {
+            $user = $this->freshUserInstanceFromLdapUserDetails($userDetails);
+        }
+
+        $this->checkForUserEmail($user, $credentials['email'] ?? '');
+        $this->saveIfNew($user);
+
+        // Sync LDAP groups if required
+        if ($this->ldapService->shouldSyncGroups()) {
+            $this->ldapService->syncGroups($user, $username);
+        }
+
+        $this->login($user, $remember);
+        return true;
+    }
+
+    /**
+     * Create a fresh user instance from details provided by a LDAP lookup.
+     */
+    protected function freshUserInstanceFromLdapUserDetails(array $ldapUserDetails): User
+    {
+        $user = new User();
+
+        $user->name = $ldapUserDetails['name'];
+        $user->external_auth_id = $ldapUserDetails['uid'];
+        $user->email = $ldapUserDetails['email'];
+        $user->email_confirmed = false;
+
+        return $user;
+    }
+
+}
diff --git a/resources/views/auth/forms/login/saml2.blade.php b/resources/views/auth/forms/login/saml2.blade.php
new file mode 100644 (file)
index 0000000..12592d4
--- /dev/null
@@ -0,0 +1,30 @@
+<form action="{{ url('/login') }}" method="POST" id="login-form" class="mt-l">
+    {!! csrf_field() !!}
+
+    <div class="stretch-inputs">
+        <div class="form-group">
+            <label for="username">{{ trans('auth.username') }}</label>
+            @include('form.text', ['name' => 'username', 'autofocus' => true])
+        </div>
+
+        @if(session('request-email', false) === true)
+            <div class="form-group">
+                <label for="email">{{ trans('auth.email') }}</label>
+                @include('form.text', ['name' => 'email'])
+                <span class="text-neg">{{ trans('auth.ldap_email_hint') }}</span>
+            </div>
+        @endif
+
+        <div class="form-group">
+            <label for="password">{{ trans('auth.password') }}</label>
+            @include('form.password', ['name' => 'password'])
+        </div>
+    </div>
+
+    <div class="grid half collapse-xs gap-xl v-center">
+        <div class="text-right">
+            <button class="button">{{ Str::title(trans('auth.log_in')) }}</button>
+        </div>
+    </div>
+
+</form>
\ No newline at end of file
Morty Proxy This is a proxified and sanitized view of the page, visit original site.