Correct unique constraints for UserConsent entity
Closes #13045 Signed-off-by: cgeorgilakis-grnet <cgeorgilakis@admin.grnet.gr>
This commit is contained in:
parent
05056330dc
commit
4bca804d5a
4 changed files with 170 additions and 7 deletions
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2024 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.connections.jpa.updater.liquibase.custom;
|
||||
|
||||
import liquibase.exception.CustomChangeException;
|
||||
import liquibase.statement.core.RawSqlStatement;
|
||||
|
||||
public class JpaUpdate25_0_0_ConsentConstraints extends CustomKeycloakTask {
|
||||
|
||||
@Override
|
||||
protected void generateStatementsImpl() throws CustomChangeException {
|
||||
final String userConsentClientScopeTable = getTableName("USER_CONSENT_CLIENT_SCOPE");
|
||||
final String userConsentTable = getTableName("USER_CONSENT");
|
||||
statements.add(new RawSqlStatement(
|
||||
"DELETE FROM "+ userConsentClientScopeTable + " WHERE USER_CONSENT_ID IN (" +
|
||||
" SELECT uc.ID FROM "+userConsentTable+" uc INNER JOIN (" +
|
||||
" SELECT CLIENT_ID, USER_ID, MAX(LAST_UPDATED_DATE) AS MAX_UPDATED_DATE FROM " + userConsentTable +
|
||||
" GROUP BY CLIENT_ID, USER_ID HAVING COUNT(*) > 1 ) max_dates ON uc.CLIENT_ID = max_dates.CLIENT_ID" +
|
||||
" AND uc.USER_ID = max_dates.USER_ID AND uc.LAST_UPDATED_DATE = max_dates.MAX_UPDATED_DATE)"
|
||||
));
|
||||
statements.add(new RawSqlStatement(
|
||||
" DELETE FROM "+userConsentTable+" WHERE ID IN (" +
|
||||
" SELECT uc.ID FROM "+userConsentTable+" uc INNER JOIN (" +
|
||||
" SELECT CLIENT_ID, USER_ID, MAX(LAST_UPDATED_DATE) AS MAX_UPDATED_DATE" +
|
||||
" FROM "+userConsentTable+" GROUP BY CLIENT_ID, USER_ID HAVING COUNT(*) > 1 )" +
|
||||
" max_dates ON uc.CLIENT_ID = max_dates.CLIENT_ID" +
|
||||
" AND uc.USER_ID = max_dates.USER_ID AND uc.LAST_UPDATED_DATE = max_dates.MAX_UPDATED_DATE )"
|
||||
));
|
||||
statements.add(new RawSqlStatement(
|
||||
" DELETE FROM "+ userConsentClientScopeTable + " WHERE USER_CONSENT_ID IN (" +
|
||||
" SELECT uc.ID FROM "+userConsentTable+" uc INNER JOIN (" +
|
||||
" SELECT CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID, MAX(LAST_UPDATED_DATE) AS MAX_UPDATED_DATE" +
|
||||
" FROM "+userConsentTable+" GROUP BY CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID HAVING COUNT(*) > 1 )" +
|
||||
" max_dates ON uc.CLIENT_STORAGE_PROVIDER = max_dates.CLIENT_STORAGE_PROVIDER" +
|
||||
" AND uc.EXTERNAL_CLIENT_ID = max_dates.EXTERNAL_CLIENT_ID AND uc.USER_ID = max_dates.USER_ID AND uc.LAST_UPDATED_DATE = max_dates.MAX_UPDATED_DATE )"
|
||||
));
|
||||
statements.add(new RawSqlStatement(
|
||||
" DELETE FROM "+userConsentTable+" WHERE ID IN (" +
|
||||
" SELECT uc.ID FROM "+userConsentTable+" uc INNER JOIN (" +
|
||||
" SELECT CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID, MAX(LAST_UPDATED_DATE) AS MAX_UPDATED_DATE" +
|
||||
" FROM "+userConsentTable+" GROUP BY CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID HAVING COUNT(*) > 1 )" +
|
||||
" max_dates ON uc.CLIENT_STORAGE_PROVIDER = max_dates.CLIENT_STORAGE_PROVIDER" +
|
||||
" AND uc.EXTERNAL_CLIENT_ID = max_dates.EXTERNAL_CLIENT_ID AND uc.USER_ID = max_dates.USER_ID AND uc.LAST_UPDATED_DATE = max_dates.MAX_UPDATED_DATE )"
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTaskId() {
|
||||
return "Correct User Consent Unique Constraints for PostgreSQL and MariaDB";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2024 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.connections.jpa.updater.liquibase.custom;
|
||||
|
||||
import liquibase.exception.CustomChangeException;
|
||||
import liquibase.statement.core.DeleteStatement;
|
||||
import liquibase.statement.core.RawSqlStatement;
|
||||
import liquibase.structure.core.Table;
|
||||
|
||||
public class JpaUpdate25_0_0_MySQL_ConsentConstraints extends CustomKeycloakTask {
|
||||
|
||||
@Override
|
||||
protected void generateStatementsImpl() throws CustomChangeException {
|
||||
final String userConsentClientScopeTable = getTableName("USER_CONSENT_CLIENT_SCOPE");
|
||||
final String userConsentTable = getTableName("USER_CONSENT");
|
||||
statements.add(new RawSqlStatement(
|
||||
"DELETE FROM "+ userConsentClientScopeTable + " WHERE USER_CONSENT_ID IN (" +
|
||||
" SELECT uc.ID FROM "+userConsentTable+" uc INNER JOIN (" +
|
||||
" SELECT CLIENT_ID, USER_ID, MAX(LAST_UPDATED_DATE) AS MAX_UPDATED_DATE FROM " + userConsentTable +
|
||||
" GROUP BY CLIENT_ID, USER_ID HAVING COUNT(*) > 1 ) max_dates ON uc.CLIENT_ID = max_dates.CLIENT_ID" +
|
||||
" AND uc.USER_ID = max_dates.USER_ID AND uc.LAST_UPDATED_DATE = max_dates.MAX_UPDATED_DATE)"
|
||||
));
|
||||
statements.add(new RawSqlStatement(
|
||||
" CREATE TEMPORARY TABLE TEMP_USER_CONSENT_IDS" +
|
||||
" AS SELECT uc.ID FROM "+userConsentTable+" uc INNER JOIN (" +
|
||||
" SELECT CLIENT_ID, USER_ID, MAX(LAST_UPDATED_DATE) AS MAX_UPDATED_DATE" +
|
||||
" FROM "+userConsentTable+" GROUP BY CLIENT_ID, USER_ID HAVING COUNT(*) > 1 )" +
|
||||
" max_dates ON uc.CLIENT_ID = max_dates.CLIENT_ID" +
|
||||
" AND uc.USER_ID = max_dates.USER_ID AND uc.LAST_UPDATED_DATE = max_dates.MAX_UPDATED_DATE"
|
||||
));
|
||||
statements.add(new DeleteStatement(null, null, database.correctObjectName("USER_CONSENT", Table.class))
|
||||
.setWhere("ID IN (SELECT ID FROM TEMP_USER_CONSENT_IDS)"));
|
||||
statements.add(new RawSqlStatement("DROP TEMPORARY TABLE IF EXISTS TEMP_USER_CONSENT_IDS"));
|
||||
|
||||
statements.add(new RawSqlStatement(
|
||||
" DELETE FROM "+ userConsentClientScopeTable + " WHERE USER_CONSENT_ID IN (" +
|
||||
" SELECT uc.ID FROM "+userConsentTable+" uc INNER JOIN (" +
|
||||
" SELECT CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID, MAX(LAST_UPDATED_DATE) AS MAX_UPDATED_DATE" +
|
||||
" FROM "+userConsentTable+" GROUP BY CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID HAVING COUNT(*) > 1 )" +
|
||||
" max_dates ON uc.CLIENT_STORAGE_PROVIDER = max_dates.CLIENT_STORAGE_PROVIDER" +
|
||||
" AND uc.EXTERNAL_CLIENT_ID = max_dates.EXTERNAL_CLIENT_ID AND uc.USER_ID = max_dates.USER_ID AND uc.LAST_UPDATED_DATE = max_dates.MAX_UPDATED_DATE )"
|
||||
));
|
||||
statements.add(new RawSqlStatement(
|
||||
"CREATE TEMPORARY TABLE TEMP_USER_CONSENT_IDS2" +
|
||||
" AS SELECT uc.ID FROM "+userConsentTable+" uc INNER JOIN (" +
|
||||
" SELECT CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID, MAX(LAST_UPDATED_DATE) AS MAX_UPDATED_DATE" +
|
||||
" FROM "+userConsentTable+" GROUP BY CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID HAVING COUNT(*) > 1 )" +
|
||||
" max_dates ON uc.CLIENT_STORAGE_PROVIDER = max_dates.CLIENT_STORAGE_PROVIDER" +
|
||||
" AND uc.EXTERNAL_CLIENT_ID = max_dates.EXTERNAL_CLIENT_ID AND uc.USER_ID = max_dates.USER_ID AND uc.LAST_UPDATED_DATE = max_dates.MAX_UPDATED_DATE;"
|
||||
));
|
||||
statements.add(new DeleteStatement(null, null, database.correctObjectName("USER_CONSENT", Table.class))
|
||||
.setWhere("ID IN (SELECT ID FROM TEMP_USER_CONSENT_IDS2)"));
|
||||
statements.add(new RawSqlStatement("DROP TEMPORARY TABLE IF EXISTS TEMP_USER_CONSENT_IDS2"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTaskId() {
|
||||
return "Correct User Consent Unique Constraints for MySQL";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -208,15 +208,10 @@ public class JpaUserProvider implements UserProvider, UserCredentialStore {
|
|||
@Override
|
||||
public void addConsent(RealmModel realm, String userId, UserConsentModel consent) {
|
||||
String clientId = consent.getClient().getId();
|
||||
|
||||
UserConsentEntity consentEntity = getGrantedConsentEntity(userId, clientId, LockModeType.NONE);
|
||||
if (consentEntity != null) {
|
||||
throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + userId + "]");
|
||||
}
|
||||
|
||||
|
||||
long currentTime = Time.currentTimeMillis();
|
||||
|
||||
consentEntity = new UserConsentEntity();
|
||||
UserConsentEntity consentEntity = new UserConsentEntity();
|
||||
consentEntity.setId(KeycloakModelUtils.generateId());
|
||||
consentEntity.setUser(em.getReference(UserEntity.class, userId));
|
||||
StorageId clientStorageId = new StorageId(clientId);
|
||||
|
|
|
@ -34,4 +34,28 @@
|
|||
<addUniqueConstraint tableName="ORGANIZATION" columnNames="REALM_ID, NAME" constraintName="UK_ORG_NAME"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="keycloak" id="unique-consentuser">
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<or>
|
||||
<dbms type="mariadb"/>
|
||||
<dbms type="postgresql"/>
|
||||
</or>
|
||||
</preConditions>
|
||||
<customChange class="org.keycloak.connections.jpa.updater.liquibase.custom.JpaUpdate25_0_0_ConsentConstraints"/>
|
||||
<dropUniqueConstraint tableName="USER_CONSENT" constraintName="UK_JKUWUVD56ONTGSUHOGM8UEWRT"/>
|
||||
<addUniqueConstraint columnNames="CLIENT_ID, USER_ID" constraintName="UK_LOCAL_CONSENT" tableName="USER_CONSENT"/>
|
||||
<addUniqueConstraint columnNames="CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID" constraintName="UK_EXTERNAL_CONSENT" tableName="USER_CONSENT"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="keycloak" id="unique-consentuser-mysql">
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<dbms type="mysql"/>
|
||||
</preConditions>
|
||||
<customChange class="org.keycloak.connections.jpa.updater.liquibase.custom.JpaUpdate25_0_0_MySQL_ConsentConstraints"/>
|
||||
<dropUniqueConstraint tableName="USER_CONSENT" constraintName="UK_JKUWUVD56ONTGSUHOGM8UEWRT"/>
|
||||
<addUniqueConstraint columnNames="CLIENT_ID, USER_ID" constraintName="UK_LOCAL_CONSENT" tableName="USER_CONSENT"/>
|
||||
<addUniqueConstraint columnNames="CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID" constraintName="UK_EXTERNAL_CONSENT" tableName="USER_CONSENT"/>
|
||||
</changeSet>
|
||||
|
||||
|
||||
</databaseChangeLog>
|
||||
|
|
Loading…
Reference in a new issue