Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
f64d84b03a
23 changed files with 525 additions and 23 deletions
|
@ -25,6 +25,11 @@
|
|||
<artifactId>keycloak-model-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-events-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
package org.keycloak.broker.provider;
|
||||
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
|
@ -50,7 +51,7 @@ public abstract class AbstractIdentityProvider<C extends IdentityProviderModel>
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback) {
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback, EventBuilder event) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
package org.keycloak.broker.provider;
|
||||
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -51,7 +52,7 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
|
|||
*
|
||||
* @return
|
||||
*/
|
||||
Object callback(RealmModel realm, AuthenticationCallback callback);
|
||||
Object callback(RealmModel realm, AuthenticationCallback callback, EventBuilder event);
|
||||
|
||||
/**
|
||||
* <p>Initiates the authentication process by sending an authentication request to an identity provider. This method is called
|
||||
|
|
|
@ -19,7 +19,7 @@ package org.keycloak.broker.oidc;
|
|||
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.ClientConnection;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.broker.oidc.util.SimpleHttp;
|
||||
|
@ -34,7 +34,6 @@ import org.keycloak.models.FederatedIdentityModel;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.services.managers.EventsManager;
|
||||
import org.keycloak.services.messages.Messages;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
@ -85,8 +84,8 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback) {
|
||||
return new Endpoint(callback, realm);
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback, EventBuilder event) {
|
||||
return new Endpoint(callback, realm, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -171,6 +170,7 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
|
|||
protected class Endpoint {
|
||||
protected AuthenticationCallback callback;
|
||||
protected RealmModel realm;
|
||||
protected EventBuilder event;
|
||||
|
||||
@Context
|
||||
protected KeycloakSession session;
|
||||
|
@ -184,17 +184,16 @@ public abstract class AbstractOAuth2IdentityProvider<C extends OAuth2IdentityPro
|
|||
@Context
|
||||
protected UriInfo uriInfo;
|
||||
|
||||
public Endpoint(AuthenticationCallback callback, RealmModel realm) {
|
||||
public Endpoint(AuthenticationCallback callback, RealmModel realm, EventBuilder event) {
|
||||
this.callback = callback;
|
||||
this.realm = realm;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@GET
|
||||
public Response authResponse(@QueryParam(AbstractOAuth2IdentityProvider.OAUTH2_PARAMETER_STATE) String state,
|
||||
@QueryParam(AbstractOAuth2IdentityProvider.OAUTH2_PARAMETER_CODE) String authorizationCode,
|
||||
@QueryParam(OAuth2Constants.ERROR) String error) {
|
||||
|
||||
EventBuilder event = new EventsManager(realm, session, clientConnection).createEventBuilder();
|
||||
if (error != null) {
|
||||
//logger.error("Failed " + getConfig().getAlias() + " broker login: " + error);
|
||||
event.event(EventType.LOGIN);
|
||||
|
|
|
@ -78,13 +78,13 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback) {
|
||||
return new OIDCEndpoint(callback, realm);
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback, EventBuilder event) {
|
||||
return new OIDCEndpoint(callback, realm, event);
|
||||
}
|
||||
|
||||
protected class OIDCEndpoint extends Endpoint {
|
||||
public OIDCEndpoint(AuthenticationCallback callback, RealmModel realm) {
|
||||
super(callback, realm);
|
||||
public OIDCEndpoint(AuthenticationCallback callback, RealmModel realm, EventBuilder event) {
|
||||
super(callback, realm, event);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.broker.saml;
|
|||
import org.keycloak.broker.provider.AbstractIdentityProvider;
|
||||
import org.keycloak.broker.provider.AuthenticationRequest;
|
||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
|
@ -45,7 +46,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback) {
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback, EventBuilder event) {
|
||||
return new SAMLEndpoint(realm, getConfig(), callback);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@
|
|||
<artifactId>keycloak-connections-jpa</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.liquibase</groupId>
|
||||
<artifactId>liquibase-core</artifactId>
|
||||
|
@ -33,6 +38,7 @@
|
|||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -28,6 +28,7 @@ import liquibase.resource.ClassLoaderResourceAccessor;
|
|||
import liquibase.servicelocator.ServiceLocator;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
|
@ -50,9 +51,12 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void update(Connection connection) {
|
||||
public void update(KeycloakSession session, Connection connection) {
|
||||
logger.debug("Starting database update");
|
||||
|
||||
// Need ThreadLocal as liquibase doesn't seem to have API to inject custom objects into tasks
|
||||
ThreadLocalSessionContext.setCurrentSession(session);
|
||||
|
||||
try {
|
||||
Liquibase liquibase = getLiquibase(connection);
|
||||
|
||||
|
@ -81,7 +85,10 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to update database", e);
|
||||
} finally {
|
||||
ThreadLocalSessionContext.removeCurrentSession();
|
||||
}
|
||||
|
||||
logger.debug("Completed database update");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package org.keycloak.connections.jpa.updater.liquibase;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ThreadLocalSessionContext {
|
||||
|
||||
private static final ThreadLocal<KeycloakSession> currentSession = new ThreadLocal<KeycloakSession>();
|
||||
|
||||
public static KeycloakSession getCurrentSession() {
|
||||
return currentSession.get();
|
||||
}
|
||||
|
||||
public static void setCurrentSession(KeycloakSession session) {
|
||||
currentSession.set(session);
|
||||
}
|
||||
|
||||
public static void removeCurrentSession() {
|
||||
currentSession.remove();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package org.keycloak.connections.jpa.updater.liquibase.custom;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import liquibase.change.custom.CustomSqlChange;
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.exception.CustomChangeException;
|
||||
import liquibase.exception.SetupException;
|
||||
import liquibase.exception.ValidationErrors;
|
||||
import liquibase.resource.ResourceAccessor;
|
||||
import liquibase.snapshot.SnapshotGeneratorFactory;
|
||||
import liquibase.statement.SqlStatement;
|
||||
import liquibase.structure.core.Table;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.ThreadLocalSessionContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class CustomKeycloakTask implements CustomSqlChange {
|
||||
|
||||
protected KeycloakSession kcSession;
|
||||
|
||||
protected Database database;
|
||||
protected JdbcConnection jdbcConnection;
|
||||
protected Connection connection;
|
||||
protected StringBuilder confirmationMessage = new StringBuilder();
|
||||
protected List<SqlStatement> statements = new ArrayList<SqlStatement>();
|
||||
|
||||
@Override
|
||||
public ValidationErrors validate(Database database) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFileOpener(ResourceAccessor resourceAccessor) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfirmationMessage() {
|
||||
return confirmationMessage.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws SetupException {
|
||||
this.kcSession = ThreadLocalSessionContext.getCurrentSession();
|
||||
if (this.kcSession == null) {
|
||||
throw new SetupException("No KeycloakSession provided in ThreadLocal");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlStatement[] generateStatements(Database database) throws CustomChangeException {
|
||||
this.database = database;
|
||||
jdbcConnection = (JdbcConnection) database.getConnection();
|
||||
connection = jdbcConnection.getWrappedConnection();
|
||||
|
||||
if (isApplicable()) {
|
||||
confirmationMessage.append(getTaskId() + ": ");
|
||||
generateStatementsImpl();
|
||||
} else {
|
||||
confirmationMessage.append(getTaskId() + ": no update applicable for this task");
|
||||
}
|
||||
|
||||
return statements.toArray(new SqlStatement[statements.size()]);
|
||||
}
|
||||
|
||||
protected boolean isApplicable() throws CustomChangeException {
|
||||
try {
|
||||
String correctedTableName = database.correctObjectName("REALM", Table.class);
|
||||
if (SnapshotGeneratorFactory.getInstance().has(new Table().setName(correctedTableName), database)) {
|
||||
ResultSet resultSet = connection.createStatement().executeQuery("SELECT ID FROM REALM");
|
||||
try {
|
||||
return (resultSet.next());
|
||||
} finally {
|
||||
resultSet.close();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CustomChangeException("Failed to check database availability", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It's supposed to fill SQL statements to the "statements" variable and fill "confirmationMessage"
|
||||
*/
|
||||
protected abstract void generateStatementsImpl() throws CustomChangeException;
|
||||
|
||||
protected abstract String getTaskId();
|
||||
}
|
|
@ -0,0 +1,337 @@
|
|||
package org.keycloak.connections.jpa.updater.liquibase.custom;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import liquibase.exception.CustomChangeException;
|
||||
import liquibase.exception.DatabaseException;
|
||||
import liquibase.statement.core.InsertStatement;
|
||||
import liquibase.statement.core.UpdateStatement;
|
||||
import liquibase.structure.core.Table;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
import org.keycloak.models.ClaimMask;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.services.util.MigrationUtils;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
||||
|
||||
private String realmTableName;
|
||||
|
||||
@Override
|
||||
protected String getTaskId() {
|
||||
return "Update 1.2.0.Beta1";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateStatementsImpl() throws CustomChangeException {
|
||||
realmTableName = database.correctObjectName("REALM", Table.class);
|
||||
|
||||
try {
|
||||
convertSocialToIdFedRealms();
|
||||
convertSocialToIdFedUsers();
|
||||
addAccessCodeLoginTimeout();
|
||||
addNewAdminRoles();
|
||||
addDefaultProtocolMappers();
|
||||
} catch (Exception e) {
|
||||
throw new CustomChangeException(getTaskId() + ": Exception when updating data from previous version", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void convertSocialToIdFedRealms() throws SQLException, DatabaseException {
|
||||
String identityProviderTableName = database.correctObjectName("IDENTITY_PROVIDER", Table.class);
|
||||
String idpConfigTableName = database.correctObjectName("IDENTITY_PROVIDER_CONFIG", Table.class);
|
||||
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select RSC.NAME, VALUE, REALM_ID, UPDATE_PROFILE_ON_SOC_LOGIN from REALM_SOCIAL_CONFIG RSC,REALM where RSC.REALM_ID = REALM.ID ORDER BY RSC.REALM_ID, RSC.NAME");
|
||||
try {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
boolean providerInProgress = false;
|
||||
String socialProviderId = null;
|
||||
String clientId = null;
|
||||
String clientSecret;
|
||||
String realmId = null;
|
||||
boolean updateProfileOnSocialLogin = false;
|
||||
boolean first = true;
|
||||
|
||||
while (resultSet.next()) {
|
||||
if (first) {
|
||||
confirmationMessage.append("Migrating social to identity providers: ");
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (!providerInProgress) {
|
||||
String key = resultSet.getString("NAME");
|
||||
int keyIndex = key.indexOf(".key");
|
||||
if (keyIndex == -1) {
|
||||
throw new IllegalStateException("Can't parse the provider from column: " + key);
|
||||
}
|
||||
|
||||
socialProviderId = key.substring(0, keyIndex);
|
||||
clientId = resultSet.getString("VALUE");
|
||||
realmId = resultSet.getString("REALM_ID");
|
||||
updateProfileOnSocialLogin = resultSet.getBoolean("UPDATE_PROFILE_ON_SOC_LOGIN");
|
||||
providerInProgress = true;
|
||||
} else {
|
||||
clientSecret = resultSet.getString("VALUE");
|
||||
|
||||
String internalId = KeycloakModelUtils.generateId();
|
||||
InsertStatement idpInsert = new InsertStatement(null, null, identityProviderTableName)
|
||||
.addColumnValue("INTERNAL_ID", internalId)
|
||||
.addColumnValue("ENABLED", true)
|
||||
.addColumnValue("PROVIDER_ALIAS", socialProviderId)
|
||||
.addColumnValue("PROVIDER_ID", socialProviderId)
|
||||
.addColumnValue("UPDATE_PROFILE_FIRST_LOGIN", updateProfileOnSocialLogin)
|
||||
.addColumnValue("STORE_TOKEN", false)
|
||||
.addColumnValue("AUTHENTICATE_BY_DEFAULT", false)
|
||||
.addColumnValue("REALM_ID", realmId);
|
||||
InsertStatement clientIdInsert = new InsertStatement(null, null, idpConfigTableName)
|
||||
.addColumnValue("IDENTITY_PROVIDER_ID", internalId)
|
||||
.addColumnValue("NAME", "clientId")
|
||||
.addColumnValue("VALUE", clientId);
|
||||
InsertStatement clientSecretInsert = new InsertStatement(null, null, idpConfigTableName)
|
||||
.addColumnValue("IDENTITY_PROVIDER_ID", internalId)
|
||||
.addColumnValue("NAME", "clientSecret")
|
||||
.addColumnValue("VALUE", clientSecret);
|
||||
|
||||
statements.add(idpInsert);
|
||||
statements.add(clientIdInsert);
|
||||
statements.add(clientSecretInsert);
|
||||
confirmationMessage.append(socialProviderId + " in realm " + realmId + ", ");
|
||||
|
||||
providerInProgress = false;
|
||||
}
|
||||
}
|
||||
|
||||
// It means that some provider where processed
|
||||
if (!first) {
|
||||
confirmationMessage.append(". ");
|
||||
}
|
||||
} finally {
|
||||
resultSet.close();
|
||||
}
|
||||
} finally {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void convertSocialToIdFedUsers() throws SQLException, DatabaseException {
|
||||
String federatedIdentityTableName = database.correctObjectName("FEDERATED_IDENTITY", Table.class);
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select REALM_ID, USER_ID, SOCIAL_PROVIDER, SOCIAL_USER_ID, SOCIAL_USERNAME from USER_SOCIAL_LINK");
|
||||
try {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
int count = 0;
|
||||
while (resultSet.next()) {
|
||||
InsertStatement insert = new InsertStatement(null, null, federatedIdentityTableName)
|
||||
.addColumnValue("REALM_ID", resultSet.getString("REALM_ID"))
|
||||
.addColumnValue("USER_ID", resultSet.getString("USER_ID"))
|
||||
.addColumnValue("IDENTITY_PROVIDER", resultSet.getString("SOCIAL_PROVIDER"))
|
||||
.addColumnValue("FEDERATED_USER_ID", resultSet.getString("SOCIAL_USER_ID"))
|
||||
.addColumnValue("FEDERATED_USERNAME", resultSet.getString("SOCIAL_USERNAME"));
|
||||
count++;
|
||||
statements.add(insert);
|
||||
}
|
||||
|
||||
confirmationMessage.append("Updating " + count + " social links to federated identities. ");
|
||||
} finally {
|
||||
resultSet.close();
|
||||
}
|
||||
} finally {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void addAccessCodeLoginTimeout() {
|
||||
UpdateStatement statement = new UpdateStatement(null, null, realmTableName)
|
||||
.addNewColumnValue("LOGIN_LIFESPAN", 1800)
|
||||
.setWhereClause("LOGIN_LIFESPAN IS NULL");
|
||||
statements.add(statement);
|
||||
|
||||
confirmationMessage.append("Updated LOGIN_LIFESPAN of all realms to 1800 seconds. ");
|
||||
}
|
||||
|
||||
private void addNewAdminRoles() throws SQLException, DatabaseException{
|
||||
addNewMasterAdminRoles();
|
||||
addNewRealmAdminRoles();
|
||||
|
||||
confirmationMessage.append("Adding new admin roles. ");
|
||||
}
|
||||
|
||||
protected void addNewMasterAdminRoles() throws SQLException, DatabaseException {
|
||||
// Retrieve ID of admin role of master realm
|
||||
String adminRoleId = getAdminRoleId();
|
||||
String masterRealmId = Config.getAdminRealm();
|
||||
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select NAME from REALM");
|
||||
try {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
while (resultSet.next()) {
|
||||
String realmName = resultSet.getString("NAME");
|
||||
String masterAdminAppName = realmName + "-realm";
|
||||
|
||||
PreparedStatement statement2 = jdbcConnection.prepareStatement("select ID from CLIENT where REALM_ID = ? AND NAME = ?");
|
||||
statement2.setString(1, masterRealmId);
|
||||
statement2.setString(2, masterAdminAppName);
|
||||
|
||||
try {
|
||||
ResultSet resultSet2 = statement2.executeQuery();
|
||||
try {
|
||||
if (resultSet2.next()) {
|
||||
String masterAdminAppId = resultSet2.getString("ID");
|
||||
|
||||
addAdminRole(AdminRoles.VIEW_IDENTITY_PROVIDERS, masterRealmId, masterAdminAppId, adminRoleId);
|
||||
addAdminRole(AdminRoles.MANAGE_IDENTITY_PROVIDERS, masterRealmId, masterAdminAppId, adminRoleId);
|
||||
} else {
|
||||
throw new IllegalStateException("Couldn't find ID of '" + masterAdminAppName + "' application in 'master' realm. ");
|
||||
}
|
||||
} finally {
|
||||
resultSet2.close();
|
||||
}
|
||||
} finally {
|
||||
statement2.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
resultSet.close();
|
||||
}
|
||||
} finally {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
|
||||
private String getAdminRoleId() throws SQLException, DatabaseException {
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select ID from KEYCLOAK_ROLE where NAME = ? AND REALM = ?");
|
||||
statement.setString(1, AdminRoles.ADMIN);
|
||||
statement.setString(2, Config.getAdminRealm());
|
||||
|
||||
try {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
if (resultSet.next()) {
|
||||
return resultSet.getString("ID");
|
||||
} else {
|
||||
throw new IllegalStateException("Couldn't find ID of 'admin' role in 'master' realm");
|
||||
}
|
||||
} finally {
|
||||
resultSet.close();
|
||||
}
|
||||
} finally {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void addNewRealmAdminRoles() throws SQLException, DatabaseException {
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select CLIENT.ID REALM_ADMIN_APP_ID, CLIENT.REALM_ID REALM_ID, KEYCLOAK_ROLE.ID ADMIN_ROLE_ID from CLIENT,KEYCLOAK_ROLE where KEYCLOAK_ROLE.APPLICATION = CLIENT.ID AND CLIENT.NAME = 'realm-management' AND KEYCLOAK_ROLE.NAME = ?");
|
||||
statement.setString(1, AdminRoles.REALM_ADMIN);
|
||||
|
||||
try {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
|
||||
while (resultSet.next()) {
|
||||
String realmAdminAppId = resultSet.getString("REALM_ADMIN_APP_ID");
|
||||
String realmId = resultSet.getString("REALM_ID");
|
||||
String adminRoleId = resultSet.getString("ADMIN_ROLE_ID");
|
||||
|
||||
addAdminRole(AdminRoles.VIEW_IDENTITY_PROVIDERS, realmId, realmAdminAppId, adminRoleId);
|
||||
addAdminRole(AdminRoles.MANAGE_IDENTITY_PROVIDERS, realmId, realmAdminAppId, adminRoleId);
|
||||
}
|
||||
} finally {
|
||||
resultSet.close();
|
||||
}
|
||||
} finally {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void addAdminRole(String roleName, String realmId, String applicationId, String realmAdminAppRoleId) {
|
||||
String roleTableName = database.correctObjectName("KEYCLOAK_ROLE", Table.class);
|
||||
String compositeRoleTableName = database.correctObjectName("COMPOSITE_ROLE", Table.class);
|
||||
String newRoleId = KeycloakModelUtils.generateId();
|
||||
|
||||
InsertStatement insertRole = new InsertStatement(null, null, roleTableName)
|
||||
.addColumnValue("ID", newRoleId)
|
||||
.addColumnValue("APP_REALM_CONSTRAINT", applicationId)
|
||||
.addColumnValue("APPLICATION_ROLE", true)
|
||||
.addColumnValue("NAME", roleName)
|
||||
.addColumnValue("REALM_ID", realmId)
|
||||
.addColumnValue("APPLICATION", applicationId);
|
||||
|
||||
// Add newly created role to the composite roles of 'realm-admin' role
|
||||
InsertStatement insertCompRole = new InsertStatement(null, null, compositeRoleTableName)
|
||||
.addColumnValue("COMPOSITE", realmAdminAppRoleId)
|
||||
.addColumnValue("CHILD_ROLE", newRoleId);
|
||||
|
||||
statements.add(insertRole);
|
||||
statements.add(insertCompRole);
|
||||
}
|
||||
|
||||
protected void addDefaultProtocolMappers() throws SQLException, DatabaseException {
|
||||
String protocolMapperTableName = database.correctObjectName("PROTOCOL_MAPPER", Table.class);
|
||||
String protocolMapperCfgTableName = database.correctObjectName("PROTOCOL_MAPPER_CONFIG", Table.class);
|
||||
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select ID, NAME, ALLOWED_CLAIMS_MASK from CLIENT");
|
||||
|
||||
try {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
boolean first = true;
|
||||
while (resultSet.next()) {
|
||||
if (first) {
|
||||
confirmationMessage.append("Migrating claimsMask to protocol mappers for clients: ");
|
||||
first = false;
|
||||
}
|
||||
|
||||
Object acmObj = resultSet.getObject("ALLOWED_CLAIMS_MASK");
|
||||
long mask = (acmObj != null) ? (Long) acmObj : ClaimMask.ALL;
|
||||
|
||||
Collection<ProtocolMapperModel> protocolMappers = MigrationUtils.getMappersForClaimMask(this.kcSession, mask);
|
||||
for (ProtocolMapperModel protocolMapper : protocolMappers) {
|
||||
String mapperId = KeycloakModelUtils.generateId();
|
||||
|
||||
InsertStatement insert = new InsertStatement(null, null, protocolMapperTableName)
|
||||
.addColumnValue("ID", mapperId)
|
||||
.addColumnValue("PROTOCOL", protocolMapper.getProtocol())
|
||||
.addColumnValue("NAME", protocolMapper.getName())
|
||||
.addColumnValue("CONSENT_REQUIRED", protocolMapper.isConsentRequired())
|
||||
.addColumnValue("CONSENT_TEXT", protocolMapper.getConsentText())
|
||||
.addColumnValue("PROTOCOL_MAPPER_NAME", protocolMapper.getProtocolMapper())
|
||||
.addColumnValue("CLIENT_ID", resultSet.getString("ID"));
|
||||
statements.add(insert);
|
||||
|
||||
for (Map.Entry<String, String> cfgEntry : protocolMapper.getConfig().entrySet()) {
|
||||
InsertStatement cfgInsert = new InsertStatement(null, null, protocolMapperCfgTableName)
|
||||
.addColumnValue("PROTOCOL_MAPPER_ID", mapperId)
|
||||
.addColumnValue("NAME", cfgEntry.getKey())
|
||||
.addColumnValue("VALUE", cfgEntry.getValue());
|
||||
statements.add(cfgInsert);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
confirmationMessage.append(resultSet.getString("NAME") + ", ");
|
||||
}
|
||||
|
||||
// It means that some provider where processed
|
||||
if (!first) {
|
||||
confirmationMessage.append(". ");
|
||||
}
|
||||
} finally {
|
||||
resultSet.close();
|
||||
}
|
||||
} finally {
|
||||
statement.close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,9 +19,6 @@
|
|||
<column name="PROTOCOL_MAPPER_NAME" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="APPLIED_BY_DEFAULT" type="BOOLEAN" defaultValueBoolean="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="CONSENT_REQUIRED" type="BOOLEAN" defaultValueBoolean="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
|
@ -153,5 +150,15 @@
|
|||
<addForeignKeyConstraint baseColumnNames="APPLICATION_ID" baseTableName="REALM_APPLICATION" constraintName="FK_82S3P0DIUXAWWQQSA528UBY2Q" referencedColumnNames="ID" referencedTableName="CLIENT"/>
|
||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_APPLICATION" constraintName="FK_M6QGA3RFME47335JY8JXYXH3I" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||
|
||||
<customChange class="org.keycloak.connections.jpa.updater.liquibase.custom.JpaUpdate1_2_0_Beta1"/>
|
||||
|
||||
<!-- Remove obsolete 'social' stuff -->
|
||||
<dropForeignKeyConstraint baseTableName="USER_SOCIAL_LINK" constraintName="FK_68CJYS5UWM55UY823Y75XG4OM" />
|
||||
<dropPrimaryKey tableName="USER_SOCIAL_LINK" constraintName="CONSTRAINT_3" />
|
||||
<dropTable tableName="USER_SOCIAL_LINK" />
|
||||
<dropForeignKeyConstraint baseTableName="REALM_SOCIAL_CONFIG" constraintName="FK_SV5I3C2TI7G0G922FGE683SOV" />
|
||||
<dropPrimaryKey tableName="REALM_SOCIAL_CONFIG" constraintName="CONSTRAINT_1" />
|
||||
<dropTable tableName="REALM_SOCIAL_CONFIG" />
|
||||
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
|
|
|
@ -140,7 +140,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||
}
|
||||
|
||||
if (currentVersion == null || !JpaUpdaterProvider.LAST_VERSION.equals(currentVersion)) {
|
||||
updater.update(connection);
|
||||
updater.update(session, connection);
|
||||
} else {
|
||||
logger.debug("Database is up to date");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.keycloak.connections.jpa.updater;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
@ -15,7 +16,7 @@ public interface JpaUpdaterProvider extends Provider {
|
|||
|
||||
public String getCurrentVersionSql();
|
||||
|
||||
public void update(Connection connection);
|
||||
public void update(KeycloakSession session, Connection connection);
|
||||
|
||||
public void validate(Connection connection);
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-core"/>
|
||||
<module name="org.keycloak.keycloak-model-api"/>
|
||||
<module name="org.keycloak.keycloak-events-api"/>
|
||||
<module name="javax.ws.rs.api"/>
|
||||
<module name="org.jboss.logging"/>
|
||||
</dependencies>
|
||||
|
||||
</module>
|
||||
|
|
|
@ -9,10 +9,13 @@
|
|||
<dependencies>
|
||||
<module name="org.keycloak.keycloak-core"/>
|
||||
<module name="org.keycloak.keycloak-model-api"/>
|
||||
<module name="org.keycloak.keycloak-events-api"/>
|
||||
<module name="org.keycloak.keycloak-broker-core"/>
|
||||
<module name="org.keycloak.keycloak-services"/>
|
||||
<module name="org.codehaus.jackson.jackson-core-asl"/>
|
||||
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
|
||||
<module name="org.codehaus.jackson.jackson-xc"/>
|
||||
<module name="org.jboss.logging"/>
|
||||
<module name="javax.ws.rs.api"/>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
<module name="javax.api" />
|
||||
<module name="org.keycloak.keycloak-core"/>
|
||||
<module name="org.keycloak.keycloak-model-api"/>
|
||||
<module name="org.keycloak.keycloak-events-api"/>
|
||||
<module name="org.keycloak.keycloak-broker-core"/>
|
||||
<module name="org.keycloak.keycloak-saml-protocol"/>
|
||||
<module name="org.picketlink.common"/>
|
||||
<module name="org.picketlink.federation"/>
|
||||
<module name="org.jboss.logging"/>
|
||||
<module name="javax.ws.rs.api"/>
|
||||
<module name="org.jboss.resteasy.resteasy-jaxrs"/>
|
||||
</dependencies>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<module name="org.keycloak.keycloak-core"/>
|
||||
<module name="org.keycloak.keycloak-model-api"/>
|
||||
<module name="org.keycloak.keycloak-connections-jpa"/>
|
||||
<module name="org.keycloak.keycloak-services"/>
|
||||
<module name="org.liquibase"/>
|
||||
<module name="javax.persistence.api"/>
|
||||
<module name="org.jboss.logging"/>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<module name="org.keycloak.keycloak-broker-core"/>
|
||||
<module name="org.keycloak.keycloak-broker-oidc"/>
|
||||
<module name="org.keycloak.keycloak-model-api"/>
|
||||
<module name="org.keycloak.keycloak-services"/>
|
||||
<module name="org.twitter4j"/>
|
||||
<module name="org.jboss.logging"/>
|
||||
<module name="javax.api"/>
|
||||
|
|
|
@ -145,7 +145,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
@Path("{provider_id}/endpoint")
|
||||
public Object getEndpoint(@PathParam("provider_id") String providerId) {
|
||||
IdentityProvider identityProvider = getIdentityProvider(session, realmModel, providerId);
|
||||
Object callback = identityProvider.callback(realmModel, this);
|
||||
Object callback = identityProvider.callback(realmModel, this, event);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(callback);
|
||||
//resourceContext.initResource(brokerService);
|
||||
return callback;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.keycloak.services.scheduled;
|
||||
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ public class TwitterIdentityProvider extends AbstractIdentityProvider<OAuth2Iden
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback) {
|
||||
public Object callback(RealmModel realm, AuthenticationCallback callback, EventBuilder event) {
|
||||
return new Endpoint(realm, callback);
|
||||
}
|
||||
|
||||
|
|
|
@ -134,6 +134,14 @@ public class KeycloakServer {
|
|||
}
|
||||
}
|
||||
|
||||
if (System.getProperty("keycloak.port") != null) {
|
||||
config.setPort(Integer.valueOf(System.getProperty("keycloak.port")));
|
||||
}
|
||||
|
||||
if (System.getProperty("keycloak.bind.address") != null) {
|
||||
config.setHost(System.getProperty("keycloak.bind.address"));
|
||||
}
|
||||
|
||||
if (System.getenv("KEYCLOAK_DEV_PORT") != null) {
|
||||
config.setPort(Integer.valueOf(System.getenv("KEYCLOAK_DEV_PORT")));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue