Skip to content

Commit

Permalink
Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
doublecompile committed Jan 6, 2018
1 parent 9c77325 commit 1bf965c
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 6 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ Releases of this library will conform to [Semantic Versioning](http://semver.org

Our code is intended to comply with [PSR-1](http://www.php-fig.org/psr/psr-1/), [PSR-2](http://www.php-fig.org/psr/psr-2/), and [PSR-4](http://www.php-fig.org/psr/psr-4/). If you find any issues related to standards compliance, please send a pull request!

## Documentation

* Head over to [Read the Docs](http://caridea-auth.readthedocs.io/en/latest/)

## Examples

Just a few quick examples.
Expand Down
87 changes: 87 additions & 0 deletions docs/01-service.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Working with the Service

The `Caridea\Auth\Service` class is your primary means of interacting with this library.

When constructed, the `Caridea\Auth\Service` needs to be provided a `Caridea\Session\Session`. It optionally accepts a `Caridea\Event\Publisher` and a `Caridea\Auth\Adapter`. It also implements `Caridea\Event\PublisherAware` and `Psr\Log\LoggerAwareInterface`.

```php
$session = \Caridea\Session\NativeSession($_COOKIE);
$manager = new \MongoDB\Driver\Manager("mongodb://localhost:27017");
$adapter = new \Caridea\Auth\Adapter\MongoDb($manager, 'collection_foobar', 'username', 'password');
$service = new \Caridea\Auth\Service($session, null, $adapter);
$service->setLogger(new \Psr\Log\NullLogger());
```

## The Principal

The currently authenticated user is represented by the `Caridea\Auth\Principal` class. It contains three methods of note.

* `getUsername` – Gets the `string` username of the authenticated principal, or `null` if the principal is anonymous
* `getDetails` – Gets an associative `array` of details about the authentication
* `isAnonymous` – Returns `true` if the principal is anonymous, `false` otherwise

## Service Methods

The `Caridea\Auth\Service` class contains only a few public methods.

* `getPrincipal` – This returns the currently authenticated `Caridea\Auth\Principal`, which could be anonymous
* `login` – Uses an adapter to authenticate a principal using details from the request; returns `true` if successful, throws exceptions otherwise
* `resume` – Resumes an authenticated session; returns `true` if one existed, `false` otherwise
* `logout` – Ends an authenticated session; returns `true` if one existed, `false` otherwise

### Login

The `login` method must be provided a PSR-7 `RequestInterface` that it uses to retrieve the credentials entered by the user. An optional second argument is the adapter to use, which is required if one was not specified when the service was constructed.

```php
// Let's say $request is a \Psr\Http\Message\RequestInterface
if ($service->login($request)) {
$principal = $service->getPrincipal();
$username = $principal->getUsername();
$details = $principal->getDetails());
var_dump($details);
}
```

This might output:

```
array(3) {
'id' =>
string(10) "1234567890"
'ua' =>
string(11) "Mozilla/5.0"
'ip' =>
string(11) "192.168.1.1"
}
```

Once `login` is invoked, the authenticated principal is stored in the session and a message about the authentication is logged using the `info` level.

### Resume

If a principal has been previously authenticated in the active session, the `resume` method will pick it back up.

```php
if ($service->resume()) {
$principal = $service->getPrincipal();
}
```

If an authentication is resumed successfully, a message about the resumption is logged using the `info` level.

### Get the Principal

The first time the `getPrincipal` method is invoked, it will attempt to invoke the `resume` method if it hasn't already been called. If no authenticated principal is available, it will return an anonymous principal.

### Logout

Invoking the `logout` method will destroy the active session and reset the principal to be anonymous.

```php
if ($service->logout()) {
// anonymous!
}
```

if an authentication is logged out successfully, a message about the logout is logged using the `info` level.
79 changes: 79 additions & 0 deletions docs/02-adapters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Adapters

The `Caridea\Auth\Service` class uses adapters to abstract away the implementation details of storing user information.

Included with this library are three adapters for authentication through MongoDB, PDO, and X.509 client SSL certificates. You can easily write your own adapter for other authentication sources like IMAP, LDAP, or OAuth2 by implementing the `Caridea\Auth\Adapter` interface.

## MongoDB

The adapter for MongoDB requires a few connection details. The `MongoDB\Driver\Manager`, the collection name, the name of the field containing the username, and the name of the field containing the password hash. There are also two optional parameters: an `array` to use as a query to limit user accounts (such as those that are not blocked), and finally a `MongoDB\Driver\ReadPreference`.

```php
$manager = new \MongoDB\Driver\Manager("mongodb://localhost:27017");
$collectionName = "users";
$fieldUser = 'email';
$fieldPassword = 'password';
$query = ['active' => 1];
$rp = new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::RP_NEAREST);
$adapter = new \Caridea\Auth\Adapter\MongoDb(
$manager,
$collectionName,
$fieldUser,
$fieldPassword,
$query, // optional
$rp // optional
);
```

This adapter expects the `$_POST` values to be contained in the keys `username` and `password`. It also expects the password stored in the MongoDB collection to be one generated by `password_hash`.

## PDO

The adapter for PDO requires a few connection details. The `PDO` object, the name of the column containing the username, the name of the column containing the password hash, and the table name. It has one optional parameter: a `WHERE` clause to limit user accounts (such as those that are not blocked).

```php
$pdo = new PDO("mysql:host=localhost;dbname=DB;charset=UTF8");
$fieldUser = 'email';
$fieldPassword = 'password';
$tableName = 'user';
$where = "foo = 'bar'";
$adapter = new \Caridea\Auth\Adapter\Pdo(
$pdo,
$fieldUser,
$fieldPassword,
$tableName,
$where // optional
);
```

This adapter expects the `$_POST` values to be contained in the keys `username` and `password`. It also expects the password stored in the MongoDB collection to be one generated by `password_hash`.

## X.509 Certificates

The adapter for X.509 certificates has two optional parameters:
* The key within the `$_SERVER` parameters where the client certificate DN is available
* If omitted, `SSL_CLIENT_S_DN` is the default
* A regular expression pattern that can be used to extract the username from the certificate DN
* It must have only one capturing group
* If omitted, the entire DN is used as the username

```php
$fieldDn = 'SSL_CLIENT_S_DN';
$regex = '#/CN=(.+)$#';
$object = new Cert(
$fieldDn,
$regex
);
// this would extract the username 'Bob' from the DN '/O=Acme, Inc./CN=Bob'
```

This adapter does not need to validate passwords. With two-way encryption, there's no need!

## Abstract Adapter

There is an abstract class, `Caridea\Auth\Adapter\AbstractAdapter`, which has several protected methods to simplify implementing your own adapter. All three provided adapters extend this abstract class.

* `checkBlank` – Used to ensure construction parameters are not blank, otherwise throws `InvalidArgumentException`.
* `ensure` – Used to ensure user-provided values are not blank, otherwise throws `Caridea\Auth\Exception\MissingCredentials`.
* `verify` – Uses the `password_verify` function to compare user-provided credentials with the stored hash, otherwise throws `Caridea\Auth\Exception\InvalidPassword`.
* `details` – Merges a provided associative array with default authentication details: the client's IP address, and the client's user agent string.
37 changes: 37 additions & 0 deletions docs/03-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Events

If the user has supplied a `Caridea\Event\Publisher`, such as `Caridea\Container\Objects`, the `Caridea\Auth\Service` class broadcasts events during the lifecycle of an authentication.

## Login

When the `login` method is invoked, a `Caridea\Auth\Event\Login` event is published, with a `source` of the service.

## Resume

When the `resume` method is invoked, a `Caridea\Auth\Event\Resume` event is published, with a `source` of the service. The event class has two methods of note:

* `getFirstActive` – Returns the `float` time when the authentication first occurred, as returned by `microtime(true)`.
* `getLastActive` – Returns the `float` time of the most recent session resume, as returned by `microtime(true)`.

## Logout

When the `logout` method is invoked, a `Caridea\Auth\Event\Logout` event is published, with a `source` of the service.

## Timeout Listener

The `Caridea\Auth\TimeoutListener` class is a `Caridea\Event\Listener` that can be registered with a `Caridea\Event\Publisher`. It listens for `Caridea\Auth\Event\Resume` notifications.

The `TimeoutListener` has two optional constructor parameters:
* The number of seconds until a session should be considered idle. If omitted, the default is 20 minutes.
* The number of seconds until a session should be considered expired. If omitted, the default is 24 hours.

```php
$idle = 2400 // 40 minutes
$expired = 43200 // 12 hours
$listener = new \Caridea\Auth\TimeoutListener($idle, $expired);
```

When the listener is notified of a resume event, the following happens:

* If the difference between the current time and the value returned by `getLastActive` is more than the idle time, the `logout` service method is invoked.
* If the difference between the current time and the value returned by `getFirstActive` is more than the expiration time, the `logout` service method is invoked.
9 changes: 9 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# caridea/auth

🍤 Caridea is a miniscule PHP application library. This shrimpy fellow is what you'd use when you just want some helping hands and not a full-blown framework.

This is its authentication component. It provides a way to authenticate principals and store their identity. It will broadcast authentication events for any listeners. It works with any implementation of [PSR-7](http://www.php-fig.org/psr/psr-7/).

* [Working with the Service](01-service.md)
* [Adapters](02-adapters.md)
* [Events](03-events.md)
12 changes: 6 additions & 6 deletions src/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* @copyright 2015-2018 LibreWorks contributors
* @license Apache-2.0
*/
class Service implements \Caridea\Event\PublisherAware
class Service implements \Caridea\Event\PublisherAware, \Psr\Log\LoggerAwareInterface
{
use \Psr\Log\LoggerAwareTrait;
use \Caridea\Event\PublisherSetter;
Expand All @@ -57,10 +57,10 @@ class Service implements \Caridea\Event\PublisherAware
* Creates a new authentication service.
*
* @param Session $session The session utility
* @param Publisher $publisher An event publisher to broadcast authentication events
* @param Adapter $adapter A default authentication adapter
* @param Publisher|null $publisher An event publisher to broadcast authentication events
* @param Adapter|null $adapter A default authentication adapter
*/
public function __construct(Session $session, Publisher $publisher = null, Adapter $adapter = null)
public function __construct(Session $session, ?Publisher $publisher = null, ?Adapter $adapter = null)
{
$this->session = $session;
$this->values = $session->getValues(__CLASS__);
Expand Down Expand Up @@ -90,7 +90,7 @@ public function getPrincipal(): Principal
* Authenticates a principal.
*
* @param ServerRequestInterface $request The Server Request message containing credentials
* @param Adapter $adapter An optional adapter to use.
* @param Adapter|null $adapter An optional adapter to use.
* Will use the default authentication adapter if none is specified.
* @return bool Whether the session could be established
* @throws \InvalidArgumentException If no adapter is provided and no default adapter is set
Expand All @@ -100,7 +100,7 @@ public function getPrincipal(): Principal
* @throws Exception\ConnectionFailed if the access to a remote data source failed
* (e.g. missing flat file, unreachable LDAP server, database login denied)
*/
public function login(ServerRequestInterface $request, Adapter $adapter = null): bool
public function login(ServerRequestInterface $request, ?Adapter $adapter = null): bool
{
$started = $this->session->resume() || $this->session->start();
if (!$started) {
Expand Down

0 comments on commit 1bf965c

Please sign in to comment.