ldap jpa migration
This commit is contained in:
parent
94076a3b24
commit
8a5f817030
19 changed files with 1419 additions and 52 deletions
4
dependencies/server-all/pom.xml
vendored
4
dependencies/server-all/pom.xml
vendored
|
@ -67,6 +67,10 @@
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-ldap-federation</artifactId>
|
<artifactId>keycloak-ldap-federation</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-ldap-storage</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-kerberos-federation</artifactId>
|
<artifactId>keycloak-kerberos-federation</artifactId>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<artifact name="${org.keycloak:keycloak-ldap-federation}"/>
|
<artifact name="${org.keycloak:keycloak-ldap-storage}"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
|
@ -1341,6 +1341,13 @@ public class RealmAdapter implements CachedRealmModel {
|
||||||
return updated.addComponentModel(model);
|
return updated.addComponentModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentModel importComponentModel(ComponentModel model) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
evictUsers(model);
|
||||||
|
return updated.importComponentModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
public void evictUsers(ComponentModel model) {
|
public void evictUsers(ComponentModel model) {
|
||||||
String parentId = model.getParentId();
|
String parentId = model.getParentId();
|
||||||
evictUsers(parentId);
|
evictUsers(parentId);
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 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.InsertStatement;
|
||||||
|
import liquibase.structure.core.Table;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public abstract class AbstractUserFedToComponent extends CustomKeycloakTask {
|
||||||
|
private final Logger logger = Logger.getLogger(getClass());
|
||||||
|
protected void convertFedProviderToComponent(String providerId, String newMapperType) throws CustomChangeException {
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = jdbcConnection.prepareStatement("select ID, REALM_ID, PRIORITY, DISPLAY_NAME, FULL_SYNC_PERIOD, CHANGED_SYNC_PERIOD, LAST_SYNC from " + getTableName("USER_FEDERATION_PROVIDER") + " WHERE PROVIDER_NAME='" + providerId + "'");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ResultSet resultSet = statement.executeQuery();
|
||||||
|
try {
|
||||||
|
while (resultSet.next()) {
|
||||||
|
int index = 1;
|
||||||
|
String id = resultSet.getString(index++);
|
||||||
|
String realmId = resultSet.getString(index++);
|
||||||
|
int priority = resultSet.getInt(index++);
|
||||||
|
String displayName = resultSet.getString(index++);
|
||||||
|
int fullSyncPeriod = resultSet.getInt(index++);
|
||||||
|
int changedSyncPeriod = resultSet.getInt(index++);
|
||||||
|
int lastSync = resultSet.getInt(index++);
|
||||||
|
|
||||||
|
|
||||||
|
InsertStatement insertComponent = new InsertStatement(null, null, database.correctObjectName("COMPONENT", Table.class))
|
||||||
|
.addColumnValue("ID", id)
|
||||||
|
.addColumnValue("REALM_ID", realmId)
|
||||||
|
.addColumnValue("PARENT_ID", realmId)
|
||||||
|
.addColumnValue("NAME", displayName)
|
||||||
|
.addColumnValue("PROVIDER_ID", LDAPConstants.LDAP_PROVIDER)
|
||||||
|
.addColumnValue("PROVIDER_TYPE", UserStorageProvider.class.getName());
|
||||||
|
|
||||||
|
statements.add(insertComponent);
|
||||||
|
|
||||||
|
statements.add(componentConfigStatement(id, "priority", Integer.toString(priority)));
|
||||||
|
statements.add(componentConfigStatement(id, "fullSyncPeriod", Integer.toString(fullSyncPeriod)));
|
||||||
|
statements.add(componentConfigStatement(id, "changedSyncPeriod", Integer.toString(changedSyncPeriod)));
|
||||||
|
statements.add(componentConfigStatement(id, "lastSync", Integer.toString(lastSync)));
|
||||||
|
PreparedStatement configStatement = jdbcConnection.prepareStatement("select name, VALUE from " + getTableName("USER_FEDERATION_CONFIG") + " WHERE USER_FEDERATION_PROVIDER_ID=?");
|
||||||
|
configStatement.setString(1, id);
|
||||||
|
try {
|
||||||
|
ResultSet configSet = configStatement.executeQuery();
|
||||||
|
try {
|
||||||
|
while (configSet.next()) {
|
||||||
|
String name = configSet.getString(1);
|
||||||
|
String value = configSet.getString(2);
|
||||||
|
//logger.info("adding component config: " + name + ": " + value);
|
||||||
|
statements.add(componentConfigStatement(id, name, value));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
configSet.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
configStatement.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newMapperType != null) {
|
||||||
|
convertFedMapperToComponent(realmId, id, newMapperType);
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteStatement configDelete = new DeleteStatement(null, null, database.correctObjectName("USER_FEDERATION_CONFIG", Table.class));
|
||||||
|
configDelete.setWhere("USER_FEDERATION_PROVIDER_ID='" + id + "'");
|
||||||
|
statements.add(configDelete);
|
||||||
|
DeleteStatement deleteStatement = new DeleteStatement(null, null, database.correctObjectName("USER_FEDERATION_PROVIDER", Table.class));
|
||||||
|
deleteStatement.setWhere("ID='" + id + "'");
|
||||||
|
statements.add(deleteStatement);
|
||||||
|
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
resultSet.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
statement.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmationMessage.append("Updated " + statements.size() + " records in USER_FEDERATION_PROVIDER table for " + providerId + " conversion to component model");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CustomChangeException(getTaskId() + ": Exception when updating data from previous version", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InsertStatement componentConfigStatement(String componentId, String name, String value) {
|
||||||
|
return new InsertStatement(null, null, database.correctObjectName("COMPONENT_CONFIG", Table.class))
|
||||||
|
.addColumnValue("ID", KeycloakModelUtils.generateId())
|
||||||
|
.addColumnValue("COMPONENT_ID", componentId)
|
||||||
|
.addColumnValue("NAME", name)
|
||||||
|
.addColumnValue("VALUE", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void convertFedMapperToComponent(String realmId, String parentId, String newMapperType) throws CustomChangeException {
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = jdbcConnection.prepareStatement("select ID, NAME, FEDERATION_MAPPER_TYPE from " + getTableName("USER_FEDERATION_MAPPER") + " WHERE FEDERATION_PROVIDER_ID='" + parentId + "'");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ResultSet resultSet = statement.executeQuery();
|
||||||
|
try {
|
||||||
|
while (resultSet.next()) {
|
||||||
|
String id = resultSet.getString(1);
|
||||||
|
String mapperName = resultSet.getString(2);
|
||||||
|
String fedMapperType = resultSet.getString(3);
|
||||||
|
|
||||||
|
InsertStatement insertComponent = new InsertStatement(null, null, database.correctObjectName("COMPONENT", Table.class))
|
||||||
|
.addColumnValue("ID", id)
|
||||||
|
.addColumnValue("REALM_ID", realmId)
|
||||||
|
.addColumnValue("PARENT_ID", parentId)
|
||||||
|
.addColumnValue("NAME", mapperName)
|
||||||
|
.addColumnValue("PROVIDER_ID", fedMapperType)
|
||||||
|
.addColumnValue("PROVIDER_TYPE", newMapperType);
|
||||||
|
|
||||||
|
statements.add(insertComponent);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PreparedStatement configStatement = jdbcConnection.prepareStatement("select name, VALUE from " + getTableName("USER_FEDERATION_MAPPER_CONFIG") + " WHERE USER_FEDERATION_MAPPER_ID=?");
|
||||||
|
configStatement.setString(1, id);
|
||||||
|
try {
|
||||||
|
ResultSet configSet = configStatement.executeQuery();
|
||||||
|
try {
|
||||||
|
while (configSet.next()) {
|
||||||
|
String name = configSet.getString(1);
|
||||||
|
String value = configSet.getString(2);
|
||||||
|
statements.add(componentConfigStatement(id, name, value));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
configSet.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
configStatement.close();
|
||||||
|
}
|
||||||
|
DeleteStatement configDelete = new DeleteStatement(null, null, database.correctObjectName("USER_FEDERATION_MAPPER_CONFIG", Table.class));
|
||||||
|
configDelete.setWhere("USER_FEDERATION_MAPPER_ID='" + id + "'");
|
||||||
|
statements.add(configDelete);
|
||||||
|
DeleteStatement deleteStatement = new DeleteStatement(null, null, database.correctObjectName("USER_FEDERATION_MAPPER", Table.class));
|
||||||
|
deleteStatement.setWhere("ID='" + id + "'");
|
||||||
|
statements.add(deleteStatement);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
resultSet.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
statement.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmationMessage.append("Updated " + statements.size() + " records in USER_FEDERATION_MAPPER table for " + parentId + " conversion to component model");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CustomChangeException(getTaskId() + ": Exception when updating data from previous version", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 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.InsertStatement;
|
||||||
|
import liquibase.structure.core.Table;
|
||||||
|
import org.keycloak.keys.KeyProvider;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class PortLdapUserFedToComponentModel extends AbstractUserFedToComponent {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateStatementsImpl() throws CustomChangeException {
|
||||||
|
String providerId = LDAPConstants.LDAP_PROVIDER;
|
||||||
|
convertFedProviderToComponent(LDAPConstants.LDAP_PROVIDER, "org.keycloak.storage.ldap.mappers.LDAPStorageMapper");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTaskId() {
|
||||||
|
return "Update 2.4.0.Final";
|
||||||
|
}
|
||||||
|
}
|
|
@ -2031,6 +2031,14 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ComponentModel addComponentModel(ComponentModel model) {
|
public ComponentModel addComponentModel(ComponentModel model) {
|
||||||
|
model = importComponentModel(model);
|
||||||
|
ComponentUtil.notifyCreated(session, this, model);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentModel importComponentModel(ComponentModel model) {
|
||||||
ComponentFactory componentFactory = ComponentUtil.getComponentFactory(session, model);
|
ComponentFactory componentFactory = ComponentUtil.getComponentFactory(session, model);
|
||||||
if (componentFactory == null) {
|
if (componentFactory == null) {
|
||||||
throw new IllegalArgumentException("Invalid component type");
|
throw new IllegalArgumentException("Invalid component type");
|
||||||
|
@ -2057,8 +2065,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
||||||
em.persist(c);
|
em.persist(c);
|
||||||
setConfig(model, c);
|
setConfig(model, c);
|
||||||
model.setId(c.getId());
|
model.setId(c.getId());
|
||||||
ComponentUtil.notifyCreated(session, this, model);
|
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,4 +37,5 @@
|
||||||
<include file="META-INF/jpa-changelog-2.1.0.xml"/>
|
<include file="META-INF/jpa-changelog-2.1.0.xml"/>
|
||||||
<include file="META-INF/jpa-changelog-2.2.0.xml"/>
|
<include file="META-INF/jpa-changelog-2.2.0.xml"/>
|
||||||
<include file="META-INF/jpa-changelog-2.3.0.xml"/>
|
<include file="META-INF/jpa-changelog-2.3.0.xml"/>
|
||||||
|
<include file="META-INF/jpa-changelog-2.4.0.xml"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|
25
model/jpa/src/main/resources/META-INF/jpa-changelog-2.4.0.xml
Executable file
25
model/jpa/src/main/resources/META-INF/jpa-changelog-2.4.0.xml
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2016 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||||
|
|
||||||
|
<changeSet author="bburke@redhat.com" id="2.4.0">
|
||||||
|
<customChange class="org.keycloak.connections.jpa.updater.liquibase.custom.PortLdapUserFedToComponentModel"/>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
|
@ -37,4 +37,5 @@
|
||||||
<include file="META-INF/jpa-changelog-2.1.0.xml"/>
|
<include file="META-INF/jpa-changelog-2.1.0.xml"/>
|
||||||
<include file="META-INF/jpa-changelog-2.2.0.xml"/>
|
<include file="META-INF/jpa-changelog-2.2.0.xml"/>
|
||||||
<include file="META-INF/jpa-changelog-2.3.0.xml"/>
|
<include file="META-INF/jpa-changelog-2.3.0.xml"/>
|
||||||
|
<include file="META-INF/jpa-changelog-2.4.0.xml"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.keycloak.connections.mongo.updater.impl.updates.Update1_7_0;
|
||||||
import org.keycloak.connections.mongo.updater.impl.updates.Update1_8_0;
|
import org.keycloak.connections.mongo.updater.impl.updates.Update1_8_0;
|
||||||
import org.keycloak.connections.mongo.updater.impl.updates.Update1_9_2;
|
import org.keycloak.connections.mongo.updater.impl.updates.Update1_9_2;
|
||||||
import org.keycloak.connections.mongo.updater.impl.updates.Update2_3_0;
|
import org.keycloak.connections.mongo.updater.impl.updates.Update2_3_0;
|
||||||
|
import org.keycloak.connections.mongo.updater.impl.updates.Update2_4_0;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -59,7 +60,8 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
|
||||||
Update1_7_0.class,
|
Update1_7_0.class,
|
||||||
Update1_8_0.class,
|
Update1_8_0.class,
|
||||||
Update1_9_2.class,
|
Update1_9_2.class,
|
||||||
Update2_3_0.class
|
Update2_3_0.class,
|
||||||
|
Update2_4_0.class
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 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.mongo.updater.impl.updates;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBList;
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBCollection;
|
||||||
|
import com.mongodb.DBCursor;
|
||||||
|
import org.keycloak.keys.KeyProvider;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class Update2_4_0 extends Update {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "2.4.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(KeycloakSession session) {
|
||||||
|
portUserFedToComponent(LDAPConstants.LDAP_PROVIDER);
|
||||||
|
portUserFedMappersToComponent(LDAPConstants.LDAP_PROVIDER, "org.keycloak.storage.ldap.mappers.LDAPStorageMapper");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void portUserFedToComponent(String providerId) {
|
||||||
|
DBCollection realms = db.getCollection("realms");
|
||||||
|
DBCursor cursor = realms.find();
|
||||||
|
while (cursor.hasNext()) {
|
||||||
|
BasicDBObject realm = (BasicDBObject) cursor.next();
|
||||||
|
|
||||||
|
String realmId = realm.getString("_id");
|
||||||
|
Set<String> removedProviders = new HashSet<>();
|
||||||
|
|
||||||
|
BasicDBList componentEntities = (BasicDBList) realm.get("componentEntities");
|
||||||
|
BasicDBList federationProviders = (BasicDBList) realm.get("userFederationProviders");
|
||||||
|
for (Object obj : federationProviders) {
|
||||||
|
BasicDBObject fedProvider = (BasicDBObject)obj;
|
||||||
|
if (fedProvider.getString("providerName").equals(providerId)) {
|
||||||
|
String id = fedProvider.getString("id");
|
||||||
|
int priority = fedProvider.getInt("priority");
|
||||||
|
String displayName = fedProvider.getString("displayName");
|
||||||
|
int fullSyncPeriod = fedProvider.getInt("fullSyncPeriod");
|
||||||
|
int changedSyncPeriod = fedProvider.getInt("changedSyncPeriod");
|
||||||
|
int lastSync = fedProvider.getInt("lastSync");
|
||||||
|
BasicDBObject component = new BasicDBObject();
|
||||||
|
component.put("id", id);
|
||||||
|
component.put("name", displayName);
|
||||||
|
component.put("providerType", UserStorageProvider.class.getName());
|
||||||
|
component.put("providerId", providerId);
|
||||||
|
component.put("parentId", realmId);
|
||||||
|
|
||||||
|
BasicDBObject config = new BasicDBObject();
|
||||||
|
config.put("priority", Collections.singletonList(Integer.toString(priority)));
|
||||||
|
config.put("fullSyncPeriod", Collections.singletonList(Integer.toString(fullSyncPeriod)));
|
||||||
|
config.put("changedSyncPeriod", Collections.singletonList(Integer.toString(changedSyncPeriod)));
|
||||||
|
config.put("lastSync", Collections.singletonList(Integer.toString(lastSync)));
|
||||||
|
|
||||||
|
BasicDBObject fedConfig = (BasicDBObject)fedProvider.get("config");
|
||||||
|
if (fedConfig != null) {
|
||||||
|
for (Map.Entry<String, Object> attr : new HashSet<>(fedConfig.entrySet())) {
|
||||||
|
String attrName = attr.getKey();
|
||||||
|
String attrValue = attr.getValue().toString();
|
||||||
|
config.put(attrName, Collections.singletonList(attrValue));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
component.put("config", config);
|
||||||
|
|
||||||
|
componentEntities.add(component);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Iterator<Object> it = federationProviders.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
BasicDBObject fedProvider = (BasicDBObject)it.next();
|
||||||
|
String id = fedProvider.getString("id");
|
||||||
|
if (removedProviders.contains(id)) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
realms.update(new BasicDBObject().append("_id", realmId), realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void portUserFedMappersToComponent(String providerId, String mapperType) {
|
||||||
|
DBCollection realms = db.getCollection("realms");
|
||||||
|
DBCursor cursor = realms.find();
|
||||||
|
while (cursor.hasNext()) {
|
||||||
|
BasicDBObject realm = (BasicDBObject) cursor.next();
|
||||||
|
|
||||||
|
String realmId = realm.getString("_id");
|
||||||
|
Set<String> removedProviders = new HashSet<>();
|
||||||
|
|
||||||
|
BasicDBList componentEntities = (BasicDBList) realm.get("componentEntities");
|
||||||
|
BasicDBList federationProviders = (BasicDBList) realm.get("userFederationProviders");
|
||||||
|
BasicDBList fedMappers = (BasicDBList) realm.get("userFederationMappers");
|
||||||
|
for (Object obj : federationProviders) {
|
||||||
|
BasicDBObject fedProvider = (BasicDBObject)obj;
|
||||||
|
if (fedProvider.getString("providerName").equals(providerId)) {
|
||||||
|
String id = fedProvider.getString("id");
|
||||||
|
for (Object obj2 : fedMappers) {
|
||||||
|
BasicDBObject fedMapper = (BasicDBObject)obj2;
|
||||||
|
if (fedMapper.getString("federationProviderId").equals(id)) {
|
||||||
|
String name = fedMapper.getString("name");
|
||||||
|
String mapperId = fedMapper.getString("id");
|
||||||
|
removedProviders.add(mapperId);
|
||||||
|
String mapperProviderId = fedMapper.getString("federationMapperType");
|
||||||
|
BasicDBObject component = new BasicDBObject();
|
||||||
|
component.put("id", mapperId);
|
||||||
|
component.put("name", name);
|
||||||
|
component.put("providerType", mapperType);
|
||||||
|
component.put("providerId", mapperProviderId);
|
||||||
|
component.put("parentId", providerId);
|
||||||
|
|
||||||
|
BasicDBObject fedConfig = (BasicDBObject)fedMapper.get("config");
|
||||||
|
BasicDBObject config = new BasicDBObject();
|
||||||
|
if (fedConfig != null) {
|
||||||
|
for (Map.Entry<String, Object> attr : new HashSet<>(fedConfig.entrySet())) {
|
||||||
|
String attrName = attr.getKey();
|
||||||
|
String attrValue = attr.getValue().toString();
|
||||||
|
config.put(attrName, Collections.singletonList(attrValue));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
component.put("config", config);
|
||||||
|
componentEntities.add(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Iterator<Object> it = fedMappers.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
BasicDBObject fedMapper = (BasicDBObject)it.next();
|
||||||
|
String id = fedMapper.getString("id");
|
||||||
|
if (removedProviders.contains(id)) {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
realms.update(new BasicDBObject().append("_id", realmId), realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1954,6 +1954,13 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ComponentModel addComponentModel(ComponentModel model) {
|
public ComponentModel addComponentModel(ComponentModel model) {
|
||||||
|
model = importComponentModel(model);
|
||||||
|
ComponentUtil.notifyCreated(session, this, model);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ComponentModel importComponentModel(ComponentModel model) {
|
||||||
ComponentUtil.getComponentFactory(session, model).validateConfiguration(session, this, model);
|
ComponentUtil.getComponentFactory(session, model).validateConfiguration(session, this, model);
|
||||||
|
|
||||||
ComponentEntity entity = new ComponentEntity();
|
ComponentEntity entity = new ComponentEntity();
|
||||||
|
@ -1970,7 +1977,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
||||||
}
|
}
|
||||||
realm.getComponentEntities().add(entity);
|
realm.getComponentEntities().add(entity);
|
||||||
updateRealm();
|
updateRealm();
|
||||||
ComponentUtil.notifyCreated(session, this, model);
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,7 +274,22 @@ public interface RealmModel extends RoleContainerModel {
|
||||||
public IdentityProviderMapperModel getIdentityProviderMapperByName(String brokerAlias, String name);
|
public IdentityProviderMapperModel getIdentityProviderMapperByName(String brokerAlias, String name);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds component model. Will call onCreate() method of ComponentFactory
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
ComponentModel addComponentModel(ComponentModel model);
|
ComponentModel addComponentModel(ComponentModel model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds component model. Will NOT call onCreate() method of ComponentFactory
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ComponentModel importComponentModel(ComponentModel model);
|
||||||
|
|
||||||
void updateComponent(ComponentModel component);
|
void updateComponent(ComponentModel component);
|
||||||
void removeComponent(ComponentModel component);
|
void removeComponent(ComponentModel component);
|
||||||
void removeComponents(String parentId);
|
void removeComponents(String parentId);
|
||||||
|
|
|
@ -352,19 +352,7 @@ public class ModelToRepresentation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UserFederationProviderModel> fedProviderModels = realm.getUserFederationProviders();
|
exportUserFederationProvidersAndMappers(realm, rep);
|
||||||
if (fedProviderModels.size() > 0) {
|
|
||||||
List<UserFederationProviderRepresentation> fedProviderReps = new ArrayList<UserFederationProviderRepresentation>();
|
|
||||||
for (UserFederationProviderModel model : fedProviderModels) {
|
|
||||||
UserFederationProviderRepresentation fedProvRep = toRepresentation(model);
|
|
||||||
fedProviderReps.add(fedProvRep);
|
|
||||||
}
|
|
||||||
rep.setUserFederationProviders(fedProviderReps);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UserFederationMapperModel mapper : realm.getUserFederationMappers()) {
|
|
||||||
rep.addUserFederationMapper(toRepresentation(realm, mapper));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IdentityProviderModel provider : realm.getIdentityProviders()) {
|
for (IdentityProviderModel provider : realm.getIdentityProviders()) {
|
||||||
rep.addIdentityProvider(toRepresentation(realm, provider));
|
rep.addIdentityProvider(toRepresentation(realm, provider));
|
||||||
|
@ -396,6 +384,22 @@ public class ModelToRepresentation {
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void exportUserFederationProvidersAndMappers(RealmModel realm, RealmRepresentation rep) {
|
||||||
|
List<UserFederationProviderModel> fedProviderModels = realm.getUserFederationProviders();
|
||||||
|
if (fedProviderModels.size() > 0) {
|
||||||
|
List<UserFederationProviderRepresentation> fedProviderReps = new ArrayList<UserFederationProviderRepresentation>();
|
||||||
|
for (UserFederationProviderModel model : fedProviderModels) {
|
||||||
|
UserFederationProviderRepresentation fedProvRep = toRepresentation(model);
|
||||||
|
fedProviderReps.add(fedProvRep);
|
||||||
|
}
|
||||||
|
rep.setUserFederationProviders(fedProviderReps);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UserFederationMapperModel mapper : realm.getUserFederationMappers()) {
|
||||||
|
rep.addUserFederationMapper(toRepresentation(realm, mapper));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void exportGroups(RealmModel realm, RealmRepresentation rep) {
|
public static void exportGroups(RealmModel realm, RealmRepresentation rep) {
|
||||||
List<GroupRepresentation> groups = toGroupHierarchy(realm, true);
|
List<GroupRepresentation> groups = toGroupHierarchy(realm, true);
|
||||||
rep.setGroups(groups);
|
rep.setGroups(groups);
|
||||||
|
|
|
@ -54,6 +54,7 @@ import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.IdentityProviderMapperModel;
|
import org.keycloak.models.IdentityProviderMapperModel;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
import org.keycloak.models.ModelException;
|
import org.keycloak.models.ModelException;
|
||||||
import org.keycloak.models.OTPPolicy;
|
import org.keycloak.models.OTPPolicy;
|
||||||
import org.keycloak.models.PasswordPolicy;
|
import org.keycloak.models.PasswordPolicy;
|
||||||
|
@ -101,6 +102,8 @@ import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentatio
|
||||||
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
|
||||||
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.storage.federated.UserFederatedStorageProvider;
|
import org.keycloak.storage.federated.UserFederatedStorageProvider;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
@ -305,36 +308,8 @@ public class RepresentationToModel {
|
||||||
String parentId = newRealm.getId();
|
String parentId = newRealm.getId();
|
||||||
importComponents(newRealm, components, parentId);
|
importComponents(newRealm, components, parentId);
|
||||||
}
|
}
|
||||||
|
importUserFederationProvidersAndMappers(rep, newRealm);
|
||||||
|
|
||||||
List<UserFederationProviderModel> providerModels = null;
|
|
||||||
if (rep.getUserFederationProviders() != null) {
|
|
||||||
providerModels = convertFederationProviders(rep.getUserFederationProviders());
|
|
||||||
newRealm.setUserFederationProviders(providerModels);
|
|
||||||
}
|
|
||||||
if (rep.getUserFederationMappers() != null) {
|
|
||||||
|
|
||||||
// Remove builtin mappers for federation providers, which have some mappers already provided in JSON (likely due to previous export)
|
|
||||||
if (rep.getUserFederationProviders() != null) {
|
|
||||||
Set<String> providerNames = new TreeSet<String>();
|
|
||||||
for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
|
|
||||||
providerNames.add(representation.getFederationProviderDisplayName());
|
|
||||||
}
|
|
||||||
for (String providerName : providerNames) {
|
|
||||||
for (UserFederationProviderModel providerModel : providerModels) {
|
|
||||||
if (providerName.equals(providerModel.getDisplayName())) {
|
|
||||||
Set<UserFederationMapperModel> toDelete = newRealm.getUserFederationMappersByFederationProvider(providerModel.getId());
|
|
||||||
for (UserFederationMapperModel mapperModel : toDelete) {
|
|
||||||
newRealm.removeUserFederationMapper(mapperModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
|
|
||||||
newRealm.addUserFederationMapper(toModel(newRealm, representation));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rep.getGroups() != null) {
|
if (rep.getGroups() != null) {
|
||||||
importGroups(newRealm, rep);
|
importGroups(newRealm, rep);
|
||||||
|
@ -390,6 +365,64 @@ public class RepresentationToModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void importUserFederationProvidersAndMappers(RealmRepresentation rep, RealmModel newRealm) {
|
||||||
|
// providers to convert to component model
|
||||||
|
Set<String> convertSet = new HashSet<>();
|
||||||
|
convertSet.add(LDAPConstants.LDAP_PROVIDER);
|
||||||
|
Map<String, String> mapperConvertSet = new HashMap<>();
|
||||||
|
mapperConvertSet.put(LDAPConstants.LDAP_PROVIDER, "org.keycloak.storage.ldap.mappers.LDAPStorageMapper");
|
||||||
|
|
||||||
|
|
||||||
|
List<UserFederationProviderModel> providerModels = null;
|
||||||
|
Map<String, ComponentModel> userStorageModels = new HashMap<>();
|
||||||
|
|
||||||
|
if (rep.getUserFederationProviders() != null) {
|
||||||
|
providerModels = new LinkedList<>();
|
||||||
|
for (UserFederationProviderRepresentation fedRep : rep.getUserFederationProviders()) {
|
||||||
|
if (convertSet.contains(fedRep.getProviderName())) {
|
||||||
|
ComponentModel component = convertFedProviderToComponent(newRealm.getId(), fedRep);
|
||||||
|
userStorageModels.put(fedRep.getDisplayName(), newRealm.importComponentModel(component));
|
||||||
|
} else {
|
||||||
|
providerModels.add(convertFederationProvider(fedRep));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
newRealm.setUserFederationProviders(providerModels);
|
||||||
|
}
|
||||||
|
if (rep.getUserFederationMappers() != null) {
|
||||||
|
|
||||||
|
// Remove builtin mappers for federation providers, which have some mappers already provided in JSON (likely due to previous export)
|
||||||
|
if (rep.getUserFederationProviders() != null) {
|
||||||
|
Set<String> providerNames = new TreeSet<String>();
|
||||||
|
for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
|
||||||
|
providerNames.add(representation.getFederationProviderDisplayName());
|
||||||
|
}
|
||||||
|
for (String providerName : providerNames) {
|
||||||
|
for (UserFederationProviderModel providerModel : providerModels) {
|
||||||
|
if (providerName.equals(providerModel.getDisplayName())) {
|
||||||
|
Set<UserFederationMapperModel> toDelete = newRealm.getUserFederationMappersByFederationProvider(providerModel.getId());
|
||||||
|
for (UserFederationMapperModel mapperModel : toDelete) {
|
||||||
|
newRealm.removeUserFederationMapper(mapperModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UserFederationMapperRepresentation representation : rep.getUserFederationMappers()) {
|
||||||
|
if (userStorageModels.containsKey(representation.getFederationProviderDisplayName())) {
|
||||||
|
ComponentModel parent = userStorageModels.get(representation.getFederationProviderDisplayName());
|
||||||
|
String newMapperType = mapperConvertSet.get(parent.getProviderId());
|
||||||
|
ComponentModel mapper = convertFedMapperToComponent(newRealm, parent, representation, newMapperType);
|
||||||
|
newRealm.importComponentModel(mapper);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
newRealm.addUserFederationMapper(toModel(newRealm, representation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static void importComponents(RealmModel newRealm, MultivaluedHashMap<String, ComponentExportRepresentation> components, String parentId) {
|
protected static void importComponents(RealmModel newRealm, MultivaluedHashMap<String, ComponentExportRepresentation> components, String parentId) {
|
||||||
for (Map.Entry<String, List<ComponentExportRepresentation>> entry : components.entrySet()) {
|
for (Map.Entry<String, List<ComponentExportRepresentation>> entry : components.entrySet()) {
|
||||||
String providerType = entry.getKey();
|
String providerType = entry.getKey();
|
||||||
|
@ -402,7 +435,7 @@ public class RepresentationToModel {
|
||||||
component.setProviderId(compRep.getProviderId());
|
component.setProviderId(compRep.getProviderId());
|
||||||
component.setSubType(compRep.getSubType());
|
component.setSubType(compRep.getSubType());
|
||||||
component.setParentId(parentId);
|
component.setParentId(parentId);
|
||||||
component = newRealm.addComponentModel(component);
|
component = newRealm.importComponentModel(component);
|
||||||
if (compRep.getSubComponents() != null) {
|
if (compRep.getSubComponents() != null) {
|
||||||
importComponents(newRealm, compRep.getSubComponents(), component.getId());
|
importComponents(newRealm, compRep.getSubComponents(), component.getId());
|
||||||
}
|
}
|
||||||
|
@ -865,14 +898,53 @@ public class RepresentationToModel {
|
||||||
List<UserFederationProviderModel> result = new ArrayList<UserFederationProviderModel>();
|
List<UserFederationProviderModel> result = new ArrayList<UserFederationProviderModel>();
|
||||||
|
|
||||||
for (UserFederationProviderRepresentation representation : providers) {
|
for (UserFederationProviderRepresentation representation : providers) {
|
||||||
UserFederationProviderModel model = new UserFederationProviderModel(representation.getId(), representation.getProviderName(),
|
UserFederationProviderModel model = convertFederationProvider(representation);
|
||||||
representation.getConfig(), representation.getPriority(), representation.getDisplayName(),
|
|
||||||
representation.getFullSyncPeriod(), representation.getChangedSyncPeriod(), representation.getLastSync());
|
|
||||||
result.add(model);
|
result.add(model);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static UserFederationProviderModel convertFederationProvider(UserFederationProviderRepresentation representation) {
|
||||||
|
return new UserFederationProviderModel(representation.getId(), representation.getProviderName(),
|
||||||
|
representation.getConfig(), representation.getPriority(), representation.getDisplayName(),
|
||||||
|
representation.getFullSyncPeriod(), representation.getChangedSyncPeriod(), representation.getLastSync());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComponentModel convertFedProviderToComponent(String realmId, UserFederationProviderRepresentation fedModel) {
|
||||||
|
UserStorageProviderModel model = new UserStorageProviderModel();
|
||||||
|
model.setId(fedModel.getId());
|
||||||
|
model.setName(fedModel.getDisplayName());
|
||||||
|
model.setParentId(realmId);
|
||||||
|
model.setProviderId(fedModel.getProviderName());
|
||||||
|
model.setProviderType(UserStorageProvider.class.getName());
|
||||||
|
model.setFullSyncPeriod(fedModel.getFullSyncPeriod());
|
||||||
|
model.setPriority(fedModel.getPriority());
|
||||||
|
model.setChangedSyncPeriod(fedModel.getChangedSyncPeriod());
|
||||||
|
model.setLastSync(fedModel.getLastSync());
|
||||||
|
if (fedModel.getConfig() != null) {
|
||||||
|
for (Map.Entry<String, String> entry : fedModel.getConfig().entrySet()) {
|
||||||
|
model.getConfig().putSingle(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComponentModel convertFedMapperToComponent(RealmModel realm, ComponentModel parent, UserFederationMapperRepresentation rep, String newMapperType) {
|
||||||
|
ComponentModel mapper = new ComponentModel();
|
||||||
|
mapper.setId(rep.getId());
|
||||||
|
mapper.setName(rep.getName());
|
||||||
|
mapper.setProviderId(rep.getFederationMapperType());
|
||||||
|
mapper.setProviderType(newMapperType);
|
||||||
|
mapper.setParentId(parent.getId());
|
||||||
|
if (rep.getConfig() != null) {
|
||||||
|
for (Map.Entry<String, String> entry : rep.getConfig().entrySet()) {
|
||||||
|
mapper.getConfig().putSingle(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static UserFederationMapperModel toModel(RealmModel realm, UserFederationMapperRepresentation rep) {
|
public static UserFederationMapperModel toModel(RealmModel realm, UserFederationMapperRepresentation rep) {
|
||||||
UserFederationMapperModel model = new UserFederationMapperModel();
|
UserFederationMapperModel model = new UserFederationMapperModel();
|
||||||
model.setId(rep.getId());
|
model.setId(rep.getId());
|
||||||
|
|
|
@ -48,7 +48,9 @@ import org.keycloak.models.UserFederationProvider;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
import org.keycloak.testsuite.federation.ldap.FederationTestUtils;
|
import org.keycloak.testsuite.federation.ldap.FederationTestUtils;
|
||||||
|
@ -61,8 +63,10 @@ import org.keycloak.testsuite.rule.KeycloakRule;
|
||||||
import org.keycloak.testsuite.rule.LDAPRule;
|
import org.keycloak.testsuite.rule.LDAPRule;
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
import org.keycloak.testsuite.rule.WebResource;
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
import org.keycloak.testsuite.rule.WebRule;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -104,6 +108,20 @@ public class FederationProvidersIntegrationTest {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
@Test
|
||||||
|
public void exportJson() throws Exception {
|
||||||
|
KeycloakSession session = keycloakRule.startSession();
|
||||||
|
FileOutputStream os = new FileOutputStream("/Users/williamburke/jboss/keycloak/p1b-repo/keycloak/fed-provider.json");
|
||||||
|
RealmManager manager = new RealmManager(session);
|
||||||
|
RealmModel appRealm = manager.getRealm("test");
|
||||||
|
RealmRepresentation rep = ModelToRepresentation.toRepresentation(appRealm, true);
|
||||||
|
JsonSerialization.writeValueToStream(os, rep);
|
||||||
|
os.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static TestRule chain = RuleChain
|
public static TestRule chain = RuleChain
|
||||||
.outerRule(ldapRule)
|
.outerRule(ldapRule)
|
||||||
|
|
|
@ -132,7 +132,7 @@ public class UserStorageTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
//@Test
|
||||||
public void testIDE() throws Exception {
|
public void testIDE() throws Exception {
|
||||||
Thread.sleep(100000000);
|
Thread.sleep(100000000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 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.testsuite.federation.storage.ldap;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.RuleChain;
|
||||||
|
import org.junit.rules.TestRule;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
import org.keycloak.OAuth2Constants;
|
||||||
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.credential.CredentialModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.LDAPConstants;
|
||||||
|
import org.keycloak.models.ModelException;
|
||||||
|
import org.keycloak.models.ModelReadOnlyException;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.UserCredentialModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.models.utils.RepresentationToModel;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.ldap.LDAPConfig;
|
||||||
|
import org.keycloak.storage.ldap.LDAPStorageProvider;
|
||||||
|
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
||||||
|
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
||||||
|
import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper;
|
||||||
|
import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory;
|
||||||
|
import org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapper;
|
||||||
|
import org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapperFactory;
|
||||||
|
import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
|
||||||
|
import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper;
|
||||||
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
|
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
||||||
|
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
||||||
|
import org.keycloak.testsuite.pages.AppPage;
|
||||||
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
|
import org.keycloak.testsuite.pages.RegisterPage;
|
||||||
|
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||||
|
import org.keycloak.testsuite.rule.LDAPRule;
|
||||||
|
import org.keycloak.testsuite.rule.WebResource;
|
||||||
|
import org.keycloak.testsuite.rule.WebRule;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that legacy UserFederationProvider json export is converted to ComponentModel
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
public class LDAPLegacyImportTest {
|
||||||
|
|
||||||
|
private static LDAPRule ldapRule = new LDAPRule();
|
||||||
|
|
||||||
|
private static ComponentModel ldapModel = null;
|
||||||
|
|
||||||
|
|
||||||
|
private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
|
LDAPTestUtils.addLocalUser(manager.getSession(), appRealm, "marykeycloak", "mary@test.com", "password-app");
|
||||||
|
|
||||||
|
RealmRepresentation imported = null;
|
||||||
|
try {
|
||||||
|
imported = JsonSerialization.readValue(getClass().getResourceAsStream("/ldap/fed-provider-export.json"), RealmRepresentation.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
RepresentationToModel.importUserFederationProvidersAndMappers(imported, appRealm);
|
||||||
|
ldapModel = appRealm.getComponents(appRealm.getId(), UserStorageProvider.class.getName()).get(0);
|
||||||
|
// Delete all LDAP users and add some new for testing
|
||||||
|
LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapModel);
|
||||||
|
LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
|
||||||
|
|
||||||
|
LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234");
|
||||||
|
LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1");
|
||||||
|
|
||||||
|
LDAPObject existing = LDAPTestUtils.addLDAPUser(ldapFedProvider, appRealm, "existing", "Existing", "Foo", "existing@email.org", null, "5678");
|
||||||
|
|
||||||
|
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static TestRule chain = RuleChain
|
||||||
|
.outerRule(ldapRule)
|
||||||
|
.around(keycloakRule);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public WebRule webRule = new WebRule(this);
|
||||||
|
|
||||||
|
@WebResource
|
||||||
|
protected OAuthClient oauth;
|
||||||
|
|
||||||
|
@WebResource
|
||||||
|
protected WebDriver driver;
|
||||||
|
|
||||||
|
@WebResource
|
||||||
|
protected AppPage appPage;
|
||||||
|
|
||||||
|
@WebResource
|
||||||
|
protected RegisterPage registerPage;
|
||||||
|
|
||||||
|
@WebResource
|
||||||
|
protected LoginPage loginPage;
|
||||||
|
|
||||||
|
@WebResource
|
||||||
|
protected AccountUpdateProfilePage profilePage;
|
||||||
|
|
||||||
|
@WebResource
|
||||||
|
protected AccountPasswordPage changePasswordPage;
|
||||||
|
|
||||||
|
//@Test
|
||||||
|
public void runit() throws Exception {
|
||||||
|
Thread.sleep(10000000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loginSuccessAndLogout(String username, String password) {
|
||||||
|
loginPage.open();
|
||||||
|
loginPage.login(username, password);
|
||||||
|
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
|
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||||
|
oauth.openLogout();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginClassic() {
|
||||||
|
loginPage.open();
|
||||||
|
loginPage.login("marykeycloak", "password-app");
|
||||||
|
|
||||||
|
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
|
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loginLdap() {
|
||||||
|
loginPage.open();
|
||||||
|
loginPage.login("johnkeycloak", "Password1");
|
||||||
|
|
||||||
|
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
|
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||||
|
|
||||||
|
profilePage.open();
|
||||||
|
Assert.assertEquals("John", profilePage.getFirstName());
|
||||||
|
Assert.assertEquals("Doe", profilePage.getLastName());
|
||||||
|
Assert.assertEquals("john@email.org", profilePage.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,622 @@
|
||||||
|
{
|
||||||
|
"id": "test",
|
||||||
|
"realm": "test",
|
||||||
|
"notBefore": 0,
|
||||||
|
"revokeRefreshToken": false,
|
||||||
|
"accessTokenLifespan": 300,
|
||||||
|
"accessTokenLifespanForImplicitFlow": 900,
|
||||||
|
"ssoSessionIdleTimeout": 1800,
|
||||||
|
"ssoSessionMaxLifespan": 36000,
|
||||||
|
"offlineSessionIdleTimeout": 2592000,
|
||||||
|
"accessCodeLifespan": 60,
|
||||||
|
"accessCodeLifespanUserAction": 300,
|
||||||
|
"accessCodeLifespanLogin": 1800,
|
||||||
|
"enabled": true,
|
||||||
|
"sslRequired": "external",
|
||||||
|
"registrationAllowed": true,
|
||||||
|
"registrationEmailAsUsername": false,
|
||||||
|
"rememberMe": false,
|
||||||
|
"verifyEmail": false,
|
||||||
|
"resetPasswordAllowed": true,
|
||||||
|
"editUsernameAllowed": true,
|
||||||
|
"bruteForceProtected": false,
|
||||||
|
"maxFailureWaitSeconds": 900,
|
||||||
|
"minimumQuickLoginWaitSeconds": 60,
|
||||||
|
"waitIncrementSeconds": 60,
|
||||||
|
"quickLoginCheckMilliSeconds": 1000,
|
||||||
|
"maxDeltaTimeSeconds": 43200,
|
||||||
|
"failureFactor": 30,
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"id": "2aa57ddd-e48f-4a62-bb8e-53ebe2ff1057",
|
||||||
|
"name": "topGroup",
|
||||||
|
"path": "/topGroup",
|
||||||
|
"attributes": {
|
||||||
|
"topAttribute": [
|
||||||
|
"true"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"realmRoles": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"clientRoles": {},
|
||||||
|
"subGroups": [
|
||||||
|
{
|
||||||
|
"id": "8e91afd4-b8e4-4de4-ba37-1edc7298d518",
|
||||||
|
"name": "level2group",
|
||||||
|
"path": "/topGroup/level2group",
|
||||||
|
"attributes": {
|
||||||
|
"level2Attribute": [
|
||||||
|
"true"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"realmRoles": [
|
||||||
|
"admin"
|
||||||
|
],
|
||||||
|
"clientRoles": {
|
||||||
|
"test-app": [
|
||||||
|
"customer-user"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"subGroups": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"defaultRoles": [
|
||||||
|
"user",
|
||||||
|
"offline_access",
|
||||||
|
"uma_authorization"
|
||||||
|
],
|
||||||
|
"requiredCredentials": [
|
||||||
|
"password"
|
||||||
|
],
|
||||||
|
"passwordPolicy": "hashIterations(20000)",
|
||||||
|
"otpPolicyType": "totp",
|
||||||
|
"otpPolicyAlgorithm": "HmacSHA1",
|
||||||
|
"otpPolicyInitialCounter": 0,
|
||||||
|
"otpPolicyDigits": 6,
|
||||||
|
"otpPolicyLookAheadWindow": 1,
|
||||||
|
"otpPolicyPeriod": 30,
|
||||||
|
"browserSecurityHeaders": {
|
||||||
|
"xContentTypeOptions": "nosniff",
|
||||||
|
"xFrameOptions": "SAMEORIGIN",
|
||||||
|
"contentSecurityPolicy": "frame-src 'self'"
|
||||||
|
},
|
||||||
|
"smtpServer": {
|
||||||
|
"host": "localhost",
|
||||||
|
"from": "auto@keycloak.org",
|
||||||
|
"port": "3025"
|
||||||
|
},
|
||||||
|
"userFederationProviders": [
|
||||||
|
{
|
||||||
|
"id": "1fc3afd2-4c18-48dd-9055-b4bbae9229b7",
|
||||||
|
"displayName": "test-ldap",
|
||||||
|
"providerName": "ldap",
|
||||||
|
"config": {
|
||||||
|
"serverPrincipal": "HTTP/localhost@KEYCLOAK.ORG",
|
||||||
|
"debug": "true",
|
||||||
|
"pagination": "true",
|
||||||
|
"keyTab": "/Users/williamburke/jboss/keycloak/p1b-repo/keycloak/testsuite/integration/target/test-classes/kerberos/http.keytab",
|
||||||
|
"connectionPooling": "true",
|
||||||
|
"usersDn": "ou=People,dc=keycloak,dc=org",
|
||||||
|
"useKerberosForPasswordAuthentication": "false",
|
||||||
|
"kerberosRealm": "KEYCLOAK.ORG",
|
||||||
|
"bindCredential": "secret",
|
||||||
|
"bindDn": "uid=admin,ou=system",
|
||||||
|
"allowPasswordAuthentication": "true",
|
||||||
|
"vendor": "other",
|
||||||
|
"editMode": "WRITABLE",
|
||||||
|
"allowKerberosAuthentication": "false",
|
||||||
|
"connectionUrl": "ldap://localhost:10389",
|
||||||
|
"syncRegistrations": "true",
|
||||||
|
"baseDn": "dc=keycloak,dc=org",
|
||||||
|
"batchSizeForSync": "3",
|
||||||
|
"updateProfileFirstLogin": "true"
|
||||||
|
},
|
||||||
|
"priority": 0,
|
||||||
|
"fullSyncPeriod": -1,
|
||||||
|
"changedSyncPeriod": -1,
|
||||||
|
"lastSync": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userFederationMappers": [
|
||||||
|
{
|
||||||
|
"id": "b2fc2d9c-2ea8-417f-96db-2565be62a646",
|
||||||
|
"name": "last name",
|
||||||
|
"federationProviderDisplayName": "test-ldap",
|
||||||
|
"federationMapperType": "user-attribute-ldap-mapper",
|
||||||
|
"config": {
|
||||||
|
"always.read.value.from.ldap": "true",
|
||||||
|
"read.only": "false",
|
||||||
|
"ldap.attribute": "sn",
|
||||||
|
"is.mandatory.in.ldap": "true",
|
||||||
|
"user.model.attribute": "lastName"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6dc25318-dc20-4927-ba19-9293ab31aa28",
|
||||||
|
"name": "zipCodeMapper",
|
||||||
|
"federationProviderDisplayName": "test-ldap",
|
||||||
|
"federationMapperType": "user-attribute-ldap-mapper",
|
||||||
|
"config": {
|
||||||
|
"always.read.value.from.ldap": "false",
|
||||||
|
"read.only": "false",
|
||||||
|
"ldap.attribute": "postalCode",
|
||||||
|
"is.mandatory.in.ldap": "false",
|
||||||
|
"user.model.attribute": "postal_code"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7afa12a2-f36e-4f87-b715-e941773c8534",
|
||||||
|
"name": "username",
|
||||||
|
"federationProviderDisplayName": "test-ldap",
|
||||||
|
"federationMapperType": "user-attribute-ldap-mapper",
|
||||||
|
"config": {
|
||||||
|
"always.read.value.from.ldap": "false",
|
||||||
|
"read.only": "false",
|
||||||
|
"ldap.attribute": "uid",
|
||||||
|
"is.mandatory.in.ldap": "true",
|
||||||
|
"user.model.attribute": "username"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "abfe054c-6d2a-4870-a239-1a312c3e5a94",
|
||||||
|
"name": "creation date",
|
||||||
|
"federationProviderDisplayName": "test-ldap",
|
||||||
|
"federationMapperType": "user-attribute-ldap-mapper",
|
||||||
|
"config": {
|
||||||
|
"always.read.value.from.ldap": "true",
|
||||||
|
"read.only": "true",
|
||||||
|
"ldap.attribute": "createTimestamp",
|
||||||
|
"is.mandatory.in.ldap": "false",
|
||||||
|
"user.model.attribute": "createTimestamp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6aef95e5-736e-4b1e-98d0-332f61f94ff9",
|
||||||
|
"name": "first name",
|
||||||
|
"federationProviderDisplayName": "test-ldap",
|
||||||
|
"federationMapperType": "user-attribute-ldap-mapper",
|
||||||
|
"config": {
|
||||||
|
"always.read.value.from.ldap": "true",
|
||||||
|
"read.only": "false",
|
||||||
|
"ldap.attribute": "cn",
|
||||||
|
"is.mandatory.in.ldap": "true",
|
||||||
|
"user.model.attribute": "firstName"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "0601e4a2-fd63-4f6a-ae3b-13cc6f4f4f1c",
|
||||||
|
"name": "email",
|
||||||
|
"federationProviderDisplayName": "test-ldap",
|
||||||
|
"federationMapperType": "user-attribute-ldap-mapper",
|
||||||
|
"config": {
|
||||||
|
"always.read.value.from.ldap": "false",
|
||||||
|
"read.only": "false",
|
||||||
|
"ldap.attribute": "mail",
|
||||||
|
"is.mandatory.in.ldap": "false",
|
||||||
|
"user.model.attribute": "email"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "fa308910-3be9-4bd8-8256-66cf04d8fcd2",
|
||||||
|
"name": "modify date",
|
||||||
|
"federationProviderDisplayName": "test-ldap",
|
||||||
|
"federationMapperType": "user-attribute-ldap-mapper",
|
||||||
|
"config": {
|
||||||
|
"always.read.value.from.ldap": "true",
|
||||||
|
"read.only": "true",
|
||||||
|
"ldap.attribute": "modifyTimestamp",
|
||||||
|
"is.mandatory.in.ldap": "false",
|
||||||
|
"user.model.attribute": "modifyTimestamp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"eventsEnabled": false,
|
||||||
|
"eventsListeners": [
|
||||||
|
"jboss-logging"
|
||||||
|
],
|
||||||
|
"enabledEventTypes": [],
|
||||||
|
"adminEventsEnabled": false,
|
||||||
|
"adminEventsDetailsEnabled": false,
|
||||||
|
"internationalizationEnabled": true,
|
||||||
|
"supportedLocales": [
|
||||||
|
"de",
|
||||||
|
"en"
|
||||||
|
],
|
||||||
|
"defaultLocale": "en",
|
||||||
|
"authenticationFlows": [
|
||||||
|
{
|
||||||
|
"id": "b12463a9-5d33-4f27-b010-4005db77e602",
|
||||||
|
"alias": "Handle Existing Account",
|
||||||
|
"description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": false,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "idp-confirm-link",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "idp-email-verification",
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 30,
|
||||||
|
"flowAlias": "Verify Existing Account by Re-authentication",
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c1684fc8-a99d-4e19-a795-478e4d793fb5",
|
||||||
|
"alias": "Verify Existing Account by Re-authentication",
|
||||||
|
"description": "Reauthentication of existing account",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": false,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "idp-username-password-form",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "auth-otp-form",
|
||||||
|
"requirement": "OPTIONAL",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "09af30d8-8c2a-45a4-a2be-b7617e9d0185",
|
||||||
|
"alias": "browser",
|
||||||
|
"description": "browser based authentication",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": true,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "auth-cookie",
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "auth-spnego",
|
||||||
|
"requirement": "DISABLED",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "identity-provider-redirector",
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 25,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 30,
|
||||||
|
"flowAlias": "forms",
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6cdf31d0-9c91-4ea6-8e37-da6e8fa7544c",
|
||||||
|
"alias": "clients",
|
||||||
|
"description": "Base authentication for clients",
|
||||||
|
"providerId": "client-flow",
|
||||||
|
"topLevel": true,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "client-secret",
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "client-jwt",
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c9a38de8-4c0c-496a-9936-b9753f73bfcc",
|
||||||
|
"alias": "direct grant",
|
||||||
|
"description": "OpenID Connect Resource Owner Grant",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": true,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "direct-grant-validate-username",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "direct-grant-validate-password",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "direct-grant-validate-otp",
|
||||||
|
"requirement": "OPTIONAL",
|
||||||
|
"priority": 30,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3755e297-7907-4c14-8c5f-d77e2bfe4b5d",
|
||||||
|
"alias": "first broker login",
|
||||||
|
"description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": true,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticatorConfig": "review profile config",
|
||||||
|
"authenticator": "idp-review-profile",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticatorConfig": "create unique user config",
|
||||||
|
"authenticator": "idp-create-user-if-unique",
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"requirement": "ALTERNATIVE",
|
||||||
|
"priority": 30,
|
||||||
|
"flowAlias": "Handle Existing Account",
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f35b2f00-3e84-4f2e-b48e-3e4159d88a06",
|
||||||
|
"alias": "forms",
|
||||||
|
"description": "Username, password, otp and other auth forms.",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": false,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "auth-username-password-form",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "auth-otp-form",
|
||||||
|
"requirement": "OPTIONAL",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "441b4480-1ace-483a-bffb-f0cb6659fe32",
|
||||||
|
"alias": "registration",
|
||||||
|
"description": "registration flow",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": true,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "registration-page-form",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 10,
|
||||||
|
"flowAlias": "registration form",
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c7de2a37-29a1-471a-9b51-699a69032b00",
|
||||||
|
"alias": "registration form",
|
||||||
|
"description": "registration form",
|
||||||
|
"providerId": "form-flow",
|
||||||
|
"topLevel": false,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "registration-user-creation",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "registration-profile-action",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 40,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "registration-password-action",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 50,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "registration-recaptcha-action",
|
||||||
|
"requirement": "DISABLED",
|
||||||
|
"priority": 60,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "d362be0a-df20-4ce7-9288-f8448e0c4647",
|
||||||
|
"alias": "reset credentials",
|
||||||
|
"description": "Reset credentials for a user if they forgot their password or something",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": true,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "reset-credentials-choose-user",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "reset-credential-email",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 20,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "reset-password",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 30,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authenticator": "reset-otp",
|
||||||
|
"requirement": "OPTIONAL",
|
||||||
|
"priority": 40,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "c2d7a1ae-57c9-4f3b-a4ce-55c3f0d9869f",
|
||||||
|
"alias": "saml ecp",
|
||||||
|
"description": "SAML ECP Profile Authentication Flow",
|
||||||
|
"providerId": "basic-flow",
|
||||||
|
"topLevel": true,
|
||||||
|
"builtIn": true,
|
||||||
|
"authenticationExecutions": [
|
||||||
|
{
|
||||||
|
"authenticator": "http-basic-authenticator",
|
||||||
|
"requirement": "REQUIRED",
|
||||||
|
"priority": 10,
|
||||||
|
"userSetupAllowed": false,
|
||||||
|
"autheticatorFlow": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"authenticatorConfig": [
|
||||||
|
{
|
||||||
|
"id": "a2490828-becb-435f-9c3c-318b3939bf64",
|
||||||
|
"alias": "create unique user config",
|
||||||
|
"config": {
|
||||||
|
"require.password.update.after.registration": "false"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "78421671-f733-4901-82bc-58bf50c43206",
|
||||||
|
"alias": "review profile config",
|
||||||
|
"config": {
|
||||||
|
"update.profile.on.first.login": "missing"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requiredActions": [
|
||||||
|
{
|
||||||
|
"alias": "CONFIGURE_TOTP",
|
||||||
|
"name": "Configure OTP",
|
||||||
|
"providerId": "CONFIGURE_TOTP",
|
||||||
|
"enabled": true,
|
||||||
|
"defaultAction": false,
|
||||||
|
"config": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "UPDATE_PASSWORD",
|
||||||
|
"name": "Update Password",
|
||||||
|
"providerId": "UPDATE_PASSWORD",
|
||||||
|
"enabled": true,
|
||||||
|
"defaultAction": false,
|
||||||
|
"config": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "UPDATE_PROFILE",
|
||||||
|
"name": "Update Profile",
|
||||||
|
"providerId": "UPDATE_PROFILE",
|
||||||
|
"enabled": true,
|
||||||
|
"defaultAction": false,
|
||||||
|
"config": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "VERIFY_EMAIL",
|
||||||
|
"name": "Verify Email",
|
||||||
|
"providerId": "VERIFY_EMAIL",
|
||||||
|
"enabled": true,
|
||||||
|
"defaultAction": false,
|
||||||
|
"config": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": "terms_and_conditions",
|
||||||
|
"name": "Terms and Conditions",
|
||||||
|
"providerId": "terms_and_conditions",
|
||||||
|
"enabled": false,
|
||||||
|
"defaultAction": false,
|
||||||
|
"config": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"browserFlow": "browser",
|
||||||
|
"registrationFlow": "registration",
|
||||||
|
"directGrantFlow": "direct grant",
|
||||||
|
"resetCredentialsFlow": "reset credentials",
|
||||||
|
"clientAuthenticationFlow": "clients",
|
||||||
|
"attributes": {
|
||||||
|
"_browser_header.xFrameOptions": "SAMEORIGIN",
|
||||||
|
"failureFactor": "30",
|
||||||
|
"quickLoginCheckMilliSeconds": "1000",
|
||||||
|
"maxDeltaTimeSeconds": "43200",
|
||||||
|
"_browser_header.xContentTypeOptions": "nosniff",
|
||||||
|
"bruteForceProtected": "false",
|
||||||
|
"maxFailureWaitSeconds": "900",
|
||||||
|
"_browser_header.contentSecurityPolicy": "frame-src 'self'",
|
||||||
|
"minimumQuickLoginWaitSeconds": "60",
|
||||||
|
"waitIncrementSeconds": "60"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue