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
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Fixed some Laravel 5.1 compatibilities, made the modle less opinionated.
Devs can now provide their own job dispatcher implementation.
Devs can now provide their own user model implementation.
Added indexes to the `oauth_access_tokens` table.
tiagoalves committed Dec 14, 2016
commit 99af02628c5dd91791e7fcad6fb376847a98eeff
62 changes: 45 additions & 17 deletions src/Cloudoki/OaStack/Controllers/BaseController.php
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
use Validator;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Validation\ValidationException;
use Illuminate\Contracts\Validation\ValidationException;
use Illuminate\Support\Facades\Redirect;


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


/**
* BaseController construct
* MQ preps
@@ -49,7 +48,10 @@ protected function prepInput ($attr)
// Add display fallback
$attr['display'] = $this->request->input ('display', self::display);

return array_merge ($this->request->all(), $attr);
$postParams = $this->request->request->all();
$queryParams = $this->request->all();

return array_merge ($queryParams, $postParams, $attr);
}

/**
@@ -63,11 +65,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 ())

@@ -90,15 +90,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);
}

@@ -111,18 +111,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.jobDispatcher', 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;
}

37 changes: 25 additions & 12 deletions src/Cloudoki/OaStack/Controllers/OAuth2Controller.php
Original file line number Diff line number Diff line change
@@ -45,15 +45,29 @@ 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.');
}

if (!isset($user) || !$user->checkPassword ($payload->password)) {
throw new \Cloudoki\InvalidParameterException ('Invalid password or e-mail.');
$userModelClass = config ('oastack.userModel', null);

if ($userModelClass != null) {
// 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.');
}
} else {
// We're allowed to use our own `user` model and authentication strategy
$user = User::email ($payload->email)->first ();

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 ();
@@ -64,7 +78,7 @@ 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'))
]);

@@ -85,7 +99,7 @@ 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 ()
]);

@@ -111,19 +125,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 ()
]);

9 changes: 5 additions & 4 deletions src/Cloudoki/OaStack/Controllers/OaStackViewController.php
Original file line number Diff line number Diff line change
@@ -14,7 +14,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'=> ''
);
@@ -75,9 +75,10 @@ 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"]);
@@ -184,10 +185,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
22 changes: 18 additions & 4 deletions src/Cloudoki/OaStack/Models/Oauth2AccessToken.php
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@

namespace Cloudoki\OaStack\Models;

use Cloudoki\OaStack\Models\User;
use Cloudoki\OaStack\Models\Oauth2Client;
use \Illuminate\Database\Eloquent\Model as Eloquent;

@@ -34,7 +33,8 @@ class Oauth2AccessToken extends Eloquent
*/
public function user ()
{
return $this->belongsTo (User::class);
$userModelClass = config ('oastack.userModel', 'Cloudoki\\OaStack\\Models\\User');
return $this->belongsTo ($userModelClass);
}

/**
@@ -98,6 +98,20 @@ public function getToken ()
return $this->access_token;
}

/**
* Expires all authentication tokens of the provided user id.
*
* @param int $userId
*
* @return null
*/
public static function expireAllUserTokens ($userId)
{
self::where('user_id', '=', $userId)
->whereRaw('expires > now()')
->update(['expires' => date('Y-m-d H:i:s')]);
}


/**
* Generates an unique access token.
@@ -112,7 +126,7 @@ public function getToken ()
*/
protected static function generateAccessToken()
{
if (function_exists('mcrypt_create_iv'))
if (function_exists('mcrypt_create_iv'))
{
$randomData = mcrypt_create_iv(20, MCRYPT_DEV_URANDOM);
if ($randomData !== false && strlen($randomData) === 20)
@@ -128,7 +142,7 @@ protected static function generateAccessToken()
return bin2hex($randomData);
}

if (@file_exists('/dev/urandom'))
if (@file_exists('/dev/urandom'))
{
$randomData = file_get_contents('/dev/urandom', false, null, 0, 20);
if ($randomData !== false && strlen($randomData) === 20)
54 changes: 54 additions & 0 deletions src/Cloudoki/OaStack/Traits/User.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Cloudoki\OaStack\Traits;

use Illuminate\Support\Facades\Hash;

trait User {

public static function findByLoginId($identifier) {
return self::where('email', '=', $identifier)->first();
}

/**
* Acces Token relationship
*
* @return hasMany
*/
public function oauth2accesstokens ()
{
return $this->hasMany('Cloudoki\OaStack\Models\Oauth2AccessToken');
}

/**
* Authorisations relationship
*
* @return hasMany
*/
public function oauth2authorizations ()
{
return $this->hasMany('Cloudoki\OaStack\Models\Oauth2Authorization');
}

/**
* Clients relationship
*
* @return hasMany
*/
public function oauth2clients ()
{
return $this->hasMany('Cloudoki\OaStack\Models\Oauth2Client');
}

/**
* Check password
*
* @param string $value
* @return bool
*/
public function checkPassword ($value)
{
return Hash::check ($value, $this->password);
}

}
13 changes: 9 additions & 4 deletions src/config/oastack.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

return array(

/*
|--------------------------------------------------------------------------
| Oauth2-Stack uri's
@@ -10,9 +10,14 @@
| The Oauth2-Stack uri's are being used in both pageviews as e-mails.
| You might want to edit this config in your .app/config/vendor environment.
|
*/
*/

'invite_url' => 'http://localhost/oauth2/invitation',
'reset_url' => 'http://localhost/oauth2/reset',
'privacy_url' => 'http://en.wikipedia.org/wiki/Privacy_policy'
'privacy_url' => 'http://en.wikipedia.org/wiki/Privacy_policy',
// Optional. A job dispatcher class with a static `dispatch` method.
'jobDispatcher' => null,
// Optional. The `user` model of the base application.
// The user model must use the provided Traits\User trait.
'userModel' => null,
);
Original file line number Diff line number Diff line change
@@ -13,13 +13,13 @@ class OastackCreateOauthAccessTokensTable extends Migration {
public function up()
{
if (!Schema::hasTable('oauth_access_tokens'))

Schema::create ('oauth_access_tokens', function (Blueprint $table)
{
$table->increments ('id');
$table->string ('access_token', 40);
$table->string ('access_token', 40)->unique();
$table->string ('client_id', 80);
$table->integer ('user_id');
$table->integer ('user_id')->index();
$table->timestamp ('expires');
$table->string ('scope', 80)->nullable ();
});