From 23918408cef2afece8908d373553329bfbc30b9d Mon Sep 17 00:00:00 2001 From: Mal'Ganis Date: Tue, 28 Dec 2021 01:24:35 +0800 Subject: [PATCH 1/2] Add custom S3 endpoint support --- storage-s3/config.php | 14 ++++++++++++++ storage-s3/storage.php | 19 +++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/storage-s3/config.php b/storage-s3/config.php index 3fff247..77b846e 100644 --- a/storage-s3/config.php +++ b/storage-s3/config.php @@ -19,6 +19,10 @@ function($x, $y, $n) { return $n != 1 ? $y : $x; }, function getOptions() { list($__, $_N) = self::translate(); return array( + 'endpoint' => new TextboxField(array( + 'label' => $__('S3 Endpoint'), + 'configuration' => array('size'=>40), + )), 'bucket' => new TextboxField(array( 'label' => $__('S3 Bucket'), 'configuration' => array('size'=>40), @@ -55,6 +59,10 @@ function getOptions() { ), 'default' => '', )), + 'capath' => new TextboxField(array( + 'label' => $__('CA Path'), + 'configuration' => array('size'=>40), + )), 'access-info' => new SectionBreakField(array( 'label' => $__('Access Information'), @@ -81,6 +89,12 @@ function pre_save(&$config, &$errors) { ?: Crypto::decrypt($this->get('secret-access-key'), SECRET_SALT, $this->getNamespace()), ); + if ($config['endpoint']) + $credentials['endpoint'] = $config['endpoint']; + + if ($config['capath']) + $credentials['ssl.certificate_authority'] = $config['capath']; + if ($config['aws-region']) $credentials['region'] = $config['aws-region']; diff --git a/storage-s3/storage.php b/storage-s3/storage.php index db2deb3..d4ef943 100644 --- a/storage-s3/storage.php +++ b/storage-s3/storage.php @@ -1,5 +1,6 @@ Crypto::decrypt(static::$config['secret-access-key'], SECRET_SALT, static::getConfig()->getNamespace()), ); - if ($config['aws-region']) - $credentials['region'] = $config['aws-region']; + if (static::$config['aws-region']) + $credentials['region'] = static::$config['aws-region']; + + if (static::$config['endpoint']) + $credentials['endpoint'] = static::$config['endpoint']; + + if (static::$config['capath']) + $credentials['ssl.certificate_authority'] = static::$config['capath']; $this->client = S3Client::factory($credentials); } @@ -87,6 +94,9 @@ function flush() { return $this->upload($this->body); } + /** + * @throws IOException + */ function upload($filepath) { if ($filepath instanceof EntityBody) { $filepath->rewind(); @@ -107,6 +117,7 @@ function upload($filepath) { if (isset($this->upload_hash)) $params['Content-MD5'] = $this->upload_hash_final = hash_final($this->upload_hash); + echo $filepath; $info = $this->client->upload( static::$config['bucket'], @@ -120,11 +131,11 @@ function upload($filepath) { catch (S3Exception $e) { throw new IOException('Unable to upload to S3: '.(string)$e); } - return false; } // Support MD5 hash via the returned ETag header; - function getNativeHashAlgos() { + function getNativeHashAlgos(): array + { return array('md5'); } From 977d55c157f4a924ba4bf17aba659fd34354b835 Mon Sep 17 00:00:00 2001 From: Mal'Ganis Date: Tue, 28 Dec 2021 02:43:06 +0800 Subject: [PATCH 2/2] Add Generic OAuth2 support --- auth-oauth/authentication.php | 15 +++- auth-oauth/config.php | 34 +++++++- auth-oauth/generic-oauth2.php | 153 ++++++++++++++++++++++++++++++++++ auth-oauth/google.php | 17 ++-- auth-oauth/plugin.php | 8 +- 5 files changed, 212 insertions(+), 15 deletions(-) create mode 100644 auth-oauth/generic-oauth2.php diff --git a/auth-oauth/authentication.php b/auth-oauth/authentication.php index 9adc349..c2efc46 100644 --- a/auth-oauth/authentication.php +++ b/auth-oauth/authentication.php @@ -21,6 +21,19 @@ function bootstrap() { UserAuthenticationBackend::register( new GoogleClientAuthBackend($this->getConfig())); } + + # ----- Generic OAuth2 --------------------- + $generic = $config->get('generic-enabled'); + if (in_array($generic, array('all', 'staff'))) { + require_once('generic-oauth2.php'); + StaffAuthenticationBackend::register( + new GenericOAuth2StaffAuthBackend($this->getConfig())); + } + if (in_array($generic, array('all', 'client'))) { + require_once('generic-oauth2.php'); + UserAuthenticationBackend::register( + new GenericOAuth2AuthBackend($this->getConfig())); + } } } @@ -29,4 +42,4 @@ function bootstrap() { $loader = new UniversalClassLoader_osTicket(); $loader->registerNamespaceFallbacks(array( dirname(__file__).'/lib')); -$loader->register(); +$loader->register(); \ No newline at end of file diff --git a/auth-oauth/config.php b/auth-oauth/config.php index 2f76742..838bea0 100644 --- a/auth-oauth/config.php +++ b/auth-oauth/config.php @@ -40,6 +40,38 @@ function getOptions() { 'configuration' => array('size'=>60, 'length'=>100), )), 'g-enabled' => clone $modes, + 'generic' => new SectionBreakField(array( + 'label' => $__('Generic OAuth2'), + )), + 'generic-servicename' => new TextboxField(array( + 'label' => $__('Service name'), + 'configuration' => array('size'=>60, 'length'=>200), + )), + 'generic-client-id' => new TextboxField(array( + 'label' => $__('Client ID'), + 'configuration' => array('size'=>60, 'length'=>200), + )), + 'generic-client-secret' => new TextboxField(array( + 'label' => $__('Client Secret'), + 'configuration' => array('size'=>60, 'length'=>200), + )), + 'generic-authorize-url' => new TextboxField(array( + 'label' => $__('Authorize URL'), + 'configuration' => array('size'=>60, 'length'=>200), + )), + 'generic-token-url' => new TextboxField(array( + 'label' => $__('Token URL'), + 'configuration' => array('size'=>60, 'length'=>200), + )), + 'generic-userinfo-url' => new TextboxField(array( + 'label' => $__('User JSON URL'), + 'configuration' => array('size'=>60, 'length'=>200), + )), + 'generic-scope' => new TextboxField(array( + 'label' => $__('Scope'), + 'configuration' => array('size'=>60, 'length'=>200), + )), + 'generic-enabled' => clone $modes, ); } -} +} \ No newline at end of file diff --git a/auth-oauth/generic-oauth2.php b/auth-oauth/generic-oauth2.php new file mode 100644 index 0000000..2338397 --- /dev/null +++ b/auth-oauth/generic-oauth2.php @@ -0,0 +1,153 @@ +config = $config; + } + + function triggerAuth() { + $self = $this; + global $ost; + return Auth2::legs(3) + ->set('id', $this->config->get('generic-client-id')) + ->set('secret', $this->config->get('generic-client-secret')) + ->set('redirect', rtrim($ost->getConfig()->getURL(), '/') . '/api/auth/ext') + ->set('scope', $this->config->get('generic-scope')) + + ->authorize($this->config->get('generic-authorize-url')) + ->access($this->config->get('generic-token-url')) + ->finally(function($data) use ($self) { + $self->access_token = $data['access_token']; + }); + } +} + +class GenericOAuth2StaffAuthBackend extends ExternalStaffAuthenticationBackend { + static $id = "oauth"; + static $name = "OAuth2"; + + static $sign_in_image_url = ""; + + var $config; + + function __construct($config) { + $this->config = $config; + $this->oauth = new GenericOAuth($config); + } + + function getServiceName() { + return $this->config->get('generic-servicename'); + } + + function signOn() { + // TODO: Check session for auth token + if (isset($_SESSION[':oauth']['profile']['nickname'])) { + if (($staff = StaffSession::lookup($_SESSION[':oauth']['profile']['nickname'])) + && $staff->getId() + ) { + $staffobject = $staff; + } + } elseif (isset($_SESSION[':oauth']['profile']['email'])) { + if (($staff = StaffSession::lookup(array('email' => $_SESSION[':oauth']['profile']['email']))) + && $staff->getId() + ) { + $staffobject = $staff; + } + } + if (isset($staffobject)) { + if (!$staffobject instanceof StaffSession) { + // osTicket <= v1.9.7 or so + $staffobject = new StaffSession($user->getId()); + } + return $staffobject; + } else { + $_SESSION['_staff']['auth']['msg'] = 'Have your administrator create a local account'; + } + } + + static function signOut($user) { + parent::signOut($user); + unset($_SESSION[':oauth']); + } + + + function triggerAuth() { + parent::triggerAuth(); + $oauth = $this->oauth->triggerAuth(); + $oauth->GET( + $this->config->get('generic-userinfo-url'), [], array('Authorization' => 'Bearer ' . $this->oauth->access_token)) + ->then(function($response) { + if (!($json = JsonDataParser::decode($response->text))) + return; + $_SESSION[':oauth']['profile'] = $json; + Http::redirect(ROOT_PATH . 'scp'); + } + ); + } +} + +class GenericOAuth2AuthBackend extends ExternalUserAuthenticationBackend { + static $id = "oauth.client"; + static $name = "OAuth2"; + + static $sign_in_image_url = ""; + + function __construct($config) { + $this->config = $config; + $this->oauth = new GenericOAuth($config); + } + + function getServiceName() { + return $this->config->get('generic-servicename'); + } + + function supportsInteractiveAuthentication() { + return false; + } + + function signOn() { + // TODO: Check session for auth token + if (isset($_SESSION[':oauth']['profile']['email'])) { + if (($acct = ClientAccount::lookupByUsername($_SESSION[':oauth']['profile']['email'])) + && $acct->getId() + && ($client = new ClientSession(new EndUser($acct->getUser())))) + return $client; + + elseif (isset($_SESSION[':oauth']['profile'])) { + // TODO: Prepare ClientCreateRequest + $profile = $_SESSION[':oauth']['profile']; + $info = array( + 'email' => $profile['email'], + 'name' => $profile['displayName'], + ); + return new ClientCreateRequest($this, $info['email'], $info); + } + } + } + + static function signOut($user) { + parent::signOut($user); + unset($_SESSION[':oauth']); + } + + function triggerAuth() { + require_once INCLUDE_DIR . 'class.json.php'; + parent::triggerAuth(); + $oauth = $this->oauth->triggerAuth(); + $oauth->GET( + $this->config->get('generic-userinfo-url'), [], array('Authorization' => 'Bearer ' . $this->oauth->access_token)) + ->then(function($response) { + if (!($json = JsonDataParser::decode($response->text))) + return; + $_SESSION[':oauth']['profile'] = $json; + Http::redirect(ROOT_PATH . 'login.php'); + } + ); + } +} + diff --git a/auth-oauth/google.php b/auth-oauth/google.php index d79d04e..20dda7d 100644 --- a/auth-oauth/google.php +++ b/auth-oauth/google.php @@ -70,14 +70,14 @@ function triggerAuth() { $google = $this->google->triggerAuth(); $google->GET( "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" - . $this->google->access_token) + . $this->google->access_token) ->then(function($response) { require_once INCLUDE_DIR . 'class.json.php'; if ($json = JsonDataParser::decode($response->text)) $_SESSION[':oauth']['email'] = $json['email']; Http::redirect(ROOT_PATH . 'scp'); } - ); + ); } } @@ -101,8 +101,8 @@ function signOn() { // TODO: Check session for auth token if (isset($_SESSION[':oauth']['email'])) { if (($acct = ClientAccount::lookupByUsername($_SESSION[':oauth']['email'])) - && $acct->getId() - && ($client = new ClientSession(new EndUser($acct->getUser())))) + && $acct->getId() + && ($client = new ClientSession(new EndUser($acct->getUser())))) return $client; elseif (isset($_SESSION[':oauth']['profile'])) { @@ -129,24 +129,23 @@ function triggerAuth() { $token = $this->google->access_token; $google->GET( "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" - . $token) + . $token) ->then(function($response) use ($google, $token) { if (!($json = JsonDataParser::decode($response->text))) return; $_SESSION[':oauth']['email'] = $json['email']; $google->GET( "https://www.googleapis.com/plus/v1/people/me?access_token=" - . $token) + . $token) ->then(function($response) { if (!($json = JsonDataParser::decode($response->text))) return; $_SESSION[':oauth']['profile'] = $json; Http::redirect(ROOT_PATH . 'login.php'); } - ); + ); } - ); + ); } } - diff --git a/auth-oauth/plugin.php b/auth-oauth/plugin.php index 589d273..f6d8cd2 100644 --- a/auth-oauth/plugin.php +++ b/auth-oauth/plugin.php @@ -2,13 +2,13 @@ return array( 'id' => 'auth:oath2', # notrans - 'version' => '0.1', + 'version' => '0.2', 'name' => /* trans */ 'Oauth2 Authentication and Lookup', - 'author' => 'Jared Hancock', + 'author' => 'Jared Hancock, Andreas Valder', 'description' => /* trans */ 'Provides a configurable authentication backend for authenticating staff and clients using an OAUTH2 server interface.', - 'url' => 'http://www.osticket.com/plugins/auth/oauth', + 'url' => 'https://github.com/osTicket/osTicket-plugins', 'plugin' => 'authentication.php:OauthAuthPlugin', 'requires' => array( "ohmy/auth" => array( @@ -20,4 +20,4 @@ interface.', ), ); -?> +?> \ No newline at end of file