summaryrefslogtreecommitdiff
path: root/core/classes/authentication
diff options
context:
space:
mode:
Diffstat (limited to 'core/classes/authentication')
-rw-r--r--core/classes/authentication/Core/PasswordTrait.php38
-rw-r--r--core/classes/authentication/Core/UserManager.php101
-rw-r--r--core/classes/authentication/Core/UserManagerInterface.php25
-rw-r--r--core/classes/authentication/Token/UserToken.php44
-rw-r--r--core/classes/authentication/Token/UserTokenInterface.php18
-rw-r--r--core/classes/authentication/User.php116
-rw-r--r--core/classes/authentication/UserInterface.php19
-rw-r--r--core/classes/authentication/info.md114
8 files changed, 475 insertions, 0 deletions
diff --git a/core/classes/authentication/Core/PasswordTrait.php b/core/classes/authentication/Core/PasswordTrait.php
new file mode 100644
index 0000000..40a7381
--- /dev/null
+++ b/core/classes/authentication/Core/PasswordTrait.php
@@ -0,0 +1,38 @@
+<?php
+/** Trait PasswordTrait
+ *
+ * @package DevCoder\Authentication\Core
+ *
+ */
+# namespace DevCoder\Authentication\Core;
+#
+# use DevCoder\Authentication\UserInterface;
+
+trait PasswordTrait
+{
+
+ private $cost = 10; // Cost must be in the range of 4-31
+ // a cost value in the range of 8-11
+ // is a good balance between performance and security
+
+
+ public function cryptPassword(string $plainPassword): string
+ {
+ return password_hash($plainPassword, PASSWORD_BCRYPT, ['cost' => $this->cost]);
+ }
+
+
+ public function isPasswordValid(UserInterface $user, string $plainPassword): bool
+ {
+ return password_verify($plainPassword, $user->getPassword());
+ }
+
+
+ public function setCost(int $cost): void
+ {
+ if ($cost < 4 || $cost > 31) {
+ throw new \InvalidArgumentException('Cost must be in the range of 4-31.');
+ }
+ $this->cost = $cost;
+ }
+}
diff --git a/core/classes/authentication/Core/UserManager.php b/core/classes/authentication/Core/UserManager.php
new file mode 100644
index 0000000..54cd2cb
--- /dev/null
+++ b/core/classes/authentication/Core/UserManager.php
@@ -0,0 +1,101 @@
+<?php
+/** Class UserManager
+ *
+ * @package DevCoder\Authentication\Core
+ *
+ */
+# namespace DevCoder\Authentication\Core;
+#
+# use DevCoder\Authentication\Token\UserToken;
+# use DevCoder\Authentication\Token\UserTokenInterface;
+# use DevCoder\Authentication\UserInterface;
+
+class UserManager implements UserManagerInterface
+{
+
+ use PasswordTrait;
+
+
+ public function __construct()
+ {
+ if (session_status() === PHP_SESSION_NONE) {
+ session_start();
+ }
+ }
+
+
+ /** getUserToken()
+ * == get user from session
+ *
+ */
+ public function getUserToken(): ?UserTokenInterface
+ {
+ $userToken = null;
+ if ($this->hasUserToken()) {
+ $userToken = unserialize($_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY]);
+ }
+
+ return $userToken;
+ }
+
+
+ /** hasUserToken()
+ * == is user loged in
+ *
+ */
+ public function hasUserToken(): bool
+ {
+ $key = UserTokenInterface::DEFAULT_PREFIX_KEY;
+ return (array_key_exists($key, $_SESSION) && unserialize($_SESSION[$key]) !== false);
+ }
+
+
+ /** isGranted
+ *
+ * checks if user is granded some role(s)
+ * from the array of roles that are passed
+ *
+ * ex. $token->isGranted(['editor', 'designer']) ...
+ * returns true if the user is editor or designer (or both)
+ *
+ */
+ public function isGranted(array $roles): bool
+ {
+ // if (!is_null($userToken = $this->getUserToken())) {
+ if (is_null($userToken = $this->getUserToken())) {
+ return false;
+ }
+
+ if ($userToken->getUser() instanceof UserInterface) {
+ return (!empty(array_intersect($roles, $userToken->getUser()->getRoles())));
+ }
+
+ return false;
+ }
+
+
+ /** createUserToken()
+ * == serializes user and stores it into session
+ * so $_SESSION[DEFAULT_PREFIX_KEY] has the serialized representaion of user
+ */
+ public function createUserToken(UserInterface $user): UserTokenInterface
+ {
+ $userToken = new UserToken($user);
+ $_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY] = $userToken->serialize();
+
+ return $userToken;
+ }
+
+
+ /** logout
+ * == clear session
+ *
+ */
+ public function logout(): void
+ {
+ if ($this->hasUserToken()) {
+ unset($_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY]);
+ }
+ }
+
+}
diff --git a/core/classes/authentication/Core/UserManagerInterface.php b/core/classes/authentication/Core/UserManagerInterface.php
new file mode 100644
index 0000000..05110fb
--- /dev/null
+++ b/core/classes/authentication/Core/UserManagerInterface.php
@@ -0,0 +1,25 @@
+<?php
+/** Interface UserManagerInterface
+ *
+ * @package DevCoder\Authentication\Core
+ *
+ */
+# namespace DevCoder\Authentication\Core;
+#
+# use DevCoder\Authentication\Token\UserTokenInterface;
+# use DevCoder\Authentication\UserInterface;
+
+interface UserManagerInterface
+{
+ public function getUserToken(): ?UserTokenInterface;
+
+ public function hasUserToken(): bool;
+
+ public function createUserToken(UserInterface $user): UserTokenInterface;
+
+ public function logout(): void;
+
+ public function cryptPassword(string $plainPassword): string;
+
+ public function isPasswordValid(UserInterface $user, string $plainPassword): bool;
+}
diff --git a/core/classes/authentication/Token/UserToken.php b/core/classes/authentication/Token/UserToken.php
new file mode 100644
index 0000000..b9bb024
--- /dev/null
+++ b/core/classes/authentication/Token/UserToken.php
@@ -0,0 +1,44 @@
+<?php
+/** Class UserToken
+ *
+ * @package DevCoder\Authentication
+ *
+ */
+# namespace DevCoder\Authentication\Token;
+#
+# use DevCoder\Authentication\UserInterface;
+
+class UserToken implements UserTokenInterface
+{
+ /**
+ * @var UserInterface
+ */
+ private $user;
+
+
+ public function __construct(UserInterface $user)
+ {
+ $this->user = $user;
+ }
+
+
+ /** getUser
+ *
+ */
+ public function getUser(): UserInterface
+ {
+ return $this->user;
+ }
+
+
+ /** serialize()
+ *
+ * serializes the user structure (with user's property values)
+ * ... then it will be saved into session[DEFAULT_PREFIX_KEY]
+ *
+ */
+ public function serialize(): string
+ {
+ return serialize($this);
+ }
+}
diff --git a/core/classes/authentication/Token/UserTokenInterface.php b/core/classes/authentication/Token/UserTokenInterface.php
new file mode 100644
index 0000000..8e8b642
--- /dev/null
+++ b/core/classes/authentication/Token/UserTokenInterface.php
@@ -0,0 +1,18 @@
+<?php
+/** Interface UserTokenInterface
+ *
+ * @package DevCoder\Authentication\Token
+ *
+ */
+# namespace DevCoder\Authentication\Token;
+#
+# use DevCoder\Authentication\UserInterface;
+
+interface UserTokenInterface
+{
+ const DEFAULT_PREFIX_KEY = 'user_security';
+
+ public function getUser(): UserInterface;
+
+ public function serialize(): string;
+}
diff --git a/core/classes/authentication/User.php b/core/classes/authentication/User.php
new file mode 100644
index 0000000..babc7fd
--- /dev/null
+++ b/core/classes/authentication/User.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * Class User
+ *
+ * based on
+ * @package DevCoder\Authentication
+ *
+ */
+# namespace DevCoder\Authentication;
+
+class User implements UserInterface
+{
+
+ // @var string
+ private $userName;
+
+ // @var string
+ private $password;
+
+ // @var array
+ private $roles = [];
+
+ // @var array
+ private $privileges = [];
+
+ // @var bool
+ private $enabled = true;
+
+
+
+ /** GETs
+ * -------------------------------------------------------------------------
+ */
+
+ /** getUserName
+ * @return null|string
+ */
+ public function getUsername(): ?string
+ {
+ return $this->userName;
+ }
+
+ /** getPassword
+ * @return null|string
+ */
+ public function getPassword(): ?string
+ {
+ return $this->password;
+ }
+
+ /** getRoles
+ * @return array
+ */
+ public function getRoles(): array
+ {
+ return $this->roles;
+ }
+
+ /** isEnabled
+ * @return bool
+ */
+ public function isEnabled(): bool
+ {
+ return $this->enabled;
+ }
+
+
+ /** SETs
+ * -------------------------------------------------------------------------
+ */
+
+ /** setUserName()
+ *
+ * @param string $userName
+ * @return User
+ */
+ public function setUserName(string $userName): self
+ {
+ $this->userName = $userName;
+ return $this;
+ }
+
+ /** setPassword()
+ *
+ * @param string $password
+ * @return User
+ */
+ public function setPassword(string $password): self
+ {
+ $this->password = $password;
+ return $this;
+ }
+
+ /** setRoles()
+ *
+ * @param array $roles
+ * @return User
+ */
+ public function setRoles(array $roles): self
+ {
+ $this->roles = $roles;
+ return $this;
+ }
+
+
+ /** setEnabled
+ *
+ * @param bool $enabled
+ * @return User
+ */
+ public function setEnabled(bool $enabled): self
+ {
+ $this->enabled = $enabled;
+ return $this;
+ }
+}
diff --git a/core/classes/authentication/UserInterface.php b/core/classes/authentication/UserInterface.php
new file mode 100644
index 0000000..b035215
--- /dev/null
+++ b/core/classes/authentication/UserInterface.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Interface UserInterface
+ *
+ * @package DevCoder\Authentication
+ *
+ */
+# namespace DevCoder\Authentication;
+
+interface UserInterface
+{
+ public function getUsername() :?string;
+
+ public function getPassword() :?string;
+
+ public function getRoles() : array;
+
+ public function isEnabled(): bool;
+} \ No newline at end of file
diff --git a/core/classes/authentication/info.md b/core/classes/authentication/info.md
new file mode 100644
index 0000000..e6d1372
--- /dev/null
+++ b/core/classes/authentication/info.md
@@ -0,0 +1,114 @@
+# Authentication System
+
+read/ref: https://dev.to/fadymr/php-create-your-own-php-authentication-4e20
+
+also for session: https://dev.to/fadymr/php-create-a-simple-session-wrapper-class-dpk
+
+
+
+## How to use ?
+
+
+### Registration
+
+
+ // use DevCoder\Authentication\Core\UserManager;
+ // use DevCoder\Authentication\User;
+
+ // register
+ $userManager = new UserManager();
+ $req = Registry::get('REQUEST);
+
+ $password = $userManager->cryptPassword($req->POST['password']);
+
+ $user = (new User())
+ ->setUserName($req->POST['username'])
+ ->setPassword($password)
+ ->setRoles(['ROLE_USER']);
+
+ $userManager->createUserToken($user);
+
+ // check Token in Session
+ var_dump($userManager->getUserToken());
+ // object(DevCoder\Authentication\Token\UserToken)[4]
+ // private 'user' =>
+ // object(DevCoder\Authentication\User)[5]
+ // private 'userName' => string 'username' (length=8)
+ // private 'password' => string '$2y$10$iWdcmebmikUFlgKMqW7/rOmUp1DjFAuWKqdUHBhL08FZ7LL6bwRey' (length=60)
+ // private 'roles' =>
+ // array (size=1)
+ // 0 => string 'ROLE_USER' (length=9)
+ // private 'enabled' => boolean true
+
+
+## Connected or not
+
+ <?php
+
+ // use DevCoder\Authentication\Core\UserManager;
+ // use DevCoder\Authentication\User;
+
+ $userManager = new UserManager();
+ if ($userManager->hasUserToken()) {
+ // connected
+
+ $token = $userManager->getUserToken();
+ $user = $token->getUser();
+ var_dump($user);
+ // object(DevCoder\Authentication\User)[5]
+ // private 'userName' => string 'username' (length=8)
+ // private 'password' => string '$2y$10$OBobeLhdvdiftuedlv1a6e4.qF6sCG/usq5WEV4E3uB.UiS1egv/m' (length=60)
+ // private 'roles' =>
+ // array (size=1)
+ // 0 => string 'ROLE_USER' (length=9)
+ // private 'enabled' => boolean true
+
+ } else {
+ // not connected
+ }
+
+
+## Access management
+
+ $userManager = new UserManager();
+ if ($userManager->isGranted(['ROLE_ADMIN'])) {
+ //is admin
+ // return Response 200
+ }else {
+ //is not admin
+ // return Response 403
+ }
+
+ Logout
+
+ $userManager = new UserManager();
+ $userManager->logout();
+
+
+## Login
+
+ <?php
+
+ use DevCoder\Authentication\Core\UserManager;
+
+ $stmt = $pdo->prepare("SELECT * FROM users WHERE username=?");
+ $stmt->execute([$_POST['username']]);
+ $userFromDataBase = $stmt->fetch();
+ /**
+ * Hydration
+ */
+ $user = (new \Test\DevCoder\Authentication\User())
+ ->setUserName($userFromDataBase['username'])
+ ->setPassword($userFromDataBase['password'])
+ ->setRoles(json_decode($userFromDataBase['roles']))
+ ->setEnabled($userFromDataBase['active']);
+
+ $userManager = new UserManager();
+ if ($userManager->isPasswordValid($user, $_POST['password'])) {
+
+ // login OK, set Token in session
+ $userManager->createUserToken($user);
+
+ } else {
+ // login failed , return error
+ }