Add Service Account Role Assignment
This commit is contained in:
parent
fead8eb47a
commit
d001f14249
|
@ -2732,7 +2732,7 @@ $projectCollections = array_merge([
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'default' => [],
|
'default' => [],
|
||||||
'array' => false,
|
'array' => false,
|
||||||
'filters' => ['json'],
|
'filters' => ['json', 'encrypt'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('resources'),
|
'$id' => ID::custom('resources'),
|
||||||
|
|
|
@ -84,56 +84,6 @@ App::post('/v1/migrations/appwrite')
|
||||||
->dynamic($migration, Response::MODEL_MIGRATION);
|
->dynamic($migration, Response::MODEL_MIGRATION);
|
||||||
});
|
});
|
||||||
|
|
||||||
App::post('/v1/migrations/firebase')
|
|
||||||
->groups(['api', 'migrations'])
|
|
||||||
->desc('Migrate Firebase Data (Service Account)')
|
|
||||||
->label('scope', 'migrations.write')
|
|
||||||
->label('event', 'migrations.create')
|
|
||||||
->label('audits.event', 'migration.create')
|
|
||||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
|
||||||
->label('sdk.namespace', 'migrations')
|
|
||||||
->label('sdk.method', 'createFirebaseMigration')
|
|
||||||
->label('sdk.description', '/docs/references/migrations/migration-firebase.md')
|
|
||||||
->label('sdk.response.code', Response::STATUS_CODE_ACCEPTED)
|
|
||||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
|
||||||
->label('sdk.response.model', Response::MODEL_MIGRATION)
|
|
||||||
->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate')
|
|
||||||
->param('serviceAccount', '', new Text(65536), 'JSON of the Firebase service account credentials')
|
|
||||||
->inject('response')
|
|
||||||
->inject('dbForProject')
|
|
||||||
->inject('project')
|
|
||||||
->inject('user')
|
|
||||||
->inject('events')
|
|
||||||
->action(function (array $resources, string $serviceAccount, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) {
|
|
||||||
$migration = $dbForProject->createDocument('migrations', new Document([
|
|
||||||
'$id' => ID::unique(),
|
|
||||||
'status' => 'pending',
|
|
||||||
'stage' => 'init',
|
|
||||||
'source' => Firebase::getName(),
|
|
||||||
'credentials' => [
|
|
||||||
'serviceAccount' => $serviceAccount,
|
|
||||||
],
|
|
||||||
'resources' => $resources,
|
|
||||||
'statusCounters' => '{}',
|
|
||||||
'resourceData' => '{}',
|
|
||||||
'errors' => [],
|
|
||||||
]));
|
|
||||||
|
|
||||||
$events->setParam('migrationId', $migration->getId());
|
|
||||||
|
|
||||||
// Trigger Transfer
|
|
||||||
$event = new Migration();
|
|
||||||
$event
|
|
||||||
->setMigration($migration)
|
|
||||||
->setProject($project)
|
|
||||||
->setUser($user)
|
|
||||||
->trigger();
|
|
||||||
|
|
||||||
$response
|
|
||||||
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
|
|
||||||
->dynamic($migration, Response::MODEL_MIGRATION);
|
|
||||||
});
|
|
||||||
|
|
||||||
App::post('/v1/migrations/firebase/oauth')
|
App::post('/v1/migrations/firebase/oauth')
|
||||||
->groups(['api', 'migrations'])
|
->groups(['api', 'migrations'])
|
||||||
->desc('Migrate Firebase Data (OAuth)')
|
->desc('Migrate Firebase Data (OAuth)')
|
||||||
|
@ -168,8 +118,7 @@ App::post('/v1/migrations/firebase/oauth')
|
||||||
Query::equal('userInternalId', [$user->getInternalId()]),
|
Query::equal('userInternalId', [$user->getInternalId()]),
|
||||||
]);
|
]);
|
||||||
if ($identity === false || $identity->isEmpty()) {
|
if ($identity === false || $identity->isEmpty()) {
|
||||||
throw new Exception(Exception::GENERAL_SERVER_ERROR); //TODO: REMOVE
|
throw new Exception(Exception::USER_IDENTITY_NOT_FOUND);
|
||||||
// throw new Exception(Exception::USER_IDENTITY_NOT_FOUND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessToken = $identity->getAttribute('providerAccessToken');
|
$accessToken = $identity->getAttribute('providerAccessToken');
|
||||||
|
@ -213,7 +162,7 @@ App::post('/v1/migrations/firebase/oauth')
|
||||||
'stage' => 'init',
|
'stage' => 'init',
|
||||||
'source' => Firebase::getName(),
|
'source' => Firebase::getName(),
|
||||||
'credentials' => [
|
'credentials' => [
|
||||||
'serviceAccount' => $serviceAccount,
|
'serviceAccount' => json_encode($serviceAccount),
|
||||||
],
|
],
|
||||||
'resources' => $resources,
|
'resources' => $resources,
|
||||||
'statusCounters' => '{}',
|
'statusCounters' => '{}',
|
||||||
|
@ -224,7 +173,56 @@ App::post('/v1/migrations/firebase/oauth')
|
||||||
$events->setParam('migrationId', $migration->getId());
|
$events->setParam('migrationId', $migration->getId());
|
||||||
|
|
||||||
// Trigger Transfer
|
// Trigger Transfer
|
||||||
var_dump($project);
|
$event = new Migration();
|
||||||
|
$event
|
||||||
|
->setMigration($migration)
|
||||||
|
->setProject($project)
|
||||||
|
->setUser($user)
|
||||||
|
->trigger();
|
||||||
|
|
||||||
|
$response
|
||||||
|
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
|
||||||
|
->dynamic($migration, Response::MODEL_MIGRATION);
|
||||||
|
});
|
||||||
|
|
||||||
|
App::post('/v1/migrations/firebase')
|
||||||
|
->groups(['api', 'migrations'])
|
||||||
|
->desc('Migrate Firebase Data (Service Account)')
|
||||||
|
->label('scope', 'migrations.write')
|
||||||
|
->label('event', 'migrations.create')
|
||||||
|
->label('audits.event', 'migration.create')
|
||||||
|
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||||
|
->label('sdk.namespace', 'migrations')
|
||||||
|
->label('sdk.method', 'createFirebaseMigration')
|
||||||
|
->label('sdk.description', '/docs/references/migrations/migration-firebase.md')
|
||||||
|
->label('sdk.response.code', Response::STATUS_CODE_ACCEPTED)
|
||||||
|
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||||
|
->label('sdk.response.model', Response::MODEL_MIGRATION)
|
||||||
|
->param('resources', [], new ArrayList(new WhiteList(Firebase::getSupportedResources())), 'List of resources to migrate')
|
||||||
|
->param('serviceAccount', '', new Text(65536), 'JSON of the Firebase service account credentials')
|
||||||
|
->inject('response')
|
||||||
|
->inject('dbForProject')
|
||||||
|
->inject('project')
|
||||||
|
->inject('user')
|
||||||
|
->inject('events')
|
||||||
|
->action(function (array $resources, string $serviceAccount, Response $response, Database $dbForProject, Document $project, Document $user, Event $events) {
|
||||||
|
$migration = $dbForProject->createDocument('migrations', new Document([
|
||||||
|
'$id' => ID::unique(),
|
||||||
|
'status' => 'pending',
|
||||||
|
'stage' => 'init',
|
||||||
|
'source' => Firebase::getName(),
|
||||||
|
'credentials' => [
|
||||||
|
'serviceAccount' => $serviceAccount,
|
||||||
|
],
|
||||||
|
'resources' => $resources,
|
||||||
|
'statusCounters' => '{}',
|
||||||
|
'resourceData' => '{}',
|
||||||
|
'errors' => [],
|
||||||
|
]));
|
||||||
|
|
||||||
|
$events->setParam('migrationId', $migration->getId());
|
||||||
|
|
||||||
|
// Trigger Transfer
|
||||||
$event = new Migration();
|
$event = new Migration();
|
||||||
$event
|
$event
|
||||||
->setMigration($migration)
|
->setMigration($migration)
|
||||||
|
@ -515,8 +513,7 @@ App::get('/v1/migrations/firebase/report/oauth')
|
||||||
Query::equal('userInternalId', [$user->getInternalId()]),
|
Query::equal('userInternalId', [$user->getInternalId()]),
|
||||||
]);
|
]);
|
||||||
if ($identity === false || $identity->isEmpty()) {
|
if ($identity === false || $identity->isEmpty()) {
|
||||||
throw new Exception(Exception::GENERAL_SERVER_ERROR); //TODO: REMOVE
|
throw new Exception(Exception::USER_IDENTITY_NOT_FOUND);
|
||||||
// throw new Exception(Exception::USER_IDENTITY_NOT_FOUND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessToken = $identity->getAttribute('providerAccessToken');
|
$accessToken = $identity->getAttribute('providerAccessToken');
|
||||||
|
@ -749,7 +746,7 @@ App::get('/v1/migrations/firebase/projects')
|
||||||
Query::equal('userInternalId', [$user->getInternalId()]),
|
Query::equal('userInternalId', [$user->getInternalId()]),
|
||||||
]);
|
]);
|
||||||
if ($identity === false || $identity->isEmpty()) {
|
if ($identity === false || $identity->isEmpty()) {
|
||||||
throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN, 'Not authenticated with Firebase'); //TODO: Replace with USER_IDENTITY_NOT_FOUND
|
throw new Exception(Exception::USER_IDENTITY_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
$accessToken = $identity->getAttribute('providerAccessToken');
|
$accessToken = $identity->getAttribute('providerAccessToken');
|
||||||
|
@ -766,7 +763,11 @@ App::get('/v1/migrations/firebase/projects')
|
||||||
|
|
||||||
$isExpired = new \DateTime($accessTokenExpiry) < new \DateTime('now');
|
$isExpired = new \DateTime($accessTokenExpiry) < new \DateTime('now');
|
||||||
if ($isExpired) {
|
if ($isExpired) {
|
||||||
$firebase->refreshTokens($refreshToken);
|
try {
|
||||||
|
$firebase->refreshTokens($refreshToken);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN, 'Failed to refresh Firebase access token');
|
||||||
|
}
|
||||||
|
|
||||||
$accessToken = $firebase->getAccessToken('');
|
$accessToken = $firebase->getAccessToken('');
|
||||||
$refreshToken = $firebase->getRefreshToken('');
|
$refreshToken = $firebase->getRefreshToken('');
|
||||||
|
|
|
@ -5,7 +5,6 @@ use Appwrite\Messaging\Adapter\Realtime;
|
||||||
use Appwrite\Permission;
|
use Appwrite\Permission;
|
||||||
use Appwrite\Resque\Worker;
|
use Appwrite\Resque\Worker;
|
||||||
use Appwrite\Role;
|
use Appwrite\Role;
|
||||||
use Appwrite\Utopia\Response\Model\Migration;
|
|
||||||
use Utopia\CLI\Console;
|
use Utopia\CLI\Console;
|
||||||
use Utopia\Database\Database;
|
use Utopia\Database\Database;
|
||||||
use Utopia\Database\Document;
|
use Utopia\Database\Document;
|
||||||
|
@ -61,7 +60,7 @@ class MigrationsV1 extends Worker
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->dbForProject = $this->getProjectDB($this->args['project']['$id']);
|
$this->dbForProject = $this->getProjectDB(new Document($this->args['project']));
|
||||||
|
|
||||||
$this->processMigration();
|
$this->processMigration();
|
||||||
}
|
}
|
||||||
|
|
|
@ -618,6 +618,11 @@ services:
|
||||||
- _APP_LOGGING_CONFIG
|
- _APP_LOGGING_CONFIG
|
||||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
|
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
|
||||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
|
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
|
||||||
|
- _APP_CONNECTIONS_DB_PROJECT
|
||||||
|
- _APP_CONNECTIONS_DB_CONSOLE
|
||||||
|
- _APP_CONNECTIONS_CACHE
|
||||||
|
- _APP_CONNECTIONS_QUEUE
|
||||||
|
- _APP_CONNECTIONS_PUBSUB
|
||||||
|
|
||||||
appwrite-maintenance:
|
appwrite-maintenance:
|
||||||
entrypoint: maintenance
|
entrypoint: maintenance
|
||||||
|
|
|
@ -87,7 +87,7 @@ class Firebase extends OAuth2
|
||||||
{
|
{
|
||||||
$response = $this->request(
|
$response = $this->request(
|
||||||
'POST',
|
'POST',
|
||||||
'https://github.com/login/oauth/access_token',
|
'https://oauth2.googleapis.com/token',
|
||||||
[],
|
[],
|
||||||
\http_build_query([
|
\http_build_query([
|
||||||
'client_id' => $this->appID,
|
'client_id' => $this->appID,
|
||||||
|
@ -195,12 +195,47 @@ class Firebase extends OAuth2
|
||||||
return $projects['results'];
|
return $projects['results'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createServiceAccount(string $accessToken, string $projectID): array
|
/*
|
||||||
|
Be careful with the setIAMPolicy method, it will overwrite all existing policies
|
||||||
|
**/
|
||||||
|
public function assignIAMRoles(string $accessToken, string $email, string $projectId) {
|
||||||
|
// Get IAM Roles
|
||||||
|
$iamRoles = $this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/'.$projectId.':getIamPolicy', [
|
||||||
|
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||||
|
'Content-Type: application/json'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$iamRoles = \json_decode($iamRoles, true);
|
||||||
|
|
||||||
|
$iamRoles['bindings'][] = [
|
||||||
|
'role' => 'roles/identitytoolkit.admin',
|
||||||
|
'members' => [
|
||||||
|
'serviceAccount:'.$email
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$iamRoles['bindings'][] = [
|
||||||
|
'role' => 'roles/firebase.admin',
|
||||||
|
'members' => [
|
||||||
|
'serviceAccount:'.$email
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
// Set IAM Roles
|
||||||
|
$this->request('POST', 'https://cloudresourcemanager.googleapis.com/v1/projects/'.$projectId.':setIamPolicy', [
|
||||||
|
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||||
|
'Content-Type: application/json'
|
||||||
|
], json_encode([
|
||||||
|
'policy' => $iamRoles
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createServiceAccount(string $accessToken, string $projectId): array
|
||||||
{
|
{
|
||||||
// Create Service Account
|
// Create Service Account
|
||||||
$response = $this->request(
|
$response = $this->request(
|
||||||
'POST',
|
'POST',
|
||||||
'https://iam.googleapis.com/v1/projects/' . $projectID . '/serviceAccounts',
|
'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts',
|
||||||
[
|
[
|
||||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||||
'Content-Type: application/json'
|
'Content-Type: application/json'
|
||||||
|
@ -215,10 +250,12 @@ class Firebase extends OAuth2
|
||||||
|
|
||||||
$response = json_decode($response, true);
|
$response = json_decode($response, true);
|
||||||
|
|
||||||
|
$this->assignIAMRoles($accessToken, $response['email'], $projectId);
|
||||||
|
|
||||||
// Create Service Account Key
|
// Create Service Account Key
|
||||||
$responseKey = $this->request(
|
$responseKey = $this->request(
|
||||||
'POST',
|
'POST',
|
||||||
'https://iam.googleapis.com/v1/projects/' . $projectID . '/serviceAccounts/' . $response['email'] . '/keys',
|
'https://iam.googleapis.com/v1/projects/' . $projectId . '/serviceAccounts/' . $response['email'] . '/keys',
|
||||||
[
|
[
|
||||||
'Authorization: Bearer ' . \urlencode($accessToken),
|
'Authorization: Bearer ' . \urlencode($accessToken),
|
||||||
'Content-Type: application/json'
|
'Content-Type: application/json'
|
||||||
|
|
Loading…
Reference in a new issue