model migration

This commit is contained in:
Bill Burke 2015-04-27 16:12:43 -04:00
parent f17863041a
commit 4166393396
29 changed files with 561 additions and 31 deletions

View file

@ -24,6 +24,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.codehaus.jackson.JsonToken;
import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.exportimport.Strategy;
@ -84,7 +86,22 @@ public class DefaultFileConnectionProviderFactory implements FileConnectionProvi
FileInputStream fis = null;
try {
fis = new FileInputStream(kcdata);
Model model = JsonSerialization.readValue(fis, Model.class);
ImportUtils.importFromStream(session, JsonSerialization.mapper, fis, Strategy.IGNORE_EXISTING);
session.realms().getMigrationModel().setStoredVersion(model.getModelVersion());
List<RealmRepresentation> realmReps = new ArrayList<RealmRepresentation>();
for (RealmRepresentation realmRep : model.getRealms()) {
if (Config.getAdminRealm().equals(realmRep.getRealm())) {
realmReps.add(0, realmRep);
} else {
realmReps.add(realmRep);
}
}
for (RealmRepresentation realmRep : realmReps) {
ImportUtils.importRealm(session, realmRep, Strategy.IGNORE_EXISTING);
}
} catch (IOException ioe) {
logger.error("Unable to read model file " + kcdata.getAbsolutePath(), ioe);
} finally {
@ -128,8 +145,10 @@ public class DefaultFileConnectionProviderFactory implements FileConnectionProvi
for (RealmModel realm : realms) {
reps.add(ExportUtils.exportRealm(session, realm, true));
}
JsonSerialization.prettyMapper.writeValue(outStream, reps);
Model model = new Model();
model.setRealms(reps);
model.setModelVersion(session.realms().getMigrationModel().getStoredVersion());
JsonSerialization.prettyMapper.writeValue(outStream, model);
}
@Override

View file

@ -37,6 +37,8 @@ public class InMemoryModel {
// realmId, userId, userModel
private final Map<String, Map<String,UserModel>> allUsers = new HashMap<String, Map<String,UserModel>>();
private String modelVersion;
public InMemoryModel() {
}
@ -45,6 +47,14 @@ public class InMemoryModel {
allUsers.put(id, new HashMap<String, UserModel>());
}
public String getModelVersion() {
return modelVersion;
}
public void setModelVersion(String modelVersion) {
this.modelVersion = modelVersion;
}
public RealmModel getRealm(String id) {
return allRealms.get(id);
}

View file

@ -0,0 +1,30 @@
package org.keycloak.connections.file;
import org.keycloak.representations.idm.RealmRepresentation;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class Model {
private String modelVersion;
private List<RealmRepresentation> realms;
public String getModelVersion() {
return modelVersion;
}
public void setModelVersion(String modelVersion) {
this.modelVersion = modelVersion;
}
public List<RealmRepresentation> getRealms() {
return realms;
}
public void setRealms(List<RealmRepresentation> realms) {
this.realms = realms;
}
}

View file

@ -5,6 +5,14 @@
<delete tableName="CLIENT_SESSION_NOTE"/>
<delete tableName="CLIENT_SESSION"/>
<delete tableName="USER_SESSION"/>
<createTable tableName="MIGRATION_MODEL">
<column name="ID" type="VARCHAR(36)">
<constraints nullable="false"/>
</column>
<column name="VERSION" type="VARCHAR(36)">
<constraints nullable="true"/>
</column>
</createTable>
<createTable tableName="IDENTITY_PROVIDER_MAPPER">
<column name="ID" type="VARCHAR(36)">
@ -70,6 +78,7 @@
<constraints nullable="false"/>
</column>
</createTable>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_MIGMOD" tableName="MIGRATION_MODEL"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_IDPM" tableName="IDENTITY_PROVIDER_MAPPER"/>
<addPrimaryKey columnNames="IDP_MAPPER_ID, NAME" constraintName="CONSTRAINT_IDPMConfig" tableName="IDP_MAPPER_CONFIG"/>
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_GRNTCSNT_PM" tableName="USER_CONSENT"/>

View file

@ -11,6 +11,7 @@
<class>org.keycloak.models.jpa.entities.UserFederationProviderEntity</class>
<class>org.keycloak.models.jpa.entities.RoleEntity</class>
<class>org.keycloak.models.jpa.entities.FederatedIdentityEntity</class>
<class>org.keycloak.models.jpa.entities.MigrationModelEntity</class>
<class>org.keycloak.models.jpa.entities.UserEntity</class>
<class>org.keycloak.models.jpa.entities.UserRequiredActionEntity</class>
<class>org.keycloak.models.jpa.entities.UserAttributeEntity</class>

View file

@ -0,0 +1,18 @@
package org.keycloak.migration;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface MigrationModel {
/**
* Must have the form of major.minor.micro as the version is parsed and numbers are compared
*/
public static final String LATEST_VERSION = "1.2.0.CR1";
String getStoredVersion();
void setStoredVersion(String version);
}

View file

@ -0,0 +1,31 @@
package org.keycloak.migration;
import org.jboss.logging.Logger;
import org.keycloak.migration.migrators.MigrationTo1_2_0_RC1;
import org.keycloak.models.KeycloakSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MigrationModelManager {
private static Logger logger = Logger.getLogger(MigrationModelManager.class);
public static void migrate(KeycloakSession session) {
MigrationModel model = session.realms().getMigrationModel();
String storedVersion = model.getStoredVersion();
if (MigrationModel.LATEST_VERSION.equals(storedVersion)) return;
ModelVersion stored = null;
if (storedVersion == null) stored = new ModelVersion(0, 0, 0);
else stored = new ModelVersion(storedVersion);
if (stored.lessThan(MigrationTo1_2_0_RC1.VERSION)) {
logger.info("Migrating older model to 1.2.0.RC1 updates");
new MigrationTo1_2_0_RC1().migrate(session);
}
model.setStoredVersion(MigrationModel.LATEST_VERSION);
}
}

View file

@ -0,0 +1,69 @@
package org.keycloak.migration;
import org.jboss.logging.Logger;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ModelVersion {
private static Logger logger = Logger.getLogger(ModelVersion.class);
int major;
int minor;
int micro;
String qualifier;
public ModelVersion(int major, int minor, int micro) {
this.major = major;
this.minor = minor;
this.micro = micro;
}
public ModelVersion(String version) {
String[] split = version.split("\\.");
try {
if (split.length > 0) {
major = Integer.parseInt(split[0]);
}
if (split.length > 1) {
minor = Integer.parseInt(split[1]);
}
if (split.length > 2) {
micro = Integer.parseInt(split[2]);
}
if (split.length > 3) {
qualifier = split[3];
}
} catch (NumberFormatException e) {
logger.warn("failed to parse version: " + version, e);
}
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getMicro() {
return micro;
}
public String getQualifier() {
return qualifier;
}
public boolean lessThan(ModelVersion version) {
if (major < version.major) return true;
if (minor < version.minor) return true;
if (micro < version.micro) return true;
if (qualifier == version.qualifier) return false;
if (qualifier == null) return false;
if (version.qualifier == null) return true;
int comp = qualifier.compareTo(version.qualifier);
if (comp < 0) return true;
return false;
}
}

View file

@ -0,0 +1,38 @@
package org.keycloak.migration.migrators;
import org.keycloak.migration.ModelVersion;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MigrationTo1_2_0_RC1 {
public static final ModelVersion VERSION = new ModelVersion("1.2.0.RC1");
public void setupBrokerService(RealmModel realm) {
ClientModel client = realm.getClientNameMap().get(Constants.BROKER_SERVICE_CLIENT_ID);
if (client == null) {
client = KeycloakModelUtils.createClient(realm, Constants.BROKER_SERVICE_CLIENT_ID);
client.setEnabled(true);
client.setFullScopeAllowed(false);
for (String role : Constants.BROKER_SERVICE_ROLES) {
client.addRole(role).setDescription("${role_"+role+"}");
}
}
}
public void migrate(KeycloakSession session) {
List<RealmModel> realms = session.realms().getRealms();
for (RealmModel realm : realms) {
setupBrokerService(realm);
}
}
}

View file

@ -12,4 +12,6 @@ public interface Constants {
String INSTALLED_APP_URN = "urn:ietf:wg:oauth:2.0:oob";
String INSTALLED_APP_URL = "http://localhost";
String READ_TOKEN_ROLE = "READ_TOKEN";
String[] BROKER_SERVICE_ROLES = {READ_TOKEN_ROLE};
}

View file

@ -1,5 +1,6 @@
package org.keycloak.models;
import org.keycloak.migration.MigrationModel;
import org.keycloak.provider.Provider;
import java.util.Set;

View file

@ -1,5 +1,6 @@
package org.keycloak.models;
import org.keycloak.migration.MigrationModel;
import org.keycloak.provider.Provider;
import java.util.List;
@ -11,7 +12,7 @@ import java.util.List;
public interface RealmProvider extends Provider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
MigrationModel getMigrationModel();
RealmModel createRealm(String name);
RealmModel createRealm(String id, String name);
RealmModel getRealm(String id);

View file

@ -1,5 +1,5 @@
org.keycloak.models.UserFederationSpi
org.keycloak.models.RealmSpi
org.keycloak.models.UserSessionSpi
org.keycloak.models.UserSpi
org.keycloak.models.UserFederationSpi
org.keycloak.models.RealmSpi
org.keycloak.models.UserSessionSpi
org.keycloak.models.UserSpi
org.keycloak.migration.MigrationSpi

View file

@ -0,0 +1,45 @@
package org.keycloak.models;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.migration.ModelVersion;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MigrationVersionTest {
@Test
public void testVersion() {
ModelVersion version_100Beta1 = new ModelVersion("1.0.0.Beta1");
Assert.assertEquals(version_100Beta1.getMajor(), 1);
Assert.assertEquals(version_100Beta1.getMinor(), 0);
Assert.assertEquals(version_100Beta1.getMicro(), 0);
ModelVersion version_100RC1 = new ModelVersion("1.0.0.RC1");
ModelVersion version_100 = new ModelVersion("1.0.0");
ModelVersion version_110Beta1 = new ModelVersion("1.1.0.Beta1");
ModelVersion version_110RC1 = new ModelVersion("1.1.0.RC1");
ModelVersion version_110 = new ModelVersion("1.1.0");
ModelVersion version_111Beta1 = new ModelVersion("1.1.1.Beta1");
ModelVersion version_111RC1 = new ModelVersion("1.1.1.RC1");
ModelVersion version_111 = new ModelVersion("1.1.1");
ModelVersion version_211Beta1 = new ModelVersion("2.1.1.Beta1");
ModelVersion version_211RC1 = new ModelVersion("2.1.1.RC1");
Assert.assertEquals(version_211RC1.getMajor(), 2);
Assert.assertEquals(version_211RC1.getMinor(), 1);
Assert.assertEquals(version_211RC1.getMicro(), 1);
Assert.assertEquals(version_211RC1.getQualifier(), "RC1");
ModelVersion version_211 = new ModelVersion("2.1.1");
Assert.assertFalse(version_100Beta1.lessThan(version_100Beta1));
Assert.assertTrue(version_100Beta1.lessThan(version_100RC1));
Assert.assertTrue(version_100Beta1.lessThan(version_100));
Assert.assertTrue(version_100Beta1.lessThan(version_110Beta1));
Assert.assertTrue(version_100Beta1.lessThan(version_110RC1));
Assert.assertTrue(version_100Beta1.lessThan(version_110));
Assert.assertFalse(version_211.lessThan(version_110RC1));
}
}

View file

@ -18,6 +18,7 @@ package org.keycloak.models.file;
import org.keycloak.connections.file.FileConnectionProvider;
import org.keycloak.connections.file.InMemoryModel;
import org.keycloak.migration.MigrationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
@ -25,6 +26,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleModel;
import org.keycloak.models.entities.RealmEntity;
import org.keycloak.models.file.adapter.MigrationModelAdapter;
import org.keycloak.models.file.adapter.RealmAdapter;
import org.keycloak.models.utils.KeycloakModelUtils;
@ -54,6 +56,11 @@ public class FileRealmProvider implements RealmProvider {
fcProvider.sessionClosed(session);
}
@Override
public MigrationModel getMigrationModel() {
return new MigrationModelAdapter(inMemoryModel);
}
@Override
public RealmModel createRealm(String name) {
return createRealm(KeycloakModelUtils.generateId(), name);

View file

@ -0,0 +1,26 @@
package org.keycloak.models.file.adapter;
import org.keycloak.connections.file.InMemoryModel;
import org.keycloak.migration.MigrationModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MigrationModelAdapter implements MigrationModel {
protected InMemoryModel em;
public MigrationModelAdapter(InMemoryModel em) {
this.em = em;
}
@Override
public String getStoredVersion() {
return em.getModelVersion();
}
@Override
public void setStoredVersion(String version) {
em.setModelVersion(version);
}
}

View file

@ -1,5 +1,6 @@
package org.keycloak.models.cache;
import org.keycloak.migration.MigrationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
@ -45,6 +46,12 @@ public class DefaultCacheRealmProvider implements CacheRealmProvider {
session.getTransaction().enlistAfterCompletion(getTransaction());
}
@Override
public MigrationModel getMigrationModel() {
return getDelegate().getMigrationModel();
}
@Override
public boolean isEnabled() {
return cache.isEnabled();

View file

@ -1,5 +1,6 @@
package org.keycloak.models.cache;
import org.keycloak.migration.MigrationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@ -49,6 +50,11 @@ public class NoCacheRealmProvider implements CacheRealmProvider {
public void registerRoleInvalidation(String id) {
}
@Override
public MigrationModel getMigrationModel() {
return getDelegate().getMigrationModel();
}
@Override
public RealmModel createRealm(String name) {
return getDelegate().createRealm(name);

View file

@ -1,5 +1,6 @@
package org.keycloak.models.jpa;
import org.keycloak.migration.MigrationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@ -30,6 +31,11 @@ public class JpaRealmProvider implements RealmProvider {
this.em = em;
}
@Override
public MigrationModel getMigrationModel() {
return new MigrationModelAdapter(em);
}
@Override
public RealmModel createRealm(String name) {
return createRealm(KeycloakModelUtils.generateId(), name);

View file

@ -0,0 +1,42 @@
package org.keycloak.models.jpa;
import org.keycloak.migration.MigrationModel;
import org.keycloak.models.jpa.entities.MigrationModelEntity;
import org.keycloak.util.Time;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MigrationModelAdapter implements MigrationModel {
protected EntityManager em;
public MigrationModelAdapter(EntityManager em) {
this.em = em;
}
@Override
public String getStoredVersion() {
MigrationModelEntity entity = em.find(MigrationModelEntity.class, MigrationModelEntity.SINGLETON_ID);
if (entity == null) return null;
return entity.getVersion();
}
@Override
public void setStoredVersion(String version) {
MigrationModelEntity entity = em.find(MigrationModelEntity.class, MigrationModelEntity.SINGLETON_ID);
if (entity == null) {
entity = new MigrationModelEntity();
entity.setId(MigrationModelEntity.SINGLETON_ID);
entity.setVersion(version);
em.persist(entity);
} else {
entity.setVersion(version);
em.flush();
}
}
}

View file

@ -0,0 +1,43 @@
package org.keycloak.models.jpa.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Table(name="MIGRATION_MODEL")
@Entity
public class MigrationModelEntity {
public static final String SINGLETON_ID = "SINGLETON";
@Id
@Column(name="ID", length = 36)
private String id;
@Column(name="VERSION", length = 36)
protected String version;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}

View file

@ -0,0 +1,57 @@
package org.keycloak.models.mongo.keycloak.adapters;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.migration.MigrationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.entities.ProtocolMapperEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
import org.keycloak.models.mongo.utils.MongoModelUtils;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class MigrationModelAdapter extends AbstractMongoAdapter<MongoMigrationModelEntity> implements MigrationModel {
protected final MongoMigrationModelEntity entity;
public MigrationModelAdapter(KeycloakSession session, MongoMigrationModelEntity entity, MongoStoreInvocationContext invContext) {
super(invContext);
this.entity = entity;
}
@Override
public MongoMigrationModelEntity getMongoEntity() {
return entity;
}
@Override
public String getStoredVersion() {
return getMongoEntity().getVersion();
}
@Override
public void setStoredVersion(String version) {
getMongoEntity().setVersion(version);
updateMongoEntity();
}
}

View file

@ -5,12 +5,14 @@ import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import org.keycloak.connections.mongo.api.MongoStore;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.migration.MigrationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleModel;
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
@ -36,6 +38,16 @@ public class MongoRealmProvider implements RealmProvider {
// TODO
}
@Override
public MigrationModel getMigrationModel() {
MongoMigrationModelEntity entity = getMongoStore().loadEntity(MongoMigrationModelEntity.class, MongoMigrationModelEntity.MIGRATION_MODEL_ID, invocationContext);
if (entity == null) {
entity = new MongoMigrationModelEntity();
getMongoStore().insertEntity(entity, invocationContext);
}
return new MigrationModelAdapter(session, entity, invocationContext);
}
@Override
public RealmModel createRealm(String name) {
return createRealm(KeycloakModelUtils.generateId(), name);

View file

@ -0,0 +1,38 @@
package org.keycloak.models.mongo.keycloak.entities;
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MongoMigrationModelEntity implements MongoIdentifiableEntity {
public static final String MIGRATION_MODEL_ID = "VERSION";
private String id = MIGRATION_MODEL_ID;
private String version;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String getId() {
return id;
}
@Override
public void setId(String id) {
this.id = id;
}
@Override
public void afterRemove(MongoStoreInvocationContext invocationContext) {
}
}

View file

@ -21,7 +21,6 @@ import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.resources.IdentityBrokerService;
import org.keycloak.timer.TimerProvider;
import java.util.Collections;
@ -226,7 +225,7 @@ public class RealmManager {
client.setEnabled(true);
client.setFullScopeAllowed(false);
for (String role : IdentityBrokerService.ROLES) {
for (String role : Constants.BROKER_SERVICE_ROLES) {
client.addRole(role).setDescription("${role_"+role+"}");
}
}

View file

@ -44,7 +44,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.ProtocolMapper;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.AccessToken;
@ -60,17 +59,13 @@ import org.keycloak.services.validation.Validation;
import org.keycloak.social.SocialIdentityProvider;
import org.keycloak.util.ObjectUtil;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
@ -95,8 +90,6 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
private static final Logger LOGGER = Logger.getLogger(IdentityBrokerService.class);
public static final String BROKER_PROVIDER_ID = "BROKER_PROVIDER_ID";
public static final String READ_TOKEN_ROLE = "READ_TOKEN";
public static final String[] ROLES = {READ_TOKEN_ROLE};
private final RealmModel realmModel;
@ -207,7 +200,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
}
Map<String, AccessToken.Access> resourceAccess = token.getResourceAccess();
AccessToken.Access brokerRoles = resourceAccess == null ? null : resourceAccess.get(Constants.BROKER_SERVICE_CLIENT_ID);
if (brokerRoles == null || !brokerRoles.isUserInRole(READ_TOKEN_ROLE)) {
if (brokerRoles == null || !brokerRoles.isUserInRole(Constants.READ_TOKEN_ROLE)) {
return corsResponse(forbidden("Client [" + audience + "] not authorized to retrieve tokens from identity provider [" + providerId + "]."), clientModel);
}
@ -536,7 +529,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
if (context.getIdpConfig().isAddReadTokenRoleOnCreate()) {
RoleModel readTokenRole = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(READ_TOKEN_ROLE);
RoleModel readTokenRole = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
federatedUser.grantRole(readTokenRole);
}

View file

@ -8,6 +8,7 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.Config;
import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.exportimport.ExportImportManager;
import org.keycloak.migration.MigrationModelManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
@ -84,9 +85,26 @@ public class KeycloakApplication extends Application {
setupDefaultRealm(context.getContextPath());
importRealms(context);
migrateModel();
setupScheduledTasks(sessionFactory);
}
protected void migrateModel() {
KeycloakSession session = sessionFactory.create();
try {
session.getTransaction().begin();
MigrationModelManager.migrate(session);
session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback();
log.error("Failed to migrate datamodel", e);
} finally {
session.close();
}
}
public String getContextPath() {
return contextPath;
}

View file

@ -32,7 +32,9 @@ import org.keycloak.account.freemarker.model.ApplicationsBean;
import org.keycloak.events.Details;
import org.keycloak.events.Event;
import org.keycloak.events.EventType;
import org.keycloak.migration.MigrationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
@ -168,6 +170,15 @@ public class AccountTest {
Thread.sleep(100000000);
}
@Test
public void testMigrationModel() {
KeycloakSession keycloakSession = keycloakRule.startSession();
Assert.assertEquals(keycloakSession.realms().getMigrationModel().getStoredVersion(), MigrationModel.LATEST_VERSION);
keycloakSession.close();
}
@Test
public void returnToAppFromQueryParam() {
driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app");

View file

@ -17,11 +17,6 @@
*/
package org.keycloak.testsuite.broker;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.After;
import org.junit.Assert;
@ -29,7 +24,6 @@ import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.FederatedIdentityModel;
@ -41,9 +35,7 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.UserModel.RequiredAction;
import org.keycloak.representations.IDToken;
import org.keycloak.services.Urls;
import org.keycloak.services.resources.IdentityBrokerService;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
import org.keycloak.testsuite.broker.util.UserSessionStatusServlet.UserSessionStatus;
import org.keycloak.testsuite.pages.AccountFederatedIdentityPage;
import org.keycloak.testsuite.pages.AccountPasswordPage;
@ -68,7 +60,6 @@ import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@ -423,7 +414,7 @@ public abstract class AbstractIdentityProviderTest {
protected void configureClientRetrieveToken(String clientId) {
RealmModel realm = getRealm();
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
ClientModel client = realm.getClientByClientId(clientId);
if (!client.hasScope(readTokenRole)) client.addScopeMapping(readTokenRole);
@ -435,7 +426,7 @@ public abstract class AbstractIdentityProviderTest {
protected void configureUserRetrieveToken(String username) {
RealmModel realm = getRealm();
UserModel user = session.users().getUserByUsername(username, realm);
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
if (user != null && !user.hasRole(readTokenRole)) {
user.grantRole(readTokenRole);
}
@ -446,7 +437,7 @@ public abstract class AbstractIdentityProviderTest {
protected void unconfigureClientRetrieveToken(String clientId) {
RealmModel realm = getRealm();
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
ClientModel client = realm.getClientByClientId(clientId);
if (client.hasScope(readTokenRole)) client.deleteScopeMapping(readTokenRole);
@ -458,7 +449,7 @@ public abstract class AbstractIdentityProviderTest {
protected void unconfigureUserRetrieveToken(String username) {
RealmModel realm = getRealm();
UserModel user = session.users().getUserByUsername(username, realm);
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(IdentityBrokerService.READ_TOKEN_ROLE);
RoleModel readTokenRole = realm.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(Constants.READ_TOKEN_ROLE);
if (user != null && user.hasRole(readTokenRole)) {
user.deleteRoleMapping(readTokenRole);
}