db); if (!$schema->hasTable('oauth2_clients')) { $output->info('oauth2_clients table does not exist.'); return; } // Create column and then migrate before handling unique index. // So that we can distinguish between legacy (from oc) and new rows (from nc). $table = $schema->getTable('oauth2_access_tokens'); if (!$table->hasColumn('hashed_code')) { $output->info('Prepare the oauth2_access_tokens table schema.'); $table->addColumn('hashed_code', 'string', [ 'notnull' => true, 'length' => 128, ]); // Regenerate schema after migrating to it $this->db->migrateToSchema($schema->getWrappedSchema()); $schema = new SchemaWrapper($this->db); } $output->info('Update the oauth2_access_tokens table schema.'); $table = $schema->getTable('oauth2_access_tokens'); if (!$table->hasColumn('encrypted_token')) { $table->addColumn('encrypted_token', 'string', [ 'notnull' => true, 'length' => 786, ]); } if (!$table->hasIndex('oauth2_access_hash_idx')) { // Drop legacy access codes first to prevent integrity constraint violations $qb = $this->db->getQueryBuilder(); $qb->delete('oauth2_access_tokens') ->where($qb->expr()->eq('hashed_code', $qb->createNamedParameter(''))); $qb->executeStatement(); $table->addUniqueIndex(['hashed_code'], 'oauth2_access_hash_idx'); } if (!$table->hasIndex('oauth2_access_client_id_idx')) { $table->addIndex(['client_id'], 'oauth2_access_client_id_idx'); } if (!$table->hasColumn('token_id')) { $table->addColumn('token_id', 'integer', [ 'notnull' => true, ]); } if ($table->hasColumn('expires')) { $table->dropColumn('expires'); } if ($table->hasColumn('user_id')) { $table->dropColumn('user_id'); } if ($table->hasColumn('token')) { $table->dropColumn('token'); } $output->info('Update the oauth2_clients table schema.'); $table = $schema->getTable('oauth2_clients'); if ($table->getColumn('name')->getLength() !== 64) { // shorten existing values before resizing the column $qb = $this->db->getQueryBuilder(); $qb->update('oauth2_clients') ->set('name', $qb->createParameter('shortenedName')) ->where($qb->expr()->eq('id', $qb->createParameter('theId'))); $qbSelect = $this->db->getQueryBuilder(); $qbSelect->select('id', 'name') ->from('oauth2_clients'); $result = $qbSelect->executeQuery(); while ($row = $result->fetch()) { $id = $row['id']; $shortenedName = mb_substr($row['name'], 0, 64); $qb->setParameter('theId', $id, IQueryBuilder::PARAM_INT); $qb->setParameter('shortenedName', $shortenedName, IQueryBuilder::PARAM_STR); $qb->executeStatement(); } $result->closeCursor(); // safely set the new column length $table->getColumn('name')->setLength(64); } if ($table->hasColumn('allow_subdomains')) { $table->dropColumn('allow_subdomains'); } if ($table->hasColumn('trusted')) { $table->dropColumn('trusted'); } if (!$schema->getTable('oauth2_clients')->hasColumn('client_identifier')) { $table->addColumn('client_identifier', 'string', [ 'notnull' => true, 'length' => 64, 'default' => '' ]); $table->addIndex(['client_identifier'], 'oauth2_client_id_idx'); } // Regenerate schema after migrating to it $this->db->migrateToSchema($schema->getWrappedSchema()); $schema = new SchemaWrapper($this->db); if ($schema->getTable('oauth2_clients')->hasColumn('identifier')) { $output->info("Move identifier column's data to the new client_identifier column."); // 1. Fetch all [id, identifier] couple. $selectQuery = $this->db->getQueryBuilder(); $selectQuery->select('id', 'identifier')->from('oauth2_clients'); $result = $selectQuery->executeQuery(); $identifiers = $result->fetchAll(); $result->closeCursor(); // 2. Insert them into the client_identifier column. foreach ($identifiers as ['id' => $id, 'identifier' => $clientIdentifier]) { $insertQuery = $this->db->getQueryBuilder(); $insertQuery->update('oauth2_clients') ->set('client_identifier', $insertQuery->createNamedParameter($clientIdentifier, IQueryBuilder::PARAM_STR)) ->where($insertQuery->expr()->eq('id', $insertQuery->createNamedParameter($id, IQueryBuilder::PARAM_INT))) ->executeStatement(); } $output->info('Drop the identifier column.'); $table = $schema->getTable('oauth2_clients'); $table->dropColumn('identifier'); // Regenerate schema after migrating to it $this->db->migrateToSchema($schema->getWrappedSchema()); $schema = new SchemaWrapper($this->db); } $output->info('Delete clients (and their related access tokens) with the redirect_uri starting with oc:// or ending with *'); // delete the access tokens $qbDeleteAccessTokens = $this->db->getQueryBuilder(); $qbSelectClientId = $this->db->getQueryBuilder(); $qbSelectClientId->select('id') ->from('oauth2_clients') ->where( $qbSelectClientId->expr()->iLike('redirect_uri', $qbDeleteAccessTokens->createNamedParameter('oc://%', IQueryBuilder::PARAM_STR)) ) ->orWhere( $qbSelectClientId->expr()->iLike('redirect_uri', $qbDeleteAccessTokens->createNamedParameter('%*', IQueryBuilder::PARAM_STR)) ); $qbDeleteAccessTokens->delete('oauth2_access_tokens') ->where( $qbSelectClientId->expr()->in('client_id', $qbDeleteAccessTokens->createFunction($qbSelectClientId->getSQL()), IQueryBuilder::PARAM_STR_ARRAY) ); $qbDeleteAccessTokens->executeStatement(); // delete the clients $qbDeleteClients = $this->db->getQueryBuilder(); $qbDeleteClients->delete('oauth2_clients') ->where( $qbDeleteClients->expr()->iLike('redirect_uri', $qbDeleteClients->createNamedParameter('oc://%', IQueryBuilder::PARAM_STR)) ) ->orWhere( $qbDeleteClients->expr()->iLike('redirect_uri', $qbDeleteClients->createNamedParameter('%*', IQueryBuilder::PARAM_STR)) ); $qbDeleteClients->executeStatement(); // Migrate legacy refresh tokens from oc if ($schema->hasTable('oauth2_refresh_tokens')) { $output->info('Migrate legacy oauth2 refresh tokens.'); $qbSelect = $this->db->getQueryBuilder(); $qbSelect->select('*') ->from('oauth2_refresh_tokens'); $result = $qbSelect->executeQuery(); $now = $this->timeFactory->now()->getTimestamp(); $index = 0; while ($row = $result->fetch()) { $clientId = $row['client_id']; $refreshToken = $row['token']; // Insert expired token so that it can be rotated on the next refresh $accessToken = $this->random->generate(72, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS); $authToken = $this->tokenProvider->generateToken( $accessToken, $row['user_id'], $row['user_id'], null, "oc_migrated_client{$clientId}_t{$now}_i$index", IToken::PERMANENT_TOKEN, IToken::DO_NOT_REMEMBER, ); $authToken->setExpires($now - 3600); $this->tokenProvider->updateToken($authToken); $accessTokenEntity = new AccessToken(); $accessTokenEntity->setTokenId($authToken->getId()); $accessTokenEntity->setClientId($clientId); $accessTokenEntity->setHashedCode(hash('sha512', $refreshToken)); $accessTokenEntity->setEncryptedToken($this->crypto->encrypt($accessToken, $refreshToken)); $accessTokenEntity->setCodeCreatedAt($now); $accessTokenEntity->setTokenCount(1); $this->accessTokenMapper->insert($accessTokenEntity); $index++; } $result->closeCursor(); $schema->dropTable('oauth2_refresh_tokens'); $schema->performDropTableCalls(); } } } ion> Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/Accounts/AccountPropertyTest.php
blob: b92e45176a37c505f6b8c6f057860211b62f33ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131