Skip to content

Commit 5dec5cb

Browse files
Add Vdlp.BasicAuthentication
0 parents  commit 5dec5cb

31 files changed

Lines changed: 991 additions & 0 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
composer.lock
2+
.idea/

Plugin.php

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Vdlp\BasicAuthentication;
6+
7+
use Backend\Helpers\Backend as BackendHelper;
8+
use Illuminate\Contracts\Config\Repository;
9+
use Illuminate\Contracts\Session\Session;
10+
use Illuminate\Database\Eloquent\ModelNotFoundException;
11+
use Illuminate\Http\Request;
12+
use October\Rain\Translation\Translator;
13+
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
14+
use System\Classes\PluginBase;
15+
use Vdlp\BasicAuthentication\Classes\Helper\AuthorizationHelper;
16+
use Vdlp\BasicAuthentication\Models\Credential;
17+
use Vdlp\BasicAuthentication\ServiceProviders\BasicAuthenticationServiceProvider;
18+
19+
/**
20+
* Class Plugin
21+
*
22+
* @package Vdlp\BasicAuthentication
23+
*/
24+
class Plugin extends PluginBase
25+
{
26+
/**
27+
* {@inheritdoc}
28+
*/
29+
public function pluginDetails(): array
30+
{
31+
return [
32+
'name' => 'vdlp.basicauthentication::lang.plugin.name',
33+
'description' => 'vdlp.basicauthentication::lang.plugin.description',
34+
'author' => 'Van der Let & Partners',
35+
'icon' => 'icon-lock',
36+
];
37+
}
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
public function register(): void
43+
{
44+
$this->app->register(BasicAuthenticationServiceProvider::class);
45+
}
46+
47+
/**
48+
* {@inheritdoc}
49+
* @throws SuspiciousOperationException
50+
*/
51+
public function boot()
52+
{
53+
/** @var Repository $config */
54+
$config = resolve(Repository::class);
55+
56+
if (!$config->get('basicauthentication.enabled')
57+
|| app()->runningInConsole()
58+
|| app()->runningUnitTests()
59+
|| app()->runningInBackend()
60+
) {
61+
return;
62+
}
63+
64+
/** @var Request $request */
65+
$request = resolve(Request::class);
66+
67+
/** @var Session $session */
68+
$session = resolve(Session::class);
69+
70+
/** @var Translator $translator */
71+
$translator = resolve('translator');
72+
73+
/** @var AuthorizationHelper $authorizationHelper */
74+
$authorizationHelper = resolve(AuthorizationHelper::class);
75+
if ($authorizationHelper->isIpAddressWhitelisted($request->ip())) {
76+
return;
77+
}
78+
79+
try {
80+
/** @var Credential $credential */
81+
$credential = Credential::query()
82+
->where('hostname', '=', $request->getHost())
83+
->where('is_enabled', '=', true)
84+
->firstOrFail();
85+
} catch (ModelNotFoundException $e) {
86+
return;
87+
}
88+
89+
if ($authorizationHelper->isUrlExcluded($request->getUri())) {
90+
return;
91+
}
92+
93+
$sessionKey = str_slug(str_replace('.', '_', $credential->getAttribute('hostname')) . '_basic_authentication');
94+
if ($session->has($sessionKey)) {
95+
return;
96+
}
97+
98+
if ($request->getUser() === $credential->getAttribute('username')
99+
&& $request->getPassword() === $credential->getAttribute('password')
100+
) {
101+
$session->put($sessionKey, $request->getUser());
102+
return;
103+
}
104+
105+
header('WWW-Authenticate: Basic realm="' . $credential->getAttribute('realm') . '"');
106+
header('HTTP/1.0 401 Unauthorized');
107+
108+
echo $translator->get('vdlp.basicauthentication::lang.output.unauthorized');
109+
exit;
110+
}
111+
112+
/**
113+
* {@inheritdoc}
114+
*/
115+
public function registerPermissions(): array
116+
{
117+
return [
118+
'vdlp.basicauthentication.access_settings' => [
119+
'label' => 'vdlp.basicauthentication::lang.permissions.access_settings.label',
120+
'tab' => 'vdlp.basicauthentication::lang.permissions.access_settings.tab',
121+
],
122+
];
123+
}
124+
125+
/**
126+
* {@inheritdoc}
127+
*/
128+
public function registerSettings(): array
129+
{
130+
/** @var BackendHelper $backendHelper */
131+
$backendHelper = resolve(BackendHelper::class);
132+
133+
return [
134+
'credentials' => [
135+
'label' => 'vdlp.basicauthentication::lang.settings.label',
136+
'description' => 'vdlp.basicauthentication::lang.settings.description',
137+
'url' => $backendHelper->url('vdlp/basicauthentication/credentials'),
138+
'category' => 'Basic Authentication',
139+
'icon' => 'icon-lock',
140+
'permissions' => ['vdlp.basicauthentication.*'],
141+
'keywords' => 'basic authentication security',
142+
'order' => 500,
143+
],
144+
'excludedurls' => [
145+
'label' => 'vdlp.basicauthentication::lang.excludedurls.label',
146+
'description' => 'vdlp.basicauthentication::lang.excludedurls.description',
147+
'url' => $backendHelper->url('vdlp/basicauthentication/excludedurls'),
148+
'category' => 'Basic Authentication',
149+
'icon' => 'icon-link',
150+
'permissions' => ['vdlp.basicauthentication.*'],
151+
'keywords' => 'basic authentication security',
152+
'order' => 501,
153+
],
154+
];
155+
}
156+
}

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# VDLP Basic Authentication plugin
2+
3+
Allows you to manage Basic Authentication credentials for multiple hostnames / environments.
4+
5+
## Requirements
6+
7+
* PHP 7.1 or higher
8+
9+
## Installation
10+
11+
*CLI:*
12+
13+
`php artisan plugin:install Vdlp.BasicAuthentication`
14+
15+
*October CMS:*
16+
17+
Go to Settings > Updates & Plugins > Install plugins and search for 'BasicAuthentication'.
18+
19+
## Configuration
20+
21+
To configure this plugin execute the following command:
22+
23+
`php artisan vendor:publish --provider="Vdlp\BasicAuthentication\ServiceProviders\BasicAuthenticationServiceProvider" --tag="config"`
24+
25+
This will create a `config/basicauthentication.php` file in your app where you can modify the configuration if you don't
26+
want to use .env variables.
27+
28+
## Questions? Need help?
29+
30+
If you have any question about how to use this plugin, please don't hesitate to contact us at octobercms@vdlp.nl. We're happy to help you. You can also visit the support forum and drop your questions/issues there.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Vdlp\BasicAuthentication\Classes\Helper;
6+
7+
use Illuminate\Contracts\Config\Repository;
8+
use Illuminate\Http\Request;
9+
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
10+
use Vdlp\BasicAuthentication\Models\ExcludedUrl;
11+
12+
/**
13+
* Class AuthorizationHelper
14+
*
15+
* @package Vdlp\BasicAuthentication\Classes\Helper
16+
*/
17+
class AuthorizationHelper
18+
{
19+
/**
20+
* @var Repository
21+
*/
22+
private $config;
23+
24+
/**
25+
* @var Request
26+
*/
27+
private $request;
28+
29+
/**
30+
* @param Repository $config
31+
* @param Request $request
32+
*/
33+
public function __construct(Repository $config, Request $request)
34+
{
35+
$this->config = $config;
36+
$this->request = $request;
37+
}
38+
39+
/**
40+
* @param string $currentUrl
41+
* @return bool
42+
* @throws SuspiciousOperationException
43+
*/
44+
public function isUrlExcluded(string $currentUrl): bool
45+
{
46+
$currentUrl = parse_url($currentUrl);
47+
48+
$excludedUrls = ExcludedUrl::all();
49+
foreach ($excludedUrls as $excludedUrl) {
50+
$excludedUrl = parse_url($excludedUrl->getAttribute('url'));
51+
if (array_key_exists('host', $excludedUrl) && $excludedUrl['host'] !== $this->request->getHost()) {
52+
continue;
53+
}
54+
55+
if (array_key_exists('path', $excludedUrl)
56+
&& array_key_exists('path', $currentUrl)
57+
&& $excludedUrl['path'] === $currentUrl['path']
58+
) {
59+
return true;
60+
}
61+
}
62+
63+
return false;
64+
}
65+
66+
/**
67+
* @param string $ipAddress
68+
* @return bool
69+
*/
70+
public function isIpAddressWhitelisted(string $ipAddress): bool
71+
{
72+
return in_array($ipAddress, explode(',', $this->config->get('basicauthentication.whitelisted_ips')), true);
73+
}
74+
}

composer.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "vdlp/oc-basicauthentication-plugin",
3+
"description": "Allows you to manage Basic Authentication credentials in October CMS powered websites.",
4+
"type": "october-plugin",
5+
"license": "GPL-2.0",
6+
"authors": [
7+
{
8+
"name": "Van der Let & Partners",
9+
"email": "octobercms@vdlp.nl"
10+
}
11+
],
12+
"require": {
13+
"php": ">=7.1"
14+
}
15+
}

config.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return [
6+
'enabled' => (bool) env('BASIC_AUTHENTICATION_ENABLED', false),
7+
'whitelisted_ips' => env('BASIC_AUTHENTICATION_WHITELISTED_IPS', ''),
8+
];

controllers/Credentials.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Vdlp\BasicAuthentication\Controllers;
6+
7+
use Backend\Behaviors\FormController;
8+
use Backend\Behaviors\ListController;
9+
use Backend\Classes\NavigationManager;
10+
use Backend\Classes\Controller;
11+
use System\Classes\SettingsManager;
12+
13+
/**
14+
* Class Credentials
15+
*
16+
* Credentials Back-end Controller.
17+
*
18+
* @package Vdlp\BasicAuthentication\Controllers
19+
* @mixin ListController
20+
* @mixin FormController
21+
*/
22+
class Credentials extends Controller
23+
{
24+
/** {@inheritdoc} */
25+
public $implement = [
26+
FormController::class,
27+
ListController::class,
28+
];
29+
30+
/** @var string */
31+
public $formConfig = 'config_form.yaml';
32+
33+
/** @var string */
34+
public $listConfig = 'config_list.yaml';
35+
36+
/** {@inheritdoc} */
37+
public $requiredPermissions = ['vdlp.basicauthentication.access_settings'];
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
public function __construct()
43+
{
44+
parent::__construct();
45+
46+
NavigationManager::instance()->setContext('October.System', 'system', 'settings');
47+
SettingsManager::setContext('Vdlp.BasicAuthentication', 'credentials');
48+
}
49+
}

controllers/ExcludedUrls.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Vdlp\BasicAuthentication\Controllers;
6+
7+
use Backend\Behaviors\FormController;
8+
use Backend\Behaviors\ListController;
9+
use Backend\Classes\NavigationManager;
10+
use Backend\Classes\Controller;
11+
use System\Classes\SettingsManager;
12+
13+
/**
14+
* Class excludedurls
15+
*
16+
* Excluded Urls Back-end Controller.
17+
*
18+
* @package Vdlp\BasicAuthentication\Controllers
19+
* @mixin ListController
20+
* @mixin FormController
21+
*/
22+
class ExcludedUrls extends Controller
23+
{
24+
/** {@inheritdoc} */
25+
public $implement = [
26+
FormController::class,
27+
ListController::class,
28+
];
29+
30+
/** @var string */
31+
public $formConfig = 'config_form.yaml';
32+
33+
/** @var string */
34+
public $listConfig = 'config_list.yaml';
35+
36+
/** {@inheritdoc} */
37+
public $requiredPermissions = ['vdlp.basicauthentication.access_settings'];
38+
39+
/**
40+
* {@inheritdoc}
41+
*/
42+
public function __construct()
43+
{
44+
parent::__construct();
45+
46+
NavigationManager::instance()->setContext('October.System', 'system', 'settings');
47+
SettingsManager::setContext('Vdlp.BasicAuthentication', 'excludedurls');
48+
}
49+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div data-control="toolbar">
2+
<a
3+
href="<?= $this->actionUrl('create') ?>"
4+
class="btn btn-primary oc-icon-plus">
5+
<?= e(trans('vdlp.basicauthentication::lang.credentials.list.create_button')); ?>
6+
</a>
7+
</div>

0 commit comments

Comments
 (0)