Create auth bundle with base classes for User and Role. Use base class for user and role in the User and Role entities in the API and the main site. #194

This commit is contained in:
Korina Cordero 2019-03-27 06:57:20 +00:00
parent d4cfa42c61
commit eaac1dfb7d
19 changed files with 198 additions and 688 deletions

View file

@ -1,7 +0,0 @@
<?php
namespace Authentication\AuthBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AuthBundle extends Bundle

View file

@ -1,120 +0,0 @@
<?php
namespace Authentication\AuthBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity
* @ORM\Table(name="api_role")
* @UniqueEntity("id")
* @UniqueEntity("name")
*/
class APIRole
{
const SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
/**
* @ORM\Id
* @ORM\Column(type="string", length=80)
* @Assert\NotBlank()
*/
protected $id;
/**
* @ORM\Column(type="string", length=80)
* @Assert\NotBlank()
*/
protected $name;
/**
* @ORM\ManyToMany(targetEntity="User", mappedBy="roles", fetch="EXTRA_LAZY")
*/
protected $users;
/**
* @ORM\Column(type="json_array")
*/
protected $acl_attributes;
public function __construct()
{
$this->users = new ArrayCollection();
$this->acl_attributes = [];
}
public function setID($id)
{
// example ROLE_SUPER_ADMIN, ROLE_CASHIER, etc
$this->id = $id;
return $this;
}
public function getID()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
public function getUsers()
{
return $this->users;
}
public function getUsersCount()
{
return $this->users->count();
}
public function isSuperAdmin()
{
if ($this->id == self::SUPER_ADMIN)
return true;
return false;
}
// TODO: shift out ACL stuff to its own class
public function clearACLAttributes()
{
$this->acl_attributes = [];
return $this;
}
public function getACLAttributes()
{
return $this->acl_attributes;
}
public function addACLAccess($attribute)
{
$this->acl_attributes[$attribute] = true;
return $this;
}
public function hasACLAccess($attribute)
{
// if it's super admin, they always have access
if ($this->isSuperAdmin())
return true;
// check ACL attributes
if (isset($this->acl_attributes[$attribute]) && $this->acl_attributes[$attribute])
return true;
return false;
}
}

View file

@ -1,156 +0,0 @@
<?php
namespace Catalyst\APIBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\Common\Collections\ArrayCollection;
use DateTime;
/**
* @ORM\Entity
* @ORM\Table(name="api_user")
*/
class APIUser implements UserInterface
{
// api key
/**
* @ORM\Id
* @ORM\Column(type="string", length=32)
*/
protected $api_key;
// secret key
/**
* @ORM\Column(type="string", length=32)
*/
protected $secret_key;
/**
* @ORM\Column(type="string", length=80)
*/
protected $name;
// date created
/**
* @ORM\Column(type="datetime")
*/
protected $date_create;
// roles
/**
* @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
* @ORM\JoinTable(name="api_user_role",
* joinColumns={@JoinColumn(name="user_api_key", referencedColumnName="api_key")},
* inverseJoinColumns={@JoinColumn(name="role_id", referencedColumnName="id")})
*/
protected $roles;
public function __construct()
{
// generate keys
$this->setAPIKey($this->generateAPIKey())
->setSecretKey($this->generateSecretKey());
// set date created
$this->date_create = new DateTime();
$this->roles = new ArrayCollection();
}
public function getID()
{
return $this->id;
}
public function setAPIKey($api_key)
{
$this->api_key = $api_key;
return $this;
}
public function getAPIKey()
{
return $this->api_key;
}
public function setSecretKey($key)
{
$this->secret_key = $key;
return $this;
}
public function getSecretKey()
{
return $this->secret_key;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
public function getRoles()
{
$str_roles = [];
foreach ($this->roles as $role)
$str_roles[] = $role->getID();
return $str_roles;
}
public function getRoleObjects()
{
return $this->roles;
}
public function getDateCreate()
{
return $this->date_create;
}
public function getPassword()
{
// we don't need this for API
return 'notneeded';
}
public function getSalt()
{
return null;
}
public function getUsername()
{
// since it's an api, the api key IS the username
return $this->api_key;
}
public function eraseCredentials()
{
return;
}
public function generateAPIKey()
{
return $this->generateKey('api');
}
public function generateSecretKey()
{
return $this->generateKey('secret');
}
protected function generateKey($prefix = '')
{
return md5(uniqid($prefix, true));
}
}

View file

@ -1,337 +0,0 @@
<?php
namespace App\Entity;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Serializable;
/**
* @ORM\Entity
* @ORM\Table(name="user")
* @UniqueEntity("username")
* @UniqueEntity("email")
*/
class User implements AdvancedUserInterface, Serializable
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=80, unique=true)
* @Assert\NotBlank()
*
*/
protected $username;
/**
* @ORM\Column(type="string", length=64)
*/
protected $password;
/**
* @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
* @ORM\JoinTable(name="user_role")
*/
protected $roles;
/**
* @ORM\ManyToMany(targetEntity="Hub", inversedBy="users")
* @ORM\JoinTable(name="user_hubs")
*/
protected $hubs;
/**
* @ORM\Column(type="boolean")
*/
protected $enabled;
/**
* @ORM\Column(type="string", length=50, nullable=true)
*/
protected $first_name;
/**
* @ORM\Column(type="string", length=50, nullable=true)
*/
protected $last_name;
/**
* @ORM\Column(type="string", length=20, nullable=true)
*/
protected $contact_num;
/**
* @ORM\Column(type="string", length=50, unique=true, nullable=true)
*/
protected $email;
// job orders made by this user
/**
* @ORM\OneToMany(targetEntity="JobOrder", mappedBy="created_by")
*/
protected $job_orders_created;
// job orders assigned by this user
/**
* @ORM\OneToMany(targetEntity="JobOrder", mappedBy="assigned_by")
*/
protected $job_orders_assigned;
// job orders processed or being processed by this user
/**
* @ORM\OneToMany(targetEntity="JobOrder", mappedBy="processed_by")
*/
protected $job_orders_processed;
// tickets made by this user
/**
* @ORM\OneToMany(targetEntity="Ticket", mappedBy="created_by")
*/
protected $tickets;
// invoices made by this user
/**
* @ORM\OneToMany(targetEntity="Invoice", mappedBy="created_by")
*/
protected $invoices;
public function __construct()
{
$this->roles = new ArrayCollection();
$this->hubs = new ArrayCollection();
$this->job_orders_created = new ArrayCollection();
$this->job_orders_assigned = new ArrayCollection();
$this->tickets = new ArrayCollection();
$this->enabled = true;
}
public function getID()
{
return $this->id;
}
public function setUsername($username)
{
$this->username = $username;
return $this;
}
public function getUsername()
{
return $this->username;
}
public function setPassword($password)
{
$this->password = $password;
return $this;
}
public function getPassword()
{
return $this->password;
}
public function setSalt($salt)
{
// do nothing
return $this;
}
public function getSalt()
{
return null;
}
public function addRole(Role $role)
{
$this->roles->add($role);
return $this;
}
public function clearRoles()
{
$this->roles->clear();
return $this;
}
public function getRoles()
{
// has to return set of strings because symfony is trying to move away from role objects
$str_roles = [];
foreach ($this->roles as $role)
$str_roles[] = $role->getID();
return $str_roles;
}
public function getRoleObjects()
{
return $this->roles;
}
public function addHub(Hub $hub)
{
$this->hubs->add($hub);
return $this;
}
public function clearHubs()
{
$this->hubs->clear();
return $this;
}
public function getHubs()
{
$str_hubs = [];
foreach ($this->hubs as $hub)
$str_hubs[] = $hub->getID();
return $str_hubs;
}
public function getHubObjects()
{
return $this->hubs;
}
public function eraseCredentials()
{
return $this;
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
public function setEnabled($enabled = true)
{
$this->enabled = $enabled;
return $this;
}
public function isEnabled()
{
return $this->enabled;
}
public function serialize()
{
return serialize([
$this->id,
$this->username,
$this->password,
$this->enabled,
]);
}
public function unserialize($serial)
{
list (
$this->id,
$this->username,
$this->password,
$this->enabled,
) = unserialize($serial);
}
public function setFirstName($name)
{
$this->first_name = $name;
return $this;
}
public function getFirstName()
{
return $this->first_name;
}
public function setLastName($name)
{
$this->last_name = $name;
return $this;
}
public function getLastName()
{
return $this->last_name;
}
public function getFullName()
{
return $this->first_name . ' ' . $this->last_name;
}
public function setContactNumber($num)
{
$this->contact_num = $num;
return $this;
}
public function getContactNumber()
{
return $this->contact_num;
}
public function setEmail($email = null)
{
$this->email = $email;
return $this;
}
public function getEmail()
{
return $this->email;
}
public function isSuperAdmin()
{
foreach ($this->roles as $role)
{
if ($role->isSuperAdmin())
return true;
}
return false;
}
public function getJobOrdersCreated()
{
return $this->job_orders_created;
}
public function getJobOrdersAssigned()
{
return $this->job_orders_assigned;
}
public function getTickets()
{
return $this->tickets;
}
public function getInvoices()
{
return $this->invoices;
}
}

View file

@ -2,6 +2,8 @@
namespace Catalyst\APIBundle\Entity; namespace Catalyst\APIBundle\Entity;
use Catalyst\AuthBundle\Entity\Role as BaseRole;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
@ -13,7 +15,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
* @UniqueEntity("id") * @UniqueEntity("id")
* @UniqueEntity("name") * @UniqueEntity("name")
*/ */
class Role class Role extends BaseRole
{ {
const SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; const SUPER_ADMIN = 'ROLE_SUPER_ADMIN';

View file

@ -2,6 +2,8 @@
namespace Catalyst\APIBundle\Entity; namespace Catalyst\APIBundle\Entity;
use Catalyst\AuthBundle\Entity\User as BaseUser;
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\JoinColumn; use Doctrine\ORM\Mapping\JoinColumn;
@ -12,7 +14,7 @@ use DateTime;
* @ORM\Entity * @ORM\Entity
* @ORM\Table(name="api_user") * @ORM\Table(name="api_user")
*/ */
class User implements UserInterface class User extends BaseUser implements UserInterface
{ {
// api key // api key
/** /**
@ -97,19 +99,19 @@ class User implements UserInterface
return $this->name; return $this->name;
} }
public function getRoles() //public function getRoles()
{ //{
$str_roles = []; // $str_roles = [];
foreach ($this->roles as $role) // foreach ($this->roles as $role)
$str_roles[] = $role->getID(); // $str_roles[] = $role->getID();
return $str_roles; // return $str_roles;
} //}
public function getRoleObjects() //public function getRoleObjects()
{ //{
return $this->roles; // return $this->roles;
} //}
public function getDateCreate() public function getDateCreate()
{ {

View file

@ -0,0 +1,111 @@
<?php
namespace Catalyst\AuthBundle\Access;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Config\ConfigCache;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Routing\RouterInterface;
class Generator
{
// TODO: make api_acl and acl yaml generator have its own bundle
protected $router;
protected $cache_dir;
protected $config_dir;
public function __construct(RouterInterface $router, string $cache_dir, string $config_dir)
{
$this->router = $router;
$this->cache_dir = $cache_dir;
$this->config_dir = $config_dir;
}
public function getACL()
{
$key = 'api_access_keys';
// cache config
$cache_file = $this->cache_dir . '/' . $key . '.serial';
$cache = new ConfigCache($cache_file, true);
// check if cache is fresh
if (!$cache->isFresh())
{
$files = [];
$resources = [];
try
{
// get location of api_acl.yaml
$path = $this->config_dir . '/api_acl.yaml';
$files[] = $path;
$resources[] = new FileResource($path);
// process api acl config file
$data = $this->parseACL($path, $key);
}
catch (\InvalidArgumentException $e)
{
error_log($e->getMessage());
error_log($key . ' key not found in api_acl.yaml file.');
return $data;
}
$acl_serial = serialize($data);
$cache->write($acl_serial, $resources);
}
else
{
$acl_serial = file_get_contents($cache_file);
$data = unserialize($acl_serial);
}
return $data;
}
protected function parseACL($path, $key)
{
$parser = new YamlParser();
$config = $parser->parse(file_get_contents($path));
// check if we have access keys
if (!isset($config[$key]))
{
error_log('No ' . $key . ' found for ' . $path);
return;
}
$acl_hierarchy = [];
$acl_index = [];
// go through each one
foreach ($config[$key] as $acl_data)
{
// build hierarchy
$acl_hierarchy[$acl_data['id']] = [
'label' => $acl_data['label'],
'acls' => []
];
foreach ($acl_data['acls'] as $acl)
{
$id = $acl['id'];
$label = $acl['label'];
// set hierarchy and index
$acl_hierarchy[$acl_data['id']]['acls'][$id] = $label;
$acl_index[$id] = $label;
}
}
return [
'hierarchy' => $acl_hierarchy,
'index' => $acl_index
];
}
}

View file

@ -1,6 +1,6 @@
<?php <?php
namespace Catalyst\APIBundle\Access; namespace Catalyst\AuthBundle\Access;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter as BaseVoter; use Symfony\Component\Security\Core\Authorization\Voter\Voter as BaseVoter;

View file

@ -0,0 +1,9 @@
<?php
namespace Catalyst\AuthBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class CatalystAuthBundle extends Bundle
{
}

View file

@ -1,43 +1,16 @@
<?php <?php
namespace App\Entity; namespace Catalyst\AuthBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/** abstract class Role
* @ORM\Entity
* @ORM\Table(name="role")
* @UniqueEntity("id")
* @UniqueEntity("name")
*/
class Role
{ {
const SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; const SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
/**
* @ORM\Id
* @ORM\Column(type="string", length=80)
* @Assert\NotBlank()
*/
protected $id; protected $id;
/**
* @ORM\Column(type="string", length=80)
* @Assert\NotBlank()
*/
protected $name; protected $name;
/**
* @ORM\ManyToMany(targetEntity="User", mappedBy="roles", fetch="EXTRA_LAZY")
*/
protected $users; protected $users;
/**
* @ORM\Column(type="json_array")
*/
protected $acl_attributes; protected $acl_attributes;
public function __construct() public function __construct()

View file

@ -0,0 +1,28 @@
<?php
namespace Catalyst\AuthBundle\Entity;
abstract class User
{
protected $roles;
public function __construct()
{
$this->roles = new ArrayCollection();
}
public function getRoles()
{
$str_roles = [];
foreach ($this->roles as $role)
$str_roles[] = $role->getID();
return $str_roles;
}
public function getRoleObjects()
{
return $this->roles;
}
}

View file

@ -39,7 +39,8 @@
"psr-4": { "psr-4": {
"App\\": "src/", "App\\": "src/",
"Catalyst\\APIBundle\\": "catalyst/api-bundle/", "Catalyst\\APIBundle\\": "catalyst/api-bundle/",
"RamcarBattery\\APIBundle\\": "ramcar-batery/api-bundle/" "RamcarBattery\\APIBundle\\": "ramcar-batery/api-bundle/",
"Catalyst\\AuthBundle\\": "catalyst/auth-bundle/"
} }
}, },
"autoload-dev": { "autoload-dev": {

View file

@ -14,5 +14,5 @@ return [
Catalyst\APIBundle\CatalystAPIBundle::class => ['all' => true], Catalyst\APIBundle\CatalystAPIBundle::class => ['all' => true],
// DataDog\AuditBundle\DataDogAuditBundle::class => ['all' => true], // DataDog\AuditBundle\DataDogAuditBundle::class => ['all' => true],
Authentication\AuthBundle\Authbundle::class => ['all' => true], Catalyst\AuthBundle\CatalystAuthBundle::class => ['all' => true],
]; ];

View file

@ -91,15 +91,15 @@ services:
Catalyst\APIBundle\Command\TestCommand: Catalyst\APIBundle\Command\TestCommand:
tags: ['console.command'] tags: ['console.command']
Catalyst\APIBundle\Access\Voter:
arguments:
$acl_gen: "@Catalyst\\APIBundle\\Access\\Generator"
tags: ['security.voter']
Catalyst\APIBundle\Command\TestAPICommand: Catalyst\APIBundle\Command\TestAPICommand:
tags: ['console.command'] tags: ['console.command']
Catalyst\APIBundle\Access\Generator: Catalyst\AuthBundle\Access\Voter:
arguments:
$acl_gen: "@Catalyst\\AuthBundle\\Access\\Generator"
tags: ['security.voter']
Catalyst\AuthBundle\Access\Generator:
arguments: arguments:
$router: "@router.default" $router: "@router.default"
$cache_dir: "%kernel.cache_dir%" $cache_dir: "%kernel.cache_dir%"

View file

@ -13,7 +13,7 @@ use App\Entity\SAPBattery;
use App\Entity\SAPBatterySize; use App\Entity\SAPBatterySize;
use App\Entity\SAPBatteryBrand; use App\Entity\SAPBatteryBrand;
use Catalyst\APIBundle\Access\Generator as ACLGenerator; use Catalyst\AuthBundle\Access\Generator as ACLGenerator;
class BatteryController extends APIController class BatteryController extends APIController
{ {

View file

@ -11,7 +11,7 @@ use Catalyst\APIBundle\Response\APIResponse;
use App\Entity\Vehicle; use App\Entity\Vehicle;
use App\Entity\VehicleManufacturer; use App\Entity\VehicleManufacturer;
use Catalyst\APIBundle\Access\Generator as ACLGenerator; use Catalyst\AuthBundle\Access\Generator as ACLGenerator;
class VehicleController extends APIController class VehicleController extends APIController
{ {

View file

@ -22,7 +22,7 @@ use App\Ramcar\WarrantyClass;
use App\Ramcar\WarrantyStatus; use App\Ramcar\WarrantyStatus;
use DateTime; use DateTime;
use Catalyst\APIBundle\Access\Generator as ACLGenerator; use Catalyst\AuthBundle\Access\Generator as ACLGenerator;
class WarrantyController extends APIController class WarrantyController extends APIController
{ {

View file

@ -2,6 +2,8 @@
namespace App\Entity; namespace App\Entity;
use Catalyst\AuthBundle\Entity\Role as BaseRole;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
@ -13,7 +15,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
* @UniqueEntity("id") * @UniqueEntity("id")
* @UniqueEntity("name") * @UniqueEntity("name")
*/ */
class Role class Role extends BaseRole
{ {
const SUPER_ADMIN = 'ROLE_SUPER_ADMIN'; const SUPER_ADMIN = 'ROLE_SUPER_ADMIN';

View file

@ -2,6 +2,8 @@
namespace App\Entity; namespace App\Entity;
use Catalyst\AuthBundle\Entity\User as BaseUser;
use Symfony\Component\Security\Core\User\AdvancedUserInterface; use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
@ -15,7 +17,7 @@ use Serializable;
* @UniqueEntity("username") * @UniqueEntity("username")
* @UniqueEntity("email") * @UniqueEntity("email")
*/ */
class User implements AdvancedUserInterface, Serializable class User extends BaseUser implements AdvancedUserInterface, Serializable
{ {
/** /**
* @ORM\Id * @ORM\Id
@ -163,20 +165,20 @@ class User implements AdvancedUserInterface, Serializable
return $this; return $this;
} }
public function getRoles() //public function getRoles()
{ //{
// has to return set of strings because symfony is trying to move away from role objects // // has to return set of strings because symfony is trying to move away from role objects
$str_roles = []; // $str_roles = [];
foreach ($this->roles as $role) // foreach ($this->roles as $role)
$str_roles[] = $role->getID(); // $str_roles[] = $role->getID();
return $str_roles; // return $str_roles;
} //}
public function getRoleObjects() //public function getRoleObjects()
{ //{
return $this->roles; // return $this->roles;
} //}
public function addHub(Hub $hub) public function addHub(Hub $hub)
{ {