mirror of
https://github.com/delight-im/PHP-Auth.git
synced 2025-08-08 00:56:28 +02:00
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
739fa7d574 | ||
|
302feb5da2 | ||
|
2ded232d8e | ||
|
70a905afd7 | ||
|
84f3ad10a9 | ||
|
81091df66b | ||
|
8926e7e708 | ||
|
eec450677f | ||
|
f1360dceba | ||
|
2cf7b27ba3 | ||
|
ecd8015acf | ||
|
1eedfd0e02 | ||
|
757579523c | ||
|
d695328a5a | ||
|
71506eaa05 | ||
|
ce8dbbc436 | ||
|
d181219e40 | ||
|
891cef2511 | ||
|
f70613b2b8 | ||
|
59816d1a40 | ||
|
1284f64f04 | ||
|
8165e8917b | ||
|
a4b68167a1 | ||
|
fc2fb4bb44 | ||
|
b2a3fde696 | ||
|
36880b87c9 | ||
|
4a66965994 | ||
|
e7b590dc80 | ||
|
33d2384c93 | ||
|
1169856217 | ||
|
fa75811679 | ||
|
fa8fa4887e | ||
|
8fecb86f15 | ||
|
04c466b309 |
57
Migration.md
57
Migration.md
@@ -1,6 +1,7 @@
|
||||
# Migration
|
||||
|
||||
* [General](#general)
|
||||
* [From `v6.x.x` to `v7.x.x`](#from-v6xx-to-v7xx)
|
||||
* [From `v5.x.x` to `v6.x.x`](#from-v5xx-to-v6xx)
|
||||
* [From `v4.x.x` to `v5.x.x`](#from-v4xx-to-v5xx)
|
||||
* [From `v3.x.x` to `v4.x.x`](#from-v3xx-to-v4xx)
|
||||
@@ -15,6 +16,62 @@ Update your version of this library via Composer [[?]](https://github.com/deligh
|
||||
$ composer update delight-im/auth
|
||||
```
|
||||
|
||||
If you want to perform a major version upgrade (e.g. from version `1.x.x` to version `2.x.x`), the version constraints defined in your `composer.json` [[?]](https://github.com/delight-im/Knowledge/blob/master/Composer%20(PHP).md) may not allow this. In that case, just add the dependency again to overwrite it with the latest version (or optionally with a specified version):
|
||||
|
||||
```
|
||||
$ composer require delight-im/auth
|
||||
```
|
||||
|
||||
## From `v6.x.x` to `v7.x.x`
|
||||
|
||||
* The method `logOutButKeepSession` from class `Auth` is now simply called `logOut`. Therefore, the former method `logout` is now called `logOutAndDestroySession`. With both methods, mind the capitalization of the letter “O”.
|
||||
|
||||
* The second argument of the `Auth` constructor, which was named `$useHttps`, has been removed. If you previously had it set to `true`, make sure to set the value of the `session.cookie_secure` directive to `1` now. You may do so either directly in your [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), via the `\ini_set` method or via the `\session_set_cookie_params` method. Otherwise, make sure that directive is set to `0`.
|
||||
|
||||
* The third argument of the `Auth` constructor, which was named `$allowCookiesScriptAccess`, has been removed. If you previously had it set to `true`, make sure to set the value of the `session.cookie_httponly` directive to `0` now. You may do so either directly in your [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), via the `\ini_set` method or via the `\session_set_cookie_params` method. Otherwise, make sure that directive is set to `1`.
|
||||
|
||||
* Only if *both* of the following two conditions are met:
|
||||
|
||||
* The directive `session.cookie_domain` is set to an empty value. It may have been set directly in your [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), via the `\ini_set` method or via the `\session_set_cookie_params` method. You can check the value of that directive by executing the following statement somewhere in your application:
|
||||
|
||||
```php
|
||||
\var_dump(\ini_get('session.cookie_domain'));
|
||||
```
|
||||
|
||||
* Your application is accessed via a registered or registrable *domain name*, either by yourself during development and testing or by your visitors and users in production. That means your application is *not*, or *not only*, accessed via `localhost` or via an IP address.
|
||||
|
||||
Then the domain scope for the [two cookies](README.md#cookies) used by this library has changed. You can handle this change in one of two different ways:
|
||||
|
||||
* Restore the old behavior by placing the following statement as early as possible in your application, and before you create the `Auth` instance:
|
||||
|
||||
```php
|
||||
\ini_set('session.cookie_domain', \preg_replace('/^www\./', '', $_SERVER['HTTP_HOST']));
|
||||
```
|
||||
|
||||
You may also evaluate the complete second parameter and put its value directly into your [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`).
|
||||
|
||||
* Use the new domain scope for your application. To do so, you only need to [rename the cookies](README.md#renaming-the-librarys-cookies) used by this library in order to prevent conflicts with old cookies that have been created previously. Renaming the cookies is critically important here. We recommend a versioned name such as `session_v1` for the session cookie.
|
||||
|
||||
* Only if *both* of the following two conditions are met:
|
||||
|
||||
* The directive `session.cookie_domain` is set to a value that starts with the `www` subdomain. It may have been set directly in your [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), via the `\ini_set` method or via the `\session_set_cookie_params` method. You can check the value of that directive by executing the following statement somewhere in your application:
|
||||
|
||||
```php
|
||||
\var_dump(\ini_get('session.cookie_domain'));
|
||||
```
|
||||
|
||||
* Your application is accessed via a registered or registrable *domain name*, either by yourself during development and testing or by your visitors and users in production. That means your application is *not*, or *not only*, accessed via `localhost` or via an IP address.
|
||||
|
||||
Then the domain scope for [one of the cookies](README.md#cookies) used by this library has changed. To make your application work correctly with the new scope, [rename the cookies](README.md#renaming-the-librarys-cookies) used by this library in order to prevent conflicts with old cookies that have been created previously. Renaming the cookies is critically important here. We recommend a versioned name such as `session_v1` for the session cookie.
|
||||
|
||||
* If the directive `session.cookie_path` is set to an empty value, then the path scope for [one of the cookies](README.md#cookies) used by this library has changed. To make your application work correctly with the new scope, [rename the cookies](README.md#renaming-the-librarys-cookies) used by this library in order to prevent conflicts with old cookies that have been created previously. Renaming the cookies is critically important here. We recommend a versioned name such as `session_v1` for the session cookie.
|
||||
|
||||
The directive may have been set directly in your [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), via the `\ini_set` method or via the `\session_set_cookie_params` method. You can check the value of that directive by executing the following statement somewhere in your application:
|
||||
|
||||
```php
|
||||
\var_dump(\ini_get('session.cookie_path'));
|
||||
```
|
||||
|
||||
## From `v5.x.x` to `v6.x.x`
|
||||
|
||||
* The database schema has changed.
|
||||
|
150
README.md
150
README.md
@@ -79,6 +79,12 @@ Migrating from an earlier version of this project? See our [upgrade guide](Migra
|
||||
* [Assigning roles to users](#assigning-roles-to-users)
|
||||
* [Taking roles away from users](#taking-roles-away-from-users)
|
||||
* [Checking roles](#checking-roles-1)
|
||||
* [Cookies](#cookies)
|
||||
* [Renaming the library’s cookies](#renaming-the-librarys-cookies)
|
||||
* [Defining the domain scope for cookies](#defining-the-domain-scope-for-cookies)
|
||||
* [Restricting the path where cookies are available](#restricting-the-path-where-cookies-are-available)
|
||||
* [Controlling client-side script access to cookies](#controlling-client-side-script-access-to-cookies)
|
||||
* [Configuring transport security for cookies](#configuring-transport-security-for-cookies)
|
||||
* [Utilities](#utilities)
|
||||
* [Creating a random string](#creating-a-random-string)
|
||||
* [Creating a UUID v4 as per RFC 4122](#creating-a-uuid-v4-as-per-rfc-4122)
|
||||
@@ -102,13 +108,9 @@ $auth = new \Delight\Auth\Auth($db);
|
||||
|
||||
If you have an open `PDO` connection already, just re-use it.
|
||||
|
||||
If you do enforce HTTPS on your site, pass `true` as the second parameter to the constructor. This is optional and the default is `false`.
|
||||
If your web server is behind a proxy server and `$_SERVER['REMOTE_ADDR']` only contains the proxy’s IP address, you must pass the user’s real IP address to the constructor in the second argument, which is named `$ipAddress`. The default is `null`.
|
||||
|
||||
Only in the very rare case that you need access to your cookies from JavaScript, pass `true` as the third argument to the constructor. This is optional and the default is `false`. There is almost always a *better* solution than enabling this, however.
|
||||
|
||||
If your web server is behind a proxy server and `$_SERVER['REMOTE_ADDR']` only contains the proxy’s IP address, you must pass the user’s real IP address to the constructor in the fourth argument. The default is `null`.
|
||||
|
||||
Should your database tables for this library need a common prefix, e.g. `my_users` instead of `users` (and likewise for the other tables), pass the prefix (e.g. `my_`) as the fifth parameter to the constructor. This is optional and the prefix is empty by default.
|
||||
Should your database tables for this library need a common prefix, e.g. `my_users` instead of `users` (and likewise for the other tables), pass the prefix (e.g. `my_`) as the third parameter to the constructor, which is named `$dbTablePrefix`. This is optional and the prefix is empty by default.
|
||||
|
||||
### Registration (sign up)
|
||||
|
||||
@@ -405,9 +407,9 @@ $url = 'https://www.example.com/verify_email?selector=' . \urlencode($selector)
|
||||
### Logout
|
||||
|
||||
```php
|
||||
$auth->logOutButKeepSession();
|
||||
$auth->logOut();
|
||||
// or
|
||||
$auth->logout();
|
||||
$auth->logOutAndDestroySession();
|
||||
|
||||
// user has been signed out
|
||||
```
|
||||
@@ -896,6 +898,138 @@ catch (\Delight\Auth\UnknownIdException $e) {
|
||||
}
|
||||
```
|
||||
|
||||
### Cookies
|
||||
|
||||
This library uses two cookies to keep state on the client: The first, whose name you can retrieve using
|
||||
|
||||
```php
|
||||
\session_name();
|
||||
```
|
||||
|
||||
is the general (mandatory) session cookie. The second (optional) cookie is only used for [persistent logins](#keeping-the-user-logged-in) and its name can be retrieved as follows:
|
||||
|
||||
```php
|
||||
\Delight\Auth\Auth::createRememberCookieName();
|
||||
```
|
||||
|
||||
#### Renaming the library’s cookies
|
||||
|
||||
You can rename the session cookie used by this library through one of the following means, in order of recommendation:
|
||||
|
||||
* In the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), find the line with the `session.name` directive and change its value to something like `session_v1`, as in:
|
||||
|
||||
```
|
||||
session.name = session_v1
|
||||
```
|
||||
|
||||
* As early as possible in your application, and before you create the `Auth` instance, call `\ini_set` to change `session.name` to something like `session_v1`, as in:
|
||||
|
||||
```php
|
||||
\ini_set('session.name', 'session_v1');
|
||||
```
|
||||
|
||||
For this to work, `session.auto_start` must be set to `0` in the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`).
|
||||
|
||||
* As early as possible in your application, and before you create the `Auth` instance, call `\session_name` with an argument like `session_v1`, as in:
|
||||
|
||||
```php
|
||||
\session_name('session_v1');
|
||||
```
|
||||
|
||||
For this to work, `session.auto_start` must be set to `0` in the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`).
|
||||
|
||||
The name of the cookie for [persistent logins](#keeping-the-user-logged-in) will change as well – automatically – following your change of the session cookie’s name.
|
||||
|
||||
#### Defining the domain scope for cookies
|
||||
|
||||
A cookie’s `domain` attribute controls which domain (and which subdomains) the cookie will be valid for, and thus where the user’s session and authentication state will be available.
|
||||
|
||||
The recommended default is an empty string, which means that the cookie will only be valid for the *exact* current host, *excluding* any subdomains that may exist. You should only use a different value if you need to share cookies between different subdomains. Often, you’ll want to share cookies between the bare domain and the `www` subdomain, but you might also want to share them between any other set of subdomains.
|
||||
|
||||
Whatever set of subdomains you choose, you should set the cookie’s attribute to the *most specific* domain name that still includes all your required subdomains. For example, to share cookies between `example.com` and `www.example.com`, you would set the attribute to `example.com`. But if you wanted to share cookies between `sub1.app.example.com` and `sub2.app.example.com`, you should set the attribute to `app.example.com`. Any explicitly specified domain name will always *include* all subdomains that may exist.
|
||||
|
||||
You can change the attribute through one of the following means, in order of recommendation:
|
||||
|
||||
* In the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), find the line with the `session.cookie_domain` directive and change its value as desired, e.g.:
|
||||
|
||||
```
|
||||
session.cookie_domain = example.com
|
||||
```
|
||||
|
||||
* As early as possible in your application, and before you create the `Auth` instance, call `\ini_set` to change the value of the `session.cookie_domain` directive as desired, e.g.:
|
||||
|
||||
```php
|
||||
\ini_set('session.cookie_domain', 'example.com');
|
||||
```
|
||||
|
||||
For this to work, `session.auto_start` must be set to `0` in the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`).
|
||||
|
||||
#### Restricting the path where cookies are available
|
||||
|
||||
A cookie’s `path` attribute controls which directories (and subdirectories) the cookie will be valid for, and thus where the user’s session and authentication state will be available.
|
||||
|
||||
In most cases, you’ll want to make cookies available for all paths, i.e. any directory and file, starting in the root directory. That is what a value of `/` for the attribute does, which is also the recommended default. You should only change this attribute to a different value, e.g. `/path/to/subfolder`, if you want to restrict which directories your cookies will be available in, e.g. to host multiple applications side-by-side, in different directories, under the same domain name.
|
||||
|
||||
You can change the attribute through one of the following means, in order of recommendation:
|
||||
|
||||
* In the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), find the line with the `session.cookie_path` directive and change its value as desired, e.g.:
|
||||
|
||||
```
|
||||
session.cookie_path = /
|
||||
```
|
||||
|
||||
* As early as possible in your application, and before you create the `Auth` instance, call `\ini_set` to change the value of the `session.cookie_path` directive as desired, e.g.:
|
||||
|
||||
```php
|
||||
\ini_set('session.cookie_path', '/');
|
||||
```
|
||||
|
||||
For this to work, `session.auto_start` must be set to `0` in the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`).
|
||||
|
||||
#### Controlling client-side script access to cookies
|
||||
|
||||
Using the `httponly` attribute, you can control whether client-side scripts, i.e. JavaScript, should be able to access your cookies or not. For security reasons, it is best to *deny* script access to your cookies, which reduces the damage that successful XSS attacks against your application could do, for example.
|
||||
|
||||
Thus, you should always set `httponly` to `1`, except for the rare cases where you really need access to your cookies from JavaScript and can’t find any better solution. In those cases, set the attribute to `0`, but be aware of the consequences.
|
||||
|
||||
You can change the attribute through one of the following means, in order of recommendation:
|
||||
|
||||
* In the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), find the line with the `session.cookie_httponly` directive and change its value as desired, e.g.:
|
||||
|
||||
```
|
||||
session.cookie_httponly = 1
|
||||
```
|
||||
|
||||
* As early as possible in your application, and before you create the `Auth` instance, call `\ini_set` to change the value of the `session.cookie_httponly` directive as desired, e.g.:
|
||||
|
||||
```php
|
||||
\ini_set('session.cookie_httponly', 1);
|
||||
```
|
||||
|
||||
For this to work, `session.auto_start` must be set to `0` in the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`).
|
||||
|
||||
#### Configuring transport security for cookies
|
||||
|
||||
Using the `secure` attribute, you can control whether cookies should be sent over *any* connection, including plain HTTP, or whether a secure connection, i.e. HTTPS (with SSL/TLS), should be required. The former (less secure) mode can be chosen by setting the attribute to `0`, and the latter (more secure) mode can be chosen by setting the attribute to `1`.
|
||||
|
||||
Obviously, this solely depends on whether you are able to serve *all* pages exclusively via HTTPS. If you can, you should set the attribute to `1` and possibly combine it with HTTP redirects to the secure protocol and HTTP Strict Transport Security (HSTS). Otherwise, you may have to keep the attribute set to `0`.
|
||||
|
||||
You can change the attribute through one of the following means, in order of recommendation:
|
||||
|
||||
* In the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), find the line with the `session.cookie_secure` directive and change its value as desired, e.g.:
|
||||
|
||||
```
|
||||
session.cookie_secure = 1
|
||||
```
|
||||
|
||||
* As early as possible in your application, and before you create the `Auth` instance, call `\ini_set` to change the value of the `session.cookie_secure` directive as desired, e.g.:
|
||||
|
||||
```php
|
||||
\ini_set('session.cookie_secure', 1);
|
||||
```
|
||||
|
||||
For this to work, `session.auto_start` must be set to `0` in the [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`).
|
||||
|
||||
### Utilities
|
||||
|
||||
#### Creating a random string
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"php": ">=5.6.0",
|
||||
"ext-openssl": "*",
|
||||
"delight-im/base64": "^1.0",
|
||||
"delight-im/cookie": "^2.1",
|
||||
"delight-im/cookie": "^3.1",
|
||||
"delight-im/db": "^1.2"
|
||||
},
|
||||
"type": "library",
|
||||
|
12
composer.lock
generated
12
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "8ab7c9ad8ef2bc7d9a6beb27f9bf4df5",
|
||||
"content-hash": "54d541ae3c5ba25b0cc06688d2b65467",
|
||||
"packages": [
|
||||
{
|
||||
"name": "delight-im/base64",
|
||||
@@ -49,16 +49,16 @@
|
||||
},
|
||||
{
|
||||
"name": "delight-im/cookie",
|
||||
"version": "v2.1.3",
|
||||
"version": "v3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/delight-im/PHP-Cookie.git",
|
||||
"reference": "a66c8a02aa4776c4b7d3d04c695411f73e04e1eb"
|
||||
"reference": "76ef2a21817cf7a034f85fc3f4d4bfc60f873947"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/delight-im/PHP-Cookie/zipball/a66c8a02aa4776c4b7d3d04c695411f73e04e1eb",
|
||||
"reference": "a66c8a02aa4776c4b7d3d04c695411f73e04e1eb",
|
||||
"url": "https://api.github.com/repos/delight-im/PHP-Cookie/zipball/76ef2a21817cf7a034f85fc3f4d4bfc60f873947",
|
||||
"reference": "76ef2a21817cf7a034f85fc3f4d4bfc60f873947",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -86,7 +86,7 @@
|
||||
"samesite",
|
||||
"xss"
|
||||
],
|
||||
"time": "2017-07-26T14:03:38+00:00"
|
||||
"time": "2017-10-18T19:48:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "delight-im/db",
|
||||
|
@@ -107,7 +107,7 @@ final class Administration extends UserManager {
|
||||
*/
|
||||
public function deleteUserByUsername($username) {
|
||||
$userData = $this->getUserDataByUsername(
|
||||
trim($username),
|
||||
\trim($username),
|
||||
[ 'id' ]
|
||||
);
|
||||
|
||||
|
238
src/Auth.php
238
src/Auth.php
@@ -28,29 +28,24 @@ final class Auth extends UserManager {
|
||||
const SESSION_FIELD_STATUS = 'auth_status';
|
||||
const SESSION_FIELD_ROLES = 'auth_roles';
|
||||
const SESSION_FIELD_REMEMBERED = 'auth_remembered';
|
||||
const COOKIE_PREFIXES = [ Cookie::PREFIX_SECURE, Cookie::PREFIX_HOST ];
|
||||
const COOKIE_CONTENT_SEPARATOR = '~';
|
||||
const COOKIE_NAME_REMEMBER = 'auth_remember';
|
||||
|
||||
/** @var boolean whether HTTPS (TLS/SSL) will be used (recommended) */
|
||||
private $useHttps;
|
||||
/** @var boolean whether cookies should be accessible via client-side scripts (*not* recommended) */
|
||||
private $allowCookiesScriptAccess;
|
||||
/** @var string the user's current IP address */
|
||||
private $ipAddress;
|
||||
/** @var string the name of the cookie used for the 'remember me' feature */
|
||||
private $rememberCookieName;
|
||||
|
||||
/**
|
||||
* @param PdoDatabase|PdoDsn|\PDO $databaseConnection the database connection to operate on
|
||||
* @param bool $useHttps whether HTTPS (TLS/SSL) will be used (recommended)
|
||||
* @param bool $allowCookiesScriptAccess whether cookies should be accessible via client-side scripts (*not* recommended)
|
||||
* @param string $ipAddress the IP address that should be used instead of the default setting (if any), e.g. when behind a proxy
|
||||
* @param string|null $dbTablePrefix (optional) the prefix for the names of all database tables used by this component
|
||||
*/
|
||||
public function __construct($databaseConnection, $useHttps = false, $allowCookiesScriptAccess = false, $ipAddress = null, $dbTablePrefix = null) {
|
||||
public function __construct($databaseConnection, $ipAddress = null, $dbTablePrefix = null) {
|
||||
parent::__construct($databaseConnection, $dbTablePrefix);
|
||||
|
||||
$this->useHttps = $useHttps;
|
||||
$this->allowCookiesScriptAccess = $allowCookiesScriptAccess;
|
||||
$this->ipAddress = !empty($ipAddress) ? $ipAddress : (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null);
|
||||
$this->rememberCookieName = self::createRememberCookieName();
|
||||
|
||||
$this->initSession();
|
||||
$this->enhanceHttpSecurity();
|
||||
@@ -61,37 +56,32 @@ final class Auth extends UserManager {
|
||||
/** Initializes the session and sets the correct configuration */
|
||||
private function initSession() {
|
||||
// use cookies to store session IDs
|
||||
ini_set('session.use_cookies', 1);
|
||||
\ini_set('session.use_cookies', 1);
|
||||
// use cookies only (do not send session IDs in URLs)
|
||||
ini_set('session.use_only_cookies', 1);
|
||||
\ini_set('session.use_only_cookies', 1);
|
||||
// do not send session IDs in URLs
|
||||
ini_set('session.use_trans_sid', 0);
|
||||
\ini_set('session.use_trans_sid', 0);
|
||||
|
||||
// get our cookie settings
|
||||
$params = $this->createCookieSettings();
|
||||
// define our new cookie settings
|
||||
session_set_cookie_params($params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
||||
|
||||
// start the session
|
||||
// start the session (requests a cookie to be written on the client)
|
||||
@Session::start();
|
||||
}
|
||||
|
||||
/** Improves the application's security over HTTP(S) by setting specific headers */
|
||||
private function enhanceHttpSecurity() {
|
||||
// remove exposure of PHP version (at least where possible)
|
||||
header_remove('X-Powered-By');
|
||||
\header_remove('X-Powered-By');
|
||||
|
||||
// if the user is signed in
|
||||
if ($this->isLoggedIn()) {
|
||||
// prevent clickjacking
|
||||
header('X-Frame-Options: sameorigin');
|
||||
\header('X-Frame-Options: sameorigin');
|
||||
// prevent content sniffing (MIME sniffing)
|
||||
header('X-Content-Type-Options: nosniff');
|
||||
\header('X-Content-Type-Options: nosniff');
|
||||
|
||||
// disable caching of potentially sensitive data
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate', true);
|
||||
header('Expires: Thu, 19 Nov 1981 00:00:00 GMT', true);
|
||||
header('Pragma: no-cache', true);
|
||||
\header('Cache-Control: no-store, no-cache, must-revalidate', true);
|
||||
\header('Expires: Thu, 19 Nov 1981 00:00:00 GMT', true);
|
||||
\header('Pragma: no-cache', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,12 +89,25 @@ final class Auth extends UserManager {
|
||||
private function processRememberDirective() {
|
||||
// if the user is not signed in yet
|
||||
if (!$this->isLoggedIn()) {
|
||||
// if there is currently no cookie for the 'remember me' feature
|
||||
if (!isset($_COOKIE[$this->rememberCookieName])) {
|
||||
// if an old cookie for that feature from versions v1.x.x to v6.x.x has been found
|
||||
if (isset($_COOKIE['auth_remember'])) {
|
||||
// use the value from that old cookie instead
|
||||
$_COOKIE[$this->rememberCookieName] = $_COOKIE['auth_remember'];
|
||||
}
|
||||
}
|
||||
|
||||
// if a remember cookie is set
|
||||
if (isset($_COOKIE[self::COOKIE_NAME_REMEMBER])) {
|
||||
if (isset($_COOKIE[$this->rememberCookieName])) {
|
||||
// assume the cookie and its contents to be invalid until proven otherwise
|
||||
$valid = false;
|
||||
|
||||
// split the cookie's content into selector and token
|
||||
$parts = explode(self::COOKIE_CONTENT_SEPARATOR, $_COOKIE[self::COOKIE_NAME_REMEMBER], 2);
|
||||
$parts = \explode(self::COOKIE_CONTENT_SEPARATOR, $_COOKIE[$this->rememberCookieName], 2);
|
||||
|
||||
// if both selector and token were found
|
||||
if (isset($parts[0]) && isset($parts[1])) {
|
||||
if (!empty($parts[0]) && !empty($parts[1])) {
|
||||
try {
|
||||
$rememberData = $this->db->selectRow(
|
||||
'SELECT a.user, a.token, a.expires, b.email, b.username, b.status, b.roles_mask FROM ' . $this->dbTablePrefix . 'users_remembered AS a JOIN ' . $this->dbTablePrefix . 'users AS b ON a.user = b.id WHERE a.selector = ?',
|
||||
@@ -116,13 +119,22 @@ final class Auth extends UserManager {
|
||||
}
|
||||
|
||||
if (!empty($rememberData)) {
|
||||
if ($rememberData['expires'] >= time()) {
|
||||
if (password_verify($parts[1], $rememberData['token'])) {
|
||||
if ($rememberData['expires'] >= \time()) {
|
||||
if (\password_verify($parts[1], $rememberData['token'])) {
|
||||
// the cookie and its contents have now been proven to be valid
|
||||
$valid = true;
|
||||
|
||||
$this->onLoginSuccessful($rememberData['user'], $rememberData['email'], $rememberData['username'], $rememberData['status'], $rememberData['roles_mask'], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the cookie or its contents have been invalid
|
||||
if (!$valid) {
|
||||
// mark the cookie as such to prevent any further futile attempts
|
||||
$this->setRememberCookie('', '', \time() + 60 * 60 * 24 * 365.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,7 +326,7 @@ final class Auth extends UserManager {
|
||||
*
|
||||
* @throws AuthError if an internal problem occurred (do *not* catch)
|
||||
*/
|
||||
public function logOutButKeepSession() {
|
||||
public function logOut() {
|
||||
// if the user has been signed in
|
||||
if ($this->isLoggedIn()) {
|
||||
// get the user's ID
|
||||
@@ -361,8 +373,8 @@ final class Auth extends UserManager {
|
||||
private function createRememberDirective($userId, $duration) {
|
||||
$selector = self::createRandomString(24);
|
||||
$token = self::createRandomString(32);
|
||||
$tokenHashed = password_hash($token, PASSWORD_DEFAULT);
|
||||
$expires = time() + ((int) $duration);
|
||||
$tokenHashed = \password_hash($token, \PASSWORD_DEFAULT);
|
||||
$expires = \time() + ((int) $duration);
|
||||
|
||||
try {
|
||||
$this->db->insert(
|
||||
@@ -399,20 +411,19 @@ final class Auth extends UserManager {
|
||||
throw new DatabaseError();
|
||||
}
|
||||
|
||||
$this->setRememberCookie(null, null, time() - 3600);
|
||||
$this->setRememberCookie(null, null, \time() - 3600);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or updates the cookie that manages the "remember me" token
|
||||
*
|
||||
* @param string $selector the selector from the selector/token pair
|
||||
* @param string $token the token from the selector/token pair
|
||||
* @param int $expires the interval in seconds after which the token should expire
|
||||
* @param string|null $selector the selector from the selector/token pair
|
||||
* @param string|null $token the token from the selector/token pair
|
||||
* @param int $expires the UNIX time in seconds which the token should expire at
|
||||
* @throws AuthError if an internal problem occurred (do *not* catch)
|
||||
*/
|
||||
private function setRememberCookie($selector, $token, $expires) {
|
||||
// get our cookie settings
|
||||
$params = $this->createCookieSettings();
|
||||
$params = \session_get_cookie_params();
|
||||
|
||||
if (isset($selector) && isset($token)) {
|
||||
$content = $selector . self::COOKIE_CONTENT_SEPARATOR . $token;
|
||||
@@ -421,29 +432,30 @@ final class Auth extends UserManager {
|
||||
$content = '';
|
||||
}
|
||||
|
||||
// set the cookie with the selector and token
|
||||
|
||||
$cookie = new Cookie(self::COOKIE_NAME_REMEMBER);
|
||||
|
||||
// save the cookie with the selector and token (requests a cookie to be written on the client)
|
||||
$cookie = new Cookie($this->rememberCookieName);
|
||||
$cookie->setValue($content);
|
||||
$cookie->setExpiryTime($expires);
|
||||
|
||||
if (!empty($params['path'])) {
|
||||
$cookie->setPath($params['path']);
|
||||
}
|
||||
|
||||
if (!empty($params['domain'])) {
|
||||
$cookie->setDomain($params['domain']);
|
||||
}
|
||||
|
||||
$cookie->setPath($params['path']);
|
||||
$cookie->setDomain($params['domain']);
|
||||
$cookie->setHttpOnly($params['httponly']);
|
||||
$cookie->setSecureOnly($params['secure']);
|
||||
|
||||
$result = $cookie->save();
|
||||
|
||||
if ($result === false) {
|
||||
throw new HeadersAlreadySentError();
|
||||
}
|
||||
|
||||
// if we've been deleting the cookie above
|
||||
if (!isset($selector) || !isset($token)) {
|
||||
// attempt to delete a potential old cookie from versions v1.x.x to v6.x.x as well (requests a cookie to be written on the client)
|
||||
$cookie = new Cookie('auth_remember');
|
||||
$cookie->setPath((!empty($params['path'])) ? $params['path'] : '/');
|
||||
$cookie->setDomain($params['domain']);
|
||||
$cookie->setHttpOnly($params['httponly']);
|
||||
$cookie->setSecureOnly($params['secure']);
|
||||
$cookie->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -461,7 +473,7 @@ final class Auth extends UserManager {
|
||||
try {
|
||||
$this->db->update(
|
||||
$this->dbTablePrefix . 'users',
|
||||
[ 'last_login' => time() ],
|
||||
[ 'last_login' => \time() ],
|
||||
[ 'id' => $userId ]
|
||||
);
|
||||
}
|
||||
@@ -469,7 +481,7 @@ final class Auth extends UserManager {
|
||||
throw new DatabaseError();
|
||||
}
|
||||
|
||||
// re-generate the session ID to prevent session fixation attacks
|
||||
// re-generate the session ID to prevent session fixation attacks (requests a cookie to be written on the client)
|
||||
Session::regenerate(true);
|
||||
|
||||
// save the user data in the session
|
||||
@@ -487,8 +499,8 @@ final class Auth extends UserManager {
|
||||
*
|
||||
* @throws AuthError if an internal problem occurred (do *not* catch)
|
||||
*/
|
||||
public function logout() {
|
||||
$this->logOutButKeepSession();
|
||||
public function logOutAndDestroySession() {
|
||||
$this->logOut();
|
||||
$this->destroySession();
|
||||
}
|
||||
|
||||
@@ -498,17 +510,12 @@ final class Auth extends UserManager {
|
||||
* @throws AuthError if an internal problem occurred (do *not* catch)
|
||||
*/
|
||||
private function deleteSessionCookie() {
|
||||
// get our cookie settings
|
||||
$params = $this->createCookieSettings();
|
||||
$params = \session_get_cookie_params();
|
||||
|
||||
// cause the session cookie to be deleted
|
||||
$cookie = new Cookie(session_name());
|
||||
if (!empty($params['path'])) {
|
||||
$cookie->setPath($params['path']);
|
||||
}
|
||||
if (!empty($params['domain'])) {
|
||||
$cookie->setDomain($params['domain']);
|
||||
}
|
||||
// ask for the session cookie to be deleted (requests a cookie to be written on the client)
|
||||
$cookie = new Cookie(\session_name());
|
||||
$cookie->setPath($params['path']);
|
||||
$cookie->setDomain($params['domain']);
|
||||
$cookie->setHttpOnly($params['httponly']);
|
||||
$cookie->setSecureOnly($params['secure']);
|
||||
$result = $cookie->delete();
|
||||
@@ -548,8 +555,8 @@ final class Auth extends UserManager {
|
||||
}
|
||||
|
||||
if (!empty($confirmationData)) {
|
||||
if (password_verify($token, $confirmationData['token'])) {
|
||||
if ($confirmationData['expires'] >= time()) {
|
||||
if (\password_verify($token, $confirmationData['token'])) {
|
||||
if ($confirmationData['expires'] >= \time()) {
|
||||
// invalidate any potential outstanding password reset requests
|
||||
try {
|
||||
$this->db->delete(
|
||||
@@ -700,7 +707,7 @@ final class Auth extends UserManager {
|
||||
* @throws AuthError if an internal problem occurred (do *not* catch)
|
||||
*/
|
||||
private function updatePassword($userId, $newPassword) {
|
||||
$newPassword = password_hash($newPassword, PASSWORD_DEFAULT);
|
||||
$newPassword = \password_hash($newPassword, \PASSWORD_DEFAULT);
|
||||
|
||||
try {
|
||||
$this->db->update(
|
||||
@@ -978,7 +985,7 @@ final class Auth extends UserManager {
|
||||
);
|
||||
}
|
||||
elseif ($username !== null) {
|
||||
$username = trim($username);
|
||||
$username = \trim($username);
|
||||
|
||||
// attempt to look up the account information using the specified username
|
||||
$userData = $this->getUserDataByUsername(
|
||||
@@ -994,9 +1001,9 @@ final class Auth extends UserManager {
|
||||
|
||||
$password = self::validatePassword($password);
|
||||
|
||||
if (password_verify($password, $userData['password'])) {
|
||||
if (\password_verify($password, $userData['password'])) {
|
||||
// if the password needs to be re-hashed to keep up with improving password cracking techniques
|
||||
if (password_needs_rehash($userData['password'], PASSWORD_DEFAULT)) {
|
||||
if (\password_needs_rehash($userData['password'], \PASSWORD_DEFAULT)) {
|
||||
// create a new hash from the password and update it in the database
|
||||
$this->updatePassword($userData['id'], $password);
|
||||
}
|
||||
@@ -1064,7 +1071,7 @@ final class Auth extends UserManager {
|
||||
*/
|
||||
private function getUserDataByEmailAddress($email, array $requestedColumns) {
|
||||
try {
|
||||
$projection = implode(', ', $requestedColumns);
|
||||
$projection = \implode(', ', $requestedColumns);
|
||||
$userData = $this->db->selectRow(
|
||||
'SELECT ' . $projection . ' FROM ' . $this->dbTablePrefix . 'users WHERE email = ?',
|
||||
[ $email ]
|
||||
@@ -1095,7 +1102,7 @@ final class Auth extends UserManager {
|
||||
'SELECT COUNT(*) FROM ' . $this->dbTablePrefix . 'users_resets WHERE user = ? AND expires > ?',
|
||||
[
|
||||
$userId,
|
||||
time()
|
||||
\time()
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1130,8 +1137,8 @@ final class Auth extends UserManager {
|
||||
private function createPasswordResetRequest($userId, $expiresAfter, callable $callback) {
|
||||
$selector = self::createRandomString(20);
|
||||
$token = self::createRandomString(20);
|
||||
$tokenHashed = password_hash($token, PASSWORD_DEFAULT);
|
||||
$expiresAt = time() + $expiresAfter;
|
||||
$tokenHashed = \password_hash($token, \PASSWORD_DEFAULT);
|
||||
$expiresAt = \time() + $expiresAfter;
|
||||
|
||||
try {
|
||||
$this->db->insert(
|
||||
@@ -1148,7 +1155,7 @@ final class Auth extends UserManager {
|
||||
throw new DatabaseError();
|
||||
}
|
||||
|
||||
if (isset($callback) && is_callable($callback)) {
|
||||
if (\is_callable($callback)) {
|
||||
$callback($selector, $token);
|
||||
}
|
||||
else {
|
||||
@@ -1188,8 +1195,8 @@ final class Auth extends UserManager {
|
||||
|
||||
if (!empty($resetData)) {
|
||||
if ((int) $resetData['resettable'] === 1) {
|
||||
if (password_verify($token, $resetData['token'])) {
|
||||
if ($resetData['expires'] >= time()) {
|
||||
if (\password_verify($token, $resetData['token'])) {
|
||||
if ($resetData['expires'] >= \time()) {
|
||||
$newPassword = self::validatePassword($newPassword);
|
||||
|
||||
// update the password in the database
|
||||
@@ -1344,7 +1351,7 @@ final class Auth extends UserManager {
|
||||
* @param int $userId the user's ID
|
||||
*/
|
||||
private function setUserId($userId) {
|
||||
$_SESSION[self::SESSION_FIELD_USER_ID] = intval($userId);
|
||||
$_SESSION[self::SESSION_FIELD_USER_ID] = (int) $userId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1729,24 +1736,6 @@ final class Auth extends UserManager {
|
||||
return new Administration($this->db, $this->dbTablePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the cookie settings that will be used to create and update cookies on the client
|
||||
*
|
||||
* @return array the cookie settings
|
||||
*/
|
||||
private function createCookieSettings() {
|
||||
// get the default cookie settings
|
||||
$params = session_get_cookie_params();
|
||||
|
||||
// check if we want to send cookies via SSL/TLS only
|
||||
$params['secure'] = $params['secure'] || $this->useHttps;
|
||||
// check if we want to send cookies via HTTP(S) only
|
||||
$params['httponly'] = $params['httponly'] || !$this->allowCookiesScriptAccess;
|
||||
|
||||
// return the modified settings
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a UUID v4 as per RFC 4122
|
||||
*
|
||||
@@ -1756,14 +1745,57 @@ final class Auth extends UserManager {
|
||||
* @author Jack @ Stack Overflow
|
||||
*/
|
||||
public static function createUuid() {
|
||||
$data = openssl_random_pseudo_bytes(16);
|
||||
$data = \openssl_random_pseudo_bytes(16);
|
||||
|
||||
// set the version to 0100
|
||||
$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
|
||||
$data[6] = \chr(\ord($data[6]) & 0x0f | 0x40);
|
||||
// set bits 6-7 to 10
|
||||
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
|
||||
$data[8] = \chr(\ord($data[8]) & 0x3f | 0x80);
|
||||
|
||||
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
|
||||
return \vsprintf('%s%s-%s-%s-%s-%s%s%s', \str_split(\bin2hex($data), 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique cookie name for the given descriptor based on the supplied seed
|
||||
*
|
||||
* @param string $descriptor a short label describing the purpose of the cookie, e.g. 'session'
|
||||
* @param string|null $seed (optional) the data to deterministically generate the name from
|
||||
* @return string
|
||||
*/
|
||||
public static function createCookieName($descriptor, $seed = null) {
|
||||
// use the supplied seed or the current UNIX time in seconds
|
||||
$seed = ($seed !== null) ? $seed : \time();
|
||||
|
||||
foreach (self::COOKIE_PREFIXES as $cookiePrefix) {
|
||||
// if the seed contains a certain cookie prefix
|
||||
if (\strpos($seed, $cookiePrefix) === 0) {
|
||||
// prepend the same prefix to the descriptor
|
||||
$descriptor = $cookiePrefix . $descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
// generate a unique token based on the name(space) of this library and on the seed
|
||||
$token = Base64::encodeUrlSafeWithoutPadding(
|
||||
\md5(
|
||||
__NAMESPACE__ . "\n" . $seed,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
return $descriptor . '_' . $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique cookie name for the 'remember me' feature
|
||||
*
|
||||
* @param string|null $sessionName (optional) the session name that the output should be based on
|
||||
* @return string
|
||||
*/
|
||||
public static function createRememberCookieName($sessionName = null) {
|
||||
return self::createCookieName(
|
||||
'remember',
|
||||
($sessionName !== null) ? $sessionName : \session_name()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -40,10 +40,10 @@ abstract class UserManager {
|
||||
*/
|
||||
public static function createRandomString($maxLength = 24) {
|
||||
// calculate how many bytes of randomness we need for the specified string length
|
||||
$bytes = floor(intval($maxLength) / 4) * 3;
|
||||
$bytes = \floor((int) $maxLength / 4) * 3;
|
||||
|
||||
// get random data
|
||||
$data = openssl_random_pseudo_bytes($bytes);
|
||||
$data = \openssl_random_pseudo_bytes($bytes);
|
||||
|
||||
// return the Base64-encoded result
|
||||
return Base64::encodeUrlSafe($data);
|
||||
@@ -103,12 +103,12 @@ abstract class UserManager {
|
||||
* @see confirmEmailAndSignIn
|
||||
*/
|
||||
protected function createUserInternal($requireUniqueUsername, $email, $password, $username = null, callable $callback = null) {
|
||||
ignore_user_abort(true);
|
||||
\ignore_user_abort(true);
|
||||
|
||||
$email = self::validateEmailAddress($email);
|
||||
$password = self::validatePassword($password);
|
||||
|
||||
$username = isset($username) ? trim($username) : null;
|
||||
$username = isset($username) ? \trim($username) : null;
|
||||
|
||||
// if the supplied username is the empty string or has consisted of whitespace only
|
||||
if ($username === '') {
|
||||
@@ -134,8 +134,8 @@ abstract class UserManager {
|
||||
}
|
||||
}
|
||||
|
||||
$password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$verified = isset($callback) && is_callable($callback) ? 0 : 1;
|
||||
$password = \password_hash($password, \PASSWORD_DEFAULT);
|
||||
$verified = \is_callable($callback) ? 0 : 1;
|
||||
|
||||
try {
|
||||
$this->db->insert(
|
||||
@@ -145,7 +145,7 @@ abstract class UserManager {
|
||||
'password' => $password,
|
||||
'username' => $username,
|
||||
'verified' => $verified,
|
||||
'registered' => time()
|
||||
'registered' => \time()
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -180,7 +180,7 @@ abstract class UserManager {
|
||||
*/
|
||||
protected function getUserDataByUsername($username, array $requestedColumns) {
|
||||
try {
|
||||
$projection = implode(', ', $requestedColumns);
|
||||
$projection = \implode(', ', $requestedColumns);
|
||||
|
||||
$users = $this->db->select(
|
||||
'SELECT ' . $projection . ' FROM ' . $this->dbTablePrefix . 'users WHERE username = ? LIMIT 2 OFFSET 0',
|
||||
@@ -195,7 +195,7 @@ abstract class UserManager {
|
||||
throw new UnknownUsernameException();
|
||||
}
|
||||
else {
|
||||
if (count($users) === 1) {
|
||||
if (\count($users) === 1) {
|
||||
return $users[0];
|
||||
}
|
||||
else {
|
||||
@@ -216,9 +216,9 @@ abstract class UserManager {
|
||||
throw new InvalidEmailException();
|
||||
}
|
||||
|
||||
$email = trim($email);
|
||||
$email = \trim($email);
|
||||
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
if (!\filter_var($email, \FILTER_VALIDATE_EMAIL)) {
|
||||
throw new InvalidEmailException();
|
||||
}
|
||||
|
||||
@@ -237,9 +237,9 @@ abstract class UserManager {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
$password = trim($password);
|
||||
$password = \trim($password);
|
||||
|
||||
if (strlen($password) < 1) {
|
||||
if (\strlen($password) < 1) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
@@ -265,10 +265,10 @@ abstract class UserManager {
|
||||
protected function createConfirmationRequest($userId, $email, callable $callback) {
|
||||
$selector = self::createRandomString(16);
|
||||
$token = self::createRandomString(16);
|
||||
$tokenHashed = password_hash($token, PASSWORD_DEFAULT);
|
||||
$tokenHashed = \password_hash($token, \PASSWORD_DEFAULT);
|
||||
|
||||
// the request shall be valid for one day
|
||||
$expires = time() + self::CONFIRMATION_REQUESTS_TTL_IN_SECONDS;
|
||||
$expires = \time() + self::CONFIRMATION_REQUESTS_TTL_IN_SECONDS;
|
||||
|
||||
try {
|
||||
$this->db->insert(
|
||||
@@ -286,7 +286,7 @@ abstract class UserManager {
|
||||
throw new DatabaseError();
|
||||
}
|
||||
|
||||
if (isset($callback) && is_callable($callback)) {
|
||||
if (\is_callable($callback)) {
|
||||
$callback($selector, $token);
|
||||
}
|
||||
else {
|
||||
|
159
tests/index.php
159
tests/index.php
@@ -15,33 +15,34 @@
|
||||
*/
|
||||
|
||||
// enable error reporting
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 'stdout');
|
||||
\error_reporting(\E_ALL);
|
||||
\ini_set('display_errors', 'stdout');
|
||||
|
||||
// enable assertions
|
||||
ini_set('assert.active', 1);
|
||||
@ini_set('zend.assertions', 1);
|
||||
ini_set('assert.exception', 1);
|
||||
\ini_set('assert.active', 1);
|
||||
@\ini_set('zend.assertions', 1);
|
||||
\ini_set('assert.exception', 1);
|
||||
|
||||
header('Content-type: text/html; charset=utf-8');
|
||||
\header('Content-type: text/html; charset=utf-8');
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$db = new PDO('mysql:dbname=php_auth;host=127.0.0.1;charset=utf8mb4', 'root', 'monkey');
|
||||
$db = new \PDO('mysql:dbname=php_auth;host=127.0.0.1;charset=utf8mb4', 'root', 'monkey');
|
||||
// or
|
||||
// $db = new PDO('sqlite:../Databases/php_auth.sqlite');
|
||||
// $db = new \PDO('sqlite:../Databases/php_auth.sqlite');
|
||||
|
||||
$auth = new \Delight\Auth\Auth($db);
|
||||
|
||||
$result = processRequestData($auth);
|
||||
$result = \processRequestData($auth);
|
||||
|
||||
showDebugData($auth, $result);
|
||||
\showGeneralForm();
|
||||
\showDebugData($auth, $result);
|
||||
|
||||
if ($auth->check()) {
|
||||
showAuthenticatedUserForm($auth);
|
||||
\showAuthenticatedUserForm($auth);
|
||||
}
|
||||
else {
|
||||
showGuestUserForm();
|
||||
\showGuestUserForm();
|
||||
}
|
||||
|
||||
function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
@@ -98,11 +99,11 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
echo "\n";
|
||||
echo ' > Selector';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($selector);
|
||||
echo \htmlspecialchars($selector);
|
||||
echo "\n";
|
||||
echo ' > Token';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($token);
|
||||
echo \htmlspecialchars($token);
|
||||
echo '</pre>';
|
||||
};
|
||||
}
|
||||
@@ -177,11 +178,11 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
echo "\n";
|
||||
echo ' > Selector';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($selector);
|
||||
echo \htmlspecialchars($selector);
|
||||
echo "\n";
|
||||
echo ' > Token';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($token);
|
||||
echo \htmlspecialchars($token);
|
||||
echo '</pre>';
|
||||
});
|
||||
|
||||
@@ -202,11 +203,11 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
echo "\n";
|
||||
echo ' > Selector';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($selector);
|
||||
echo \htmlspecialchars($selector);
|
||||
echo "\n";
|
||||
echo ' > Token';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($token);
|
||||
echo \htmlspecialchars($token);
|
||||
echo '</pre>';
|
||||
});
|
||||
|
||||
@@ -227,11 +228,11 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
echo "\n";
|
||||
echo ' > Selector';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($selector);
|
||||
echo \htmlspecialchars($selector);
|
||||
echo "\n";
|
||||
echo ' > Token';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($token);
|
||||
echo \htmlspecialchars($token);
|
||||
echo '</pre>';
|
||||
});
|
||||
|
||||
@@ -320,11 +321,11 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
echo "\n";
|
||||
echo ' > Selector';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($selector);
|
||||
echo \htmlspecialchars($selector);
|
||||
echo "\n";
|
||||
echo ' > Token';
|
||||
echo "\t\t\t\t";
|
||||
echo htmlspecialchars($token);
|
||||
echo \htmlspecialchars($token);
|
||||
echo '</pre>';
|
||||
});
|
||||
|
||||
@@ -356,13 +357,13 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
return 'not logged in';
|
||||
}
|
||||
}
|
||||
else if ($_POST['action'] === 'logOutButKeepSession') {
|
||||
$auth->logOutButKeepSession();
|
||||
else if ($_POST['action'] === 'logOut') {
|
||||
$auth->logOut();
|
||||
|
||||
return 'ok';
|
||||
}
|
||||
else if ($_POST['action'] === 'logout') {
|
||||
$auth->logout();
|
||||
else if ($_POST['action'] === 'logOutAndDestroySession') {
|
||||
$auth->logOutAndDestroySession();
|
||||
|
||||
return 'ok';
|
||||
}
|
||||
@@ -523,7 +524,7 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Exception('Unexpected action: '.$_POST['action']);
|
||||
throw new Exception('Unexpected action: ' . $_POST['action']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -534,57 +535,65 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
function showDebugData(\Delight\Auth\Auth $auth, $result) {
|
||||
echo '<pre>';
|
||||
|
||||
echo 'Last operation'."\t\t\t\t";
|
||||
var_dump($result);
|
||||
echo 'Session ID'."\t\t\t\t";
|
||||
var_dump(session_id());
|
||||
echo 'Last operation' . "\t\t\t\t";
|
||||
\var_dump($result);
|
||||
echo 'Session ID' . "\t\t\t\t";
|
||||
\var_dump(\session_id());
|
||||
echo "\n";
|
||||
|
||||
echo '$auth->isLoggedIn()'."\t\t\t";
|
||||
var_dump($auth->isLoggedIn());
|
||||
echo '$auth->check()'."\t\t\t\t";
|
||||
var_dump($auth->check());
|
||||
echo '$auth->isLoggedIn()' . "\t\t\t";
|
||||
\var_dump($auth->isLoggedIn());
|
||||
echo '$auth->check()' . "\t\t\t\t";
|
||||
\var_dump($auth->check());
|
||||
echo "\n";
|
||||
|
||||
echo '$auth->getUserId()'."\t\t\t";
|
||||
var_dump($auth->getUserId());
|
||||
echo '$auth->id()'."\t\t\t\t";
|
||||
var_dump($auth->id());
|
||||
echo '$auth->getUserId()' . "\t\t\t";
|
||||
\var_dump($auth->getUserId());
|
||||
echo '$auth->id()' . "\t\t\t\t";
|
||||
\var_dump($auth->id());
|
||||
echo "\n";
|
||||
|
||||
echo '$auth->getEmail()'."\t\t\t";
|
||||
var_dump($auth->getEmail());
|
||||
echo '$auth->getUsername()'."\t\t\t";
|
||||
var_dump($auth->getUsername());
|
||||
echo '$auth->getEmail()' . "\t\t\t";
|
||||
\var_dump($auth->getEmail());
|
||||
echo '$auth->getUsername()' . "\t\t\t";
|
||||
\var_dump($auth->getUsername());
|
||||
|
||||
echo '$auth->getStatus()'."\t\t\t";
|
||||
echo convertStatusToText($auth);
|
||||
echo '$auth->getStatus()' . "\t\t\t";
|
||||
echo \convertStatusToText($auth);
|
||||
echo ' / ';
|
||||
var_dump($auth->getStatus());
|
||||
\var_dump($auth->getStatus());
|
||||
|
||||
echo "\n";
|
||||
|
||||
echo 'Roles (super moderator)'."\t\t\t";
|
||||
var_dump($auth->hasRole(\Delight\Auth\Role::SUPER_MODERATOR));
|
||||
echo 'Roles (super moderator)' . "\t\t\t";
|
||||
\var_dump($auth->hasRole(\Delight\Auth\Role::SUPER_MODERATOR));
|
||||
|
||||
echo 'Roles (developer *or* manager)'."\t\t";
|
||||
var_dump($auth->hasAnyRole(\Delight\Auth\Role::DEVELOPER, \Delight\Auth\Role::MANAGER));
|
||||
echo 'Roles (developer *or* manager)' . "\t\t";
|
||||
\var_dump($auth->hasAnyRole(\Delight\Auth\Role::DEVELOPER, \Delight\Auth\Role::MANAGER));
|
||||
|
||||
echo 'Roles (developer *and* manager)'."\t\t";
|
||||
var_dump($auth->hasAllRoles(\Delight\Auth\Role::DEVELOPER, \Delight\Auth\Role::MANAGER));
|
||||
echo 'Roles (developer *and* manager)' . "\t\t";
|
||||
\var_dump($auth->hasAllRoles(\Delight\Auth\Role::DEVELOPER, \Delight\Auth\Role::MANAGER));
|
||||
|
||||
echo "\n";
|
||||
|
||||
echo '$auth->isRemembered()'."\t\t\t";
|
||||
var_dump($auth->isRemembered());
|
||||
echo '$auth->getIpAddress()'."\t\t\t";
|
||||
var_dump($auth->getIpAddress());
|
||||
echo '$auth->isRemembered()' . "\t\t\t";
|
||||
\var_dump($auth->isRemembered());
|
||||
echo '$auth->getIpAddress()' . "\t\t\t";
|
||||
\var_dump($auth->getIpAddress());
|
||||
echo "\n";
|
||||
|
||||
echo 'Auth::createRandomString()'."\t\t";
|
||||
var_dump(\Delight\Auth\Auth::createRandomString());
|
||||
echo 'Auth::createUuid()'."\t\t\t";
|
||||
var_dump(\Delight\Auth\Auth::createUuid());
|
||||
echo 'Session name' . "\t\t\t\t";
|
||||
\var_dump(\session_name());
|
||||
echo 'Auth::createRememberCookieName()' . "\t";
|
||||
\var_dump(\Delight\Auth\Auth::createRememberCookieName());
|
||||
echo "\n";
|
||||
|
||||
echo 'Auth::createCookieName(\'session\')' . "\t";
|
||||
\var_dump(\Delight\Auth\Auth::createCookieName('session'));
|
||||
echo 'Auth::createRandomString()' . "\t\t";
|
||||
\var_dump(\Delight\Auth\Auth::createRandomString());
|
||||
echo 'Auth::createUuid()' . "\t\t\t";
|
||||
\var_dump(\Delight\Auth\Auth::createUuid());
|
||||
|
||||
echo '</pre>';
|
||||
}
|
||||
@@ -626,8 +635,6 @@ function showGeneralForm() {
|
||||
}
|
||||
|
||||
function showAuthenticatedUserForm(\Delight\Auth\Auth $auth) {
|
||||
showGeneralForm();
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="reconfirmPassword" />';
|
||||
echo '<input type="text" name="password" placeholder="Password" /> ';
|
||||
@@ -653,7 +660,7 @@ function showAuthenticatedUserForm(\Delight\Auth\Auth $auth) {
|
||||
echo '<button type="submit">Change email address</button>';
|
||||
echo '</form>';
|
||||
|
||||
showConfirmEmailForm();
|
||||
\showConfirmEmailForm();
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="setPasswordResetEnabled" />';
|
||||
@@ -665,19 +672,17 @@ function showAuthenticatedUserForm(\Delight\Auth\Auth $auth) {
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="logOutButKeepSession" />';
|
||||
echo '<button type="submit">Log out but keep session</button>';
|
||||
echo '<input type="hidden" name="action" value="logOut" />';
|
||||
echo '<button type="submit">Log out</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="logout" />';
|
||||
echo '<button type="submit">Log out</button>';
|
||||
echo '<input type="hidden" name="action" value="logOutAndDestroySession" />';
|
||||
echo '<button type="submit">Log out and destroy session</button>';
|
||||
echo '</form>';
|
||||
}
|
||||
|
||||
function showGuestUserForm() {
|
||||
showGeneralForm();
|
||||
|
||||
echo '<h1>Public</h1>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
@@ -718,7 +723,7 @@ function showGuestUserForm() {
|
||||
echo '<button type="submit">Register</button>';
|
||||
echo '</form>';
|
||||
|
||||
showConfirmEmailForm();
|
||||
\showConfirmEmailForm();
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="forgotPassword" />';
|
||||
@@ -769,49 +774,49 @@ function showGuestUserForm() {
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.addRole" />';
|
||||
echo '<input type="text" name="id" placeholder="ID" /> ';
|
||||
echo '<select name="role">' . createRolesOptions() . '</select>';
|
||||
echo '<select name="role">' . \createRolesOptions() . '</select>';
|
||||
echo '<button type="submit">Add role for user by ID</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.addRole" />';
|
||||
echo '<input type="text" name="email" placeholder="Email" /> ';
|
||||
echo '<select name="role">' . createRolesOptions() . '</select>';
|
||||
echo '<select name="role">' . \createRolesOptions() . '</select>';
|
||||
echo '<button type="submit">Add role for user by email</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.addRole" />';
|
||||
echo '<input type="text" name="username" placeholder="Username" /> ';
|
||||
echo '<select name="role">' . createRolesOptions() . '</select>';
|
||||
echo '<select name="role">' . \createRolesOptions() . '</select>';
|
||||
echo '<button type="submit">Add role for user by username</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.removeRole" />';
|
||||
echo '<input type="text" name="id" placeholder="ID" /> ';
|
||||
echo '<select name="role">' . createRolesOptions() . '</select>';
|
||||
echo '<select name="role">' . \createRolesOptions() . '</select>';
|
||||
echo '<button type="submit">Remove role for user by ID</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.removeRole" />';
|
||||
echo '<input type="text" name="email" placeholder="Email" /> ';
|
||||
echo '<select name="role">' . createRolesOptions() . '</select>';
|
||||
echo '<select name="role">' . \createRolesOptions() . '</select>';
|
||||
echo '<button type="submit">Remove role for user by email</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.removeRole" />';
|
||||
echo '<input type="text" name="username" placeholder="Username" /> ';
|
||||
echo '<select name="role">' . createRolesOptions() . '</select>';
|
||||
echo '<select name="role">' . \createRolesOptions() . '</select>';
|
||||
echo '<button type="submit">Remove role for user by username</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.hasRole" />';
|
||||
echo '<input type="text" name="id" placeholder="ID" /> ';
|
||||
echo '<select name="role">' . createRolesOptions() . '</select>';
|
||||
echo '<select name="role">' . \createRolesOptions() . '</select>';
|
||||
echo '<button type="submit">Does user have role?</button>';
|
||||
echo '</form>';
|
||||
}
|
||||
|
Reference in New Issue
Block a user