Refactor authentication system (#2602)
Make auth configuration available via UI, remove FOSUserBundle and SAML-Bundle dependency
This commit is contained in:
@@ -12,14 +12,15 @@ namespace App\Entity;
|
||||
use App\Constants;
|
||||
use App\Export\Annotation as Exporter;
|
||||
use App\Utils\StringHelper;
|
||||
use App\Validator\Constraints as Constraints;
|
||||
use DateTime;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Exception;
|
||||
use FOS\UserBundle\Model\User as BaseUser;
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\EquatableInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
@@ -33,6 +34,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
* )
|
||||
* @UniqueEntity("username")
|
||||
* @UniqueEntity("email")
|
||||
* @Constraints\User(groups={"UserCreate", "Registration", "Default"})
|
||||
*
|
||||
* @Serializer\ExclusionPolicy("all")
|
||||
* @Serializer\VirtualProperty(
|
||||
@@ -64,12 +66,12 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
* @ Exporter\Expose("teams", label="label.team", exp="object.getTeams().toArray()", type="array")
|
||||
* @Exporter\Expose("active", label="label.active", exp="object.isEnabled()", type="boolean")
|
||||
*/
|
||||
class User extends BaseUser implements UserInterface
|
||||
class User implements UserInterface, EquatableInterface, \Serializable
|
||||
{
|
||||
public const ROLE_USER = 'ROLE_USER';
|
||||
public const ROLE_TEAMLEAD = 'ROLE_TEAMLEAD';
|
||||
public const ROLE_ADMIN = 'ROLE_ADMIN';
|
||||
//public const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
|
||||
public const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
|
||||
|
||||
public const DEFAULT_ROLE = self::ROLE_USER;
|
||||
public const DEFAULT_LANGUAGE = Constants::DEFAULT_LOCALE;
|
||||
@@ -156,6 +158,8 @@ class User extends BaseUser implements UserInterface
|
||||
/**
|
||||
* @var string
|
||||
* @internal to be set via form, must not be persisted
|
||||
* @Assert\NotBlank(groups={"ApiTokenUpdate"})
|
||||
* @Assert\Length(min="8", max="60", groups={"ApiTokenUpdate"})
|
||||
*/
|
||||
private $plainApiToken;
|
||||
/**
|
||||
@@ -205,10 +209,79 @@ class User extends BaseUser implements UserInterface
|
||||
* @internal has no database mapping as the value is calculated from a permission
|
||||
*/
|
||||
private $isAllowedToSeeAllData = null;
|
||||
/**
|
||||
* @Serializer\Expose()
|
||||
* @Serializer\Groups({"Default"})
|
||||
*
|
||||
* @var string
|
||||
* @ORM\Column(name="username", type="string", length=180)
|
||||
* @Assert\NotBlank(groups={"Registration", "UserCreate", "Profile"})
|
||||
* @Assert\Length(min="2", max="60", groups={"Registration", "UserCreate", "Profile"})
|
||||
*/
|
||||
private $username;
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(name="email", type="string", length=180)
|
||||
* @Assert\NotBlank(groups={"Registration", "UserCreate", "Profile"})
|
||||
* @Assert\Length(min="2", max="180")
|
||||
* @Assert\Email(groups={"Registration", "UserCreate", "Profile"})
|
||||
*/
|
||||
private $email;
|
||||
/**
|
||||
* @Serializer\Expose()
|
||||
* @Serializer\Groups({"Default"})
|
||||
*
|
||||
* @var bool
|
||||
* @ORM\Column(name="enabled", type="boolean")
|
||||
*/
|
||||
private $enabled = false;
|
||||
/**
|
||||
* Encrypted password. Must be persisted.
|
||||
*
|
||||
* @var string
|
||||
* @ORM\Column(name="password", type="string")
|
||||
*/
|
||||
private $password;
|
||||
/**
|
||||
* Plain password. Used for model validation, not persisted.
|
||||
*
|
||||
* TODO make the password rules configurable
|
||||
*
|
||||
* @var string|null
|
||||
* @Assert\NotBlank(groups={"Registration", "PasswordUpdate", "UserCreate"})
|
||||
* @Assert\Length(min="8", max="60", groups={"Registration", "PasswordUpdate", "UserCreate", "ResetPassword", "ChangePassword"})
|
||||
*/
|
||||
private $plainPassword;
|
||||
/**
|
||||
* @var \DateTime|null
|
||||
* @ORM\Column(name="last_login", type="datetime", nullable=true)
|
||||
*/
|
||||
private $lastLogin;
|
||||
/**
|
||||
* Random string sent to the user email address in order to verify it.
|
||||
*
|
||||
* @var string|null
|
||||
* @ORM\Column(name="confirmation_token", type="string", length=180, unique=true, nullable=true)
|
||||
*/
|
||||
private $confirmationToken;
|
||||
/**
|
||||
* @var \DateTime|null
|
||||
* @ORM\Column(name="password_requested_at", type="datetime", nullable=true)
|
||||
*/
|
||||
private $passwordRequestedAt;
|
||||
/**
|
||||
* @Serializer\Expose()
|
||||
* @Serializer\Groups({"User_Entity"})
|
||||
* @Serializer\Type("array<string>")
|
||||
*
|
||||
* @var array
|
||||
* @ORM\Column(name="roles", type="array")
|
||||
* @Constraints\Role(groups={"RolesUpdate"})
|
||||
*/
|
||||
private $roles = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->registeredAt = new DateTime();
|
||||
$this->preferences = new ArrayCollection();
|
||||
$this->teams = new ArrayCollection();
|
||||
@@ -557,6 +630,265 @@ class User extends BaseUser implements UserInterface
|
||||
return $this->auth === null || $this->auth === self::AUTH_INTERNAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addRole($role)
|
||||
{
|
||||
$role = strtoupper($role);
|
||||
if ($role === static::DEFAULT_ROLE) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (!\in_array($role, $this->roles, true)) {
|
||||
$this->roles[] = $role;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function eraseCredentials()
|
||||
{
|
||||
$this->plainPassword = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEmail()
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function getPlainPassword(): ?string
|
||||
{
|
||||
return $this->plainPassword;
|
||||
}
|
||||
|
||||
public function getLastLogin(): ?DateTime
|
||||
{
|
||||
return $this->lastLogin;
|
||||
}
|
||||
|
||||
public function getConfirmationToken(): ?string
|
||||
{
|
||||
return $this->confirmationToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRoles()
|
||||
{
|
||||
$roles = $this->roles;
|
||||
|
||||
// we need to make sure to have at least one role
|
||||
$roles[] = static::DEFAULT_ROLE;
|
||||
|
||||
return array_values(array_unique($roles));
|
||||
}
|
||||
|
||||
public function hasRole($role): bool
|
||||
{
|
||||
return \in_array(strtoupper($role), $this->getRoles(), true);
|
||||
}
|
||||
|
||||
public function setSuperAdmin(bool $isSuper): void
|
||||
{
|
||||
if (true === $isSuper) {
|
||||
$this->addRole(static::ROLE_SUPER_ADMIN);
|
||||
} else {
|
||||
$this->removeRole(static::ROLE_SUPER_ADMIN);
|
||||
}
|
||||
}
|
||||
|
||||
public function isSuperAdmin(): bool
|
||||
{
|
||||
return $this->hasRole(static::ROLE_SUPER_ADMIN);
|
||||
}
|
||||
|
||||
public function removeRole($role): User
|
||||
{
|
||||
if (false !== $key = array_search(strtoupper($role), $this->roles, true)) {
|
||||
unset($this->roles[$key]);
|
||||
$this->roles = array_values($this->roles);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUsername($username): User
|
||||
{
|
||||
$this->username = $username;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setEmail($email): User
|
||||
{
|
||||
$this->email = $email;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
public function setEnabled(bool $enabled): User
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPassword($password): User
|
||||
{
|
||||
$this->password = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPlainPassword($password): User
|
||||
{
|
||||
$this->plainPassword = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLastLogin(\DateTime $time = null): User
|
||||
{
|
||||
$this->lastLogin = $time;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setConfirmationToken($confirmationToken): User
|
||||
{
|
||||
$this->confirmationToken = $confirmationToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPasswordRequestedAt(\DateTime $date = null): User
|
||||
{
|
||||
$this->passwordRequestedAt = $date;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timestamp that the user requested a password reset.
|
||||
*
|
||||
* @return DateTime|null
|
||||
*/
|
||||
public function getPasswordRequestedAt(): ?DateTime
|
||||
{
|
||||
return $this->passwordRequestedAt;
|
||||
}
|
||||
|
||||
public function isPasswordRequestNonExpired(int $seconds): bool
|
||||
{
|
||||
$date = $this->getPasswordRequestedAt();
|
||||
|
||||
if ($date === null || !($date instanceof DateTime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $date->getTimestamp() + $seconds > time();
|
||||
}
|
||||
|
||||
public function setRoles(array $roles): User
|
||||
{
|
||||
$this->roles = [];
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->addRole($role);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isEqualTo(UserInterface $user)
|
||||
{
|
||||
if (!$user instanceof self) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->password !== $user->getPassword()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->username !== $user->getUsername()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize([
|
||||
$this->password,
|
||||
$this->username,
|
||||
$this->enabled,
|
||||
$this->id,
|
||||
$this->email,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$data = unserialize($serialized);
|
||||
|
||||
// unserialize a user object from <= 1.14
|
||||
if (8 === \count($data)) {
|
||||
unset($data[1], $data[2], $data[7]);
|
||||
$data = array_values($data);
|
||||
}
|
||||
|
||||
list(
|
||||
$this->password,
|
||||
$this->username,
|
||||
$this->enabled,
|
||||
$this->id,
|
||||
$this->email) = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSalt()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user