]> BookStack Code Mirror - bookstack/commitdiff
Merge branch 'master' of https://github.com/theodor-franke/BookStack into theodor...
authorDan Brown <redacted>
Thu, 21 Oct 2021 13:04:23 +0000 (14:04 +0100)
committerDan Brown <redacted>
Thu, 21 Oct 2021 13:04:23 +0000 (14:04 +0100)
1  2 
.env.example.complete
app/Auth/Access/Saml2Service.php

diff --combined .env.example.complete
index 4188751654e8c22491f8f07e2b82fe4dc10fa95f,58e4e47543d9df1b0d9fbc7ba66c5dc5f9e9f982..a29afaafd014f600cd90784f39d04b1b76841670
@@@ -42,14 -42,6 +42,14 @@@ APP_TIMEZONE=UT
  # overrides can be made. Defaults to disabled.
  APP_THEME=false
  
 +# Trusted Proxies
 +# Used to indicate trust of systems that proxy to the application so
 +# certain header values (Such as "X-Forwarded-For") can be used from the
 +# incoming proxy request to provide origin detail.
 +# Set to an IP address, or multiple comma seperated IP addresses.
 +# Can alternatively be set to "*" to trust all proxy addresses.
 +APP_PROXIES=null
 +
  # Database details
  # Host can contain a port (localhost:3306) or a separate DB_PORT option can be used.
  DB_HOST=localhost
@@@ -232,6 -224,11 +232,11 @@@ SAML2_ONELOGIN_OVERRIDES=nul
  SAML2_DUMP_USER_DETAILS=false
  SAML2_AUTOLOAD_METADATA=false
  SAML2_IDP_AUTHNCONTEXT=true
+ SAML2_SP_CERTIFICATE=null
+ SAML2_SP_PRIVATEKEY=null
+ SAML2_SP_NAME_ID_Format=null
+ SAML2_SP_NAME_ID_SP_NAME_QUALIFIER=null
+ SAML2_RETRIEVE_PARAMETERS_FROM_SERVER=false
  
  # SAML group sync configuration
  # Refer to https://www.bookstackapp.com/docs/admin/saml2-auth/
@@@ -239,18 -236,6 +244,18 @@@ SAML2_USER_TO_GROUPS=fals
  SAML2_GROUP_ATTRIBUTE=group
  SAML2_REMOVE_FROM_GROUPS=false
  
 +# OpenID Connect authentication configuration
 +OIDC_NAME=SSO
 +OIDC_DISPLAY_NAME_CLAIMS=name
 +OIDC_CLIENT_ID=null
 +OIDC_CLIENT_SECRET=null
 +OIDC_ISSUER=null
 +OIDC_ISSUER_DISCOVER=false
 +OIDC_PUBLIC_KEY=null
 +OIDC_AUTH_ENDPOINT=null
 +OIDC_TOKEN_ENDPOINT=null
 +OIDC_DUMP_USER_DETAILS=false
 +
  # Disable default third-party services such as Gravatar and Draw.IO
  # Service-specific options will override this option
  DISABLE_EXTERNAL_SERVICES=false
@@@ -301,12 -286,6 +306,12 @@@ ALLOW_CONTENT_SCRIPTS=fals
  # Contents of the robots.txt file can be overridden, making this option obsolete.
  ALLOW_ROBOTS=null
  
 +# Allow server-side fetches to be performed to potentially unknown
 +# and user-provided locations. Primarily used in exports when loading
 +# in externally referenced assets.
 +# Can be 'true' or 'false'.
 +ALLOW_UNTRUSTED_SERVER_FETCHING=false
 +
  # A list of hosts that BookStack can be iframed within.
  # Space separated if multiple. BookStack host domain is auto-inferred.
  # For Example: ALLOWED_IFRAME_HOSTS="https://example.com https://a.example.com"
index 9c208832aba1b43aafb4864dae60991865502f45,339701d27c89fcad4530657916bdd898a2c73210..58f999709e881fab60142017a4d1e9cef56b572c
@@@ -8,6 -8,7 +8,6 @@@ use BookStack\Exceptions\SamlException
  use BookStack\Exceptions\StoppedAuthenticationException;
  use BookStack\Exceptions\UserRegistrationException;
  use Exception;
 -use Illuminate\Support\Str;
  use OneLogin\Saml2\Auth;
  use OneLogin\Saml2\Error;
  use OneLogin\Saml2\IdPMetadataParser;
@@@ -17,25 -18,20 +17,25 @@@ use OneLogin\Saml2\ValidationError
   * Class Saml2Service
   * Handles any app-specific SAML tasks.
   */
 -class Saml2Service extends ExternalAuthService
 +class Saml2Service
  {
      protected $config;
      protected $registrationService;
      protected $loginService;
 +    protected $groupSyncService;
  
      /**
       * Saml2Service constructor.
       */
 -    public function __construct(RegistrationService $registrationService, LoginService $loginService)
 -    {
 +    public function __construct(
 +        RegistrationService $registrationService,
 +        LoginService $loginService,
 +        GroupSyncService $groupSyncService
 +    ) {
          $this->config = config('saml2');
          $this->registrationService = $registrationService;
          $this->loginService = $loginService;
 +        $this->groupSyncService = $groupSyncService;
      }
  
      /**
          $returnRoute = url('/');
  
          try {
-             $url = $toolKit->logout($returnRoute, [], null, null, true);
+             $email = auth()->user()['email'];
+             $nameIdFormat = env('SAML2_SP_NAME_ID_Format', null);
+             $nameIdSPNameQualifier = env('SAML2_SP_NAME_ID_SP_NAME_QUALIFIER', null);
+             $url = $toolKit->logout($returnRoute, [], $email, null, true, $nameIdFormat, null, $nameIdSPNameQualifier);
              $id = $toolKit->getLastRequestID();
          } catch (Error $error) {
              if ($error->getCode() !== Error::SAML_SINGLE_LOGOUT_NOT_SUPPORTED) {
       * @throws JsonDebugException
       * @throws UserRegistrationException
       */
 -    public function processAcsResponse(?string $requestId): ?User
 +    public function processAcsResponse(string $requestId, string $samlResponse): ?User
      {
 +        // The SAML2 toolkit expects the response to be within the $_POST superglobal
 +        // so we need to manually put it back there at this point.
 +        $_POST['SAMLResponse'] = $samlResponse;
          $toolkit = $this->getToolkit();
          $toolkit->processResponse($requestId);
          $errors = $toolkit->getErrors();
      public function processSlsResponse(?string $requestId): ?string
      {
          $toolkit = $this->getToolkit();
-         $redirect = $toolkit->processSLO(true, $requestId, false, null, true);
+         $retrieveParametersFromServer = env('SAML2_RETRIEVE_PARAMETERS_FROM_SERVER', false);
+         $redirect = $toolkit->processSLO(true, $requestId, $retrieveParametersFromServer, null, true);
  
          $errors = $toolkit->getErrors();
  
  
      /**
       * Extract the details of a user from a SAML response.
 +     *
 +     * @return array{external_id: string, name: string, email: string, saml_id: string}
       */
      protected function getUserDetails(string $samlID, $samlAttributes): array
      {
          return $defaultValue;
      }
  
 -    /**
 -     * Get the user from the database for the specified details.
 -     *
 -     * @throws UserRegistrationException
 -     */
 -    protected function getOrRegisterUser(array $userDetails): ?User
 -    {
 -        $user = User::query()
 -          ->where('external_auth_id', '=', $userDetails['external_id'])
 -          ->first();
 -
 -        if (is_null($user)) {
 -            $userData = [
 -                'name'             => $userDetails['name'],
 -                'email'            => $userDetails['email'],
 -                'password'         => Str::random(32),
 -                'external_auth_id' => $userDetails['external_id'],
 -            ];
 -
 -            $user = $this->registrationService->registerUser($userData, null, false);
 -        }
 -
 -        return $user;
 -    }
 -
      /**
       * Process the SAML response for a user. Login the user when
       * they exist, optionally registering them automatically.
              throw new SamlException(trans('errors.saml_already_logged_in'), '/login');
          }
  
 -        $user = $this->getOrRegisterUser($userDetails);
 +        $user = $this->registrationService->findOrRegister(
 +            $userDetails['name'],
 +            $userDetails['email'],
 +            $userDetails['external_id']
 +        );
 +
          if ($user === null) {
              throw new SamlException(trans('errors.saml_user_not_registered', ['name' => $userDetails['external_id']]), '/login');
          }
  
          if ($this->shouldSyncGroups()) {
              $groups = $this->getUserGroups($samlAttributes);
 -            $this->syncWithGroups($user, $groups);
 +            $this->groupSyncService->syncUserWithFoundGroups($user, $groups, $this->config['remove_from_groups']);
          }
  
          $this->loginService->login($user, 'saml2');