mirror of
https://gitlab.linphone.org/BC/public/flexisip-account-manager.git
synced 2026-01-17 10:08:05 +00:00
Add a permanent provisioning URL, authenticated
Complete the documentation Add a few tests for the provisioning urls Update the dependencies Bump the package version
This commit is contained in:
parent
877cae94f7
commit
b48c8f505d
7 changed files with 172 additions and 54 deletions
|
|
@ -51,7 +51,15 @@ class ProvisioningController extends Controller
|
|||
return response($result->getString())->header('Content-Type', $result->getMimeType());
|
||||
}
|
||||
|
||||
public function show(Request $request, $confirmationKey = null)
|
||||
/**
|
||||
* Authenticated provisioning
|
||||
*/
|
||||
public function me(Request $request)
|
||||
{
|
||||
return $this->show($request, null, $request->user());
|
||||
}
|
||||
|
||||
public function show(Request $request, $confirmationKey = null, Account $requestAccount = null)
|
||||
{
|
||||
// Load the hooks if they exists
|
||||
$provisioningHooks = config_path('provisioning_hooks.php');
|
||||
|
|
@ -99,67 +107,71 @@ class ProvisioningController extends Controller
|
|||
$account = null;
|
||||
|
||||
// Account handling
|
||||
if ($confirmationKey) {
|
||||
if ($requestAccount) {
|
||||
$account = $requestAccount;
|
||||
} else if ($confirmationKey) {
|
||||
$account = Account::withoutGlobalScopes()
|
||||
->where('confirmation_key', $confirmationKey)
|
||||
->first();
|
||||
}
|
||||
|
||||
if ($account && !$account->activationExpired()) {
|
||||
if ($account && !$account->activationExpired()) {
|
||||
$section = $dom->createElement('section');
|
||||
$section->setAttribute('name', 'proxy_' . $proxyConfigIndex);
|
||||
|
||||
$entry = $dom->createElement('entry', $account->identifier);
|
||||
$entry->setAttribute('name', 'reg_identity');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', 1);
|
||||
$entry->setAttribute('name', 'reg_sendregister');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', 'push_notification');
|
||||
$entry->setAttribute('name', 'refkey');
|
||||
$section->appendChild($entry);
|
||||
|
||||
// Complete the section with the Proxy hook
|
||||
if (function_exists('provisioningProxyHook')) {
|
||||
provisioningProxyHook($section, $request, $account);
|
||||
}
|
||||
|
||||
$config->appendChild($section);
|
||||
|
||||
$passwords = $account->passwords()->get();
|
||||
|
||||
foreach ($passwords as $password) { // => foreach ($passwords)
|
||||
$section = $dom->createElement('section');
|
||||
$section->setAttribute('name', 'proxy_' . $proxyConfigIndex);
|
||||
$section->setAttribute('name', 'auth_info_' . $authInfoIndex);
|
||||
|
||||
$entry = $dom->createElement('entry', $account->identifier);
|
||||
$entry->setAttribute('name', 'reg_identity');
|
||||
$entry->setAttribute('name', 'username');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', 1);
|
||||
$entry->setAttribute('name', 'reg_sendregister');
|
||||
$entry = $dom->createElement('entry', $password->password);
|
||||
$entry->setAttribute('name', 'ha1');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', 'push_notification');
|
||||
$entry->setAttribute('name', 'refkey');
|
||||
$entry = $dom->createElement('entry', $account->resolvedRealm);
|
||||
$entry->setAttribute('name', 'realm');
|
||||
$section->appendChild($entry);
|
||||
|
||||
// Complete the section with the Proxy hook
|
||||
if (function_exists('provisioningProxyHook')) {
|
||||
provisioningProxyHook($section, $request, $account);
|
||||
$entry = $dom->createElement('entry', $password->algorithm);
|
||||
$entry->setAttribute('name', 'algorithm');
|
||||
$section->appendChild($entry);
|
||||
|
||||
// Complete the section with the Auth hook
|
||||
if (function_exists('provisioningAuthHook')) {
|
||||
provisioningAuthHook($section, $request, $password);
|
||||
}
|
||||
|
||||
$config->appendChild($section);
|
||||
|
||||
$passwords = $account->passwords()->get();
|
||||
$authInfoIndex++;
|
||||
|
||||
foreach ($passwords as $password) { // => foreach ($passwords)
|
||||
$section = $dom->createElement('section');
|
||||
$section->setAttribute('name', 'auth_info_' . $authInfoIndex);
|
||||
|
||||
$entry = $dom->createElement('entry', $account->identifier);
|
||||
$entry->setAttribute('name', 'username');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $password->password);
|
||||
$entry->setAttribute('name', 'ha1');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $account->resolvedRealm);
|
||||
$entry->setAttribute('name', 'realm');
|
||||
$section->appendChild($entry);
|
||||
|
||||
$entry = $dom->createElement('entry', $password->algorithm);
|
||||
$entry->setAttribute('name', 'algorithm');
|
||||
$section->appendChild($entry);
|
||||
|
||||
// Complete the section with the Auth hook
|
||||
if (function_exists('provisioningAuthHook')) {
|
||||
provisioningAuthHook($section, $request, $password);
|
||||
}
|
||||
|
||||
$config->appendChild($section);
|
||||
|
||||
$authInfoIndex++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ($confirmationKey) {
|
||||
$account->confirmation_key = null;
|
||||
$account->save();
|
||||
}
|
||||
|
|
|
|||
15
flexiapi/composer.lock
generated
15
flexiapi/composer.lock
generated
|
|
@ -979,16 +979,16 @@
|
|||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v8.52.0",
|
||||
"version": "v8.53.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "8fe9877d52e25f8aed36c51734e5a8510be967e6"
|
||||
"reference": "4b2e3e7317da82dd9f5b88d477abd93444748b43"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/8fe9877d52e25f8aed36c51734e5a8510be967e6",
|
||||
"reference": "8fe9877d52e25f8aed36c51734e5a8510be967e6",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/4b2e3e7317da82dd9f5b88d477abd93444748b43",
|
||||
"reference": "4b2e3e7317da82dd9f5b88d477abd93444748b43",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -1061,7 +1061,7 @@
|
|||
"illuminate/view": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"aws/aws-sdk-php": "^3.155",
|
||||
"aws/aws-sdk-php": "^3.186.4",
|
||||
"doctrine/dbal": "^2.6|^3.0",
|
||||
"filp/whoops": "^2.8",
|
||||
"guzzlehttp/guzzle": "^6.5.5|^7.0.1",
|
||||
|
|
@ -1074,7 +1074,7 @@
|
|||
"symfony/cache": "^5.1.4"
|
||||
},
|
||||
"suggest": {
|
||||
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.155).",
|
||||
"aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage and SES mail driver (^3.186.4).",
|
||||
"brianium/paratest": "Required to run tests in parallel (^6.0).",
|
||||
"doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6|^3.0).",
|
||||
"ext-ftp": "Required to use the Flysystem FTP driver.",
|
||||
|
|
@ -1143,7 +1143,7 @@
|
|||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2021-07-27T13:03:29+00:00"
|
||||
"time": "2021-08-03T14:36:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/tinker",
|
||||
|
|
@ -7493,7 +7493,6 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2020-09-28T06:45:17+00:00"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
namespace Database\Factories;
|
||||
|
||||
use App\Account;
|
||||
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class AccountFactory extends Factory
|
||||
|
|
@ -33,6 +35,7 @@ class AccountFactory extends Factory
|
|||
'domain' => config('app.sip_domain'),
|
||||
'email' => $this->faker->email,
|
||||
'user_agent' => $this->faker->userAgent,
|
||||
'confirmation_key' => Str::random(WebAuthenticateController::$emailCodeSize),
|
||||
'ip_address' => $this->faker->ipv4,
|
||||
'creation_time' => $this->faker->dateTime,
|
||||
'activated' => true
|
||||
|
|
|
|||
|
|
@ -192,9 +192,17 @@ When an account is having an available `confirmation_key` it can be provisioned
|
|||
|
||||
Those two URL are <b>not API endpoints</b>, they are not located under `/api`.
|
||||
|
||||
### `VISIT /provisioning/{confirmation_key}`
|
||||
### `VISIT /provisioning/`
|
||||
Return the provisioning information available in the liblinphone configuration file (if correctly configured).
|
||||
If the `confirmation_key` is valid the related account information are added to the returned XML. The account is then considered as "provisioned" and those account related information will be removed in the upcoming requests.
|
||||
|
||||
### `VISIT /provisioning/{confirmation_key}`
|
||||
Return the provisioning information available in the liblinphone configuration file.
|
||||
If the `confirmation_key` is valid the related account information are added to the returned XML. The account is then considered as "provisioned" and those account related information will be removed in the upcoming requests (the content will be the same as the previous url).
|
||||
|
||||
### `VISIT /provisioning/qrcode/{confirmation_key}`
|
||||
Return a QRCode that points to the provisioning URL.
|
||||
|
||||
## Authenticated provisioning
|
||||
|
||||
### `VISIT /provisioning/me`
|
||||
Return the same base content as the previous URL and the account related information, similar to the `confirmation_key` endpoint. However this endpoint will always return those information.
|
||||
|
|
@ -32,6 +32,10 @@ Route::get('login/phone', 'Account\AuthenticateController@loginPhone')->name('ac
|
|||
Route::post('authenticate/phone', 'Account\AuthenticateController@authenticatePhone')->name('account.authenticate.phone');
|
||||
Route::post('authenticate/phone/confirm', 'Account\AuthenticateController@validatePhone')->name('account.authenticate.phone_confirm');
|
||||
|
||||
Route::group(['middleware' => 'auth.digest_or_key'], function () {
|
||||
Route::get('provisioning/me', 'Account\ProvisioningController@me')->name('provisioning.me');
|
||||
});
|
||||
|
||||
Route::get('provisioning/qrcode/{confirmation}', 'Account\ProvisioningController@qrcode')->name('provisioning.qrcode');
|
||||
Route::get('provisioning/{confirmation?}', 'Account\ProvisioningController@show')->name('provisioning.show');
|
||||
|
||||
|
|
|
|||
92
flexiapi/tests/Feature/AccountProvisioningTest.php
Normal file
92
flexiapi/tests/Feature/AccountProvisioningTest.php
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
/*
|
||||
Flexisip Account Manager is a set of tools to manage SIP accounts.
|
||||
Copyright (C) 2021 Belledonne Communications SARL, All rights reserved.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
use App\Password;
|
||||
|
||||
class AccountProvisioningTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected $route = '/provisioning';
|
||||
protected $accountRoute = '/provisioning/me';
|
||||
protected $method = 'GET';
|
||||
|
||||
protected $pnProvider = 'provider';
|
||||
protected $pnParam = 'param';
|
||||
protected $pnPrid = 'id';
|
||||
|
||||
public function testBaseProvisioning()
|
||||
{
|
||||
$response = $this->get($this->route);
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/xml');
|
||||
$response->assertDontSee('ha1');
|
||||
}
|
||||
|
||||
public function testAuthenticatedProvisioning()
|
||||
{
|
||||
$response = $this->get($this->accountRoute);
|
||||
$response->assertStatus(302);
|
||||
|
||||
$password = Password::factory()->create();
|
||||
$password->account->generateApiKey();
|
||||
|
||||
// Ensure that we get the authentication password once
|
||||
$response = $this->keyAuthenticated($password->account)
|
||||
->get($this->accountRoute)
|
||||
->assertStatus(200)
|
||||
->assertHeader('Content-Type', 'application/xml')
|
||||
->assertSee('ha1');
|
||||
|
||||
// And then twice
|
||||
$response = $this->keyAuthenticated($password->account)
|
||||
->get($this->accountRoute)
|
||||
->assertStatus(200)
|
||||
->assertHeader('Content-Type', 'application/xml')
|
||||
->assertSee('ha1');
|
||||
}
|
||||
|
||||
public function testConfirmationKeyProvisioning()
|
||||
{
|
||||
$response = $this->get($this->route.'/1234');
|
||||
$response->assertStatus(200);
|
||||
$response->assertHeader('Content-Type', 'application/xml');
|
||||
$response->assertDontSee('ha1');
|
||||
|
||||
$password = Password::factory()->create();
|
||||
$password->account->generateApiKey();
|
||||
|
||||
// Ensure that we get the authentication password once
|
||||
$response = $this->get($this->route.'/'.$password->account->confirmation_key)
|
||||
->assertStatus(200)
|
||||
->assertHeader('Content-Type', 'application/xml')
|
||||
->assertSee('ha1');
|
||||
|
||||
// And then twice
|
||||
$response = $this->get($this->route.'/'.$password->account->confirmation_key)
|
||||
->assertStatus(200)
|
||||
->assertHeader('Content-Type', 'application/xml')
|
||||
->assertDontSee('ha1');
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
#%define _datadir %{_datarootdir}
|
||||
#%define _docdir %{_datadir}/doc
|
||||
|
||||
%define build_number 94
|
||||
%define build_number 95
|
||||
%define var_dir /var/opt/belledonne-communications
|
||||
%define opt_dir /opt/belledonne-communications/share/flexisip-account-manager
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue