Skip to content

Commit

Permalink
Application credentials (#380)
Browse files Browse the repository at this point in the history
* add endpoints to create/get/remove application credentials
* add token creation using application credentials
* cancel running workflows on new commit

---------

Co-authored-by: smarcet <smarcet@gmail.com>
Co-authored-by: k0ka <k0ka@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 7, 2024
1 parent 7651038 commit aeb5012
Show file tree
Hide file tree
Showing 23 changed files with 568 additions and 26 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
branches:
- master

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
tests:
if: |
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
branches:
- master

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
tests:
runs-on: ubuntu-22.04
Expand Down
17 changes: 17 additions & 0 deletions doc/services/identity/v3/application-credentials.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Application Credentials
=======================

Add application credential
--------------------------

.. sample:: Identity/v3/application_credentials/add_application_credentials.php

Show application credential details
-----------------------------------

.. sample:: Identity/v3/application_credentials/show_application_credentials.php

Delete application credential
-----------------------------

.. sample:: Identity/v3/application_credentials/delete_application_credentials.php
1 change: 1 addition & 0 deletions doc/services/identity/v3/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Identity v3
.. toctree::
:maxdepth: 3

application-credentials
credentials
domains
endpoints
Expand Down
6 changes: 6 additions & 0 deletions doc/services/identity/v3/tokens.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ Generate token with username

.. sample:: Identity/v3/tokens/generate_token_with_username.php

Generate token with application credential ID
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. sample:: Identity/v3/tokens/generate_token_with_application_credential_id.php


Generate token from ID
~~~~~~~~~~~~~~~~~~~~~~

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

require 'vendor/autoload.php';

$openstack = new OpenStack\OpenStack([
'authUrl' => '{authUrl}',
'region' => '{region}',
'user' => [
'id' => '{userId}',
'password' => '{password}'
],
'scope' => [
'project' => [
'id' => '{projectId}'
]
]
]);

$identity = $openstack->identityV3(['region' => '{region}']);

$user = $identity->getUser('{userId}');
$applicationCredential = $user->createApplicationCredential([
'name' => '{name}',
'description' => '{description}',
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

require 'vendor/autoload.php';

$openstack = new OpenStack\OpenStack([
'authUrl' => '{authUrl}',
'region' => '{region}',
'user' => [
'id' => '{userId}',
'password' => '{password}'
],
'scope' => [
'project' => [
'id' => '{projectId}'
]
]
]);

$identity = $openstack->identityV3(['region' => '{region}']);

$user = $identity->getUser('{userId}');
$applicationCredential = $user->getApplicationCredential('{applicationCredentialId}');
$applicationCredential->delete();

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

require 'vendor/autoload.php';

$openstack = new OpenStack\OpenStack([
'authUrl' => '{authUrl}',
'region' => '{region}',
'user' => [
'id' => '{userId}',
'password' => '{password}'
],
'scope' => [
'project' => [
'id' => '{projectId}'
]
]
]);

$identity = $openstack->identityV3(['region' => '{region}']);

$user = $identity->getUser('{userId}');
$applicationCredential = $user->getApplicationCredential('{applicationCredentialId}');
$applicationCredential->retrieve();

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

require 'vendor/autoload.php';

$openstack = new OpenStack\OpenStack([
'authUrl' => '{authUrl}',
'region' => '{region}',
'user' => [
'id' => '{userId}',
'password' => '{password}'
],
'scope' => [
'project' => ['id' => '{projectId}']
]
]);

$identity = $openstack->identityV3();

$token = $identity->generateToken([
'application_credential' => [
'id' => '{applicationCredentialId}',
'secret' => '{secret}'
]
]);
3 changes: 1 addition & 2 deletions samples/Identity/v3/tokens/generate_token_with_username.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@
$identity = $openstack->identityV3();

// Since usernames will not be unique across an entire OpenStack installation,
// when authenticating with them you must also provide your domain ID. You do
// when authenticating with them, you must also provide your domain ID. You do
// not have to do this if you authenticate with a user ID.

$token = $identity->generateToken([
'user' => [
'name' => '{username}',
Expand Down
48 changes: 44 additions & 4 deletions src/Identity/v3/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ public function postTokens(): array
'method' => 'POST',
'path' => 'auth/tokens',
'params' => [
'methods' => $this->params->methods(),
'user' => $this->params->user(),
'tokenId' => $this->params->tokenBody(),
'scope' => $this->params->scope(),
'methods' => $this->params->methods(),
'user' => $this->params->user(),
'application_credential' => $this->params->applicationCredential(),
'tokenId' => $this->params->tokenBody(),
'scope' => $this->params->scope(),
],
];
}
Expand Down Expand Up @@ -837,4 +838,43 @@ public function deletePolicy(): array
'params' => ['id' => $this->params->idUrl('policy')],
];
}

public function getApplicationCredential(): array
{
return [
'method' => 'GET',
'path' => 'users/{userId}/application_credentials/{id}',
'jsonKey' => 'application_credential',
'params' => [
'id' => $this->params->idUrl('application_credential'),
'userId' => $this->params->idUrl('user'),
],
];
}

public function postApplicationCredential(): array
{
return [
'method' => 'POST',
'path' => 'users/{userId}/application_credentials',
'jsonKey' => 'application_credential',
'params' => [
'userId' => $this->params->idUrl('user'),
'name' => $this->params->name('application_credential'),
'description' => $this->params->desc('application_credential'),
],
];
}

public function deleteApplicationCredential(): array
{
return [
'method' => 'DELETE',
'path' => 'users/{userId}/application_credentials/{id}',
'params' => [
'id' => $this->params->idUrl('application_credential'),
'userId' => $this->params->idUrl('user'),
],
];
}
}
69 changes: 69 additions & 0 deletions src/Identity/v3/Models/ApplicationCredential.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace OpenStack\Identity\v3\Models;

use OpenStack\Common\Resource\Creatable;
use OpenStack\Common\Resource\Deletable;
use OpenStack\Common\Resource\Listable;
use OpenStack\Common\Resource\OperatorResource;
use OpenStack\Common\Resource\Retrievable;

/**
* @property \OpenStack\Identity\v3\Api $api
*/
class ApplicationCredential extends OperatorResource implements Creatable, Listable, Retrievable, Deletable
{
/** @var string */
public $id;

/** @var string */
public $userId;

/** @var string */
public $name;

/** @var string */
public $description;

/** @var string|null */
public $secret = null;

protected $aliases = [
'user_id' => 'userId',
];

protected $resourceKey = 'application_credential';
protected $resourcesKey = 'application_credentials';

/**
* {@inheritdoc}
*
* @param array $userOptions {@see \OpenStack\Identity\v3\Api::postApplicationCredential}
*/
public function create(array $userOptions): Creatable
{
$response = $this->execute($this->api->postApplicationCredential(), $userOptions);

return $this->populateFromResponse($response);
}

/**
* {@inheritdoc}
*/
public function retrieve()
{
$response = $this->execute(
$this->api->getApplicationCredential(),
['id' => $this->id, 'userId' => $this->userId]
);
$this->populateFromResponse($response);
}

/**
* {@inheritdoc}
*/
public function delete()
{
$this->executeWithState($this->api->deleteApplicationCredential());
}
}
4 changes: 2 additions & 2 deletions src/Identity/v3/Models/Credential.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ class Credential extends OperatorResource implements Creatable, Updateable, Retr
'user_id' => 'userId',
];

public function create(array $data): Creatable
public function create(array $userOptions): Creatable
{
$response = $this->execute($this->api->postCredentials(), $data);
$response = $this->execute($this->api->postCredentials(), $userOptions);

return $this->populateFromResponse($response);
}
Expand Down
10 changes: 8 additions & 2 deletions src/Identity/v3/Models/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace OpenStack\Identity\v3\Models;

use InvalidArgumentException;
use OpenStack\Common\Resource\Alias;
use OpenStack\Common\Resource\Creatable;
use OpenStack\Common\Resource\OperatorResource;
Expand Down Expand Up @@ -94,12 +95,17 @@ public function create(array $data): Creatable
if (isset($data['user'])) {
$data['methods'] = ['password'];
if (!isset($data['user']['id']) && empty($data['user']['domain'])) {
throw new \InvalidArgumentException('When authenticating with a username, you must also provide either the domain name or domain ID to which the user belongs to. Alternatively, if you provide a user ID instead, you do not need to provide domain information.');
throw new InvalidArgumentException('When authenticating with a username, you must also provide either the domain name '.'or domain ID to which the user belongs to. Alternatively, if you provide a user ID instead, '.'you do not need to provide domain information.');
}
} elseif (isset($data['application_credential'])) {
$data['methods'] = ['application_credential'];
if (!isset($data['application_credential']['id']) || !isset($data['application_credential']['secret'])) {
throw new InvalidArgumentException('When authenticating with a application_credential, you must provide application credential ID '.' and application credential secret.');
}
} elseif (isset($data['tokenId'])) {
$data['methods'] = ['token'];
} else {
throw new \InvalidArgumentException('Either a user or token must be provided.');
throw new InvalidArgumentException('Either a user, tokenId or application_credential must be provided.');
}

$response = $this->execute($this->api->postTokens(), $data);
Expand Down
24 changes: 21 additions & 3 deletions src/Identity/v3/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ public function delete()
*/
public function listGroups(): \Generator
{
$options['id'] = $this->id;

return $this->model(Group::class)->enumerate($this->api->getUserGroups(), $options);
return $this->model(Group::class)->enumerate($this->api->getUserGroups(), ['id' => $this->id]);
}

/**
Expand All @@ -92,4 +90,24 @@ public function listProjects(): \Generator
{
return $this->model(Project::class)->enumerate($this->api->getUserProjects(), ['id' => $this->id]);
}

/**
* Creates a new application credential according to the provided options.
*
* @param array $options {@see \OpenStack\Identity\v3\Api::postApplicationCredential}
*/
public function createApplicationCredential(array $options): ApplicationCredential
{
return $this->model(ApplicationCredential::class)->create(['userId' => $this->id] + $options);
}

/**
* Retrieves an application credential object and populates its unique identifier object. This operation will not
* perform a GET or HEAD request by default; you will need to call retrieve() if you want to pull in remote state
* from the API.
*/
public function getApplicationCredential(string $id): ApplicationCredential
{
return $this->model(ApplicationCredential::class, ['id' => $id, 'userId' => $this->id]);
}
}
Loading

0 comments on commit aeb5012

Please sign in to comment.