Skip to content

Commit

Permalink
0.2.0 (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Pierce committed Oct 6, 2019
1 parent 0e56ae0 commit 7815b69
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 129 deletions.
58 changes: 18 additions & 40 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,45 @@

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 0.1.2 - 2019-10-05
## 0.2.0 - 2019-10-06

### Added

- Additional instructions to the PR template

### Changed
- `JWT::getJWTFromRequest()`: Attempts to find a JWT in request headers and return it.

- Nothing.
- `JWT::parseAndVerifyJWT()`: Attempts to parse a JWT and verify that it is signed using the shared secret.

### Deprecated
- `JWT::parseJWT()`: Attempts to parse a JWT string.

- Nothing.
- `JWT::verifyJWT()`: Attempts to verify a JWT token with the shared secret key.

### Removed
- `JWT::getUserByJWT()`: Looks for a Craft user that matches the claimed email in the verified token.

- Deleted some unneeded asset files
- `JWT::createUserByJWT()`: Creates a Craft user based on the claims found in the verified token.

- Cleaned up various files of unneeded cruft
- Roadmap to 1.0 in README

### Fixed
### Changed

- Nothing.
- Refactored authentication logic into service calls

## 0.1.1 - 2019-10-04
## 0.1.2 - 2019-10-05

### Added

- Nothing.

### Changed

- Changed the name of the package to edenspiekermann/craft-jwt-auth
- Additional instructions to the PR template

### Deprecated
### Removed

- Nothing.
- Deleted some unneeded asset files

### Removed
- Cleaned up various files of unneeded cruft

- Nothing.
## 0.1.1 - 2019-10-04

### Fixed
### Changed

- Nothing.
- Changed the name of the package to edenspiekermann/craft-jwt-auth

## 0.1.0 - 2019-10-04

Expand All @@ -59,19 +53,3 @@ All notable changes to this project will be documented in this file, in reverse
- Match a validated JWT to a user account in Craft CMS and login as that user.

- Optionally create a new account if no existing account can be found.

### Changed

- Nothing.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,25 @@ If the token is verifiable but a matching user account does NOT exist, but the `

## Craft JWT Auth Roadmap

### Features

The plugin does or will offer the following features:

- [x] Validate incoming requests with a JWT present in the Authentication headers.
- [x] Match a validated JWT to a user account in Craft CMS and login as that user.
- [x] Optionally create a new account if no existing account can be found.
- [ ] Generate a JWT from a user’s account data to enable sharing with other services that implement the same secret key.

### Milestones

While the plugin is already useable, it is by no means finished. Use at your own risk. Some things to do before I'm comfortable taking it to version 1.0.0:

- [ ] Better error and exception handling in general.
- [ ] Better testing for the presence of an actual JWT, rather than some other type of token.
- [ ] Checking for the presence of valid claims and handling if they aren't there.
- [ ] Handle edge case of successful user creation but failed image creation.
- [ ] Add test cases for all of that.
- [ ] `0.2.0` Refactor into more logical set of services and classes.
- [ ] `0.3.0` Better testing for the presence of an actual JWT, rather than some other type of token.
- [ ] `0.3.1` Checking for the presence of valid claims and handling if they aren't there.
- [ ] `0.3.2` Handle edge case of successful user creation but failed image creation.
- [ ] `0.3.3` Better exception handling in general.
- [ ] `0.4.0` Add test cases for all of that.
- [ ] Have really smart people review the code for vulnerabilities.
- [ ] Other stuff I haven't though of because I haven't done 👆 yet.

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "edenspiekermann/craft-jwt-auth",
"description": "Enable authentication to Craft through the use of JSON Web Tokens (JWT)",
"type": "craft-plugin",
"version": "0.1.2",
"version": "0.2.0",
"keywords": [
"craft",
"cms",
Expand Down
95 changes: 12 additions & 83 deletions src/CraftJwtAuth.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@

use Craft;
use craft\base\Plugin;
use craft\elements\User;
use craft\helpers\StringHelper;
use craft\web\Application;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Hmac\Sha256;

use yii\base\Event;

Expand Down Expand Up @@ -63,88 +59,21 @@ public function init()
self::$plugin = $this;

Craft::$app->on(Application::EVENT_INIT, function (Event $event) {
// Get relevant settings
$secretKey = self::$plugin->getSettings()->secretKey;
$autoCreateUser = self::$plugin->getSettings()->autoCreateUser;
$allowPublicRegistration = Craft::$app->getProjectConfig()->get('users.allowPublicRegistration') ?: false;
$token = self::$plugin->jWT->parseAndVerifyJWT(self::$plugin->jWT->getJWTFromRequest());

// Look for an access token in the settings
$accessToken = Craft::$app->request->headers->get('authorization') ?: Craft::$app->request->headers->get('x-access-token');
// If the token passes verification...
if ($token) {
// Look for the user
$user = self::$plugin->jWT->getUserByJWT($token);

// If "Bearer " is present, strip it to get the token.
if (StringHelper::startsWith($accessToken, 'Bearer ')) {
$accessToken = StringHelper::substr($accessToken, 7);
}


// If we find one, and it looks like a JWT...
if ($accessToken && count(explode('.', $accessToken)) === 3) {
// Attempt to parse the token
$token = (new Parser())->parse((string) $accessToken);

// Attempt to verify the token
$signer = new Sha256();
$verify = $token->verify($signer, $secretKey);

// If the token passes verification...
if ($verify) {
// Derive the username from the subject in the token
$userName = $token->getClaim('sub');

// Look for the user
$user = Craft::$app->users->getUserByUsernameOrEmail($userName);

// If we don't have a user, but we're allowed to create one...
if (!$user && $autoCreateUser && $allowPublicRegistration) {
// Create a new user and populate with claims
$newUser = new User();
$newUser->username = $userName;
$newUser->email = $token->getClaim('email');
$newUser->firstName = $token->getClaim('given_name') ?: '';
$newUser->lastName = $token->getClaim('family_name') ?: '';

// Attempt to save the user
$newUserSuccess = Craft::$app->getElements()->saveElement($newUser);

// If user saved ok...
if ($newUserSuccess) {
// Assign the user to the default public group
Craft::$app->users->assignUserToDefaultGroup($newUser);

// Look for a picture in the claim
$picture = $token->getClaim('picture');

// If there is a picture...
if ($picture) {
// Create a guzzel client
$guzzle = Craft::createGuzzleClient();

// Attempt to fetch the image
$imageUpload = $guzzle->get($picture);

// Derive the file extension from the content type
$ext = self::$plugin->jWT->mime2ext($imageUpload->getHeader('Content-Type'));

// Make a filename from the username, and add some randomness
$fileName = $userName . StringHelper::randomString() . '.' . $ext;
$tempFile = Craft::$app->path->getTempAssetUploadsPath() . '/' . $fileName;

// Fetch it again, this time saving it to a temp file
$imageUpload = $guzzle->get($picture, ['save_to' => $tempFile]);

// Save the tempfile to the user’s account as profile image
Craft::$app->getUsers()->saveUserPhoto($tempFile, $newUser, $fileName);
}

// Switch our unfound user to our newly created user
$user = $newUser;
}
}
// If we don't have a user, but we're allowed to create one...
if (!$user) {
$user = self::$plugin->jWT->createUserByJWT($token);
}

// Attempt to login as the user we have found or created
if ($user->id) {
Craft::$app->user->loginByUserId($user->id);
}
// Attempt to login as the user we have found or created
if ($user->id) {
Craft::$app->user->loginByUserId($user->id);
}
}
});
Expand Down
Loading

0 comments on commit 7815b69

Please sign in to comment.