diff --git a/src/Authorize/Header/BasicMethod.php b/src/Authorize/Header/BasicMethod.php index 954dde7..4cd06bd 100644 --- a/src/Authorize/Header/BasicMethod.php +++ b/src/Authorize/Header/BasicMethod.php @@ -5,11 +5,13 @@ namespace Ulmus\User\Authorize\Header; use Psr\Http\Message\ServerRequestInterface; use Ulmus\User\Entity\BasicAuthUserInterface; use Ulmus\User\Entity\UserInterface; +use Ulmus\User\Lib\Authenticate; use Ulmus\User\Lib\Authorize; class BasicMethod implements MethodInterface { public function __construct( + protected Authenticate $authorize, protected BasicAuthUserInterface $user, protected string|array $arguments ) {} @@ -29,7 +31,8 @@ class BasicMethod implements MethodInterface throw new \RuntimeException("A password must be provided"); } - ( new Authorize($this->user) )->authenticate([ $this->user->usernameField() => $userName ], $password); + $this->authorize->user = $this->user; + $this->authorize->authenticate([ $this->user->usernameField() => $userName ], $password); return $this->user->loggedIn(); } diff --git a/src/Authorize/Header/BearerMethod.php b/src/Authorize/Header/BearerMethod.php index ccd010c..99d731f 100644 --- a/src/Authorize/Header/BearerMethod.php +++ b/src/Authorize/Header/BearerMethod.php @@ -6,6 +6,7 @@ use Psr\Http\Message\ServerRequestInterface; use Ulmus\User\Authorize\Bearer\JsonWebToken; use Ulmus\User\Authorize\Bearer\JsonWebTokenDecoder; use Ulmus\User\Entity\UserInterface; +use Ulmus\User\Lib\Authenticate; use Ulmus\User\Lib\Authorize; class BearerMethod implements MethodInterface @@ -13,20 +14,21 @@ class BearerMethod implements MethodInterface protected JsonWebTokenDecoder $jwt; public function __construct( + protected Authenticate $authorize, protected UserInterface $user, protected string $token ) {} public function execute(ServerRequestInterface $request) : bool { + $this->authorize->user = $this->user; + switch($this->autodetectTokenType()) { case BearerTokenTypeEnum::JsonWebToken: - $authorize = new Authorize($this->user); - $payload = $this->jwt->getPayload(); if ($payload['sub'] ?? false) { - if ( ! $authorize->logUser((int) $payload['sub']) ) { + if ( ! $this->authorize->logUser($payload['sub']) ) { throw new \Exception("Given user id do not match with an existing/active user"); } } diff --git a/src/Authorize/Header/DigestMethod.php b/src/Authorize/Header/DigestMethod.php index 7968a85..1dfbd7c 100644 --- a/src/Authorize/Header/DigestMethod.php +++ b/src/Authorize/Header/DigestMethod.php @@ -4,10 +4,12 @@ namespace Ulmus\User\Authorize\Header; use Psr\Http\Message\ServerRequestInterface; use Ulmus\User\Entity\DigestAuthUserInterface; +use Ulmus\User\Lib\Authenticate; class DigestMethod implements MethodInterface { public function __construct( + protected Authenticate $authorize, protected DigestAuthUserInterface $user, protected string|array $arguments ) {} diff --git a/src/Authorize/HeaderAuthentication.php b/src/Authorize/HeaderAuthentication.php index 7eb4d45..749d0b0 100644 --- a/src/Authorize/HeaderAuthentication.php +++ b/src/Authorize/HeaderAuthentication.php @@ -5,9 +5,14 @@ namespace Ulmus\User\Authorize; use Psr\Http\Message\ServerRequestInterface; use Ulmus\User\Common\AuthorizeContentTypeEnum; use Ulmus\User\Entity\{ DigestAuthUserInterface, UserInterface }; +use Ulmus\User\Lib\Authenticate; class HeaderAuthentication implements AuthorizeMethodInterface { + public function __construct( + protected Authenticate $authorize, + ) { } + public function connect(ServerRequestInterface $request, UserInterface $user): bool { if (null !== ( $auth = $request->getHeaderLine('Authorization') )) { @@ -15,7 +20,7 @@ class HeaderAuthentication implements AuthorizeMethodInterface switch(strtolower($method)) { case "basic": - $methodObj = new Header\BasicMethod($user, $value); + $methodObj = new Header\BasicMethod($this->authorize, $user, $value); break; case "digest": @@ -23,11 +28,11 @@ class HeaderAuthentication implements AuthorizeMethodInterface throw new \RuntimeException("Your user entity must provide a valid hash of `user:realm:password` "); } - $methodObj = new Header\DigestMethod($user, $value); + $methodObj = new Header\DigestMethod($this->authorize, $user, $value); break; case "bearer": - $methodObj = new Header\BearerMethod($user, $value); + $methodObj = new Header\BearerMethod($this->authorize, $user, $value); break; case "token": diff --git a/src/Authorize/MacAddressAuthentication.php b/src/Authorize/MacAddressAuthentication.php new file mode 100644 index 0000000..41727da --- /dev/null +++ b/src/Authorize/MacAddressAuthentication.php @@ -0,0 +1,55 @@ +getServerParams(); + + # var_dump($server, $this->getArpMacAddress($server['REMOTE_ADDR']));die(); + + return false; + + return $this->authenticate->authenticate([ $this->fieldUser => $post[$this->postFieldUser] ], $post[$this->postFieldPassword]); + } + + public function catchRequest(ServerRequestInterface $request): bool + { + return true; + + $post = $request->getParsedBody(); + + return strtoupper( $request->getMethod() ) === "POST" && isset($post[$this->postFieldUser], $post[$this->postFieldPassword]); + } + + protected function getArpMacAddress(string $ip) : ?string + { + #run the external command, break output into lines + $arp = shell_exec(sprintf("arp -a %s", escapeshellarg($ip))); + $lines = explode("\n", $arp); + + #look for the output line describing our IP address + foreach($lines as $line) + { + $cols = preg_split('/\s+/', trim($line)); + + if ($cols[0] === $ip) + { + return $cols[0]; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/Lib/Authenticate.php b/src/Lib/Authenticate.php index 88e17b2..ba139ad 100644 --- a/src/Lib/Authenticate.php +++ b/src/Lib/Authenticate.php @@ -121,15 +121,19 @@ class Authenticate { return $this; } - public function logUser(?int $id) : ? UserInterface + public function logUser(null|int|object $id) : ? UserInterface { - try { - if ($id === null || null === ($entity = $this->user::repository()->loadFromPk($id))) { + if (! is_object($id)) { + try { + if ($id === null || null === ($entity = $this->user::repository()->loadFromPk($id))) { + return null; + } + } catch (\Exception $ex) { return null; } } - catch(\Exception $ex) { - return null; + else { + $entity = $id; } $this->user->fromArray($entity); diff --git a/src/Middleware/HeaderAuthenticationMiddleware.php b/src/Middleware/HeaderAuthenticationMiddleware.php index e97f270..7c35d0f 100644 --- a/src/Middleware/HeaderAuthenticationMiddleware.php +++ b/src/Middleware/HeaderAuthenticationMiddleware.php @@ -10,17 +10,19 @@ use Psr\Http\{ }; use Ulmus\User\Entity\UserInterface; use Ulmus\User\Authorize\HeaderAuthentication; +use Ulmus\User\Lib\Authenticate; class HeaderAuthenticationMiddleware implements MiddlewareInterface { protected HeaderAuthentication $authenticator; public function __construct( + protected Authenticate $authorize, protected UserInterface $entity, protected \Closure $loginFailedResponse, - HeaderAuthentication $authenticator = null, + ? HeaderAuthentication $authenticator = null, ) { - $this->authenticator = $authenticator ?: new HeaderAuthentication(); + $this->authenticator = $authenticator ?: new HeaderAuthentication($authorize); } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface diff --git a/src/Middleware/LocalMacAddressMiddleware.php b/src/Middleware/LocalMacAddressMiddleware.php new file mode 100644 index 0000000..0abf272 --- /dev/null +++ b/src/Middleware/LocalMacAddressMiddleware.php @@ -0,0 +1,40 @@ +authenticator = $authenticator ?: new MacAddressAuthentication(new Authenticate($entity)); + } + + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $this->authenticator->authenticate->rememberMe(); + + if ( $this->authenticator->catchRequest($request) ) { + if ( ! $this->authenticator->connect($request, $this->entity) ) { + return call_user_func($this->loginFailedResponse, "Login failed"); + } + } + + return $handler->handle($request); + } +} diff --git a/src/Middleware/PostRequestAuthenticationMiddleware.php b/src/Middleware/PostRequestAuthenticationMiddleware.php index e7c3a45..8168a24 100644 --- a/src/Middleware/PostRequestAuthenticationMiddleware.php +++ b/src/Middleware/PostRequestAuthenticationMiddleware.php @@ -19,7 +19,7 @@ class PostRequestAuthenticationMiddleware implements MiddlewareInterface public function __construct( protected UserInterface $entity, protected \Closure $loginFailedResponse, - PostRequestAuthentication $authenticator = null, + ? PostRequestAuthentication $authenticator = null, ) { $this->authenticator = $authenticator ?: new PostRequestAuthentication(new Authenticate($entity)); } @@ -30,6 +30,9 @@ class PostRequestAuthenticationMiddleware implements MiddlewareInterface if ( $this->authenticator->catchRequest($request) ) { if ( ! $this->authenticator->connect($request, $this->entity) ) { + # Adds random sleep after a bad login attempts + sleep(random_int(2,8)); + return call_user_func($this->loginFailedResponse, "Login failed"); } }