diff --git a/flexiapi/README.md b/flexiapi/README.md index cc194a7..6680881 100644 --- a/flexiapi/README.md +++ b/flexiapi/README.md @@ -105,3 +105,29 @@ To expire and/or clear old nonces a specific command should be called periodical ## Usage The `/api` page contains all the required documentation to authenticate and request the API. + +## Console commands + +FlexiAPI is shipped with several console commands that you can launch using the `artisan` executable available at the root of this project. + +### Clear Expired Nonces for DIGEST authentication + +This will remove the nonces stored that were not updated after `x minutes`. + + php artisan digest:expired-nonces-clear {minutes} + +### Remove the unconfirmed accounts + +This request will remove the accounts that were not confirmed after `x days`. In the database an unconfirmed account is having the `activated` attribute set to `false`. + + php artisan accounts:clear-unconfirmed {days} {--apply} + +The base request will not delete the related accounts by default. You need to add `--apply` to remove them. + +### Set an account admin + +This command will set the admin role to any available FlexiSIP account (the external FlexiSIP database need to be configured beforehand). You need to use the account DB id as a parameter in this command. + + php artisan accounts:set-admin {account_id} + +Once one account is declared as administrator, you can directly configure the other ones using the web panel. \ No newline at end of file diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php index 29c071c..bf19dd9 100644 --- a/flexiapi/app/Account.php +++ b/flexiapi/app/Account.php @@ -23,6 +23,9 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Support\Str; + +use App\ApiKey; class Account extends Authenticatable { @@ -60,6 +63,11 @@ class Account extends Authenticatable return $this->hasOne('App\Admin'); } + public function apiKey() + { + return $this->hasOne('App\ApiKey'); + } + public function emailChanged() { return $this->hasOne('App\EmailChanged'); @@ -70,6 +78,16 @@ class Account extends Authenticatable return $this->attributes['username'].'@'.$this->attributes['domain']; } + public function generateApiKey() + { + $this->apiKey()->delete(); + + $apiKey = new ApiKey; + $apiKey->account_id = $this->id; + $apiKey->key = Str::random(40); + $apiKey->save(); + } + public function isAdmin() { return ($this->admin); diff --git a/flexiapi/app/ApiKey.php b/flexiapi/app/ApiKey.php new file mode 100644 index 0000000..41a9633 --- /dev/null +++ b/flexiapi/app/ApiKey.php @@ -0,0 +1,36 @@ +. +*/ + +namespace App; + +use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Model; + +class ApiKey extends Model +{ + use HasFactory; + + protected $connection = 'local'; + protected $table = 'api_keys'; + + public function account() + { + return $this->belongsTo('App\Account'); + } +} diff --git a/flexiapi/app/Http/Controllers/Admin/AccountController.php b/flexiapi/app/Http/Controllers/Admin/AccountController.php index 583e34b..ee8fac3 100644 --- a/flexiapi/app/Http/Controllers/Admin/AccountController.php +++ b/flexiapi/app/Http/Controllers/Admin/AccountController.php @@ -93,4 +93,12 @@ class AccountController extends Controller return redirect()->back(); } + + public function generateApiKey(Request $request) + { + $account = $request->user(); + $account->generateApiKey(); + + return redirect()->back(); + } } diff --git a/flexiapi/app/Http/Controllers/Api/AccountController.php b/flexiapi/app/Http/Controllers/Api/AccountController.php index e091a5b..cfff1c4 100644 --- a/flexiapi/app/Http/Controllers/Api/AccountController.php +++ b/flexiapi/app/Http/Controllers/Api/AccountController.php @@ -36,6 +36,7 @@ class AccountController extends Controller 'algorithm' => 'required|in:SHA-256,MD5', 'password' => 'required|filled', 'domain' => 'min:3', + 'activated' => 'boolean|nullable', ]); $algorithm = $request->has('password_sha256') ? 'SHA-256' : 'MD5'; @@ -43,7 +44,9 @@ class AccountController extends Controller $account = new Account; $account->username = $request->get('username'); $account->email = $request->get('email'); - $account->activated = true; + $account->activated = $request->has('activated') + ? (bool)$request->get('activated') + : false; $account->domain = $request->has('domain') ? $request->get('domain') : config('app.sip_domain'); diff --git a/flexiapi/app/Http/Kernel.php b/flexiapi/app/Http/Kernel.php index 704b630..3b59d55 100644 --- a/flexiapi/app/Http/Kernel.php +++ b/flexiapi/app/Http/Kernel.php @@ -71,7 +71,7 @@ class Kernel extends HttpKernel 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.admin' => \App\Http\Middleware\AuthenticateAdmin::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, - 'auth.digest' => \App\Http\Middleware\AuthenticateDigest::class, + 'auth.digest_or_key' => \App\Http\Middleware\AuthenticateDigestOrKey::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, diff --git a/flexiapi/app/Http/Middleware/AuthenticateDigest.php b/flexiapi/app/Http/Middleware/AuthenticateDigestOrKey.php similarity index 93% rename from flexiapi/app/Http/Middleware/AuthenticateDigest.php rename to flexiapi/app/Http/Middleware/AuthenticateDigestOrKey.php index 9cca585..6ac2275 100644 --- a/flexiapi/app/Http/Middleware/AuthenticateDigest.php +++ b/flexiapi/app/Http/Middleware/AuthenticateDigestOrKey.php @@ -29,7 +29,7 @@ use Illuminate\Http\Response; use Closure; use Validator; -class AuthenticateDigest +class AuthenticateDigestOrKey { const ALGORITHMS = [ 'MD5' => 'md5', @@ -56,6 +56,21 @@ class AuthenticateDigest ->where('domain', $domain) ->firstOrFail(); + // Key authentication + if ($request->header('x-api-key')) { + if ($account->apiKey + && $account->apiKey->key == $request->header('x-api-key')) { + Auth::login($account); + $response = $next($request); + + return $response; + } + + return $this->generateUnauthorizedResponse($account); + } + + // DIGEST authentication + if ($request->header('Authorization')) { $auth = $this->extractAuthorizationHeader($request->header('Authorization')); $storedNonce = $account->nonces()->where('nonce', $auth['nonce'])->first(); diff --git a/flexiapi/composer.lock b/flexiapi/composer.lock index 538e8ff..a31fca4 100644 --- a/flexiapi/composer.lock +++ b/flexiapi/composer.lock @@ -320,27 +320,27 @@ }, { "name": "dragonmantank/cron-expression", - "version": "3.0.1", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "fa4e95ff5a7f1d62c3fbc05c32729b7f3ca14b52" + "reference": "48212cdc0a79051d50d7fc2f0645c5a321caf926" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/fa4e95ff5a7f1d62c3fbc05c32729b7f3ca14b52", - "reference": "fa4e95ff5a7f1d62c3fbc05c32729b7f3ca14b52", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/48212cdc0a79051d50d7fc2f0645c5a321caf926", + "reference": "48212cdc0a79051d50d7fc2f0645c5a321caf926", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.1|^8.0" }, "replace": { "mtdowling/cron-expression": "^1.0" }, "require-dev": { - "phpstan/phpstan": "^0.11", - "phpunit/phpunit": "^6.4|^7.0" + "phpstan/phpstan": "^0.11|^0.12", + "phpunit/phpunit": "^7.0|^8.0|^9.0" }, "type": "library", "autoload": { @@ -370,7 +370,7 @@ "type": "github" } ], - "time": "2020-08-21T02:30:13+00:00" + "time": "2020-10-13T01:26:01+00:00" }, { "name": "egulias/email-validator", @@ -900,16 +900,16 @@ }, { "name": "laravel/framework", - "version": "v8.9.0", + "version": "v8.10.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "8a6bf870bcfa1597e514a9c7ee6df44db98abb54" + "reference": "0c80950806cd1bc6d9a7068585a12c2bfa23bdf3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/8a6bf870bcfa1597e514a9c7ee6df44db98abb54", - "reference": "8a6bf870bcfa1597e514a9c7ee6df44db98abb54", + "url": "https://api.github.com/repos/laravel/framework/zipball/0c80950806cd1bc6d9a7068585a12c2bfa23bdf3", + "reference": "0c80950806cd1bc6d9a7068585a12c2bfa23bdf3", "shasum": "" }, "require": { @@ -1059,7 +1059,7 @@ "framework", "laravel" ], - "time": "2020-10-06T14:22:36+00:00" + "time": "2020-10-13T14:20:53+00:00" }, { "name": "laravel/tinker", @@ -1195,16 +1195,16 @@ }, { "name": "league/commonmark", - "version": "1.5.5", + "version": "1.5.6", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "45832dfed6007b984c0d40addfac48d403dc6432" + "reference": "a56e91e0fa1f6d0049153a9c34f63488f6b7ce61" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/45832dfed6007b984c0d40addfac48d403dc6432", - "reference": "45832dfed6007b984c0d40addfac48d403dc6432", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/a56e91e0fa1f6d0049153a9c34f63488f6b7ce61", + "reference": "a56e91e0fa1f6d0049153a9c34f63488f6b7ce61", "shasum": "" }, "require": { @@ -1286,7 +1286,7 @@ "type": "tidelift" } ], - "time": "2020-09-13T14:44:46+00:00" + "time": "2020-10-17T21:33:03+00:00" }, { "name": "league/flysystem", @@ -1435,16 +1435,16 @@ }, { "name": "league/mime-type-detection", - "version": "1.5.0", + "version": "1.5.1", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "ea2fbfc988bade315acd5967e6d02274086d0f28" + "reference": "353f66d7555d8a90781f6f5e7091932f9a4250aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ea2fbfc988bade315acd5967e6d02274086d0f28", - "reference": "ea2fbfc988bade315acd5967e6d02274086d0f28", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/353f66d7555d8a90781f6f5e7091932f9a4250aa", + "reference": "353f66d7555d8a90781f6f5e7091932f9a4250aa", "shasum": "" }, "require": { @@ -1482,7 +1482,7 @@ "type": "tidelift" } ], - "time": "2020-09-21T18:10:53+00:00" + "time": "2020-10-18T11:50:25+00:00" }, { "name": "monolog/monolog", @@ -1577,16 +1577,16 @@ }, { "name": "nesbot/carbon", - "version": "2.41.2", + "version": "2.41.3", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "35959c93ada06469107a05df6b15b65074a960cf" + "reference": "e148788eeae9b9b7b87996520358b86faad37b52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/35959c93ada06469107a05df6b15b65074a960cf", - "reference": "35959c93ada06469107a05df6b15b65074a960cf", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e148788eeae9b9b7b87996520358b86faad37b52", + "reference": "e148788eeae9b9b7b87996520358b86faad37b52", "shasum": "" }, "require": { @@ -1662,7 +1662,7 @@ "type": "tidelift" } ], - "time": "2020-10-10T23:35:06+00:00" + "time": "2020-10-12T20:36:09+00:00" }, { "name": "nikic/php-parser", @@ -1814,20 +1814,20 @@ }, { "name": "paragonie/random_compat", - "version": "v9.99.99", + "version": "v9.99.100", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", "shasum": "" }, "require": { - "php": "^7" + "php": ">= 7" }, "require-dev": { "phpunit/phpunit": "4.*|5.*", @@ -1855,7 +1855,7 @@ "pseudorandom", "random" ], - "time": "2018-07-02T15:55:56+00:00" + "time": "2020-10-15T08:29:30+00:00" }, { "name": "parsedown/laravel", @@ -3133,16 +3133,16 @@ }, { "name": "symfony/http-client-contracts", - "version": "v2.2.0", + "version": "v2.3.1", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "3a5d0fe7908daaa23e3dbf4cee3ba4bfbb19fdd3" + "reference": "41db680a15018f9c1d4b23516059633ce280ca33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/3a5d0fe7908daaa23e3dbf4cee3ba4bfbb19fdd3", - "reference": "3a5d0fe7908daaa23e3dbf4cee3ba4bfbb19fdd3", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/41db680a15018f9c1d4b23516059633ce280ca33", + "reference": "41db680a15018f9c1d4b23516059633ce280ca33", "shasum": "" }, "require": { @@ -3153,8 +3153,9 @@ }, "type": "library", "extra": { + "branch-version": "2.3", "branch-alias": { - "dev-master": "2.2-dev" + "dev-main": "2.3-dev" }, "thanks": { "name": "symfony/contracts", @@ -3204,7 +3205,7 @@ "type": "tidelift" } ], - "time": "2020-09-07T11:33:47+00:00" + "time": "2020-10-14T17:08:19+00:00" }, { "name": "symfony/http-foundation", @@ -5156,16 +5157,16 @@ }, { "name": "facade/ignition", - "version": "2.3.8", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "e8fed9c382cd1d02b5606688576a35619afdf82c" + "reference": "9fc6c3d3de5271a1b94cff19dce2c9295abf0ffa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/e8fed9c382cd1d02b5606688576a35619afdf82c", - "reference": "e8fed9c382cd1d02b5606688576a35619afdf82c", + "url": "https://api.github.com/repos/facade/ignition/zipball/9fc6c3d3de5271a1b94cff19dce2c9295abf0ffa", + "reference": "9fc6c3d3de5271a1b94cff19dce2c9295abf0ffa", "shasum": "" }, "require": { @@ -5224,29 +5225,29 @@ "laravel", "page" ], - "time": "2020-10-01T23:01:14+00:00" + "time": "2020-10-14T08:59:59+00:00" }, { "name": "facade/ignition-contracts", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/facade/ignition-contracts.git", - "reference": "aeab1ce8b68b188a43e81758e750151ad7da796b" + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/aeab1ce8b68b188a43e81758e750151ad7da796b", - "reference": "aeab1ce8b68b188a43e81758e750151ad7da796b", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.3|^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.14", - "phpunit/phpunit": "^7.5|^8.0", - "vimeo/psalm": "^3.12" + "friendsofphp/php-cs-fixer": "^v2.15.8", + "phpunit/phpunit": "^9.3.11", + "vimeo/psalm": "^3.17.1" }, "type": "library", "autoload": { @@ -5273,29 +5274,29 @@ "flare", "ignition" ], - "time": "2020-07-14T10:10:28+00:00" + "time": "2020-10-16T08:27:54+00:00" }, { "name": "filp/whoops", - "version": "2.7.3", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "5d5fe9bb3d656b514d455645b3addc5f7ba7714d" + "reference": "fa50d9db1c0c2fae99cf988d27023effda5524a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/5d5fe9bb3d656b514d455645b3addc5f7ba7714d", - "reference": "5d5fe9bb3d656b514d455645b3addc5f7ba7714d", + "url": "https://api.github.com/repos/filp/whoops/zipball/fa50d9db1c0c2fae99cf988d27023effda5524a3", + "reference": "fa50d9db1c0c2fae99cf988d27023effda5524a3", "shasum": "" }, "require": { - "php": "^5.5.9 || ^7.0", + "php": "^5.5.9 || ^7.0 || ^8.0", "psr/log": "^1.0.1" }, "require-dev": { "mockery/mockery": "^0.9 || ^1.0", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" }, "suggest": { @@ -5305,7 +5306,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.7-dev" } }, "autoload": { @@ -5334,7 +5335,7 @@ "throwable", "whoops" ], - "time": "2020-06-14T09:00:00+00:00" + "time": "2020-10-17T09:00:00+00:00" }, { "name": "fzaninotto/faker", @@ -6350,16 +6351,16 @@ }, { "name": "scrivo/highlight.php", - "version": "v9.18.1.2", + "version": "v9.18.1.3", "source": { "type": "git", "url": "https://github.com/scrivo/highlight.php.git", - "reference": "efb6e445494a9458aa59b0af5edfa4bdcc6809d9" + "reference": "6a1699707b099081f20a488ac1f92d682181018c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/efb6e445494a9458aa59b0af5edfa4bdcc6809d9", - "reference": "efb6e445494a9458aa59b0af5edfa4bdcc6809d9", + "url": "https://api.github.com/repos/scrivo/highlight.php/zipball/6a1699707b099081f20a488ac1f92d682181018c", + "reference": "6a1699707b099081f20a488ac1f92d682181018c", "shasum": "" }, "require": { @@ -6421,7 +6422,7 @@ "type": "github" } ], - "time": "2020-08-27T03:24:44+00:00" + "time": "2020-10-16T07:43:22+00:00" }, { "name": "sebastian/cli-parser", diff --git a/flexiapi/database/migrations/2020_10_19_085412_create_api_keys_table.php b/flexiapi/database/migrations/2020_10_19_085412_create_api_keys_table.php new file mode 100644 index 0000000..28f45a4 --- /dev/null +++ b/flexiapi/database/migrations/2020_10_19_085412_create_api_keys_table.php @@ -0,0 +1,40 @@ +. +*/ + +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class CreateApiKeysTable extends Migration +{ + public function up() + { + Schema::connection('local')->create('api_keys', function (Blueprint $table) { + $table->bigIncrements('id'); + $table->integer('account_id')->unsigned()->unique(); + $table->string('key')->unique(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('api_keys'); + } +} diff --git a/flexiapi/resources/views/account/panel.blade.php b/flexiapi/resources/views/account/panel.blade.php index b76ec11..aa0287a 100644 --- a/flexiapi/resources/views/account/panel.blade.php +++ b/flexiapi/resources/views/account/panel.blade.php @@ -47,7 +47,7 @@ @if($account->isAdmin())

Admin area

-
+
+ +
API Key
+ +

As an administrator you can generate an API key and use it to request the different API endpoints, check the related API documentation to know how to use that key.

+ + {!! Form::open(['route' => 'admin.api_key.generate']) !!} +
+
+ apiKey) + value="{{ $account->apiKey->key }}" + @endif + > +
+
+ +
+
+{!! Form::close() !!} @endif

Account information

diff --git a/flexiapi/resources/views/documentation.blade.php b/flexiapi/resources/views/documentation.blade.php index 8c3eefb..e2fcb81 100644 --- a/flexiapi/resources/views/documentation.blade.php +++ b/flexiapi/resources/views/documentation.blade.php @@ -14,7 +14,23 @@ > accept: application/json

Authentication

-

Restricted endpoints are protected using a DIGEST authentication mechanism.

+ +

Restricted endpoints are protected using a DIGEST authentication or an API Key mechanisms.

+ +

Using the API Key

+ +

To authenticate using an API Key, you need to authenticate to your account panel and being an administrator.

+

On your panel you will then find a form to generate your personnal key.

+ +

You can then use your freshly generated key by adding a new x-api-key header to your API requests:

+ +
+    > GET /api/{endpoint}
+    > from: sip:foobar@sip.example.org
+    > x-api-key: {your-api-key}
+    > …
+ +

Using DIGEST

To discover the available hashing algorythm you MUST send an unauthenticated request to one of the restricted endpoints.
For the moment only DIGEST-MD5 and DIGEST-SHA-256 are supported through the authentication layer.

@@ -43,6 +59,7 @@ For the moment only DIGEST-MD5 and DIGEST-SHA-256 are supported through the auth
  • password required minimum 6 characters
  • algorithm required, values can be SHA-256 or MD5
  • domain optional, the value is set to the default registration domain if not set
  • +
  • activated optional, a boolean, set to false by default
  • To create an account directly from the API.
    This endpoint is authenticated and requires an admin account.

    diff --git a/flexiapi/routes/api.php b/flexiapi/routes/api.php index cecc695..8e46595 100644 --- a/flexiapi/routes/api.php +++ b/flexiapi/routes/api.php @@ -25,7 +25,7 @@ Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user(); }); -Route::group(['middleware' => ['auth.digest']], function () { +Route::group(['middleware' => ['auth.digest_or_key']], function () { Route::get('ping', 'Api\PingController@ping'); Route::get('devices', 'Api\DeviceController@index'); Route::delete('devices/{uuid}', 'Api\DeviceController@destroy'); diff --git a/flexiapi/routes/web.php b/flexiapi/routes/web.php index 49cc637..79ff042 100644 --- a/flexiapi/routes/web.php +++ b/flexiapi/routes/web.php @@ -66,6 +66,8 @@ Route::group(['middleware' => 'auth.admin'], function () { Route::get('admin/accounts/{search?}', 'Admin\AccountController@index')->name('admin.account.index'); Route::post('admin/search', 'Admin\AccountController@search')->name('admin.account.search'); + Route::post('admin/api_key', 'Admin\AccountController@generateApiKey')->name('admin.api_key.generate'); + Route::get('admin/accounts/show/{id}', 'Admin\AccountController@show')->name('admin.account.show'); Route::get('admin/accounts/{id}/activate', 'Admin\AccountController@activate')->name('admin.account.activate'); Route::get('admin/accounts/{id}/deactivate', 'Admin\AccountController@deactivate')->name('admin.account.deactivate'); diff --git a/flexiapi/tests/Feature/AccountApiTest.php b/flexiapi/tests/Feature/AccountApiTest.php index ca07419..964252c 100644 --- a/flexiapi/tests/Feature/AccountApiTest.php +++ b/flexiapi/tests/Feature/AccountApiTest.php @@ -71,7 +71,8 @@ class AccountApiTest extends TestCase ->assertStatus(200) ->assertJson([ 'id' => 2, - 'username' => $username + 'username' => $username, + 'activated' => false, ]); } @@ -97,6 +98,7 @@ class AccountApiTest extends TestCase 'id' => 2, 'username' => $username, 'domain' => $domain, + 'activated' => false, ]); } @@ -121,6 +123,7 @@ class AccountApiTest extends TestCase 'id' => 2, 'username' => $username, 'domain' => config('app.sip_domain'), + 'activated' => false, ]); } @@ -129,8 +132,6 @@ class AccountApiTest extends TestCase $admin = Admin::factory()->create(); $password = $admin->account->passwords()->first(); - $username = 'username'; - $response0 = $this->generateFirstResponse($password); $response1 = $this->generateSecondResponse($password, $response0) ->json($this->method, $this->route, [ @@ -141,4 +142,30 @@ class AccountApiTest extends TestCase $response1->assertStatus(422); } + + public function testActivated() + { + $admin = Admin::factory()->create(); + $password = $admin->account->passwords()->first(); + + $username = 'username'; + + $response0 = $this->generateFirstResponse($password); + $response1 = $this->generateSecondResponse($password, $response0) + ->json($this->method, $this->route, [ + 'username' => $username, + 'algorithm' => 'SHA-256', + 'password' => '2', + 'activated' => true, + ]); + + $response1 + ->assertStatus(200) + ->assertJson([ + 'id' => 2, + 'username' => $username, + 'domain' => config('app.sip_domain'), + 'activated' => true, + ]);; + } } diff --git a/flexiapi/tests/Feature/AuthenticateDigestTest.php b/flexiapi/tests/Feature/AuthenticateDigestAndKeyTest.php similarity index 94% rename from flexiapi/tests/Feature/AuthenticateDigestTest.php rename to flexiapi/tests/Feature/AuthenticateDigestAndKeyTest.php index 1e9347f..82b9271 100644 --- a/flexiapi/tests/Feature/AuthenticateDigestTest.php +++ b/flexiapi/tests/Feature/AuthenticateDigestAndKeyTest.php @@ -25,7 +25,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\WithFaker; use Tests\TestCase; -class AuthenticateDigestTest extends TestCase +class AuthenticateDigestAndKeyTest extends TestCase { use RefreshDatabase; @@ -58,6 +58,18 @@ class AuthenticateDigestTest extends TestCase $response->assertStatus(401); } + public function testAuthenticateWithKey() + { + $password = Password::factory()->create(); + $password->account->generateApiKey(); + + $response = $this->withHeaders([ + 'From' => 'sip:'.$password->account->identifier, + 'x-api-key' => $password->account->apiKey->key, + ])->json($this->method, $this->route); + $response->assertStatus(200); + } + public function testMultiHash() { // Two password and we link the second to the first related account diff --git a/flexisip-account-manager.spec b/flexisip-account-manager.spec index 4b0c222..99a2f24 100644 --- a/flexisip-account-manager.spec +++ b/flexisip-account-manager.spec @@ -8,7 +8,7 @@ #%define _datadir %{_datarootdir} #%define _docdir %{_datadir}/doc -%define build_number 32 +%define build_number 34 %define var_dir /var/opt/belledonne-communications %define opt_dir /opt/belledonne-communications/share/flexisip-account-manager %define env_file "$RPM_BUILD_ROOT/etc/flexisip-account-manager/flexiapi.env"