From d342a7b1af3385565fe05ff19b277b9e7826b00b Mon Sep 17 00:00:00 2001 From: nd Date: Fri, 22 Jan 2021 15:05:44 +0100 Subject: [PATCH] Add generic OAuth backend to auth-oauth --- auth-oauth/authentication.php | 13 +++ auth-oauth/config.php | 32 +++++++ auth-oauth/generic-oauth2.php | 154 ++++++++++++++++++++++++++++++++++ auth-oauth/plugin.php | 6 +- 4 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 auth-oauth/generic-oauth2.php diff --git a/auth-oauth/authentication.php b/auth-oauth/authentication.php index 9adc349..d27ff56 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())); + } } } diff --git a/auth-oauth/config.php b/auth-oauth/config.php index 2f76742..54b28ae 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, ); } } diff --git a/auth-oauth/generic-oauth2.php b/auth-oauth/generic-oauth2.php new file mode 100644 index 0000000..d153e0c --- /dev/null +++ b/auth-oauth/generic-oauth2.php @@ -0,0 +1,154 @@ +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/plugin.php b/auth-oauth/plugin.php index 589d273..6d909f4 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(