Skip to content
This repository has been archived by the owner on Apr 20, 2021. It is now read-only.

Decoupling improvements #5

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
526c352
Larval 5.1 Branch
Dec 2, 2016
54c1424
replace resource_path
Dec 2, 2016
ec88389
added Html package v5.1
Dec 4, 2016
6b73d63
Blade updates
Dec 4, 2016
6b90705
Merge branch 'master' into lvl51
tiagoalves Dec 14, 2016
99af026
Fixed some Laravel 5.1 compatibilities, made the modle less opinionated.
tiagoalves Dec 14, 2016
5893f2d
Decoupled the `user` object view/presentation.
tiagoalves Dec 15, 2016
c969c65
Added possibility to configure module through env vars.
tiagoalves Dec 15, 2016
99b2d7f
Showing the correct error message on authentication errors
tiagoalves Dec 20, 2016
a6bec94
Added a custom package-level exception handler
tiagoalves Dec 21, 2016
8a29ce0
Using the custom exception handler only for the view-related endpoints.
tiagoalves Dec 21, 2016
5ef6951
Several improvements including decoupling from internal transport req…
tiagoalves Dec 21, 2016
142b89b
Merge branch 'lvl51' into feature/decoupling-improvements
tiagoalves Dec 21, 2016
0ce11b7
Fixed login issue related to the decoupling.
tiagoalves Dec 21, 2016
e0f7291
Added info to README about the Laravel 5.1 maintenance branch and tags.
tiagoalves Jan 10, 2017
147442c
Merge branch 'lvl51' into feature/decoupling-improvements
tiagoalves Jan 10, 2017
344e2dd
Improved README again for the laravel 5.1 maintenance branch.
tiagoalves Jan 10, 2017
13fb0a4
Merge branch 'lvl51' into feature/decoupling-improvements
tiagoalves Jan 10, 2017
2cb1dcf
Providing a more explicit error message for `InvalidParameterExceptio…
tiagoalves Jan 30, 2017
0514a5b
Merge branch 'lvl51' into feature/decoupling-improvements
tiagoalves Jan 30, 2017
6f22481
Reverted a Laravel 5.1 compatibility change.
tiagoalves Mar 20, 2017
764b9e9
Merge branch 'master' into feature/decoupling-improvements
tiagoalves Mar 20, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The goal of this package is to split it up in multiple Framework Branches. Right

**v0.5** is the stable Laravel 5.2 compatible release

**v5.1.x** is the tag pattern for the the stable Laravel 5.1 compatible release

##### Dependencies
**Oauth2 Server** - The Oauth2 Stack is based on [Brent Shaffer's Oauth2 Server](https://github.com/bshaffer/oauth2-server-php), tweaked for multi-layer usage.
Expand Down Expand Up @@ -88,6 +89,20 @@ $ nano app/config/app.php
$ php artisan dump-autoload
```

##Laravel 5.1

Laravel 5.1 maintenance is kept in the `lvl51` branch and the releases are tagged as `v5.1.x`.

For the installation follow the same instructions of the Laravel 5.2 installation. Just change the relevant line in `composer.json` to

```
"cloudoki/oauth2-stack": "v5.1.*"
```

or use a specific version to lock the dependency to it.

---

If you go deep into the package you'll find out that the `/oauth2` routes are defined right there.
Feel free to override this by copy-pasting the routes to your project `./app/routes.php` file and disabling the include in `OaStackServiceProvider.php`. The same goes for the filters file, which identifies `auth`, a basic token check.

Expand All @@ -100,7 +115,7 @@ $ php artisan config:publish cloudoki/oauth2-stack
```
*You may also create environment specific configs by placing them like so `app/config/packages/cloudoki/oastack/environment`.*

**Laravel 5.2**
**Laravel 5.1 and 5.2**
```
$ php artisan vendor:publish
```
Expand All @@ -119,7 +134,7 @@ The Oauth2 related models, **Oauth2AccessToken**, **Oauth2Authorization**, **Oau
$ php artisan migrate --package="cloudoki/oauth2-stack"
```

**Laravel 5.2**
**Laravel 5.1 and 5.2**
```
$ php artisan vendor:publish --tag="migrations"
```
Expand Down
56 changes: 40 additions & 16 deletions src/Cloudoki/OaStack/Controllers/BaseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Redirect;


class BaseController extends Controller
{
/**
Expand All @@ -28,7 +27,6 @@ class BaseController extends Controller
*/
var $request;


/**
* BaseController construct
* MQ preps
Expand Down Expand Up @@ -63,11 +61,9 @@ public function validate ($input, $rules = [])
// Add path attributes
$input = $this->prepInput ($input);


// Perform validation
$validator = Validator::make ($input, $rules);


// Check if the validator failed
if ($validator->fails ())

Expand All @@ -90,15 +86,15 @@ public static function jobdispatch($job, $jobload, $direct = false)

# Response
$response = app()->frontqueue->request($job, $jobload);
if (isset ($response->error))

if (isset ($response->error))

return response ($response->error, $response->code);

# Frontqueue call
return $direct?
$response:
return $direct?

$response:
response()->json ($response);
}

Expand All @@ -111,18 +107,46 @@ public static function jobdispatch($job, $jobload, $direct = false)
*/
public function restDispatch ($method, $controller, $input = [], $rules = [])
{

# Extend rules
$rules = array_merge ($this->baseValidationRules, $rules);

# Validation
$payload = array_intersect_key ($this->validate ($input, $rules), $rules);

# Request Foreground Job
$response = self::jobdispatch ('controllerDispatch', (object) ['action'=> $method, 'controller'=> $controller, 'payload'=> (object) $payload], true);

return is_string ($response)?

json_decode ($response):
$externalDispatcher = config ('oastack.job_dispatcher', null);

if ($externalDispatcher !== null) {
// Instead of using the built-in job dispatching logic,
// we call the user-specified method that handles it
// in the base application.
$dispatchFunc = array($externalDispatcher, 'dispatch');

$response = call_user_func($dispatchFunc,
'controllerDispatch',
(object) [
'action'=> $method,
'controller'=> $controller,
'payload'=> (object) $payload
],
true
);
} else {
# Request Foreground Job
$response = self::jobdispatch (
'controllerDispatch',
(object) [
'action'=> $method,
'controller'=> $controller,
'payload'=> (object) $payload
],
true
);
}

return is_string ($response)?

json_decode ($response):
(object) $response;
}

Expand Down
38 changes: 23 additions & 15 deletions src/Cloudoki/OaStack/Controllers/OAuth2Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,22 @@ public static function login ($payload)
throw new \Cloudoki\InvalidParameterException ('Invalid client id or redirect uri');

}
# Validate user
if (!empty($payload->email)) {
$user = User::email ($payload->email)->first ();
} else {

if (empty($payload->email)) {
throw new \Cloudoki\InvalidParameterException ('Invalid e-mail.');
}

$userModelClass = config ('oastack.user_model', User::class);

// We have to use the base app's user model and authentication strategy
$userModel = app()->make($userModelClass);

$user = call_user_func(array($userModel, 'findByLoginId'), $payload->email);

if (!isset($user) || !$user->checkPassword ($payload->password)) {
throw new \Cloudoki\InvalidParameterException ('Invalid password or e-mail.');
}

# Validate Authorization
$authorization = $user->oauth2authorizations ()->where ('client_id', $client->getClientId ())->first ();

Expand All @@ -64,15 +70,17 @@ public static function login ($payload)
[
'access_token'=> Oauth2AccessToken::generateAccessToken(),
'client_id'=> $client->getClientId (),
'user_id'=> $user->getId (),
'user_id'=> $user->id,
'expires'=> new Carbon('+ 2 minute', Config::get ('app.timezone'))
]);



return
[
'view'=> 'approve',
'session_token'=> $sessiontoken->getToken (),
'user'=> $user->schema ('basic'),
'user'=> $user->getViewPresenter (),
'client'=> $client->schema ('basic')
];
}
Expand All @@ -85,10 +93,11 @@ public static function login ($payload)
[
'access_token'=> Oauth2AccessToken::generateAccessToken(),
'client_id'=> $client->getClientId (),
'user_id'=> $user->getId (),
'user_id'=> $user->id,
'expires'=> Carbon::now(new DateTimeZone(Config::get ('app.timezone')))->addYear ()
]);


return
[
'uri'=> $client->getRedirectUri () . '?access_token=' . $accesstoken->getToken ()
Expand All @@ -111,19 +120,18 @@ public static function authorize ($payload)
# Validate session token
$sessiontoken = Oauth2AccessToken::whereAccessToken ($payload->session_token)->valid ()->first ();

if (!$sessiontoken || $sessiontoken->user->getId () != (int) $payload->approve)
if (!$sessiontoken || $sessiontoken->user->id != (int) $payload->approve)

throw new \Cloudoki\InvalidParameterException ('Session expired or invalid approval.');


# Token handling
Oauth2Authorization::create (['client_id'=> $sessiontoken->client->getClientId (), 'user_id'=> $sessiontoken->user->getId (), 'authorization_date'=> Carbon::now(new DateTimeZone(Config::get ('app.timezone')))]);
Oauth2Authorization::create (['client_id'=> $sessiontoken->client->getClientId (), 'user_id'=> $sessiontoken->user->id, 'authorization_date'=> Carbon::now(new DateTimeZone(Config::get ('app.timezone')))]);

$accesstoken = Oauth2AccessToken::create (
[
'access_token'=> Oauth2AccessToken::generateAccessToken(),
'client_id'=> $sessiontoken->client->getClientId (),
'user_id'=> $sessiontoken->user->getId (),
'user_id'=> $sessiontoken->user->id,
'expires'=> Carbon::now(new DateTimeZone(Config::get ('app.timezone')))->addYear ()
]);

Expand Down Expand Up @@ -235,7 +243,7 @@ public static function resetpassword ($payload)
public static function changepassword ($payload)
{
$token = $payload->reset_token;

$user = User::email ($payload->email)
->whereHas ('accounts', function ($q) use ($token) { $q->where ('account_user.reset_token', $token); })
->first ();
Expand All @@ -250,7 +258,7 @@ public static function changepassword ($payload)

throw new \Cloudoki\InvalidParameterException ('The passwords do not match.');


# Update user
$user->setPassword ($payload->password)
->setResetToken (null)
Expand Down Expand Up @@ -292,7 +300,7 @@ public function identifyinvite ($payload)

else return
[
'user'=> $user->schema ('full'),
'user'=> $user->getViewPresenter (),
'account'=> $account->schema ('basic')
];
}
Expand Down Expand Up @@ -348,7 +356,7 @@ public function registeruser ()
public function registerclient ($payload = null)
{
$payload = $payload ?: json_decode (Input::get ('payload'));

$client = new Oauth2Client();
$client->appendPayload ($payload)
->save();
Expand Down
24 changes: 19 additions & 5 deletions src/Cloudoki/OaStack/Controllers/OaStackViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Http\Request;
use Cloudoki\OaStack\Controllers\BaseController;
use Cloudoki\InvalidParameterException;
use Cloudoki\OaStack\Exceptions\Handler as OaStackHandler;

class OaStackViewController extends BaseController {

Expand All @@ -14,7 +15,7 @@ class OaStackViewController extends BaseController {
'email'=> 'required|email',
'password'=> 'required|min:4',
'client_id'=> 'required|min:18',
'response_type'=> 'required|min:5',
'response_type'=> 'required|min:4',
'redirect_uri'=> 'required|min:8',
'state'=> ''
);
Expand Down Expand Up @@ -59,6 +60,18 @@ class OaStackViewController extends BaseController {
'user_id' => 'required|integer',
);

public function __construct (Request $request)
{
parent::__construct($request);
// Override the base app's global exception handler with this
// package's custom exception handler
// As seen here: https://laracasts.com/discuss/channels/requests/custom-exception-handler-based-on-route-group
\App::singleton(
\Illuminate\Contracts\Debug\ExceptionHandler::class,
OaStackHandler::class
);
}

/**
* User Login
* Show user login fields
Expand All @@ -75,12 +88,13 @@ public function login ()
*/
public function loginrequest ()
{

// Request Foreground Job
$login = $this->restDispatch ('login', 'Cloudoki\OaStack\OAuth2Controller', [], self::$loginRules);

if (isset ($login->error))

return view('oastack::oauth2.login', ['error'=> isset ($login->message)? $login->message: "something went wrong"]);
return view('oastack::oauth2.login', ['error'=> isset ($login->error)? $login->error: "something went wrong"]);

else if (isset ($login->view))

Expand Down Expand Up @@ -188,10 +202,10 @@ public function subscribe ($token)
{
// Request Foreground Job
$invite = $this->restDispatch ('identifyinvite', 'Cloudoki\OaStack\OAuth2Controller', ['token'=> $token], self::$invitationRules);


// Build View
return view ('oastack::oauth2.subscribe',
return view ('oastack::oauth2.subscribe',
[
'user'=> (array) $invite->user,
'account'=> (array) $invite->account
Expand Down
56 changes: 56 additions & 0 deletions src/Cloudoki/OaStack/Exceptions/Handler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Cloudoki\OaStack\Exceptions;

use Exception;
use Cloudoki\InvalidParameterException;
use App\Exceptions\Handler as AppExceptionHandler;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends AppExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
HttpException::class,
ModelNotFoundException::class,
];

/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return ResponseFactory
*/
public function report(Exception $e)
{
// Log the error
parent::report($e);
}

/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
if ($e instanceof InvalidParameterException) {
$message = $e->getMessage();
} else {
$message = 'Invalid request.';
}
return response()->view('oastack::oauth2.login', ['error'=> $message]);
}
}
Loading