├── public
├── favicon.ico
├── robots.txt
├── css
│ ├── style.css
│ └── admin.css
├── images
│ ├── eye.png
│ ├── logo.png
│ ├── eye-off.png
│ └── favicon.png
├── mix-manifest.json
├── .htaccess
├── web.config
├── index.php
└── svg
│ └── 404.svg
├── vendor
└── .gitkeep
├── database
├── .gitignore
├── factories
│ ├── RoleFactory.php
│ ├── ProviderFactory.php
│ ├── OauthClientFactory.php
│ ├── UserRoleFactory.php
│ └── UserFactory.php
├── migrations
│ ├── 2018_04_13_143608_create_password_resets_table.php
│ ├── 2018_04_13_143303_role.php
│ ├── 2019_03_05_152925_create_providers_table.php
│ ├── 2019_07_16_093832_alter_user_table.php
│ ├── 2019_10_03_094707_create_table_clients.php
│ ├── 2019_08_02_090547_delete_user_roles_on_delete_role.php
│ ├── 2019_08_29_143421_create_verification_tokens_table.php
│ ├── 2018_04_13_143711_create_user_verification_table.php
│ ├── 2018_04_13_143446_user_role.php
│ ├── 2018_11_09_090028_create_sessions_table.php
│ └── 2018_04_13_143152_user.php
└── seeds
│ └── DatabaseSeeder.php
├── resources
├── views
│ ├── vendor
│ │ └── l5-swagger
│ │ │ └── .gitkeep
│ ├── admin
│ │ ├── users.blade.php
│ │ ├── create-provider.blade.php
│ │ ├── create-role.blade.php
│ │ └── oauth-clients.blade.php
│ ├── auth
│ │ ├── login.blade.php
│ │ ├── logged.blade.php
│ │ ├── complete-registration-form.blade.php
│ │ └── register.blade.php
│ ├── emails
│ │ └── users
│ │ │ └── registered.blade.php
│ ├── base.blade.php
│ └── mail
│ │ ├── complete-registration.blade.php
│ │ └── base.blade.php
├── js
│ ├── event-bus.js
│ ├── app.js
│ ├── bootstrap.js
│ └── components
│ │ ├── LoginForm.vue
│ │ ├── Paginator.vue
│ │ ├── NotificationComponent.vue
│ │ ├── CompleteRegistrationForm.vue
│ │ └── Chip.vue
├── images
│ ├── eye.png
│ ├── logo.png
│ ├── eye-off.png
│ ├── favicon.png
│ └── eye-slash-solid.svg
├── assets
│ ├── images
│ │ └── logo.png
│ ├── sass
│ │ ├── _variables.scss
│ │ └── app.scss
│ └── js
│ │ ├── components
│ │ └── ExampleComponent.vue
│ │ ├── app.js
│ │ └── bootstrap.js
├── sass
│ ├── _variables.scss
│ └── app.scss
└── lang
│ ├── en
│ ├── pagination.php
│ ├── passwords.php
│ └── auth.php
│ └── it
│ └── auth.php
├── bootstrap
├── cache
│ └── .gitignore
└── app.php
├── storage
├── logs
│ └── .gitignore
├── app
│ ├── public
│ │ └── .gitignore
│ └── .gitignore
└── framework
│ ├── testing
│ └── .gitignore
│ ├── views
│ └── .gitignore
│ ├── cache
│ ├── .gitignore
│ └── data
│ │ └── .gitignore
│ ├── sessions
│ └── .gitignore
│ └── .gitignore
├── .gitattributes
├── app
├── Constants
│ └── Role.php
├── Models
│ ├── Role.php
│ ├── OauthClient.php
│ ├── VerificationToken.php
│ ├── Client.php
│ ├── UserRole.php
│ ├── Provider.php
│ └── User.php
├── Repositories
│ ├── ClientRoleRepository.php
│ ├── UserRepositoryInterface.php
│ ├── BaseRepository.php
│ ├── ClientRepositoryInterface.php
│ ├── ClientRepository.php
│ ├── RepositoryInterface.php
│ ├── RoleRepository.php
│ ├── UserRoleRepository.php
│ ├── ProviderRepository.php
│ ├── VerificationTokenRepository.php
│ ├── UserRepository.php
│ └── OauthClientsRepository.php
├── Http
│ ├── Middleware
│ │ ├── EncryptCookies.php
│ │ ├── VerifyCsrfToken.php
│ │ ├── TrimStrings.php
│ │ ├── Localization.php
│ │ ├── TrustProxies.php
│ │ ├── RedirectIfUnauthenticated.php
│ │ ├── CheckRole.php
│ │ ├── RedirectIfAuthenticated.php
│ │ ├── Authenticated.php
│ │ └── CheckClientRole.php
│ ├── Controllers
│ │ ├── Controller.php
│ │ ├── JwtAuth
│ │ │ ├── SessionManager.php
│ │ │ └── VerificationController.php
│ │ ├── ClientRoleController.php
│ │ └── Manage
│ │ │ └── OauthClientsController.php
│ ├── Resources
│ │ ├── UserResource.php
│ │ ├── RoleResource.php
│ │ └── OauthClientsResource.php
│ ├── Requests
│ │ ├── UserRoleRequest.php
│ │ └── LoginRequest.php
│ ├── Services
│ │ └── Mailer.php
│ └── Kernel.php
├── Exceptions
│ ├── SqlException.php
│ └── Handler.php
├── Events
│ ├── LogoutEvent.php
│ └── LoginEvent.php
├── Providers
│ ├── BroadcastServiceProvider.php
│ ├── EventServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── RouteServiceProvider.php
│ └── AppServiceProvider.php
├── Services
│ ├── Interfaces
│ │ └── IAccountService.php
│ └── AccountService.php
├── Listeners
│ ├── LogLoginListener.php
│ ├── RegistrationListener.php
│ └── LogoutProvidersListener.php
├── Mail
│ └── UserRegistered.php
├── Console
│ └── Kernel.php
└── swagger.php
├── tests
├── TestCase.php
├── Unit
│ └── ExampleTest.php
├── Integration
│ ├── RoleTest.php
│ ├── ProviderWithoutMiddlewareTest.php
│ ├── UserWithoutMiddlewareTest.php
│ ├── VerificationTest.php
│ ├── RoleWithoutMiddlewareTest.php
│ └── ProviderTest.php
├── CreatesApplication.php
├── Utility
│ └── UserUtility.php
└── Feature
│ ├── ProviderWithoutMiddlewareTest.php
│ └── LoginWithoutMiddlewareTest.php
├── CONTRIBUTING.md
├── .gitignore
├── routes
├── api.php
├── channels.php
├── console.php
├── idp.php
└── web.php
├── .github
├── pull_request_template.md
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── config
├── hashing.php
├── view.php
├── services.php
├── broadcasting.php
├── logging.php
├── filesystems.php
├── queue.php
├── cache.php
└── auth.php
├── .travis.yml
├── server.php
├── webpack.mix.js
├── .env.example
├── LICENSE
├── package.json
├── phpunit.xml
├── composer.json
├── artisan
├── readme.md
└── CODE_OF_CONDUCT.md
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite
2 |
--------------------------------------------------------------------------------
/resources/views/vendor/l5-swagger/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/storage/app/public/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !public/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/storage/framework/testing/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !data/
3 | !.gitignore
--------------------------------------------------------------------------------
/storage/framework/cache/data/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/public/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #ffffff;
3 | }
4 |
--------------------------------------------------------------------------------
/resources/js/event-bus.js:
--------------------------------------------------------------------------------
1 | window.Vue = require('vue');
2 |
3 | export const EventBus = new Vue();
--------------------------------------------------------------------------------
/public/images/eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/public/images/eye.png
--------------------------------------------------------------------------------
/public/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/public/images/logo.png
--------------------------------------------------------------------------------
/public/mix-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "/js/app.js": "/js/app.js",
3 | "/css/app.css": "/css/app.css"
4 | }
5 |
--------------------------------------------------------------------------------
/resources/images/eye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/resources/images/eye.png
--------------------------------------------------------------------------------
/public/images/eye-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/public/images/eye-off.png
--------------------------------------------------------------------------------
/public/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/public/images/favicon.png
--------------------------------------------------------------------------------
/resources/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/resources/images/logo.png
--------------------------------------------------------------------------------
/resources/images/eye-off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/resources/images/eye-off.png
--------------------------------------------------------------------------------
/resources/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/resources/images/favicon.png
--------------------------------------------------------------------------------
/resources/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZanichelliEditore/laravel-jwt-idp/HEAD/resources/assets/images/logo.png
--------------------------------------------------------------------------------
/resources/views/admin/users.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.home')
2 |
3 | @section('content')
4 |
5 |
6 |
7 | @endsection
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/storage/framework/.gitignore:
--------------------------------------------------------------------------------
1 | config.php
2 | routes.php
3 | schedule-*
4 | compiled.php
5 | services.json
6 | events.scanned.php
7 | routes.scanned.php
8 | down
9 |
--------------------------------------------------------------------------------
/resources/views/admin/create-provider.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.home')
2 |
3 | @section('content')
4 |
5 |
6 |
7 | @endsection
--------------------------------------------------------------------------------
/resources/views/admin/create-role.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.home')
2 |
3 | @section('content')
4 |
5 |
6 |
7 | @endsection
--------------------------------------------------------------------------------
/app/Constants/Role.php:
--------------------------------------------------------------------------------
1 |
6 |
7 | @endsection
--------------------------------------------------------------------------------
/resources/views/auth/logged.blade.php:
--------------------------------------------------------------------------------
1 | @extends('base')
2 |
3 | @section('content')
4 |
{{ auth()->user()->name }} @lang('auth.label-logged')
5 | @endsection
--------------------------------------------------------------------------------
/resources/sass/_variables.scss:
--------------------------------------------------------------------------------
1 |
2 | // Body
3 | $body-bg: #f5f8fa;
4 |
5 | // Typography
6 | $font-family-sans-serif: "Raleway", sans-serif;
7 | $font-size-base: 0.9rem;
8 | $line-height-base: 1.6;
9 |
--------------------------------------------------------------------------------
/resources/views/admin/oauth-clients.blade.php:
--------------------------------------------------------------------------------
1 | @extends('admin.home')
2 |
3 | @section('content')
4 |
5 |
6 |
7 |
8 | @endsection
--------------------------------------------------------------------------------
/resources/assets/sass/_variables.scss:
--------------------------------------------------------------------------------
1 |
2 | // Body
3 | $body-bg: #f5f8fa;
4 |
5 | // Typography
6 | $font-family-sans-serif: "Raleway", sans-serif;
7 | $font-size-base: 0.9rem;
8 | $line-height-base: 1.6;
9 |
--------------------------------------------------------------------------------
/resources/views/auth/complete-registration-form.blade.php:
--------------------------------------------------------------------------------
1 | @extends('base')
2 |
3 | @section('content')
4 |
5 |
6 |
7 | @endsection
--------------------------------------------------------------------------------
/database/factories/RoleFactory.php:
--------------------------------------------------------------------------------
1 | define(App\Models\Role::class, function () {
6 | return [
7 | 'name' => Str::random(20),
8 | ];
9 | });
10 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | hasOne('App\Models\Client', 'oauth_client_id');
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/resources/assets/sass/app.scss:
--------------------------------------------------------------------------------
1 |
2 | // Fonts
3 | @import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
4 |
5 | // Variables
6 | @import "variables";
7 |
8 | // Bootstrap
9 | @import '~bootstrap/scss/bootstrap';
10 |
11 | .navbar-laravel {
12 | background-color: #fff;
13 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
14 | }
15 |
--------------------------------------------------------------------------------
/resources/sass/app.scss:
--------------------------------------------------------------------------------
1 |
2 | // Fonts
3 | @import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600");
4 |
5 | // Variables
6 | @import "variables";
7 |
8 | // Bootstrap
9 | @import '../../node_modules/bootstrap/scss/bootstrap';
10 |
11 | .navbar-laravel {
12 | background-color: #fff;
13 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
14 | }
15 |
--------------------------------------------------------------------------------
/database/factories/ProviderFactory.php:
--------------------------------------------------------------------------------
1 | define(App\Models\Provider::class, function () {
6 | return [
7 | 'domain' => Str::random(20),
8 | 'username' => encrypt(Str::random(20)),
9 | 'password' => encrypt(Str::random(20)),
10 | 'logoutUrl' => Str::random(20),
11 | ];
12 | });
--------------------------------------------------------------------------------
/resources/views/emails/users/registered.blade.php:
--------------------------------------------------------------------------------
1 | @component('mail::message')
2 | # Verify your e-mail
3 |
4 | {{ $user->name }}, thanks for sign up on Laravel IDP.
5 |
6 | @component('mail::button', ['url' => route('verification-account', ['code' => $verificationCode])])
7 | Verify e-mail
8 | @endcomponent
9 |
10 | Thanks,
11 | {{ config('app.name') }}
12 | @endcomponent
13 |
--------------------------------------------------------------------------------
/app/Repositories/ClientRoleRepository.php:
--------------------------------------------------------------------------------
1 | assertTrue(true);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 | json('GET', '/v1/roles');
17 | $response->assertStatus(401);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | hasOne('App\Models\OauthClient', 'id');
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/Repositories/BaseRepository.php:
--------------------------------------------------------------------------------
1 | delete();
23 | }
24 | }
--------------------------------------------------------------------------------
/routes/api.php:
--------------------------------------------------------------------------------
1 | user = $user;
16 | }
17 |
18 | /**
19 | * Returns the logged-out user
20 | * @return User
21 | */
22 | public function getUser(){
23 | return $this->user;
24 | }
25 |
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Pull Request Process
2 |
3 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a
4 | build.
5 | 2. Update the README.md with details of changes to the interface, this includes new environment
6 | variables, exposed ports, useful file locations and container parameters.
7 | 3. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
8 | do not have permission to do that, you may request the second reviewer to merge it for you.
9 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | roles);
19 |
20 | return $user;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tests/CreatesApplication.php:
--------------------------------------------------------------------------------
1 | make(Kernel::class)->bootstrap();
20 |
21 | Hash::driver('bcrypt')->setRounds(4);
22 |
23 | return $app;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/Http/Controllers/JwtAuth/SessionManager.php:
--------------------------------------------------------------------------------
1 | where('user_id', '=', $userId)
23 | ->delete();
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/app/Http/Resources/RoleResource.php:
--------------------------------------------------------------------------------
1 | $this->id,
20 | 'roleId' => $this->role->id,
21 | 'roleName' => $this->role->name
22 | ];
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/database/factories/OauthClientFactory.php:
--------------------------------------------------------------------------------
1 | define(OauthClient::class, function (Faker $faker) {
10 | return [
11 | 'user_id' => null,
12 | 'name' => $faker->name,
13 | 'secret' => Str::random(20),
14 | 'redirect' => 'http://localhost:8081/auth/callback',
15 | 'personal_access_client' => 0,
16 | 'password_client' => 0,
17 | 'revoked' => 0
18 | ];
19 | });
20 |
--------------------------------------------------------------------------------
/config/hashing.php:
--------------------------------------------------------------------------------
1 | 'bcrypt',
19 |
20 | ];
21 |
--------------------------------------------------------------------------------
/resources/lang/en/pagination.php:
--------------------------------------------------------------------------------
1 | '« Previous',
17 | 'next' => 'Next »',
18 |
19 | ];
20 |
--------------------------------------------------------------------------------
/routes/channels.php:
--------------------------------------------------------------------------------
1 | id === (int) $id;
18 | });
19 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.4
5 |
6 | services:
7 | - mysql
8 |
9 | before_script:
10 | - mysql -e 'CREATE DATABASE IF NOT EXISTS zanichelli_idp;'
11 | - cp .env.example .env
12 | - composer self-update
13 | - composer install --no-interaction
14 | - php artisan key:generate
15 | - php artisan migrate:fresh --seed --no-interaction
16 | - php artisan passport:install
17 | - php artisan jwt:secret --no-interaction
18 |
19 | script:
20 | - vendor/bin/phpunit --coverage-clover=coverage.xml
21 |
22 | after_success:
23 | - bash <(curl -s https://codecov.io/bash) -t ab59f408-dd5d-405d-9695-14dc5aa3b1da
24 |
--------------------------------------------------------------------------------
/server.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 |
10 | $uri = urldecode(
11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
12 | );
13 |
14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the
15 | // built-in PHP web server. This provides a convenient way to test a Laravel
16 | // application without having installed a "real" web server software here.
17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) {
18 | return false;
19 | }
20 |
21 | require_once __DIR__.'/public/index.php';
22 |
--------------------------------------------------------------------------------
/webpack.mix.js:
--------------------------------------------------------------------------------
1 | let mix = require('laravel-mix');
2 |
3 | /*
4 | |--------------------------------------------------------------------------
5 | | Mix Asset Management
6 | |--------------------------------------------------------------------------
7 | |
8 | | Mix provides a clean, fluent API for defining some Webpack build steps
9 | | for your Laravel application. By default, we are compiling the Sass
10 | | file for the application as well as bundling up all the JS files.
11 | |
12 | */
13 |
14 | mix.js('resources/js/app.js', 'public/js')
15 | .sass('resources/sass/app.scss', 'public/css');
16 |
17 | if (mix.inProduction()) {
18 | mix.version();
19 | }
--------------------------------------------------------------------------------
/app/Http/Resources/OauthClientsResource.php:
--------------------------------------------------------------------------------
1 | $this->id,
19 | "oauth_name" => $this->name,
20 | "roles" => $this->client ? json_decode($this->client->roles) : json_decode("[]")
21 | ];
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/Models/UserRole.php:
--------------------------------------------------------------------------------
1 | belongsTo('App\Models\Role', 'role_id');
22 | }
23 |
24 | /**
25 | * @return mixed
26 | */
27 | public function user(){
28 | return $this->belongsTo('App\Models\User', 'user_id');
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/routes/console.php:
--------------------------------------------------------------------------------
1 | comment(Inspiring::quote());
19 | })->describe('Display an inspiring quote');
20 |
--------------------------------------------------------------------------------
/public/.htaccess:
--------------------------------------------------------------------------------
1 |
2 |
3 | Options -MultiViews -Indexes
4 |
5 |
6 | RewriteEngine On
7 |
8 | # Handle Authorization Header
9 | RewriteCond %{HTTP:Authorization} .
10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
11 |
12 | # Redirect Trailing Slashes If Not A Folder...
13 | RewriteCond %{REQUEST_FILENAME} !-d
14 | RewriteCond %{REQUEST_URI} (.+)/$
15 | RewriteRule ^ %1 [L,R=301]
16 |
17 | # Handle Front Controller...
18 | RewriteCond %{REQUEST_FILENAME} !-d
19 | RewriteCond %{REQUEST_FILENAME} !-f
20 | RewriteRule ^ index.php [L]
21 |
22 |
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfUnauthenticated.php:
--------------------------------------------------------------------------------
1 | check()) {
23 | return $next($request);
24 | }
25 |
26 | return redirect('loginForm');
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/database/factories/UserRoleFactory.php:
--------------------------------------------------------------------------------
1 | define(App\Models\UserRole::class, function (Faker $faker) {
17 | return [
18 | 'role_id' => 1,
19 | 'user_id' => 1
20 | ];
21 | });
22 |
--------------------------------------------------------------------------------
/app/Http/Requests/UserRoleRequest.php:
--------------------------------------------------------------------------------
1 | 'required|integer|exists:roles,id',
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/resources/assets/js/components/ExampleComponent.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | I'm an example component.
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 |
--------------------------------------------------------------------------------
/tests/Utility/UserUtility.php:
--------------------------------------------------------------------------------
1 | 'ADMIN_IDP']);
19 | $user = factory(User::class)->create([
20 | 'is_verified' => true
21 | ]);
22 |
23 | factory(UserRole::class)->create([
24 | 'user_id' => $user->id,
25 | 'role_id' => $role->id,
26 | ]);
27 |
28 | return $user;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/app/Repositories/ClientRepositoryInterface.php:
--------------------------------------------------------------------------------
1 | 'required|string|max:255',
28 | 'password' => 'required|string',
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/resources/assets/js/app.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * First we will load all of this project's JavaScript dependencies which
4 | * includes Vue and other libraries. It is a great starting point when
5 | * building robust, powerful web applications using Vue and Laravel.
6 | */
7 |
8 | require('./bootstrap');
9 |
10 | window.Vue = require('vue');
11 |
12 | /**
13 | * Next, we will create a fresh Vue application instance and attach it to
14 | * the page. Then, you may begin adding components to this application
15 | * or customize the JavaScript scaffolding to fit your unique needs.
16 | */
17 |
18 | Vue.component('example-component', require('./components/ExampleComponent.vue'));
19 |
20 | const app = new Vue({
21 | el: '#app'
22 | });
23 |
--------------------------------------------------------------------------------
/public/css/admin.css:
--------------------------------------------------------------------------------
1 | #nav-bar {
2 | height: 74px;
3 | z-index: 100;
4 | }
5 |
6 | #side-menu {
7 | -webkit-box-shadow: 2px 0px 4px 0px rgba(0,0,0,0.26);
8 | -moz-box-shadow: 2px 0px 4px 0px rgba(0,0,0,0.26);
9 | box-shadow: 2px 0px 4px 0px rgba(0,0,0,0.26);
10 | width: 300px;
11 | margin-top: 73px !important;
12 | background-color: #eeeeee;
13 | }
14 |
15 | #content {
16 | padding-top: 120px;
17 | margin-left: 300px;
18 | }
19 |
20 | .no-text-decoration:hover {
21 | text-decoration: none;
22 | }
23 |
24 | .menu-item:hover {
25 | background-color: #e0e0e0;
26 | }
27 |
28 | body {
29 | position: relative;
30 | min-width: 800px;
31 | overflow-x: hidden;
32 | }
33 |
34 | #content {
35 | /*min-width: 600px;*/
36 | }
--------------------------------------------------------------------------------
/app/Services/Interfaces/IAccountService.php:
--------------------------------------------------------------------------------
1 | [
16 | 'App\Listeners\LogLoginListener',
17 | ],
18 | 'App\Events\LogoutEvent' => [
19 | 'App\Listeners\LogoutProvidersListener'
20 | ]
21 | ];
22 |
23 | /**
24 | * Register any events for your application.
25 | *
26 | * @return void
27 | */
28 | public function boot() {
29 | parent::boot();
30 |
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/Http/Middleware/CheckRole.php:
--------------------------------------------------------------------------------
1 | check()) {
22 | return redirect('loginForm');
23 | }
24 |
25 | $user = auth()->user();
26 |
27 | foreach ($user->roles as $role) {
28 | if ($role->role->name === $mandatoryRole) {
29 | return $next($request);
30 | }
31 | }
32 |
33 | return redirect('authenticated');
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/database/migrations/2018_04_13_143608_create_password_resets_table.php:
--------------------------------------------------------------------------------
1 | string('email')->index();
18 | $table->string('token');
19 | $table->timestamp('created_at')->nullable();
20 | });
21 | }
22 |
23 | /**
24 | * Reverse the migrations.
25 | *
26 | * @return void
27 | */
28 | public function down(){
29 | Schema::dropIfExists('password_resets');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/Listeners/LogLoginListener.php:
--------------------------------------------------------------------------------
1 | getUser();
19 | $ip = $event->getIp();
20 |
21 | $message = json_encode([
22 | 'ip' => $ip,
23 | 'userId' => $user->id,
24 | 'action' => 'Login',
25 | 'url' => route('login')
26 | ]);
27 |
28 | Log::info($message);
29 | }
30 |
31 | public function failed(LoginEvent $event, $exception){
32 | // Quando si verifica un problema con la coda e non viene processato
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/database/migrations/2018_04_13_143303_role.php:
--------------------------------------------------------------------------------
1 | engine = 'InnoDB';
17 | $table->charset = 'utf8';
18 | $table->collation = 'utf8_unicode_ci';
19 |
20 | $table->increments('id');
21 | $table->string('name', 20)->unique();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down(){
31 | Schema::dropIfExists('roles');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/resources/lang/en/passwords.php:
--------------------------------------------------------------------------------
1 | 'Passwords must be at least six characters and match the confirmation.',
17 | 'reset' => 'Your password has been reset!',
18 | 'sent' => 'We have e-mailed your password reset link!',
19 | 'token' => 'This password reset token is invalid.',
20 | 'user' => "We can't find a user with that e-mail address.",
21 |
22 | ];
23 |
--------------------------------------------------------------------------------
/database/migrations/2019_03_05_152925_create_providers_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
17 | $table->string('domain')->unique();
18 | $table->string('username');
19 | $table->string('password');
20 | $table->string('logoutUrl');
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down() {
30 | Schema::dropIfExists('providers');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Integration/ProviderWithoutMiddlewareTest.php:
--------------------------------------------------------------------------------
1 | create();
21 | $response = $this->json('GET', '/v1/providers');
22 | $response->assertStatus(200)
23 | ->assertJsonStructure([
24 | [
25 | 'id',
26 | 'domain',
27 | 'username',
28 | 'password',
29 | 'logoutUrl'
30 | ]
31 | ]);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/Repositories/ClientRepository.php:
--------------------------------------------------------------------------------
1 | update($data);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/Events/LoginEvent.php:
--------------------------------------------------------------------------------
1 | user = $user;
28 | $this->ip = $ip;
29 | }
30 |
31 | /**
32 | * Returns the current logged user
33 | * @return User
34 | */
35 | public function getUser(){
36 | return $this->user;
37 | }
38 |
39 | /**
40 | * Returns the request of the user
41 | * @return string
42 | */
43 | public function getIp(){
44 | return $this->ip;
45 | }
46 |
47 | }
--------------------------------------------------------------------------------
/app/Http/Middleware/RedirectIfAuthenticated.php:
--------------------------------------------------------------------------------
1 | check()) {
21 | return $next($request);
22 | }
23 |
24 | $redirectUrl = $request->input('redirect');
25 |
26 | if (empty($redirectUrl)) {
27 | return redirect('authenticated');
28 | }
29 | $token = auth()->getToken();
30 | $url = $redirectUrl . '?token=' . $token;
31 |
32 | return redirect()->away($url);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/Repositories/RepositoryInterface.php:
--------------------------------------------------------------------------------
1 | unique('email');
18 | $table->string('surname')->nullable()->change();
19 | });
20 | }
21 |
22 | /**
23 | * Reverse the migrations.
24 | *
25 | * @return void
26 | */
27 | public function down()
28 | {
29 | Schema::table('users', function (Blueprint $table) {
30 | $table->dropUnique('users_email_unique');
31 | $table->string('surname')->nullable(false)->change();
32 | });
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | define(App\Models\User::class, function (Faker $faker) {
18 | return [
19 | 'name' => $faker->name,
20 | 'surname' => $faker->name,
21 | 'email' => $faker->unique()->safeEmail,
22 | 'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
23 | 'remember_token' => Str::random(10),
24 | 'is_verified' => false,
25 | ];
26 | });
27 |
--------------------------------------------------------------------------------
/database/migrations/2019_10_03_094707_create_table_clients.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('oauth_client_id')->foreign('oauth_client_id')->references('id')->on('oauth_clients')->onDelete('cascade');
19 | $table->string('roles')->default('[]');
20 | $table->timestamps();
21 | });
22 | }
23 |
24 | /**
25 | * Reverse the migrations.
26 | *
27 | * @return void
28 | */
29 | public function down()
30 | {
31 | Schema::dropIfExists('clients');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/resources/images/eye-slash-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Listeners/RegistrationListener.php:
--------------------------------------------------------------------------------
1 | getUser();
32 | $verificationCode = $event->getVerificationCode();
33 |
34 | Mail::to($user)->send(new UserRegistered($user, $verificationCode));
35 | }
36 |
37 | public function failed(RegistrationEvent $event, $exception){
38 | // error queue
39 | }
40 |
41 | }
--------------------------------------------------------------------------------
/app/Mail/UserRegistered.php:
--------------------------------------------------------------------------------
1 | user = $user;
24 | $this->verificationCode = $verificationCode;
25 | }
26 |
27 | /**
28 | * Build the message.
29 | *
30 | * @return $this
31 | */
32 | public function build(){
33 | return $this->markdown('emails.users.registered')->with([
34 | 'user' => $this->user,
35 | 'verificationCode' => $this->verificationCode
36 | ]);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/public/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/app/Providers/AuthServiceProvider.php:
--------------------------------------------------------------------------------
1 | 'App\Policies\ModelPolicy',
18 | ];
19 |
20 | /**
21 | * Register any authentication / authorization services.
22 | *
23 | * @return void
24 | */
25 | public function boot() {
26 |
27 | $this->registerPolicies();
28 |
29 | Passport::routes();
30 |
31 | Passport::tokensExpireIn(now()->addMinutes(2));
32 |
33 | Passport::tokensCan([
34 | 'manage-user' => 'Create and manage IDP users',
35 | 'manage-idp' => 'Create and manage providers',
36 | ]);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('inspire')
28 | // ->hourly();
29 | }
30 |
31 | /**
32 | * Register the commands for the application.
33 | *
34 | * @return void
35 | */
36 | protected function commands()
37 | {
38 | $this->load(__DIR__.'/Commands');
39 |
40 | require base_path('routes/console.php');
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/database/migrations/2019_08_02_090547_delete_user_roles_on_delete_role.php:
--------------------------------------------------------------------------------
1 | dropForeign('user_roles_role_id_foreign');
18 | $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
19 | });
20 | }
21 |
22 | /**
23 | * Reverse the migrations.
24 | *
25 | * @return void
26 | */
27 | public function down()
28 | {
29 | Schema::table('user_roles', function (Blueprint $table) {
30 | $table->dropForeign('user_roles_role_id_foreign');
31 | $table->foreign('role_id')->references('id')->on('roles');
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/database/migrations/2019_08_29_143421_create_verification_tokens_table.php:
--------------------------------------------------------------------------------
1 | bigIncrements('id');
18 | $table->string('token')->unique();
19 | $table->unsignedInteger('user_id');
20 | $table->boolean('is_valid')->default(true);
21 | $table->timestamps();
22 |
23 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists('verification_tokens');
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/database/migrations/2018_04_13_143711_create_user_verification_table.php:
--------------------------------------------------------------------------------
1 | engine = 'InnoDB';
18 | $table->charset = 'utf8';
19 | $table->collation = 'utf8_unicode_ci';
20 |
21 | $table->increments('id');
22 | $table->unsignedInteger('user_id');
23 | $table->string('verification_code');
24 |
25 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down(){
35 | Schema::dropIfExists('user_verifications');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Repositories/RoleRepository.php:
--------------------------------------------------------------------------------
1 | update($data);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/database/migrations/2018_04_13_143446_user_role.php:
--------------------------------------------------------------------------------
1 | engine = 'InnoDB';
19 | $table->charset = 'utf8';
20 | $table->collation = 'utf8_unicode_ci';
21 |
22 | $table->increments('id');
23 | $table->unsignedInteger('user_id');
24 | $table->unsignedInteger('role_id');
25 |
26 | $table->foreign('user_id')->references('id')->on('users');
27 | $table->foreign('role_id')->references('id')->on('roles');
28 | });
29 | }
30 |
31 | /**
32 | * Reverse the migrations.
33 | *
34 | * @return void
35 | */
36 | public function down(){
37 | Schema::dropIfExists('user_roles');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/database/migrations/2018_11_09_090028_create_sessions_table.php:
--------------------------------------------------------------------------------
1 | string('id')->unique();
18 | $table->unsignedInteger('user_id')->nullable();
19 | $table->string('ip_address', 45)->nullable();
20 | $table->text('user_agent')->nullable();
21 | $table->text('payload');
22 | $table->integer('last_activity');
23 |
24 | $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
25 | });
26 | }
27 |
28 | /**
29 | * Reverse the migrations.
30 | *
31 | * @return void
32 | */
33 | public function down()
34 | {
35 | Schema::dropIfExists('sessions');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/swagger.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => realpath(storage_path('framework/views')),
32 |
33 | ];
34 |
--------------------------------------------------------------------------------
/tests/Integration/UserWithoutMiddlewareTest.php:
--------------------------------------------------------------------------------
1 | create([
22 | 'is_verified' => true
23 | ]);
24 | $response = $this->json('GET', '/v1/users/' . $user->id);
25 | $response->assertStatus(200);
26 | }
27 |
28 |
29 | /**
30 | * Find not exists user
31 | * @test
32 | * @return void
33 | */
34 | public function notFoundUserTest()
35 | {
36 | $user = factory(User::class)->create([
37 | 'is_verified' => true
38 | ]);
39 | User::destroy($user->id);
40 | $response = $this->json('GET', '/v1/users/' . $user->id);
41 | $response->assertStatus(404);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Zanichelli Editore S.p.A.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
18 | 'domain' => env('MAILGUN_DOMAIN'),
19 | 'secret' => env('MAILGUN_SECRET'),
20 | ],
21 |
22 | 'ses' => [
23 | 'key' => env('SES_KEY'),
24 | 'secret' => env('SES_SECRET'),
25 | 'region' => 'us-east-1',
26 | ],
27 |
28 | 'sparkpost' => [
29 | 'secret' => env('SPARKPOST_SECRET'),
30 | ],
31 |
32 | 'stripe' => [
33 | 'model' => App\Models\User::class,
34 | 'key' => env('STRIPE_KEY'),
35 | 'secret' => env('STRIPE_SECRET'),
36 | ],
37 |
38 | ];
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "npm run development",
5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
7 | "watch-poll": "npm run watch -- --watch-poll",
8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
9 | "prod": "npm run production",
10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
11 | },
12 | "devDependencies": {
13 | "axios": "^0.19",
14 | "bootstrap": "^4.0.0",
15 | "popper.js": "^1.12",
16 | "cross-env": "^5.1",
17 | "jquery": "^3.2",
18 | "laravel-mix": "^2.0",
19 | "lodash": "^4.17.4",
20 | "vue": "^2.5.7"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/database/migrations/2018_04_13_143152_user.php:
--------------------------------------------------------------------------------
1 | nullable();
11 | *
12 | * @return void
13 | */
14 | public function up()
15 | {
16 |
17 | Schema::create('users', function (Blueprint $table) {
18 |
19 | $table->engine = 'InnoDB';
20 | $table->charset = 'utf8';
21 | $table->collation = 'utf8_unicode_ci';
22 |
23 | $table->increments('id');
24 | $table->string('email', 60)->nullable();
25 | $table->string('password')->nullable();
26 | $table->boolean('is_verified')->default(false);
27 | $table->string('name', 50);
28 | $table->string('surname', 50);
29 | $table->rememberToken();
30 | $table->timestamp('created_at')->useCurrent();
31 | $table->timestamp('updated_at')->nullable();
32 | });
33 | }
34 |
35 | /**
36 | * Reverse the migrations.
37 | *
38 | * @return void
39 | */
40 | public function down()
41 | {
42 | Schema::dropIfExists('users');
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/Http/Controllers/ClientRoleController.php:
--------------------------------------------------------------------------------
1 | clientRoleRepository = $clientRoleRepository;
15 | }
16 |
17 | /**
18 | * @OA\Get(
19 | * path="/v1/client-roles",
20 | * summary="list of client roles",
21 | * description="Returns the entire list of client roles",
22 | * operationId="all",
23 | * tags={"ClientRoles"},
24 | * security={{"web":{}}},
25 | * @OA\Response(
26 | * response=200,
27 | * description="Operation successful",
28 | * @OA\MediaType(
29 | * mediaType="application/json",
30 | * )
31 | * ),
32 | * @OA\Response(
33 | * response=401,
34 | * description="Unauthorized",
35 | * @OA\MediaType(
36 | * mediaType="application/json",
37 | * )
38 | * )
39 | * )
40 | */
41 | public function all(){
42 |
43 | return $this->clientRoleRepository->all();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 | ./tests/Feature
14 |
15 |
16 | ./tests/Integration
17 |
18 |
19 |
20 | ./tests/Unit
21 |
22 |
23 |
24 |
25 | ./app
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/Models/User.php:
--------------------------------------------------------------------------------
1 | hasMany('App\Models\UserRole', 'user_id');
37 | }
38 |
39 |
40 | /**
41 | * Get the identifier that will be stored in the subject claim of the JWT.
42 | *
43 | * @return mixed
44 | */
45 | public function getJWTIdentifier()
46 | {
47 | return $this->getKey();
48 | }
49 |
50 | /**
51 | * Return a key value array, containing any custom claims to be added to the JWT.
52 | *
53 | * @return array
54 | */
55 | public function getJWTCustomClaims()
56 | {
57 | return array();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/resources/lang/it/auth.php:
--------------------------------------------------------------------------------
1 | 'Grazie per esserti registrato! Controlla la tua e-mail per completare la registrazione.',
6 | 'err-verification' => 'Utente non verificato. Accedi alla tua casella di posta per verificare il tuo account.',
7 | 'err-login' => 'E-mail o password errati.',
8 | 'err-jwt' => 'Errore durante il login. Riprovare più tardi',
9 | 'err-fields' => 'Rimepire correttamente tutti i campi obbligatori',
10 |
11 | 'label-email' => 'Indirizzo e-mail',
12 | 'label-enter-email' => 'Inserisci la tua e-mail',
13 | 'label-username' => 'Username',
14 | 'label-enter-username' => 'Inserisci il tuo username',
15 | 'label-enter-password' => 'Inserisci una password sicura',
16 | 'label-confirm-password' => 'Conferma la password',
17 | 'label-repeat-password' => 'Ripeti la password',
18 | 'label-name' => 'Nome',
19 | 'label-surname' => 'Cognome',
20 | 'label-enter-name' => 'Inserisci il nome',
21 | 'label-enter-surname' => 'Inserisci il cognome',
22 | 'label-sign-up' => 'Registrati',
23 | 'label-login' => 'Accedi',
24 | 'label-logout' => 'Esci',
25 | 'label-logged' => 'sei autenticato',
26 |
27 | 'user-error' => 'Utente non trovato',
28 | 'token-expired' => 'Token scaduto',
29 | 'token-invalid' => 'Token invalido',
30 | 'token-error' => 'Token invalido',
31 | 'token-absent' => 'Token assente'
32 | ];
--------------------------------------------------------------------------------
/app/Repositories/UserRoleRepository.php:
--------------------------------------------------------------------------------
1 | get();
40 | }
41 |
42 | /**
43 | * Returns a list of all @see user-roles.
44 | *
45 | * @return array
46 | */
47 | public function all()
48 | {
49 | return UserRole::all();
50 | }
51 |
52 | /**
53 | * Updates a user-role by id.
54 | *
55 | * @param array $data
56 | * @param int $id
57 | * @return int
58 | */
59 | public function update(int $id, array $data)
60 | {
61 | return UserRole::find($id)->update($data);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/tests/Feature/ProviderWithoutMiddlewareTest.php:
--------------------------------------------------------------------------------
1 | json('POST', 'v2/login', [
27 | 'username' => $user->email,
28 | 'password' => 'secret'
29 | ]);
30 |
31 | $cookie = ['token' => json_decode($response->getContent())->token];
32 | $body = [
33 | 'domain' => Str::random(85),
34 | 'username' => 'user',
35 | 'password' => 'secret',
36 | 'logoutUrl' => 'valid'
37 | ];
38 |
39 | $mock = Mockery::mock(ProviderRepository::class)->makePartial()
40 | ->shouldReceive(['create'=> null])
41 | ->once()
42 | ->getMock();
43 | $this->app->instance('App\Repositories\ProviderRepository', $mock);
44 |
45 | $response = $this->json('POST', '/admin/providers', $body, $cookie);
46 | $response->assertStatus(500);
47 | }
48 | }
--------------------------------------------------------------------------------
/app/Repositories/ProviderRepository.php:
--------------------------------------------------------------------------------
1 | $data['domain'],
23 | 'username' => encrypt($data['username']),
24 | 'password' => encrypt($data['password']),
25 | 'logoutUrl' => $logoutUrl
26 | ]);
27 | }
28 |
29 | /**
30 | * Finds a @see Provider by id.
31 | *
32 | * @param integer $id
33 | * @return Provider
34 | */
35 | public function find(int $id)
36 | {
37 | return Provider::find($id);
38 | }
39 |
40 | /**
41 | * Returns a list of all @see Provider
42 | *
43 | * @return array
44 | */
45 | public function all()
46 | {
47 | return Provider::all();
48 | }
49 |
50 | /**
51 | * Updates a provider by id.
52 | *
53 | * @param array $data
54 | * @param int $id
55 | * @return int
56 | */
57 | public function update(int $id, array $data)
58 | {
59 | return Provider::where('id', $id)->update($data);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/Repositories/VerificationTokenRepository.php:
--------------------------------------------------------------------------------
1 | update($data);
50 | }
51 |
52 | /**
53 | * Find Verification token by token param
54 | *
55 | * @param string $token
56 | * @return VerificationToken
57 | */
58 | public function retrieveByToken(string $token)
59 | {
60 | return VerificationToken::where('token', $token)->first();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/Http/Middleware/Authenticated.php:
--------------------------------------------------------------------------------
1 | checkOrFail()) {
27 | return response()->json([
28 | 'message' => __('auth.user-error')
29 | ], 404);
30 | }
31 |
32 | } catch (TokenExpiredException $e) {
33 | return response()->json([
34 | 'message' => __('auth.token-expired')
35 | ], 403);
36 | } catch (TokenBlacklistedException $e) {
37 | return response()->json([
38 | 'message' => __('auth.token-invalid')
39 | ], 403);
40 | } catch (TokenInvalidException $e) {
41 | return response()->json([
42 | 'message' => __('auth.token-error')
43 | ], 400);
44 | } catch (JWTException $e) {
45 | return response()->json([
46 | 'message' => __('auth.token-absent')
47 | ], 400);
48 | }
49 |
50 | return $next($request);
51 | }
52 |
53 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel/laravel",
3 | "description": "The Laravel Framework.",
4 | "keywords": [
5 | "framework",
6 | "laravel"
7 | ],
8 | "license": "MIT",
9 | "type": "project",
10 | "require": {
11 | "darkaonline/l5-swagger": "^6.0",
12 | "doctrine/dbal": "^2.9",
13 | "fideloper/proxy": "^4.0",
14 | "laravel/framework": "^6.0",
15 | "laravel/passport": "^7.0",
16 | "laravel/tinker": "^1.0",
17 | "predis/predis": "^1.1",
18 | "tymon/jwt-auth": "1.*",
19 | "zircote/swagger-php": "3.*"
20 | },
21 | "require-dev": {
22 | "filp/whoops": "^2.0",
23 | "fzaninotto/faker": "^1.4",
24 | "mockery/mockery": "^1.0",
25 | "nunomaduro/collision": "^2.0",
26 | "phpunit/phpunit": "^7.0"
27 | },
28 | "autoload": {
29 | "classmap": [
30 | "database/seeds",
31 | "database/factories"
32 | ],
33 | "psr-4": {
34 | "App\\": "app/"
35 | }
36 | },
37 | "autoload-dev": {
38 | "psr-4": {
39 | "Tests\\": "tests/"
40 | }
41 | },
42 | "extra": {
43 | "laravel": {}
44 | },
45 | "scripts": {
46 | "post-root-package-install": "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
47 | "post-create-project-cmd": "@php artisan key:generate",
48 | "post-autoload-dump": [
49 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
50 | "@php artisan package:discover"
51 | ]
52 | },
53 | "config": {
54 | "preferred-install": "dist",
55 | "sort-packages": true,
56 | "optimize-autoloader": true
57 | },
58 | "minimum-stability": "dev",
59 | "prefer-stable": true
60 | }
61 |
--------------------------------------------------------------------------------
/resources/views/base.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Zanichelli
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
39 |
40 | @yield('content')
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/Repositories/UserRepository.php:
--------------------------------------------------------------------------------
1 | $data['email'],
20 | 'name' => $data['name'],
21 | 'surname' => isset($data['surname']) ? $data['surname'] : null,
22 | 'password' => isset($data['password']) ? bcrypt($data['password']) : null,
23 | 'is_verified' => false,
24 | ]);
25 | }
26 |
27 | /**
28 | * Finds a @see User by id.
29 | *
30 | * @param integer $id
31 | * @return User
32 | */
33 | public function find(int $id)
34 | {
35 | return User::find($id);
36 | }
37 |
38 | /**
39 | * Returns a paginated list of all @see User.
40 | *
41 | * @param null $query
42 | * @return array
43 | */
44 | public function all($query = null)
45 | {
46 | if (empty($query)) {
47 | return User::paginate(10);
48 | }
49 |
50 | return User::where('email', 'like', '%' . $query . '%')
51 | ->paginate(10);
52 | }
53 |
54 | /**
55 | * Updates a @see User.
56 | *
57 | * @param array $data
58 | * @param int $id
59 | * @return int
60 | */
61 | public function update(int $id, array $data)
62 | {
63 | return User::where('id', $id)->update($data);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | App\Http\Kernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | App\Console\Kernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | App\Exceptions\Handler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/config/broadcasting.php:
--------------------------------------------------------------------------------
1 | env('BROADCAST_DRIVER', 'null'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Broadcast Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the broadcast connections that will be used
26 | | to broadcast events to other systems or over websockets. Samples of
27 | | each available type of connection are provided inside this array.
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'pusher' => [
34 | 'driver' => 'pusher',
35 | 'key' => env('PUSHER_APP_KEY'),
36 | 'secret' => env('PUSHER_APP_SECRET'),
37 | 'app_id' => env('PUSHER_APP_ID'),
38 | 'options' => [
39 | 'cluster' => env('PUSHER_APP_CLUSTER'),
40 | 'encrypted' => true,
41 | ],
42 | ],
43 |
44 | 'redis' => [
45 | 'driver' => 'redis',
46 | 'connection' => 'default',
47 | ],
48 |
49 | 'log' => [
50 | 'driver' => 'log',
51 | ],
52 |
53 | 'null' => [
54 | 'driver' => 'null',
55 | ],
56 |
57 | ],
58 |
59 | ];
60 |
--------------------------------------------------------------------------------
/artisan:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/app/Listeners/LogoutProvidersListener.php:
--------------------------------------------------------------------------------
1 | providerRepository = $providerRepository;
32 | }
33 |
34 | /**
35 | * Logout the user from every registered providers.
36 | *
37 | * @param LogoutEvent $event
38 | */
39 | public function handle(LogoutEvent $event) {
40 |
41 | $user = $event->getUser();
42 |
43 | $providers = $this->providerRepository->all();
44 |
45 | if (!count($providers)) {
46 | return;
47 | }
48 |
49 | $client = new Client();
50 |
51 | foreach ($providers as $provider) {
52 | try {
53 | $client->get($provider->logoutUrl, [
54 | 'query' => [
55 | 'id' => $user->id
56 | ],
57 | 'auth' => [
58 | decrypt($provider->username),
59 | decrypt($provider->password)
60 | ]
61 | ]);
62 | } catch (RequestException $e) {
63 | Log::error($e->getMessage());
64 | }
65 | }
66 |
67 | }
68 |
69 | }
70 |
71 |
--------------------------------------------------------------------------------
/resources/lang/en/auth.php:
--------------------------------------------------------------------------------
1 | 'These credentials do not match our records.',
17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
18 |
19 | 'registration-success' => 'Thanks for signing up! Please check your email to complete your registration.',
20 | 'err-verification' => 'User not verified. Check your e-mail box to verify your account.',
21 | 'err-login' => 'Wrong e-mail or password.',
22 | 'err-jwt' => 'Error during login. Try later.',
23 | 'err-fields' => 'Fill correctly all required fields',
24 |
25 | 'label-email' => 'E-mail address',
26 | 'label-enter-email' => 'Enter e-mail',
27 | 'label-username' => 'Username',
28 | 'label-enter-username' => 'Enter username',
29 | 'label-enter-password' => 'Enter a secure password',
30 | 'label-confirm-password' => 'Confirm password',
31 | 'label-repeat-password' => 'Repeat password',
32 | 'label-name' => 'Name',
33 | 'label-surname' => 'Surname',
34 | 'label-enter-name' => 'Enter name',
35 | 'label-enter-surname' => 'Enter surname',
36 | 'label-sign-up' => 'Sign up',
37 | 'label-login' => 'Login',
38 | 'label-logout' => 'Logout',
39 | 'label-logged' => 'is logged',
40 |
41 | 'user-error' => 'User not found',
42 | 'token-expired' => 'Token expired',
43 | 'token-invalid' => 'Token blacklisted',
44 | 'token-error' => 'Invalid token',
45 | 'token-absent' => 'Token absent'
46 | ];
47 |
--------------------------------------------------------------------------------
/resources/js/bootstrap.js:
--------------------------------------------------------------------------------
1 |
2 | window._ = require('lodash');
3 | window.Popper = require('popper.js').default;
4 |
5 | /**
6 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support
7 | * for JavaScript based Bootstrap features such as modals and tabs. This
8 | * code may be modified to fit the specific needs of your application.
9 | */
10 |
11 | try {
12 | window.$ = window.jQuery = require('jquery');
13 |
14 | require('bootstrap');
15 | } catch (e) {}
16 |
17 | /**
18 | * We'll load the axios HTTP library which allows us to easily issue requests
19 | * to our Laravel back-end. This library automatically handles sending the
20 | * CSRF token as a header based on the value of the "XSRF" token cookie.
21 | */
22 |
23 | window.axios = require('axios');
24 |
25 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
26 |
27 | /**
28 | * Next we will register the CSRF Token as a common header with Axios so that
29 | * all outgoing HTTP requests automatically have it attached. This is just
30 | * a simple convenience so we don't have to attach every token manually.
31 | */
32 |
33 | let token = document.head.querySelector('meta[name="csrf-token"]');
34 |
35 | if (token) {
36 | window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
37 | } else {
38 | console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
39 | }
40 |
41 | /**
42 | * Echo exposes an expressive API for subscribing to channels and listening
43 | * for events that are broadcast by Laravel. Echo and event broadcasting
44 | * allows your team to easily build robust real-time web applications.
45 | */
46 |
47 | // import Echo from 'laravel-echo'
48 |
49 | // window.Pusher = require('pusher-js');
50 |
51 | // window.Echo = new Echo({
52 | // broadcaster: 'pusher',
53 | // key: process.env.MIX_PUSHER_APP_KEY,
54 | // cluster: process.env.MIX_PUSHER_APP_CLUSTER,
55 | // encrypted: true
56 | // });
57 |
--------------------------------------------------------------------------------
/resources/assets/js/bootstrap.js:
--------------------------------------------------------------------------------
1 |
2 | window._ = require('lodash');
3 | window.Popper = require('popper.js').default;
4 |
5 | /**
6 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support
7 | * for JavaScript based Bootstrap features such as modals and tabs. This
8 | * code may be modified to fit the specific needs of your application.
9 | */
10 |
11 | try {
12 | window.$ = window.jQuery = require('jquery');
13 |
14 | require('bootstrap');
15 | } catch (e) {}
16 |
17 | /**
18 | * We'll load the axios HTTP library which allows us to easily issue requests
19 | * to our Laravel back-end. This library automatically handles sending the
20 | * CSRF token as a header based on the value of the "XSRF" token cookie.
21 | */
22 |
23 | window.axios = require('axios');
24 |
25 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
26 |
27 | /**
28 | * Next we will register the CSRF Token as a common header with Axios so that
29 | * all outgoing HTTP requests automatically have it attached. This is just
30 | * a simple convenience so we don't have to attach every token manually.
31 | */
32 |
33 | let token = document.head.querySelector('meta[name="csrf-token"]');
34 |
35 | if (token) {
36 | window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
37 | } else {
38 | console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
39 | }
40 |
41 | /**
42 | * Echo exposes an expressive API for subscribing to channels and listening
43 | * for events that are broadcast by Laravel. Echo and event broadcasting
44 | * allows your team to easily build robust real-time web applications.
45 | */
46 |
47 | // import Echo from 'laravel-echo'
48 |
49 | // window.Pusher = require('pusher-js');
50 |
51 | // window.Echo = new Echo({
52 | // broadcaster: 'pusher',
53 | // key: process.env.MIX_PUSHER_APP_KEY,
54 | // cluster: process.env.MIX_PUSHER_APP_CLUSTER,
55 | // encrypted: true
56 | // });
57 |
--------------------------------------------------------------------------------
/app/Http/Services/Mailer.php:
--------------------------------------------------------------------------------
1 | retrieveToken();
22 |
23 | $client = new Client;
24 | $response = $client->request('POST', env('URL_SENDY') . '/api/v1/emails',
25 | [
26 | 'headers' => [
27 | 'Accept' => 'application/json',
28 | 'Content-Type' => 'application/json',
29 | 'Authorization' => 'Bearer ' . $token,
30 | ],
31 | 'body' => json_encode(
32 | [
33 | 'to' => $to,
34 | 'from' => env('EMAIL_FROM'),
35 | 'subject' => $subject,
36 | 'body' => $body
37 |
38 | ]
39 | )
40 | ]);
41 | return json_decode((string) $response->getBody(), true)['message'];
42 | }
43 |
44 | /**
45 | * Function to retrieve authenticated token
46 | *
47 | * @return string token from oauth route
48 | */
49 | public function retrieveToken()
50 | {
51 | $client = new Client;
52 |
53 | $response = $client->post(env('URL_SENDY') . '/oauth/token', [
54 | 'form_params' => [
55 | 'grant_type' => 'client_credentials',
56 | 'client_id' => env('CLIENT_ID_SENDY'),
57 | 'client_secret' => env('CLIENT_SECRET_SENDY'),
58 | 'scope' => '',
59 | ],
60 | ]);
61 |
62 | return json_decode((string) $response->getBody(), true)['access_token'];
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 |
8 | */
9 |
10 | define('LARAVEL_START', microtime(true));
11 |
12 | /*
13 | |--------------------------------------------------------------------------
14 | | Register The Auto Loader
15 | |--------------------------------------------------------------------------
16 | |
17 | | Composer provides a convenient, automatically generated class loader for
18 | | our application. We just need to utilize it! We'll simply require it
19 | | into the script here so that we don't have to worry about manual
20 | | loading any of our classes later on. It feels great to relax.
21 | |
22 | */
23 |
24 | require __DIR__.'/../vendor/autoload.php';
25 |
26 | /*
27 | |--------------------------------------------------------------------------
28 | | Turn On The Lights
29 | |--------------------------------------------------------------------------
30 | |
31 | | We need to illuminate PHP development, so let us turn on the lights.
32 | | This bootstraps the framework and gets it ready for use, then it
33 | | will load up this application so that we can run it and send
34 | | the responses back to the browser and delight our users.
35 | |
36 | */
37 |
38 | $app = require_once __DIR__.'/../bootstrap/app.php';
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Run The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once we have the application, we can handle the incoming request
46 | | through the kernel, and send the associated response back to
47 | | the client's browser allowing them to enjoy the creative
48 | | and wonderful application we have prepared for them.
49 | |
50 | */
51 |
52 | $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
53 |
54 | $response = $kernel->handle(
55 | $request = Illuminate\Http\Request::capture()
56 | );
57 |
58 | $response->send();
59 |
60 | $kernel->terminate($request, $response);
61 |
--------------------------------------------------------------------------------
/resources/views/mail/complete-registration.blade.php:
--------------------------------------------------------------------------------
1 | @extends('mail.base')
2 | @section('title', 'Completa la registrazione')
3 |
4 | @section('body')
5 |
6 |
Completa la registrazione
7 |
Hai ricevuto questa e-mail in seguito alla registrazione da parte di un collaboratore Zanichelli.
8 |
9 |
Di seguito trovi i tuoi dati.
10 |
11 |
12 |
15 |
16 |
{{ $user->email }}
17 |
18 |
19 |
20 |
23 |
24 |
{{ $user->name }}
25 |
26 |
27 |
28 |
31 |
32 |
{{ $user->surname }}
33 |
34 |
35 |
36 |
37 |
Se non hai richiesto tu la registrazione ignora questa e-mail, altrimenti clicca sul bottone sottostante per completare la registrazione.
38 |
39 |
Completa la registrazione
41 |
Se il bottone non dovesse funzionare, copia e incolla sul tuo browser il seguente link:
42 |
{{route('complete-registration', ['token' => $token])}}
43 |
44 | @endsection
--------------------------------------------------------------------------------
/app/Http/Middleware/CheckClientRole.php:
--------------------------------------------------------------------------------
1 | server = $server;
37 | $this->clientRepository = $clientRepository;
38 | }
39 | /**
40 | * Handle an incoming request.
41 | *
42 | * @param \Illuminate\Http\Request $request
43 | * @param \Closure $next
44 | * @param string $roles
45 | * @return mixed
46 | */
47 | public function handle($request, Closure $next, string $roles)
48 | {
49 | $psr = (new DiactorosFactory)->createRequest($request);
50 |
51 | try {
52 | $psr = $this->server->validateAuthenticatedRequest($psr);
53 | $clientReqId = $psr->getAttribute('oauth_client_id');
54 | $client = $this->clientRepository->find($clientReqId);
55 | $check = !empty($client->roles) && !array_diff([$roles], json_decode($client->roles));
56 | } catch (OAuthServerException $e) {
57 | throw new AuthenticationException;
58 | }
59 |
60 | if (!$check) {
61 | return response()->json([
62 | 'message' => 'You are not authorized to use this resource'
63 | ], 403);
64 | }
65 | return $next($request);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/config/logging.php:
--------------------------------------------------------------------------------
1 | env('LOG_CHANNEL', 'syslog'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Log Channels
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here you may configure the log channels for your application. Out of
24 | | the box, Laravel uses the Monolog PHP logging library. This gives
25 | | you a variety of powerful log handlers / formatters to utilize.
26 | |
27 | | Available Drivers: "single", "daily", "slack", "syslog",
28 | | "errorlog", "custom", "stack"
29 | |
30 | */
31 |
32 | 'channels' => [
33 | 'stack' => [
34 | 'driver' => 'stack',
35 | 'channels' => ['single'],
36 | ],
37 |
38 | 'single' => [
39 | 'driver' => 'single',
40 | 'path' => storage_path('logs/laravel.log'),
41 | 'level' => 'debug',
42 | ],
43 |
44 | 'daily' => [
45 | 'driver' => 'daily',
46 | 'path' => storage_path('logs/laravel.log'),
47 | 'level' => 'debug',
48 | 'days' => 7,
49 | ],
50 |
51 | 'slack' => [
52 | 'driver' => 'slack',
53 | 'url' => env('LOG_SLACK_WEBHOOK_URL'),
54 | 'username' => 'Laravel Log',
55 | 'emoji' => ':boom:',
56 | 'level' => 'critical',
57 | ],
58 |
59 | 'syslog' => [
60 | 'driver' => 'syslog',
61 | 'level' => 'debug',
62 | ],
63 |
64 | 'errorlog' => [
65 | 'driver' => 'errorlog',
66 | 'level' => 'debug',
67 | ],
68 | ],
69 |
70 | ];
71 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapApiRoutes();
39 |
40 | $this->mapWebRoutes();
41 |
42 | $this->mapIdpRoutes();
43 |
44 | //
45 | }
46 |
47 | /**
48 | * Define the "web" routes for the application.
49 | *
50 | * These routes all receive session state, CSRF protection, etc.
51 | *
52 | * @return void
53 | */
54 | protected function mapWebRoutes()
55 | {
56 | Route::middleware('web')
57 | ->namespace($this->namespace)
58 | ->group(base_path('routes/web.php'));
59 | }
60 |
61 | /**
62 | * Define the "api" routes for the application.
63 | *
64 | * These routes are typically stateless.
65 | *
66 | * @return void
67 | */
68 | protected function mapApiRoutes()
69 | {
70 | Route::prefix('api')
71 | ->middleware('api')
72 | ->namespace($this->namespace)
73 | ->group(base_path('routes/api.php'));
74 | }
75 |
76 | /**
77 | * Define the "idp" routes for the application.
78 | *
79 | * These routes are typically stateless.
80 | *
81 | * @return void
82 | */
83 | protected function mapIdpRoutes()
84 | {
85 | Route::namespace($this->namespace)
86 | ->group(base_path('routes/idp.php'));
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/Repositories/OauthClientsRepository.php:
--------------------------------------------------------------------------------
1 | $word) {
32 | if ($word) {
33 | $searchWord = '%' . $word . '%';
34 | $words[$key] = "(name LIKE ? or roles like ? )" ;
35 | array_push($params, $searchWord, $searchWord);
36 | }
37 | }
38 | $searchTerm = implode(' and ', $words);
39 |
40 | $result = OauthClient::join('clients', 'oauth_clients.id', '=', 'clients.oauth_client_id' )
41 | ->select('oauth_clients.*')
42 | ->whereRaw($searchTerm, $params)
43 | ->paginate(10);
44 |
45 | return OauthClientsResource::collection($result);
46 | }
47 |
48 | /**
49 | * @purpose
50 | *
51 | * Create new Oauth Clients
52 | * @param array $data
53 | * @return OauthClient
54 | */
55 |
56 | public function create(array $data)
57 | {
58 | return OauthClient::create($data);
59 | }
60 |
61 | /**
62 | * @purpose
63 | *
64 | * Find an Oauth Client by id
65 | * @param int $id
66 | * @return OauthClient
67 | */
68 |
69 | public function find(int $id)
70 | {
71 | return OauthClient::find($id);
72 | }
73 |
74 | /**
75 | * Update OauthClient
76 | * @param int &id array $data
77 | * @param array $data
78 | * @return OauthClient
79 | */
80 |
81 | public function update(int $id, array $data)
82 | {
83 | return OauthClient::where('id', $id)->update($data);
84 | }
85 | }
--------------------------------------------------------------------------------
/config/filesystems.php:
--------------------------------------------------------------------------------
1 | env('FILESYSTEM_DRIVER', 'local'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Default Cloud Filesystem Disk
21 | |--------------------------------------------------------------------------
22 | |
23 | | Many applications store files both locally and in the cloud. For this
24 | | reason, you may specify a default "cloud" driver here. This driver
25 | | will be bound as the Cloud disk implementation in the container.
26 | |
27 | */
28 |
29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'),
30 |
31 | /*
32 | |--------------------------------------------------------------------------
33 | | Filesystem Disks
34 | |--------------------------------------------------------------------------
35 | |
36 | | Here you may configure as many filesystem "disks" as you wish, and you
37 | | may even configure multiple disks of the same driver. Defaults have
38 | | been setup for each driver as an example of the required options.
39 | |
40 | | Supported Drivers: "local", "ftp", "sftp", "s3", "rackspace"
41 | |
42 | */
43 |
44 | 'disks' => [
45 |
46 | 'local' => [
47 | 'driver' => 'local',
48 | 'root' => storage_path('app'),
49 | ],
50 |
51 | 'public' => [
52 | 'driver' => 'local',
53 | 'root' => storage_path('app/public'),
54 | 'url' => env('APP_URL').'/storage',
55 | 'visibility' => 'public',
56 | ],
57 |
58 | 's3' => [
59 | 'driver' => 's3',
60 | 'key' => env('AWS_ACCESS_KEY_ID'),
61 | 'secret' => env('AWS_SECRET_ACCESS_KEY'),
62 | 'region' => env('AWS_DEFAULT_REGION'),
63 | 'bucket' => env('AWS_BUCKET'),
64 | 'url' => env('AWS_URL'),
65 | ],
66 |
67 | ],
68 |
69 | ];
70 |
--------------------------------------------------------------------------------
/resources/views/auth/register.blade.php:
--------------------------------------------------------------------------------
1 | @extends('base')
2 |
3 | @section('content')
4 |
5 | @if ($errors->any())
6 |
7 |
8 | @foreach ($errors->all() as $error)
9 | {{ $error }}
10 | @endforeach
11 |
12 |
13 | @endif
14 |
15 |
48 |
49 | @endsection
--------------------------------------------------------------------------------
/routes/idp.php:
--------------------------------------------------------------------------------
1 | group(function () {
19 |
20 | Route::middleware(['api', 'authenticated'])->get('user', 'JwtAuth\LoginController@userByToken');
21 | Route::middleware(['api', 'authenticated'])->get('loginWithToken', 'JwtAuth\LoginController@userByToken'); // TODO da cancellare dopo allineamento
22 | Route::middleware(['api', 'authenticated'])->get('logout', 'JwtAuth\LoginController@logout');
23 |
24 | Route::middleware('web')->get('roles/{id}/user-roles', 'Manage\UserRoleController@getRoles')->where(['id' => '[0-9]+']);
25 | Route::middleware('web')->get('client-roles', 'ClientRoleController@all');
26 | Route::post('complete-registration', 'JwtAuth\VerificationController@verify');
27 |
28 | // Routes to manage users
29 | Route::middleware(['client', 'checkclientrole:manager'])->group(function () {
30 |
31 | Route::post('user', 'Manage\UserController@create');
32 |
33 | Route::post('users/{id}/user-roles', 'Manage\UserRoleController@create')->where(['id' => '[0-9]+']);
34 |
35 | Route::delete('user-role/{id}', 'Manage\UserRoleController@delete')->where(['id' => '[0-9]+']);
36 |
37 | });
38 |
39 | // Routes to manage idp
40 | Route::middleware(['client', 'checkclientrole:admin'])->group(function () {
41 |
42 | Route::post('providers', 'Manage\ProviderController@create');
43 |
44 | Route::post('roles', 'Manage\RoleController@create');
45 |
46 | Route::delete('roles/{id}', 'Manage\RoleController@delete')->where(['id' => '[0-9]+']);
47 | });
48 |
49 | Route::middleware('client')->group(function () {
50 |
51 | Route::get('roles', 'Manage\RoleController@all');
52 |
53 | Route::get('providers', 'Manage\ProviderController@all');
54 |
55 | Route::get('users/{id}', 'Manage\UserController@find')->where('id', '[0-9]+');
56 |
57 | Route::get('users/{id}/user-roles', 'Manage\UserRoleController@getUserRole')->where(['id' => '[0-9]+']);
58 | });
59 | });
60 |
61 | Route::prefix('v2')->group(function () {
62 |
63 | Route::middleware('web')->post('login', 'JwtAuth\LoginController@login')->name('login');
64 | });
65 |
--------------------------------------------------------------------------------
/routes/web.php:
--------------------------------------------------------------------------------
1 | back();
24 | });
25 |
26 | Route::middleware('guest')
27 | ->get('loginForm', 'JwtAuth\LoginController@showLoginForm')
28 | ->name('loginForm');
29 |
30 | Route::get('logout', 'JwtAuth\LoginController@logout')->name('logout');
31 |
32 | Route::middleware('web.authenticated')
33 | ->get('authenticated', 'JwtAuth\LoginController@authenticated')
34 | ->name('authenticated');
35 |
36 | Route::get('complete-registration', function () {
37 | return view('auth.complete-registration-form');
38 | })->name('complete-registration');
39 |
40 | /********* ADMIN ROUTES ************/
41 |
42 | Route::prefix('admin')->middleware('role:ADMIN_IDP')->group(function () {
43 |
44 | Route::get('/', function () {
45 | return redirect()->route('users-panel');
46 | })->name('admin-board');
47 |
48 | Route::post('users', 'Manage\UserController@create');
49 |
50 | Route::get('users-panel', function () {
51 | return view('admin.users');
52 | })->name('users-panel');
53 |
54 | Route::post('providers', 'Manage\ProviderController@create');
55 |
56 | Route::get('create-provider', function () {
57 | return view('admin.create-provider');
58 | })->name('create-provider');
59 |
60 | Route::get('oauth-clients', function () {
61 | return view('admin.oauth-clients');
62 | })->name('oauth-clients');
63 |
64 | Route::get('oauth-clients-all', 'Manage\OauthClientsController@all');
65 | Route::put('update-roles', 'Manage\OauthClientsController@updateClientRoles');
66 |
67 | Route::get('roles', 'Manage\RoleController@all');
68 | Route::post('roles', 'Manage\RoleController@create');
69 | Route::delete('roles/{id}', 'Manage\RoleController@delete')->where(['id' => '[0-9]+']);
70 |
71 | Route::get('users', 'Manage\UserController@all');
72 |
73 | Route::get('manage-role', function () {
74 | return view('admin.create-role');
75 | })->name('manage-role');
76 | });
77 |
--------------------------------------------------------------------------------
/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->when(LogoutProvidersListener::class)
44 | ->needs(RepositoryInterface::class)
45 | ->give(ProviderRepository::class);
46 |
47 | $this->app->bind(UserRepositoryInterface::class, UserRepository::class);
48 |
49 | $this->app->when(ProviderController::class)
50 | ->needs(RepositoryInterface::class)
51 | ->give(ProviderRepository::class);
52 |
53 | $this->app->when(RoleController::class)
54 | ->needs(RepositoryInterface::class)
55 | ->give(RoleRepository::class);
56 |
57 | $this->app->when(UserRoleController::class)
58 | ->needs(RepositoryInterface::class)
59 | ->give(UserRoleRepository::class);
60 |
61 | $this->app->bind(ClientRepositoryInterface::class, ClientRepository::class);
62 |
63 | $this->app->when(UserController::class)
64 | ->needs(RepositoryInterface::class)
65 | ->give(VerificationTokenRepository::class);
66 |
67 | $this->app->when(VerificationController::class)
68 | ->needs(RepositoryInterface::class)
69 | ->give(VerificationTokenRepository::class);
70 |
71 | $this->app->when(OauthClientsController::class)
72 | ->needs(OauthClientsRepository::class)
73 | ->give(OauthClientsRepository::class);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/database/seeds/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | insert([
17 | 'email' => 'mario.rossi@example.com',
18 | 'password' => Hash::make('secret'),
19 | 'is_verified' => true,
20 | 'name' => 'Mario',
21 | 'surname' => 'Rossi'
22 | ]);
23 |
24 | DB::table('roles')->insert([
25 | 'name' => 'USER'
26 | ]);
27 |
28 | DB::table('roles')->insert([
29 | 'name' => 'ADMIN'
30 | ]);
31 |
32 | DB::table('user_roles')->insert([
33 | 'user_id' => 1,
34 | 'role_id' => 1
35 | ]);
36 |
37 | DB::table('user_roles')->insert([
38 | 'user_id' => 1,
39 | 'role_id' => 2
40 | ]);
41 |
42 | DB::table('clients')->insert([
43 | 'oauth_client_id' => 1,
44 | 'roles' => '["manager"]',
45 | ]);
46 |
47 | DB::table('clients')->insert([
48 | 'oauth_client_id' => 2,
49 | 'roles' => '["manager", "admin"]',
50 | ]);
51 |
52 | DB::table('clients')->insert([
53 | 'oauth_client_id' => 3,
54 | 'roles' => '[]',
55 | ]);
56 |
57 | // STEP: seeding passport oauth_clients
58 | DB::table('oauth_clients')->insert([
59 | 'user_id' => 1,
60 | 'name' => 'manager',
61 | 'secret' => 'HkZ5sCBaAKRH0B5CIlBGjNIQazfYDxi4EDth3ANa',
62 | 'redirect' => 'http://localhost:8000/auth/callback',
63 | 'personal_access_client' => 0,
64 | 'password_client' => 0,
65 | 'revoked' => 0
66 | ]);
67 |
68 | DB::table('oauth_clients')->insert([
69 | 'user_id' => 2,
70 | 'name' => 'admin',
71 | 'secret' => '6ZWpCgKPYc93TbgKHKnZMiULFStw88lIvquDQETQ',
72 | 'redirect' => 'http://localhost:8000/auth/callback',
73 | 'personal_access_client' => 0,
74 | 'password_client' => 0,
75 | 'revoked' => 0
76 | ]);
77 |
78 | DB::table('oauth_clients')->insert([
79 | 'user_id' => 3,
80 | 'name' => 'client',
81 | 'secret' => 'mydhRDjLRMNuubmmHfs8u2DURLEc91qoc6fS58kT',
82 | 'redirect' => 'http://localhost:8000/auth/callback',
83 | 'personal_access_client' => 0,
84 | 'password_client' => 0,
85 | 'revoked' => 0
86 | ]);
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/tests/Feature/LoginWithoutMiddlewareTest.php:
--------------------------------------------------------------------------------
1 | create([
26 | 'is_verified' => true
27 | ]);
28 |
29 | $loginController = new LoginController();
30 |
31 | $request = new LoginRequest([], [], [], [], [], ['REMOTE_ADDR' => '127.0.0.1']);
32 |
33 | $request->merge([
34 | 'username' => $user->email,
35 | 'password' => 'secret'
36 | ]);
37 |
38 | $response = $loginController->login($request);
39 | $this->assertEquals(200, $response->status());
40 | $this->assertContains('user', $response->getContent());
41 | }
42 |
43 | /**
44 | * @test
45 | * @return void
46 | */
47 | public function loginNotVerifiedUserTest()
48 | {
49 | $user = factory(User::class)->create([
50 | 'is_verified' => false
51 | ]);
52 |
53 | $loginController = new LoginController();
54 |
55 | $request = new LoginRequest([], [], [], [], [], ['REMOTE_ADDR' => '127.0.0.1']);
56 |
57 | $request->merge([
58 | 'username' => $user->email,
59 | 'password' => 'secret'
60 | ]);
61 |
62 | $response = $loginController->login($request);
63 | $this->assertEquals(403, $response->status());
64 | }
65 |
66 | /**
67 | * Logout without provider register on system
68 | * @test
69 | * @return void
70 | */
71 | public function logoutWithoutProviderTest()
72 | {
73 | $user = factory(User::class)->create([
74 | 'is_verified' => true
75 | ]);
76 | $response = $this->json('POST', 'v2/login', [
77 | 'username' => $user->email,
78 | 'password' => 'secret'
79 | ]);
80 | $cookies = ['token' => json_decode($response->getContent())->token];
81 |
82 | $mock = Mockery::mock(ProviderRepository::class)->makePartial()
83 | ->shouldReceive(['all' => []])
84 | ->withAnyArgs()
85 | ->once()
86 | ->getMock();
87 | $this->app->instance('App\Repositories\ProviderRepository', $mock);
88 |
89 | $response = $this->get('/v1/logout', [], $cookies);
90 | $response->assertStatus(302)->assertRedirect('/loginForm');
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Manage/OauthClientsController.php:
--------------------------------------------------------------------------------
1 | oauthClientsRepository = $oauthClientsRepository;
28 | $this->clientRoleRepository = $clientRoleRepository;
29 | $this->clientRepository = $clientRepository;
30 | }
31 |
32 | /**
33 | * @purpose
34 | *
35 | * Return a resource of all oauth clients
36 | * @param Request $request
37 | * @return void
38 | */
39 |
40 | public function all(Request $request)
41 | {
42 | $query = $request->input('q');
43 |
44 | return $this->oauthClientsRepository->all($query);
45 | }
46 |
47 | /**
48 | * @purpose
49 | *
50 | * Update the roles of single oauth client
51 | * @param Request $request
52 | * @return void
53 | */
54 |
55 | public function updateClientRoles(Request $request) {
56 |
57 | $admittedRoles = $this->clientRoleRepository->all();
58 |
59 | $validatedData = $request->validate([
60 | 'clientId' => 'required|integer',
61 | 'roles' => ['array',
62 | Rule::in($admittedRoles)
63 | ]
64 | ]);
65 |
66 | $id = $validatedData['clientId'];
67 | $roles = json_encode($validatedData['roles']);
68 |
69 | $data = ["oauth_client_id" => $id,
70 | "roles" => $roles
71 | ];
72 |
73 | $oauthClient = $this->oauthClientsRepository->find($id);
74 |
75 | if (empty($oauthClient)) {
76 | return response()->json([
77 | 'message' => 'Error during updating roles'
78 | ], 500);
79 | }
80 |
81 | if(empty($oauthClient->client)){
82 | if (!$this->clientRepository->create($data)) {
83 | return response()->json([
84 | 'message' => 'Error during updating roles'
85 | ], 500);
86 | }
87 | }
88 |
89 | $oauthClient->client = $this->clientRepository->update($id, $data);
90 |
91 | return response()->json([], Response::HTTP_NO_CONTENT);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/ZanichelliEditore/laravel-jwt-idp)
2 | [](https://codecov.io/gh/ZanichelliEditore/laravel-jwt-idp)
3 |
4 | # Laravel JWT IDP
5 |
6 | ## What is it?
7 |
8 | This project is a basic identity provider developed using Laravel Framework. The user
9 | authentication is based on JWT standard. It is possible use a single sign-on point to log-in
10 | users of several application.
11 |
12 | ## How can I use it?
13 |
14 | It is possible to integrate the single sign-on in an existing project in few steps. Protect your route
15 | with a middleware that checks if the user exists in the session. If the user is not in the session
16 | redirect the user to the IDP login. After the login success the IDP will redirect the user to the
17 | application passing a token. The application must use that token to retrieve the user data.
18 |
19 | ### Setup project
20 |
21 | - Clone the project
22 | - Duplicate the file .env.example and change the name in .env
23 | - In the root the project execute `composer install`
24 | - In the project root execute the command `php artisan key:generate`
25 | - Set a secret key (for jwt authentication) executing from command line `php artisan jwt:secret`
26 | - Create passport keys (for api authentication) executing from command line `php artisan passport:install`
27 | - Compile vuejs view with _**yarn**_ and use `yarn dev` (or use `npm run dev` with _**npm**_)
28 |
29 | ### Routes
30 |
31 | GET Requests
32 |
33 | - **/loginForm** shows the IDP login form. Parameter: "redirect".
34 | - **/v1/user** retrieve the user data by token. Parameters: "token"
35 | - **/v1/logout** logout
36 |
37 | POST Requests
38 |
39 | - **/v2/login** login the user into the application. Parameters: "username" and "password".
40 |
41 | ### Views
42 |
43 | There is 1 default views: login form.
44 | There is also an admin section (**/admin**) through which you can manage idp system; the view is available for "ADMIN_IDP" user-role.
45 |
46 | ### Database
47 |
48 | The IDP manages users using 3 table: users, users_roles, roles.
49 | In the users tables are stored basic users data like email, password,
50 | name, surname, is_verified. Each user can have a role or many roles associated;
51 | it can be usefull in a context with RBAC (Role-based access control).
52 |
53 | ### User structure
54 |
55 | ```json
56 | {
57 | "user": {
58 | "id": 1,
59 | "email": "mario.rossi@example.com",
60 | "is_verified": 1,
61 | "name": "Mario",
62 | "surname": "Rossi",
63 | "created_at": "2018-09-14 12:30:20",
64 | "updated_at": null,
65 | "roles": [
66 | {
67 | "roleId": 1,
68 | "roleName": "USER"
69 | },
70 | {
71 | "roleId": 2,
72 | "roleName": "ADMIN"
73 | }
74 | ]
75 | }
76 | }
77 | ```
78 |
--------------------------------------------------------------------------------
/config/queue.php:
--------------------------------------------------------------------------------
1 | env('QUEUE_DRIVER', 'sync'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Queue Connections
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here you may configure the connection information for each server that
24 | | is used by your application. A default configuration has been added
25 | | for each back-end shipped with Laravel. You are free to add more.
26 | |
27 | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'sync' => [
34 | 'driver' => 'sync',
35 | ],
36 |
37 | 'database' => [
38 | 'driver' => 'database',
39 | 'table' => 'jobs',
40 | 'queue' => 'default',
41 | 'retry_after' => 90,
42 | ],
43 |
44 | 'beanstalkd' => [
45 | 'driver' => 'beanstalkd',
46 | 'host' => 'localhost',
47 | 'queue' => 'default',
48 | 'retry_after' => 90,
49 | ],
50 |
51 | 'sqs' => [
52 | 'driver' => 'sqs',
53 | 'key' => env('SQS_KEY', 'your-public-key'),
54 | 'secret' => env('SQS_SECRET', 'your-secret-key'),
55 | 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
56 | 'queue' => env('SQS_QUEUE', 'your-queue-name'),
57 | 'region' => env('SQS_REGION', 'us-east-1'),
58 | ],
59 |
60 | 'redis' => [
61 | 'driver' => 'redis',
62 | 'connection' => 'default',
63 | 'queue' => 'default',
64 | 'retry_after' => 90,
65 | 'block_for' => null,
66 | ],
67 |
68 | ],
69 |
70 | /*
71 | |--------------------------------------------------------------------------
72 | | Failed Queue Jobs
73 | |--------------------------------------------------------------------------
74 | |
75 | | These options configure the behavior of failed queue job logging so you
76 | | can control which database and table are used to store the jobs that
77 | | have failed. You may change them to any database / table you wish.
78 | |
79 | */
80 |
81 | 'failed' => [
82 | 'database' => env('DB_CONNECTION', 'mysql'),
83 | 'table' => 'failed_jobs',
84 | ],
85 |
86 | ];
87 |
--------------------------------------------------------------------------------
/tests/Integration/VerificationTest.php:
--------------------------------------------------------------------------------
1 | '', 'password' => ''];
22 | $response = $this->json('POST', '/v1/complete-registration', $data);
23 | $response->assertStatus(422)
24 | ->assertJson([
25 | 'message' => 'Invalid parameters.'
26 | ]);
27 |
28 |
29 | $user = User::create([
30 | 'email' => Str::random(30) . '@example.com',
31 | 'name' => 'myName2',
32 | 'surname' => 'mySurname2',
33 | 'is_verified' => true
34 | ]);
35 |
36 | // Invalid parameters for empty password
37 | $token2 = VerificationToken::create([
38 | 'user_id' => $user->id,
39 | 'token' => Str::random(50)
40 | ]);
41 |
42 | $data = ['token' => $token2->token, 'password' => ' '];
43 | $response = $this->json('POST', '/v1/complete-registration', $data);
44 | $response->assertStatus(422)
45 | ->assertJson([
46 | 'message' => 'Invalid parameters.'
47 | ]);
48 |
49 | // Invalid Token with empty field
50 | $data = ['token' => 'a', 'password' => 'testpassword'];
51 | $response = $this->json('POST', '/v1/complete-registration', $data);
52 | $response->assertStatus(422)
53 | ->assertJson([
54 | 'message' => 'Invalid token'
55 | ]);
56 |
57 |
58 | // Invalid Token with token set not valid
59 | $token = VerificationToken::create([
60 | 'user_id' => $user->id,
61 | 'token' => Str::random(50),
62 | 'is_valid' => 0
63 | ]);
64 |
65 | $data = ['token' => $token->token, 'password' => 'testpassword'];
66 | $response = $this->json('POST', '/v1/complete-registration', $data);
67 | $response->assertStatus(422)
68 | ->assertJson([
69 | 'message' => 'Invalid token'
70 | ]);
71 | }
72 |
73 | /**
74 | * @test
75 | * @return void
76 | */
77 | public function validationTokenTest()
78 | {
79 | $user = User::create([
80 | 'email' => Str::random(30) . '@example.com',
81 | 'name' => 'myName2',
82 | 'surname' => 'mySurname2',
83 | 'is_verified' => true
84 | ]);
85 |
86 |
87 | $token = VerificationToken::create([
88 | 'user_id' => $user->id,
89 | 'token' => Str::random(50)
90 | ]);
91 |
92 | $data = ['token' => $token->token, 'password' => 'testpassword'];
93 | $response = $this->json('POST', '/v1/complete-registration', $data);
94 | $response->assertStatus(204);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/config/cache.php:
--------------------------------------------------------------------------------
1 | env('CACHE_DRIVER', 'redis'),
21 |
22 | /*
23 | |--------------------------------------------------------------------------
24 | | Cache Stores
25 | |--------------------------------------------------------------------------
26 | |
27 | | Here you may define all of the cache "stores" for your application as
28 | | well as their drivers. You may even define multiple stores for the
29 | | same cache driver to group types of items stored in your caches.
30 | |
31 | */
32 |
33 | 'stores' => [
34 |
35 | 'apc' => [
36 | 'driver' => 'apc',
37 | ],
38 |
39 | 'array' => [
40 | 'driver' => 'array',
41 | ],
42 |
43 | 'database' => [
44 | 'driver' => 'database',
45 | 'table' => 'cache',
46 | 'connection' => null,
47 | ],
48 |
49 | 'file' => [
50 | 'driver' => 'file',
51 | 'path' => storage_path('framework/cache/data'),
52 | ],
53 |
54 | 'memcached' => [
55 | 'driver' => 'memcached',
56 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
57 | 'sasl' => [
58 | env('MEMCACHED_USERNAME'),
59 | env('MEMCACHED_PASSWORD'),
60 | ],
61 | 'options' => [
62 | // Memcached::OPT_CONNECT_TIMEOUT => 2000,
63 | ],
64 | 'servers' => [
65 | [
66 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'),
67 | 'port' => env('MEMCACHED_PORT', 11211),
68 | 'weight' => 100,
69 | ],
70 | ],
71 | ],
72 |
73 | 'redis' => [
74 | 'driver' => 'redis',
75 | 'connection' => 'default',
76 | ],
77 |
78 | ],
79 |
80 | /*
81 | |--------------------------------------------------------------------------
82 | | Cache Key Prefix
83 | |--------------------------------------------------------------------------
84 | |
85 | | When utilizing a RAM based store such as APC or Memcached, there might
86 | | be other applications utilizing the same cache. So, we'll specify a
87 | | value to get prefixed to all our keys so we can avoid collisions.
88 | |
89 | */
90 |
91 | 'prefix' => env(
92 | 'CACHE_PREFIX',
93 | Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'
94 | ),
95 |
96 | ];
97 |
--------------------------------------------------------------------------------
/app/Services/AccountService.php:
--------------------------------------------------------------------------------
1 | $email,
48 | 'password' => Hash::make($password),
49 | 'name' => $name,
50 | 'surname' => $surname
51 | ]);
52 |
53 | $verificationCode = VerificationCode::create([
54 | 'user_id' => $user->id,
55 | 'verification_code' => Str::random(30)
56 | ]);
57 | } catch (Exception $e){
58 | Log::error($e->getMessage());
59 | DB::rollBack();
60 |
61 | throw new SqlException($e->getMessage());
62 | }
63 |
64 | DB::commit();
65 |
66 | event(new RegistrationEvent($user, $verificationCode->verification_code));
67 | }
68 |
69 | /**
70 | * @param string $verificationCode
71 | * @throws SqlException
72 | */
73 | public function verifyUser(string $verificationCode){
74 | // TODO decidere i messaggi degli errori
75 |
76 | try {
77 |
78 | $userVerification = VerificationCode::where('verification_code', $verificationCode)->first();
79 |
80 | if(empty($userVerification)){
81 | throw new Exception('Non trovato il codice');
82 | }
83 |
84 | $user = User::where('id', $userVerification->user_id)->first();
85 | $user->is_verified = 1;
86 |
87 | if(!$user->save()){
88 | throw new Exception('Non è salvato');
89 | }
90 |
91 | if(!$userVerification->delete()){
92 | throw new Exception('Non è cancellato');
93 | }
94 |
95 | } catch (Exception $e){
96 | Log::error($e->getMessage());
97 | throw new SqlException($e->getMessage());
98 | }
99 |
100 | }
101 |
102 | }
--------------------------------------------------------------------------------
/app/Http/Kernel.php:
--------------------------------------------------------------------------------
1 | [
36 | \App\Http\Middleware\EncryptCookies::class,
37 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
38 | \Illuminate\Session\Middleware\StartSession::class,
39 | // \Illuminate\Session\Middleware\AuthenticateSession::class,
40 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
41 | // \App\Http\Middleware\VerifyCsrfToken::class,
42 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
43 | \App\Http\Middleware\Localization::class,
44 | ],
45 |
46 | 'api' => [
47 | 'throttle:60,1',
48 | 'bindings',
49 | ],
50 | ];
51 |
52 | /**
53 | * The application's route middleware.
54 | *
55 | * These middleware may be assigned to groups or used individually.
56 | *
57 | * @var array
58 | */
59 | protected $routeMiddleware = [
60 | 'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
61 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
62 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
63 | 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
64 | 'can' => \Illuminate\Auth\Middleware\Authorize::class,
65 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
66 | 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
67 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
68 |
69 | 'client' => CheckClientCredentials::class,
70 | 'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
71 | 'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
72 | 'checkclientrole' => CheckClientRole::class,
73 | 'role' => CheckRole::class,
74 | 'authenticated' => Authenticated::class,
75 |
76 | 'web.authenticated' => RedirectIfUnauthenticated::class,
77 | ];
78 | }
79 |
--------------------------------------------------------------------------------
/resources/js/components/LoginForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
17 |
18 |
19 |
20 |
21 | {{ errorMessage }}
22 |
23 |
24 |
25 |
26 |
27 |
85 |
86 |
--------------------------------------------------------------------------------
/tests/Integration/RoleWithoutMiddlewareTest.php:
--------------------------------------------------------------------------------
1 | create();
23 | $response = $this->json('GET', '/v1/roles');
24 | $response->assertStatus(200)
25 | ->assertJsonStructure([
26 | [
27 | 'id',
28 | 'name'
29 | ]
30 | ]);
31 | }
32 |
33 | /**
34 | * Create a new role.
35 | * @test
36 | * @return void
37 | */
38 | public function createRoleTest()
39 | {
40 | $role = factory(Role::class)->make();
41 | $role->id = 1;
42 |
43 | $repositoryMock = Mockery::mock(RoleRepository::class)->makePartial()
44 | ->shouldReceive(['create'=> collect(['name' => $role->name])])
45 | ->once()
46 | ->andReturn($role)
47 | ->getMock();
48 |
49 | $this->app->instance('App\Repositories\RoleRepository', $repositoryMock);
50 |
51 | $response = $this->json('POST', '/v1/roles', ['name' => $role->name]);
52 | $response->assertStatus(201)
53 | ->assertJsonStructure([
54 | 'id',
55 | 'name'
56 | ]);
57 | }
58 |
59 | /**
60 | * Existing role test.
61 | * @test
62 | * @return void
63 | */
64 | public function existingRoleTest()
65 | {
66 | $role = factory(Role::class)->create();
67 |
68 | $response = $this->json('POST', '/v1/roles', ['name' => $role->name]);
69 | $response->assertStatus(422);
70 |
71 | $role->delete();
72 | }
73 |
74 | /**
75 | * Existing role test.
76 | * @test
77 | * @return void
78 | */
79 | public function deletingInexistentRole()
80 | {
81 | $response = $this->json('DELETE', '/v1/roles/99999999999999');
82 | $response->assertStatus(404);
83 | }
84 |
85 | /**
86 | * Delete role test.
87 | * @test
88 | * @return void
89 | */
90 | public function deletingRole()
91 | {
92 | $role = factory(Role::class)->create();
93 |
94 | $response = $this->json('DELETE', '/v1/roles/' . $role->id);
95 | $response->assertStatus(204);
96 | }
97 |
98 | /**
99 | * Delete role test.
100 | * @test
101 | * @return void
102 | */
103 | public function errorOnDeletingRole()
104 | {
105 | $role = factory(Role::class)->create();
106 |
107 | $repositoryMock = Mockery::mock(RoleRepository::class)->makePartial()
108 | ->shouldReceive(['delete' => false])
109 | ->once()
110 | ->getMock();
111 |
112 | $this->app->instance('App\Repositories\RoleRepository', $repositoryMock);
113 |
114 | $response = $this->json('DELETE', '/v1/roles/' . $role->id);
115 | $response->assertStatus(500);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/resources/js/components/Paginator.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
20 |
21 |
97 |
98 |
--------------------------------------------------------------------------------
/resources/js/components/NotificationComponent.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{currentNotification.message}}
4 |
5 |
6 |
7 |
8 |
9 |
10 |
79 |
80 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at developers@zanichelli.it. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/resources/js/components/CompleteRegistrationForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Completa la registrazione
4 |
5 |
38 |
39 |
Registrazione terminata con successo
40 |
43 |
44 |
45 |
Si è verificato un errore durante l'attivazione
50 |
51 |
52 |
53 |
109 |
110 |
--------------------------------------------------------------------------------
/resources/js/components/Chip.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ id }}
5 |
6 |
7 | {{ name }}
8 |
9 |
14 |
15 |
16 |
17 | Loading...
18 |
19 | Conferma
20 |
21 |
Annulla
22 |
23 |
24 |
25 |
26 |
86 |
87 |
--------------------------------------------------------------------------------
/config/auth.php:
--------------------------------------------------------------------------------
1 | [
17 | 'guard' => 'jwt',
18 | 'passwords' => 'users',
19 | ],
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Authentication Guards
24 | |--------------------------------------------------------------------------
25 | |
26 | | Next, you may define every authentication guard for your application.
27 | | Of course, a great default configuration has been defined for you
28 | | here which uses session storage and the Eloquent user provider.
29 | |
30 | | All authentication drivers have a user provider. This defines how the
31 | | users are actually retrieved out of your database or other storage
32 | | mechanisms used by this application to persist your user's data.
33 | |
34 | | Supported: "session", "token"
35 | |
36 | */
37 |
38 | 'guards' => [
39 |
40 | 'web' => [
41 | 'driver' => 'session',
42 | 'provider' => 'users',
43 | ],
44 |
45 | 'api' => [
46 | 'driver' => 'passport',
47 | 'provider' => 'users',
48 | ],
49 |
50 | 'jwt' => [
51 | 'driver' => 'jwt',
52 | 'provider' => 'users'
53 | ]
54 | ],
55 |
56 | /*
57 | |--------------------------------------------------------------------------
58 | | User Providers
59 | |--------------------------------------------------------------------------
60 | |
61 | | All authentication drivers have a user provider. This defines how the
62 | | users are actually retrieved out of your database or other storage
63 | | mechanisms used by this application to persist your user's data.
64 | |
65 | | If you have multiple user tables or models you may configure multiple
66 | | sources which represent each model / table. These sources may then
67 | | be assigned to any extra authentication guards you have defined.
68 | |
69 | | Supported: "database", "eloquent"
70 | |
71 | */
72 |
73 | 'providers' => [
74 |
75 | 'users' => [
76 | 'driver' => 'eloquent',
77 | 'model' => App\Models\User::class,
78 | ],
79 |
80 | // 'users' => [
81 | // 'driver' => 'database',
82 | // 'table' => 'users',
83 | // ],
84 | ],
85 |
86 | /*
87 | |--------------------------------------------------------------------------
88 | | Resetting Passwords
89 | |--------------------------------------------------------------------------
90 | |
91 | | You may specify multiple password reset configurations if you have more
92 | | than one user table or model in the application and you want to have
93 | | separate password reset settings based on the specific user types.
94 | |
95 | | The expire time is the number of minutes that the reset token should be
96 | | considered valid. This security feature keeps tokens short-lived so
97 | | they have less time to be guessed. You may change this as needed.
98 | |
99 | */
100 |
101 | 'passwords' => [
102 | 'users' => [
103 | 'provider' => 'users',
104 | 'table' => 'password_resets',
105 | 'expire' => 60,
106 | ],
107 | ],
108 |
109 | ];
110 |
--------------------------------------------------------------------------------
/public/svg/404.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Http/Controllers/JwtAuth/VerificationController.php:
--------------------------------------------------------------------------------
1 | verificationTokenRepository = $verificationTokenRepository;
24 | $this->userRepository = $userRepository;
25 | }
26 |
27 | /**
28 | * @OA\Post(
29 | * path="/v1/complete-registration",
30 | * summary="Active user",
31 | * description="Activate user using token received in the email",
32 | * operationId="VerificationController.verify",
33 | * tags={"JWT Auth"},
34 | * @OA\RequestBody(
35 | * @OA\MediaType(
36 | * mediaType="application/x-www-form-urlencoded",
37 | * @OA\Schema(
38 | * type="object",
39 | * @OA\Property(
40 | * property="token",
41 | * description="Token",
42 | * type="string"
43 | * ),
44 | * @OA\Property(
45 | * property="password",
46 | * description="User password",
47 | * type="string",
48 | * format="password"
49 | * )
50 | * )
51 | * )
52 | * ),
53 | * @OA\Response(
54 | * response=204,
55 | * description="Operation successful",
56 | * @OA\MediaType(
57 | * mediaType="application/json",
58 | * )
59 | * ),
60 | * @OA\Response(
61 | * response=422,
62 | * description="Invalid data",
63 | * @OA\MediaType(
64 | * mediaType="application/json",
65 | * )
66 | * ),
67 | * @OA\Response(
68 | * response=500,
69 | * description="General error",
70 | * @OA\MediaType(
71 | * mediaType="application/json",
72 | * )
73 | * )
74 | * )
75 | */
76 | public function verify(Request $request)
77 | {
78 | $validator = $this->validator($request->only('token', 'password'));
79 | if ($validator->fails()) {
80 | return response()->json([
81 | 'message' => 'Invalid parameters.'
82 | ], 422);
83 | }
84 |
85 | $token = $request->input('token');
86 | $password = $request->input('password');
87 |
88 | $hashedPassword = Hash::make($password);
89 |
90 | $verificationToken = $this->verificationTokenRepository->retrieveByToken($token);
91 |
92 | if (empty($verificationToken) || !$verificationToken->is_valid) {
93 | return response()->json([
94 | 'message' => 'Invalid token'
95 | ], 422);
96 | }
97 |
98 | $user = $this->userRepository->find($verificationToken->user_id);
99 |
100 | DB::beginTransaction();
101 |
102 | $user->is_verified = true;
103 | $user->password = $hashedPassword;
104 |
105 | $verificationToken->is_valid = false;
106 |
107 | if (!$user->save() || !$verificationToken->save()) {
108 | DB::rollBack();
109 | return response()->json([
110 | 'message' => 'Error during user activation'
111 | ], 500);
112 | }
113 |
114 | DB::commit();
115 |
116 | return response()->json([], 204);
117 | }
118 |
119 | private function validator($parameters)
120 | {
121 | return Validator::make($parameters, [
122 | 'token' => 'required|string',
123 | 'password' => 'required|min:5'
124 | ]);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/tests/Integration/ProviderTest.php:
--------------------------------------------------------------------------------
1 | json('GET', '/v1/providers');
20 | $response->assertStatus(401);
21 | }
22 |
23 | /**
24 | * Create provider for unauthorized user.
25 | * @test
26 | * @return void
27 | */
28 | public function providerCreateUnauthorizedTest()
29 | {
30 | $response = $this->json('POST', '/v1/providers');
31 | $response->assertStatus(401);
32 | }
33 |
34 | /**
35 | * Error validation in create provider
36 | * @test
37 | * @return void
38 | */
39 | public function providerCreateValidationErrorByAdminTest()
40 | {
41 | $user = UserUtility::getAdmin();
42 |
43 | $response = $this->json('POST', 'v2/login', [
44 | 'username' => $user->email,
45 | 'password' => 'secret'
46 | ]);
47 |
48 | $cookie = ['token' => json_decode($response->getContent())->token];
49 | $response = $this->json('POST', '/admin/providers', [], $cookie);
50 | $response->assertStatus(422)->assertJsonStructure([
51 | 'message',
52 | 'errors' => [
53 | 'domain',
54 | 'username',
55 | 'password'
56 | ]
57 | ]);
58 |
59 | $body = [
60 | 'domain' => 123,
61 | 'username' => 123,
62 | 'password' => 123,
63 | 'logoutUrl' => 123
64 | ];
65 | $response = $this->json('POST', '/admin/providers', $body, $cookie);
66 | $response->assertStatus(422)->assertJsonStructure([
67 | 'message',
68 | 'errors' => [
69 | 'domain',
70 | 'username',
71 | 'password',
72 | 'logoutUrl'
73 | ]
74 | ]);
75 |
76 | $body = [
77 | 'domain' => Str::random(256),
78 | 'username' => Str::random(51),
79 | 'password' => Str::random(51),
80 | 'logoutUrl' => Str::random(256)
81 | ];
82 | $response = $this->json('POST', '/admin/providers', $body, $cookie);
83 | $response->assertStatus(422)->assertJsonStructure([
84 | 'message',
85 | 'errors' => [
86 | 'domain',
87 | 'username',
88 | 'password',
89 | 'logoutUrl'
90 | ]
91 | ]);
92 |
93 | $provider = factory(Provider::class)->create();
94 | $body = [
95 | 'domain' => $provider->domain,
96 | 'username' => 'valid',
97 | 'password' => 'a',
98 | 'logoutUrl' => 'valid'
99 | ];
100 | $response = $this->json('POST', '/admin/providers', $body, $cookie);
101 | $response->assertStatus(422)->assertJsonStructure([
102 | 'message',
103 | 'errors' => [
104 | 'domain',
105 | 'password',
106 | ]
107 | ]);
108 | }
109 |
110 | /**
111 | * Create provider by admin.
112 | * @test
113 | * @return void
114 | */
115 | public function providerCreateByAdminTest()
116 | {
117 | $user = UserUtility::getAdmin();
118 |
119 | $response = $this->json('POST', 'v2/login', [
120 | 'username' => $user->email,
121 | 'password' => 'secret'
122 | ]);
123 |
124 | $cookie = ['token' => json_decode($response->getContent())->token];
125 | $body = [
126 | 'domain' => Str::random(85),
127 | 'username' => 'user',
128 | 'password' => 'secret',
129 | 'logoutUrl' => 'valid'
130 | ];
131 | $response = $this->json('POST', '/admin/providers', $body, $cookie);
132 | $response->assertStatus(201)
133 | ->assertJsonStructure([
134 | 'provider' => [
135 | 'id',
136 | 'logoutUrl',
137 | 'domain',
138 | 'username',
139 | 'password'
140 | ]
141 | ]);
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/resources/views/mail/base.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | @yield('title')
5 |
6 |
145 |
146 |
147 |
148 |
149 |
152 |
153 | @yield('body')
154 |
155 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------