openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit c1d457911fd8dbf5d1b7f6b9d3d394afed213fa4
parent 05e6df939cb50575a11a4e5a7d9e8db801c16742
Author: Jan Dankert <develop@jandankert.de>
Date:   Thu, 28 Apr 2022 00:28:24 +0200

New: Login with Json webtoken (JWT)

Diffstat:
Mmodules/cms/Dispatcher.class.php | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mmodules/cms/action/RequestParams.class.php | 20++++++++++++++------
Mmodules/cms/base/DefaultConfig.class.php | 7++++++-
Mmodules/util/json/JSON.class.php | 6+++---
4 files changed, 79 insertions(+), 16 deletions(-)

diff --git a/modules/cms/Dispatcher.class.php b/modules/cms/Dispatcher.class.php @@ -173,13 +173,63 @@ class Dispatcher private function checkLogin() { if ( $this->request->withAuthorization ) { - $userAuth = new InternalAuth(); - $status = $userAuth->login( $this->request->authUser,$this->request->authPassword,'' ); - if ( ! ($status & Auth::STATUS_SUCCESS) ) - throw new SecurityException('user cannot be authenticated'); + $securityConfig = Configuration::subset('security'); + $authConfig = $securityConfig->subset('authorization'); - $user = User::loadWithName( $this->request->authUser,User::AUTH_TYPE_INTERNAL ); - Request::setUser( $user ); + if ( $this->request->authUser ) { + if ( ! $authConfig->is('basic')) + throw new SecurityException('Basic Authorization is disabled'); + + $userAuth = new InternalAuth(); + $status = $userAuth->login( $this->request->authUser,$this->request->authPassword,'' ); + if ( ! ($status & Auth::STATUS_SUCCESS) ) + throw new SecurityException('user cannot be authenticated'); + + $user = User::loadWithName( $this->request->authUser,User::AUTH_TYPE_INTERNAL ); + Request::setUser( $user ); + } + elseif ( $authToken = $this->request->authToken ) { + if ( ! $authConfig->is('bearer')) + throw new SecurityException('Bearer Authorization is disabled'); + + // We are expecting a JSON webtoken here + function base64url_decode( $data ){ + return base64_decode( strtr( $data, '-_', '+/') . str_repeat('=', 3 - ( 3 + strlen( $data )) % 4 )); + } + + list( $b64Header,$b64Payload,$signature ) = array_pad(explode('.',$authToken),3,''); + $header = JSON::decode( base64url_decode($b64Header) ); + $supportedAlgos = [ + 'HS256' => 'sha256', + 'HS384' => 'sha384', + 'HS512' => 'sha512', + ]; + if ( ! $algo = @$supportedAlgos[ @$header['alg'] ] ) + throw new SecurityException('Unknown algorithm in JWT, only supporting: '.implode(',',array_keys($supportedAlgos) )); + elseif( ! in_array( $algo,hash_algos() ) ) + throw new SecurityException('Unsupported algorithm'); + elseif( hash_hmac( $algo,$b64Header.'.'.$b64Payload,$securityConfig->get('key'),true) != base64url_decode($signature) ) + throw new SecurityException('Signature does not match'); + + $payload = JSON::decode( base64url_decode($b64Payload)); + + if ( $notBefore = @$payload['nbf'] ) + if ( $notBefore < Startup::getStartTime() ) + throw new SecurityException('token is not valid'); + + if ( $expires = @$payload['exp'] ) + if ( $expires > Startup::getStartTime() ) + throw new SecurityException('token is not valid'); + + if ( $subject = @$payload['sub'] ) { + if ( $user = User::loadWithName( $subject,User::AUTH_TYPE_INTERNAL ) ) + Request::setUser( $user ); + else + throw new SecurityException('User not found'); + } + else + throw new SecurityException('User not found'); + } } } diff --git a/modules/cms/action/RequestParams.class.php b/modules/cms/action/RequestParams.class.php @@ -35,6 +35,7 @@ class RequestParams public $headers; public $authUser; public $authPassword; + public $authToken; private $parameter; @@ -397,12 +398,19 @@ class RequestParams if ( $auth = @$this->headers['authorization'] ) { $this->withAuthorization = true; - if ( substr( $auth,0,6 ) == 'Basic ' ) - list($this->authUser,$this->authPassword) = explode(':',base64_decode( substr( $this->headers['authorization'],6) ) ); - else - // Only supporting Basic Auth - // Maybe in the future we will support JWT Bearer tokens... - error_log('Only supporting basic authorization. Authorization header will be ignored.'); + list( $type,$value ) = array_pad( explode(' ',$auth),2,''); + switch( $type ) { + case 'Basic': + list($this->authUser,$this->authPassword) = array_pad(explode(':',base64_decode( $value )),2,'' ); + break; + case 'Bearer': + $this->authToken = $value; + break; + default: + // Only supporting Basic Auth and Bearer Auth + error_log('Only supporting Basic and Bearer authorization. Authorization header will be ignored.'); + } + } } } \ No newline at end of file diff --git a/modules/cms/base/DefaultConfig.class.php b/modules/cms/base/DefaultConfig.class.php @@ -348,7 +348,12 @@ class DefaultConfig { ], ], 'security' => - [ + [ + 'key' => 'OAp5M3GYvm2U7r1FEdvVhqDBxJjMTWgKvN8VfJrHLa7D9pVdrYkMyA', + 'authorization' => [ + 'basic' => true, + 'bearer' => false, + ], 'cookie' => [ 'secure' => false, diff --git a/modules/util/json/JSON.class.php b/modules/util/json/JSON.class.php @@ -32,10 +32,10 @@ class JSON } public static function decode($jsonText) { - if (!function_exists('json_decode')) { - return json_decode( $jsonText ); + if (function_exists('json_decode')) { + return json_decode( $jsonText,true ); } else { - $json = new \JSON(); + $json = new JSON(); return $json->decode($jsonText); } }