Skip to content

Commit

Permalink
Merge pull request #20 from ristekusdi/fix-ci3
Browse files Browse the repository at this point in the history
Fix SSO Service and Stubs for CodeIgniter 3
  • Loading branch information
kresnasatya authored Jun 27, 2024
2 parents 21a549f + fe90c19 commit d732861
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 97 deletions.
36 changes: 15 additions & 21 deletions src/Services/SSOService.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,6 @@ protected function getState()
*/
public function retrieveToken()
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
}

if (isset($_SESSION[self::SSO_SESSION_IMPERSONATE])) {
return $_SESSION[self::SSO_SESSION_IMPERSONATE];
} else if (isset($_SESSION[self::SSO_SESSION])) {
Expand Down Expand Up @@ -204,7 +200,7 @@ public function retrieveImpersonateToken()
public function saveToken($credentials)
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
throw new Exception("Cannot save token. Please start session!", 500);
}

$decoded_access_token = (new AccessToken($credentials))->parseAccessToken();
Expand All @@ -229,19 +225,17 @@ public function saveToken($credentials)
*/
public function forgetToken()
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
}

// Remove all session variables.
if (isset($_SESSION[self::SSO_SESSION_IMPERSONATE])) {
$this->forgetImpersonateToken();
} else {
} else if (isset($_SESSION[self::SSO_SESSION])) {
unset($_SESSION[self::SSO_SESSION]);
}

// Destroy the session
session_destroy();
if (session_status() === PHP_SESSION_ACTIVE) {
session_destroy();
}
}

/**
Expand All @@ -262,8 +256,9 @@ public function forgetImpersonateToken()
public function validateState($state)
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
throw new Exception("Cannot validate state. Please start session!", 500);
}

$challenge = $_SESSION[self::SSO_SESSION_STATE];
return (! empty($state) && ! empty($challenge) && $challenge === $state);
}
Expand All @@ -276,8 +271,9 @@ public function validateState($state)
public function saveState()
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
throw new Exception("Cannot save state. Please start session!", 500);
}

$_SESSION[self::SSO_SESSION_STATE] = $this->state;
}

Expand All @@ -288,15 +284,13 @@ public function saveState()
*/
public function forgetState()
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
if (session_status() === PHP_SESSION_ACTIVE) {
// Remove all session variables.
session_unset();

// Destroy the session
session_destroy();
}

// Remove all session variables.
session_unset();

// Destroy the session
session_destroy();
}

/**
Expand Down
81 changes: 47 additions & 34 deletions stubs/ci3/controllers/Webauth.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
use RistekUSDI\SSO\PHP\Exceptions\CallbackException;
use RistekUSDI\SSO\PHP\Services\SSOService;
use RistekUSDI\SSO\PHP\Auth\Guard\WebGuard;
use RistekUSDI\SSO\PHP\Auth\AccessToken;

class Webauth extends CI_Controller {

public function __construct()
{
parent::__construct();
$this->CI =& get_instance();
$this->load->helper('url');
$this->load->library('session');
}

public function login()
Expand Down Expand Up @@ -60,7 +59,7 @@ public function callback()
// You may need to create a custom session for your internal app
$this->createSession();

redirect('/home');
redirect('home', 'location', 301);
} catch (\Exception $e) {
throw new CallbackException($e->getCode(), $e->getMessage());
}
Expand All @@ -82,51 +81,65 @@ public function impersonate()

$this->createSession();

redirect('/home');
redirect('home', 'location', 301);
} catch (\Throwable $th) {
echo "Status code: {$th->getCode()} \n";
echo "Error message: {$th->getMessage()}\n";
die();
}
}

/**
* You may be create a session to get roles and permission that belongs to each role.
* After user logged in, they may have list of roles based on a client (app) that stored in client_roles property.
* Use "client_roles" property as parameter to get roles and permissions in your app database.
* Expected result is a serialize of array that store in a session called serialize session.
* The array contains:
* - roles (list of roles with permissions belongs to each role)
* - role (active or current role)
*/
private function createSession()
{
$client_roles = (new WebGuard)->user()->client_roles;

$roles = $this->db->query("SELECT role_id AS id, role_name as `name` FROM rbac_roles
WHERE rbac_roles.role_name IN ?", array($client_roles))->result();

foreach ($roles as $key => $role) {
$role_permissions = $this->db->query("SELECT rbac_permissions.perm_desc
FROM rbac_permissions
INNER JOIN rbac_role_perm ON rbac_role_perm.perm_id = rbac_permissions.perm_id
WHERE rbac_role_perm.`role_id` = ?", array($role->id))->result_array();

$roles[$key]->permissions = array_column($role_permissions, 'perm_desc');
}

// NOTE: You maybe want to get roles from your database by using $client_roles
// and put permissions to each role.
// Here's is example of result.
$roles = json_decode(json_encode([
[
'id' => 1,
'name' => 'Operator',
'permissions' => [
'user:view',
'user:edit',
]
],
[
'id' => 2,
'name' => 'User',
'permissions' => [
'profile:view',
'profile:edit',
]
],
]));
// Here's is the expected result.
// $roles = json_decode(json_encode([
// [
// 'id' => 1,
// 'name' => 'Operator',
// 'permissions' => [
// 'user:view',
// 'user:edit',
// ]
// ],
// [
// 'id' => 2,
// 'name' => 'User',
// 'permissions' => [
// 'profile:view',
// 'profile:edit',
// ]
// ],
// ]));

$serialize_session = serialize(array(
$_SESSION['serialize_session'] = serialize(array(
'roles' => $roles,
'role' => $roles[0],
));

// PHP_SESSION_NONE if sessions are enabled, but none exists.
// https://www.php.net/manual/en/function.session-status.php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}

$_SESSION['serialize_session'] = $serialize_session;
'role' => $roles[0], // This is a active or current role
));
}

/**
Expand Down
60 changes: 18 additions & 42 deletions stubs/ci3/libraries/Webguard.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<?php

use RistekUSDI\SSO\PHP\Exceptions\CallbackException;
use RistekUSDI\SSO\PHP\Services\SSOService;
use RistekUSDI\SSO\PHP\Auth\Guard\WebGuard as Guard;
use RistekUSDI\SSO\PHP\Auth\AccessToken;

class Webguard {

private $user;
private $ci;

public function __construct()
{
$ci =& get_instance();
$this->ci = $ci;
$this->ci->load->library('session');
$this->user = (new Guard)->user();
}

Expand All @@ -26,7 +28,13 @@ public function authenticated()

public function check()
{
return (new Guard())->check();
$credentials = (new SSOService())->retrieveToken();
if ($credentials) {
$user = (new SSOService)->getUserProfile($credentials);
return $user ? true : false;
} else {
return false;
}
}

public function guest()
Expand All @@ -48,55 +56,23 @@ public function get()
return $this->user;
}

/**
* Check if user has specific role
* @return boolean
*/
public function hasRole($role)
public function hasRole($roles)
{
$result = false;
$roles_attr = $this->user->roles;
$role_names = array_column($roles_attr, 'name');
if (is_array($role)) {
$roles = $role;
$result = !empty(array_intersect($role_names , (array) $roles));
} else {
$result = in_array($role, $role_names) ? true : false;
}

$result = empty(array_diff((array) $roles, $this->user()->get()->roles));
$this->user->hasRole = $result;
return $this->user->hasRole;
}

/**
* Check if user has permission(s) from specific role
* @return boolean
*/
public function hasPermission($permission)
public function hasPermission($permissions)
{
$result = false;
$role_permissions = [];
if (isset($this->user->role->permissions)) {
foreach ($this->user->role->permissions as $perm) {
array_push($role_permissions, $perm);
}
}

if (is_array($permission)) {
$permissions = $permission;

$result = !empty(array_intersect((array) $role_permissions, (array) $permissions));
} else {
$result = in_array($permission, $role_permissions) ? true : false;
}

$result = !empty(array_intersect((array) $permissions, $this->user->role->permissions));
$this->user->hasPermission = $result;
return $this->user->hasPermission;
}

public function restrictAjax()
public function restrictAjaxLogin()
{
if (!$this->is_logged_in()) {
if (!$this->check()) {
$response['submit'] = 403;
$response['error'] = 'Your session has been expired, please login again';
header('Content-Type: application/json; charset=utf-8');
Expand Down

0 comments on commit d732861

Please sign in to comment.