vendor/bundles/FOS/UserBundle/Model/User.php
changeset 3 e54dfe4d0b2b
equal deleted inserted replaced
2:806e57d67020 3:e54dfe4d0b2b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of the FOSUserBundle package.
       
     5  *
       
     6  * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
       
     7  *
       
     8  * For the full copyright and license information, please view the LICENSE
       
     9  * file that was distributed with this source code.
       
    10  */
       
    11 
       
    12 namespace FOS\UserBundle\Model;
       
    13 
       
    14 use Symfony\Component\Security\Core\Role\RoleInterface;
       
    15 use Doctrine\Common\Collections\Collection;
       
    16 use Doctrine\Common\Collections\ArrayCollection;
       
    17 use Symfony\Component\Security\Core\User\UserInterface as SecurityUserInterface;
       
    18 
       
    19 /**
       
    20  * Storage agnostic user object
       
    21  *
       
    22  * @author Thibault Duplessis <thibault.duplessis@gmail.com>
       
    23  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
       
    24  */
       
    25 abstract class User implements UserInterface, GroupableInterface
       
    26 {
       
    27     const ROLE_DEFAULT = 'ROLE_USER';
       
    28     const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';
       
    29 
       
    30     protected $id;
       
    31 
       
    32     /**
       
    33      * @var string
       
    34      */
       
    35     protected $username;
       
    36 
       
    37     /**
       
    38      * @var string
       
    39      */
       
    40     protected $usernameCanonical;
       
    41 
       
    42     /**
       
    43      * @var string
       
    44      */
       
    45     protected $email;
       
    46 
       
    47     /**
       
    48      * @var string
       
    49      */
       
    50     protected $emailCanonical;
       
    51 
       
    52     /**
       
    53      * @var boolean
       
    54      */
       
    55     protected $enabled;
       
    56 
       
    57     /**
       
    58      * The algorithm to use for hashing
       
    59      *
       
    60      * @var string
       
    61      */
       
    62     protected $algorithm;
       
    63 
       
    64     /**
       
    65      * The salt to use for hashing
       
    66      *
       
    67      * @var string
       
    68      */
       
    69     protected $salt;
       
    70 
       
    71     /**
       
    72      * Encrypted password. Must be persisted.
       
    73      *
       
    74      * @var string
       
    75      */
       
    76     protected $password;
       
    77 
       
    78     /**
       
    79      * Plain password. Used for model validation. Must not be persisted.
       
    80      *
       
    81      * @var string
       
    82      */
       
    83     protected $plainPassword;
       
    84 
       
    85     /**
       
    86      * @var \DateTime
       
    87      */
       
    88     protected $lastLogin;
       
    89 
       
    90     /**
       
    91      * Random string sent to the user email address in order to verify it
       
    92      *
       
    93      * @var string
       
    94      */
       
    95     protected $confirmationToken;
       
    96 
       
    97     /**
       
    98      * @var \DateTime
       
    99      */
       
   100     protected $passwordRequestedAt;
       
   101 
       
   102     /**
       
   103      * @var Collection
       
   104      */
       
   105     protected $groups;
       
   106 
       
   107     /**
       
   108      * @var Boolean
       
   109      */
       
   110     protected $locked;
       
   111 
       
   112     /**
       
   113      * @var Boolean
       
   114      */
       
   115     protected $expired;
       
   116 
       
   117     /**
       
   118      * @var \DateTime
       
   119      */
       
   120     protected $expiresAt;
       
   121 
       
   122     /**
       
   123      * @var array
       
   124      */
       
   125     protected $roles;
       
   126 
       
   127     /**
       
   128      * @var Boolean
       
   129      */
       
   130     protected $credentialsExpired;
       
   131 
       
   132     /**
       
   133      * @var \DateTime
       
   134      */
       
   135     protected $credentialsExpireAt;
       
   136 
       
   137     public function __construct()
       
   138     {
       
   139         $this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
       
   140         $this->generateConfirmationToken();
       
   141         $this->enabled = false;
       
   142         $this->locked = false;
       
   143         $this->expired = false;
       
   144         $this->roles = array();
       
   145         $this->credentialsExpired = false;
       
   146     }
       
   147 
       
   148     /**
       
   149      * Adds a role to the user.
       
   150      *
       
   151      * @param string $role
       
   152      */
       
   153     public function addRole($role)
       
   154     {
       
   155         $role = strtoupper($role);
       
   156         if ($role === static::ROLE_DEFAULT) {
       
   157             return;
       
   158         }
       
   159 
       
   160         if (!in_array($role, $this->roles, true)) {
       
   161             $this->roles[] = $role;
       
   162         }
       
   163     }
       
   164 
       
   165     /**
       
   166      * Implementation of SecurityUserInterface.
       
   167      *
       
   168      * @param \Symfony\Component\Security\Core\User\UserInterface $user
       
   169      * @return Boolean
       
   170      */
       
   171     public function equals(SecurityUserInterface $user)
       
   172     {
       
   173         if (!$user instanceof User) {
       
   174             return false;
       
   175         }
       
   176 
       
   177         if ($this->password !== $user->getPassword()) {
       
   178             return false;
       
   179         }
       
   180         if ($this->getSalt() !== $user->getSalt()) {
       
   181             return false;
       
   182         }
       
   183         if ($this->usernameCanonical !== $user->getUsernameCanonical()) {
       
   184             return false;
       
   185         }
       
   186         if ($this->isAccountNonExpired() !== $user->isAccountNonExpired()) {
       
   187             return false;
       
   188         }
       
   189         if (!$this->locked !== $user->isAccountNonLocked()) {
       
   190             return false;
       
   191         }
       
   192         if ($this->isCredentialsNonExpired() !== $user->isCredentialsNonExpired()) {
       
   193             return false;
       
   194         }
       
   195         if ($this->enabled !== $user->isEnabled()) {
       
   196             return false;
       
   197         }
       
   198 
       
   199         return true;
       
   200     }
       
   201 
       
   202     /**
       
   203      * Serializes the user.
       
   204      *
       
   205      * The serialized data have to contain the fields used by the equals method and the username.
       
   206      *
       
   207      * @return string
       
   208      */
       
   209     public function serialize()
       
   210     {
       
   211         return serialize(array(
       
   212             $this->password,
       
   213             $this->salt,
       
   214             $this->usernameCanonical,
       
   215             $this->username,
       
   216             $this->expired,
       
   217             $this->locked,
       
   218             $this->credentialsExpired,
       
   219             $this->enabled,
       
   220         ));
       
   221     }
       
   222 
       
   223     /**
       
   224      * Unserializes the user.
       
   225      *
       
   226      * @param string $serialized
       
   227      */
       
   228     public function unserialize($serialized)
       
   229     {
       
   230         list(
       
   231             $this->password,
       
   232             $this->salt,
       
   233             $this->usernameCanonical,
       
   234             $this->username,
       
   235             $this->expired,
       
   236             $this->locked,
       
   237             $this->credentialsExpired,
       
   238             $this->enabled
       
   239         ) = unserialize($serialized);
       
   240     }
       
   241 
       
   242     /**
       
   243      * Removes sensitive data from the user.
       
   244      *
       
   245      * Implements SecurityUserInterface
       
   246      */
       
   247     public function eraseCredentials()
       
   248     {
       
   249         $this->plainPassword = null;
       
   250     }
       
   251 
       
   252     /**
       
   253      * Returns the user unique id.
       
   254      *
       
   255      * @return mixed
       
   256      */
       
   257     public function getId()
       
   258     {
       
   259         return $this->id;
       
   260     }
       
   261 
       
   262     /**
       
   263      * @return string
       
   264      */
       
   265     public function getUsername()
       
   266     {
       
   267         return $this->username;
       
   268     }
       
   269 
       
   270     /**
       
   271      * Gets the canonical username in search and sort queries.
       
   272      *
       
   273      * @return string
       
   274      */
       
   275     public function getUsernameCanonical()
       
   276     {
       
   277         return $this->usernameCanonical;
       
   278     }
       
   279 
       
   280     /**
       
   281      * Implementation of SecurityUserInterface
       
   282      *
       
   283      * @return string
       
   284      */
       
   285     public function getSalt()
       
   286     {
       
   287         return $this->salt;
       
   288     }
       
   289 
       
   290     /**
       
   291      * Gets the algorithm used to encode the password.
       
   292      *
       
   293      * @return string
       
   294      */
       
   295     public function getAlgorithm()
       
   296     {
       
   297         return $this->algorithm;
       
   298     }
       
   299 
       
   300     /**
       
   301      * Gets email.
       
   302      *
       
   303      * @return string
       
   304      */
       
   305     public function getEmail()
       
   306     {
       
   307         return $this->email;
       
   308     }
       
   309 
       
   310     /**
       
   311      * Gets the canonical email in search and sort queries.
       
   312      *
       
   313      * @return string
       
   314      */
       
   315     public function getEmailCanonical()
       
   316     {
       
   317         return $this->emailCanonical;
       
   318     }
       
   319 
       
   320     /**
       
   321      * Gets the encrypted password.
       
   322      *
       
   323      * Implements SecurityUserInterface
       
   324      * @return string
       
   325      */
       
   326     public function getPassword()
       
   327     {
       
   328         return $this->password;
       
   329     }
       
   330 
       
   331     /**
       
   332      * Gets the plain password.
       
   333      *
       
   334      * @return string
       
   335      */
       
   336     public function getPlainPassword()
       
   337     {
       
   338         return $this->plainPassword;
       
   339     }
       
   340 
       
   341     /**
       
   342      * Gets the last login time.
       
   343      *
       
   344      * @return \DateTime
       
   345      */
       
   346     public function getLastLogin()
       
   347     {
       
   348         return $this->lastLogin;
       
   349     }
       
   350 
       
   351     /**
       
   352      * Gets the confirmation token.
       
   353      *
       
   354      * @return string
       
   355      */
       
   356     public function getConfirmationToken()
       
   357     {
       
   358         return $this->confirmationToken;
       
   359     }
       
   360 
       
   361     /**
       
   362      * Returns the user roles
       
   363      *
       
   364      * Implements SecurityUserInterface
       
   365      *
       
   366      * @return array The roles
       
   367      */
       
   368     public function getRoles()
       
   369     {
       
   370         $roles = $this->roles;
       
   371 
       
   372         foreach ($this->getGroups() as $group) {
       
   373             $roles = array_merge($roles, $group->getRoles());
       
   374         }
       
   375 
       
   376         // we need to make sure to have at least one role
       
   377         $roles[] = static::ROLE_DEFAULT;
       
   378 
       
   379         return array_unique($roles);
       
   380     }
       
   381 
       
   382     /**
       
   383      * Never use this to check if this user has access to anything!
       
   384      *
       
   385      * Use the SecurityContext, or an implementation of AccessDecisionManager
       
   386      * instead, e.g.
       
   387      *
       
   388      *         $securityContext->isGranted('ROLE_USER');
       
   389      *
       
   390      * @param string $role
       
   391      * @return Boolean
       
   392      */
       
   393     public function hasRole($role)
       
   394     {
       
   395         return in_array(strtoupper($role), $this->getRoles(), true);
       
   396     }
       
   397 
       
   398     /**
       
   399      * Checks whether the user's account has expired.
       
   400      *
       
   401      * Implements AdvancedUserInterface
       
   402      *
       
   403      * @return Boolean true if the user's account is non expired, false otherwise
       
   404      */
       
   405     public function isAccountNonExpired()
       
   406     {
       
   407         if (true === $this->expired) {
       
   408             return false;
       
   409         }
       
   410 
       
   411         if (null !== $this->expiresAt && $this->expiresAt->getTimestamp() < time()) {
       
   412             return false;
       
   413         }
       
   414 
       
   415         return true;
       
   416     }
       
   417 
       
   418     /**
       
   419      * Checks whether the user is locked.
       
   420      *
       
   421      * Implements AdvancedUserInterface
       
   422      *
       
   423      * @return Boolean true if the user is not locked, false otherwise
       
   424      */
       
   425     public function isAccountNonLocked()
       
   426     {
       
   427         return !$this->locked;
       
   428     }
       
   429 
       
   430     /**
       
   431      * Checks whether the user's credentials (password) has expired.
       
   432      *
       
   433      * Implements AdvancedUserInterface
       
   434      *
       
   435      * @return Boolean true if the user's credentials are non expired, false otherwise
       
   436      */
       
   437     public function isCredentialsNonExpired()
       
   438     {
       
   439         if (true === $this->credentialsExpired) {
       
   440             return false;
       
   441         }
       
   442 
       
   443         if (null !== $this->credentialsExpireAt && $this->credentialsExpireAt->getTimestamp() < time()) {
       
   444             return false;
       
   445         }
       
   446 
       
   447         return true;
       
   448     }
       
   449 
       
   450     public function isCredentialsExpired()
       
   451     {
       
   452         return !$this->isCredentialsNonExpired();
       
   453     }
       
   454 
       
   455     /**
       
   456      * Checks whether the user is enabled.
       
   457      *
       
   458      * Implements AdvancedUserInterface
       
   459      *
       
   460      * @return Boolean true if the user is enabled, false otherwise
       
   461      */
       
   462     public function isEnabled()
       
   463     {
       
   464         return $this->enabled;
       
   465     }
       
   466 
       
   467     public function isExpired()
       
   468     {
       
   469         return !$this->isAccountNonExpired();
       
   470     }
       
   471 
       
   472     public function isLocked()
       
   473     {
       
   474         return $this->locked;
       
   475     }
       
   476 
       
   477     /**
       
   478      * Tells if the the given user has the super admin role.
       
   479      *
       
   480      * @return Boolean
       
   481      */
       
   482     public function isSuperAdmin()
       
   483     {
       
   484         return $this->hasRole(static::ROLE_SUPER_ADMIN);
       
   485     }
       
   486 
       
   487     /**
       
   488      * Tells if the the given user is this user.
       
   489      *
       
   490      * Useful when not hydrating all fields.
       
   491      *
       
   492      * @param UserInterface $user
       
   493      * @return Boolean
       
   494      */
       
   495     public function isUser(UserInterface $user = null)
       
   496     {
       
   497         return null !== $user && $this->getId() === $user->getId();
       
   498     }
       
   499 
       
   500     /**
       
   501      * Removes a role to the user.
       
   502      *
       
   503      * @param string $role
       
   504      */
       
   505     public function removeRole($role)
       
   506     {
       
   507         if (false !== $key = array_search(strtoupper($role), $this->roles, true)) {
       
   508             unset($this->roles[$key]);
       
   509             $this->roles = array_values($this->roles);
       
   510         }
       
   511     }
       
   512 
       
   513     /**
       
   514      * Sets the username.
       
   515      *
       
   516      * @param string $username
       
   517      */
       
   518     public function setUsername($username)
       
   519     {
       
   520         $this->username = $username;
       
   521     }
       
   522 
       
   523     /**
       
   524      * Sets the canonical username.
       
   525      *
       
   526      * @param string $usernameCanonical
       
   527      */
       
   528     public function setUsernameCanonical($usernameCanonical)
       
   529     {
       
   530         $this->usernameCanonical = $usernameCanonical;
       
   531     }
       
   532 
       
   533     /**
       
   534      * Sets the algorithm
       
   535      *
       
   536      * @param string $algorithm
       
   537      */
       
   538     public function setAlgorithm($algorithm)
       
   539     {
       
   540         $this->algorithm = $algorithm;
       
   541     }
       
   542 
       
   543     public function setCredentialsExpireAt(\DateTime $date)
       
   544     {
       
   545         $this->credentialsExpireAt = $date;
       
   546     }
       
   547 
       
   548     public function setCredentialsExpired($boolean)
       
   549     {
       
   550         $this->credentialsExpired = $boolean;
       
   551     }
       
   552 
       
   553     /**
       
   554      * Sets the email.
       
   555      *
       
   556      * @param string $email
       
   557      */
       
   558     public function setEmail($email)
       
   559     {
       
   560         $this->email = $email;
       
   561     }
       
   562 
       
   563     /**
       
   564      * Set the canonical email.
       
   565      *
       
   566      * @param string $emailCanonical
       
   567      */
       
   568     public function setEmailCanonical($emailCanonical)
       
   569     {
       
   570         $this->emailCanonical = $emailCanonical;
       
   571     }
       
   572 
       
   573     /**
       
   574      * @param Boolean $boolean
       
   575      */
       
   576     public function setEnabled($boolean)
       
   577     {
       
   578         $this->enabled = (Boolean) $boolean;
       
   579     }
       
   580 
       
   581     /**
       
   582      * Sets this user to expired.
       
   583      *
       
   584      * @param Boolean $boolean
       
   585      */
       
   586     public function setExpired($boolean)
       
   587     {
       
   588         $this->expired = (Boolean) $boolean;
       
   589     }
       
   590 
       
   591     public function setExpiresAt(\DateTime $date)
       
   592     {
       
   593         $this->expiresAt = $date;
       
   594     }
       
   595 
       
   596     /**
       
   597      * Sets the hashed password.
       
   598      *
       
   599      * @param string $password
       
   600      */
       
   601     public function setPassword($password)
       
   602     {
       
   603         $this->password = $password;
       
   604     }
       
   605 
       
   606     /**
       
   607      * Sets the super admin status
       
   608      *
       
   609      * @param Boolean $boolean
       
   610      */
       
   611     public function setSuperAdmin($boolean)
       
   612     {
       
   613         if (true === $boolean) {
       
   614             $this->addRole(static::ROLE_SUPER_ADMIN);
       
   615         } else {
       
   616             $this->removeRole(static::ROLE_SUPER_ADMIN);
       
   617         }
       
   618     }
       
   619 
       
   620     /**
       
   621      * Sets the plain password.
       
   622      *
       
   623      * @param string $password
       
   624      */
       
   625     public function setPlainPassword($password)
       
   626     {
       
   627         $this->plainPassword = $password;
       
   628     }
       
   629 
       
   630     /**
       
   631      * Sets the last login time
       
   632      *
       
   633      * @param \DateTime $time
       
   634      */
       
   635     public function setLastLogin(\DateTime $time)
       
   636     {
       
   637         $this->lastLogin = $time;
       
   638     }
       
   639 
       
   640     /**
       
   641      * Sets the locking status of the user.
       
   642      *
       
   643      * @param Boolean $boolean
       
   644      */
       
   645     public function setLocked($boolean)
       
   646     {
       
   647         $this->locked = $boolean;
       
   648     }
       
   649 
       
   650     /**
       
   651      * Sets the confirmation token
       
   652      *
       
   653      * @param string $confirmationToken
       
   654      */
       
   655     public function setConfirmationToken($confirmationToken)
       
   656     {
       
   657         $this->confirmationToken = $confirmationToken;
       
   658     }
       
   659 
       
   660     /**
       
   661      * Sets the timestamp that the user requested a password reset.
       
   662      *
       
   663      * @param \DateTime $date
       
   664      */
       
   665     public function setPasswordRequestedAt(\DateTime $date)
       
   666     {
       
   667         $this->passwordRequestedAt = $date;
       
   668     }
       
   669 
       
   670     /**
       
   671      * Gets the timestamp that the user requested a password reset.
       
   672      *
       
   673      * @return \DateTime
       
   674      */
       
   675     public function getPasswordRequestedAt()
       
   676     {
       
   677         return $this->passwordRequestedAt;
       
   678     }
       
   679 
       
   680     /**
       
   681      * Checks whether the password reset request has expired.
       
   682      *
       
   683      * @param integer $ttl Requests older than this many seconds will be considered expired
       
   684      * @return Boolean true if the user's password request is non expired, false otherwise
       
   685      */
       
   686     public function isPasswordRequestNonExpired($ttl)
       
   687     {
       
   688         return $this->passwordRequestedAt instanceof \DateTime &&
       
   689                $this->passwordRequestedAt->getTimestamp() + $ttl > time();
       
   690     }
       
   691 
       
   692     /**
       
   693      * Generates the confirmation token if it is not set.
       
   694      */
       
   695     public function generateConfirmationToken()
       
   696     {
       
   697         if (null === $this->confirmationToken) {
       
   698             $this->confirmationToken = $this->generateToken();
       
   699         }
       
   700     }
       
   701 
       
   702     /**
       
   703      * Sets the roles of the user.
       
   704      *
       
   705      * This overwrites any previous roles.
       
   706      *
       
   707      * @param array $roles
       
   708      */
       
   709     public function setRoles(array $roles)
       
   710     {
       
   711         $this->roles = array();
       
   712 
       
   713         foreach ($roles as $role) {
       
   714             $this->addRole($role);
       
   715         }
       
   716     }
       
   717 
       
   718     /**
       
   719      * Gets the groups granted to the user.
       
   720      *
       
   721      * @return Collection
       
   722      */
       
   723     public function getGroups()
       
   724     {
       
   725         return $this->groups ?: $this->groups = new ArrayCollection();
       
   726     }
       
   727 
       
   728     /**
       
   729      * Gets the name of the groups which includes the user.
       
   730      *
       
   731      * @return array
       
   732      */
       
   733     public function getGroupNames()
       
   734     {
       
   735         $names = array();
       
   736         foreach ($this->getGroups() as $group) {
       
   737             $names[] = $group->getName();
       
   738         }
       
   739 
       
   740         return $names;
       
   741     }
       
   742 
       
   743     /**
       
   744      * Indicates whether the user belongs to the specified group or not.
       
   745      *
       
   746      * @param string $name Name of the group
       
   747      * @return Boolean
       
   748      */
       
   749     public function hasGroup($name)
       
   750     {
       
   751         return in_array($name, $this->getGroupNames());
       
   752     }
       
   753 
       
   754     /**
       
   755      * Add a group to the user groups.
       
   756      *
       
   757      * @param GroupInterface $group
       
   758      */
       
   759     public function addGroup(GroupInterface $group)
       
   760     {
       
   761         if (!$this->getGroups()->contains($group)) {
       
   762             $this->getGroups()->add($group);
       
   763         }
       
   764     }
       
   765 
       
   766     /**
       
   767      * Remove a group from the user groups.
       
   768      *
       
   769      * @param GroupInterface $group
       
   770      */
       
   771     public function removeGroup(GroupInterface $group)
       
   772     {
       
   773         if ($this->getGroups()->contains($group)) {
       
   774             $this->getGroups()->removeElement($group);
       
   775         }
       
   776     }
       
   777 
       
   778     public function __toString()
       
   779     {
       
   780         return (string) $this->getUsername();
       
   781     }
       
   782 
       
   783     /**
       
   784      * Generates a token.
       
   785      *
       
   786      * @return string
       
   787      */
       
   788     protected function generateToken()
       
   789     {
       
   790         $bytes = false;
       
   791         if (function_exists('openssl_random_pseudo_bytes') && 0 !== stripos(PHP_OS, 'win')) {
       
   792             $bytes = openssl_random_pseudo_bytes(32, $strong);
       
   793 
       
   794             if (true !== $strong) {
       
   795                 $bytes = false;
       
   796             }
       
   797         }
       
   798 
       
   799         // let's just hope we got a good seed
       
   800         if (false === $bytes) {
       
   801             $bytes = hash('sha256', uniqid(mt_rand(), true), true);
       
   802         }
       
   803 
       
   804         return base_convert(bin2hex($bytes), 16, 36);
       
   805     }
       
   806 }