/* * 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.BasicDBObjectBuilder; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; import org.keycloak.Config; import org.keycloak.connections.mongo.impl.types.MapMapper; import org.keycloak.migration.MigrationProvider; import org.keycloak.models.AdminRoles; import org.keycloak.models.KeycloakSession; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import java.util.List; import java.util.Map; /** * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> */ public class Update1_2_0_Beta1 extends Update { @Override public String getId() { return "1.2.0.Beta1"; } @Override public void update(KeycloakSession session) { deleteEntries("clientSessions"); deleteEntries("sessions"); convertSocialToIdFedRealms(); convertSocialToIdFedUsers(); addAccessCodeLoginTimeout(); addNewAdminRoles(); addDefaultProtocolMappers(session); } private void convertSocialToIdFedRealms() { DBCollection realms = db.getCollection("realms"); DBCursor realmsCursor = realms.find(); try { while (realmsCursor.hasNext()) { BasicDBObject realm = (BasicDBObject) realmsCursor.next(); boolean updateProfileOnInitialSocialLogin = realm.getBoolean("updateProfileOnInitialSocialLogin"); BasicDBObject socialConfig = (BasicDBObject) realm.get("socialConfig"); BasicDBList identityProviders = (BasicDBList) realm.get("identityProviders"); if (identityProviders == null) { identityProviders = new BasicDBList(); realm.put("identityProviders", identityProviders); } if (socialConfig != null) { for (Map.Entry<String, Object> entry : socialConfig.entrySet()) { if (entry.getKey().endsWith("###key")) { String socialProviderId = entry.getKey().substring(0, entry.getKey().indexOf("###")); String clientId = (String) entry.getValue(); String clientSecret = socialConfig.getString(socialProviderId + "###secret"); DBObject identityProviderConfig = new BasicDBObjectBuilder() .add("clientId", clientId) .add("clientSecret", clientSecret).get(); DBObject identityProvider = new BasicDBObjectBuilder() .add("internalId", KeycloakModelUtils.generateId()) .add("providerId", socialProviderId) .add("alias", socialProviderId) .add("updateProfileFirstLogin", updateProfileOnInitialSocialLogin) .add("enabled", true) .add("storeToken", false) .add("authenticateByDefault", false) .add("config", identityProviderConfig).get(); identityProviders.add(identityProvider); log.debugv("Converted social provider {0} to identity provider", socialProviderId); } } } // Remove obsolete keys from realm realm.remove("social"); realm.remove("updateProfileOnInitialSocialLogin"); realm.remove("socialConfig"); // Update realm in DB now realms.save(realm); log.debugv("Social providers of realm {0} converted to identity providers", realm.get("_id")); } } finally { realmsCursor.close(); } } private void convertSocialToIdFedUsers() { DBCollection users = db.getCollection("users"); DBCursor usersCursor = users.find(); try { while (usersCursor.hasNext()) { BasicDBObject user = (BasicDBObject) usersCursor.next(); BasicDBList socialLinks = (BasicDBList) user.get("socialLinks"); if (socialLinks != null) { BasicDBList federatedIdentities = (BasicDBList) user.get("federatedIdentities"); if (federatedIdentities == null) { federatedIdentities = new BasicDBList(); user.put("federatedIdentities", federatedIdentities); } for (Object socialLinkObj : socialLinks) { BasicDBObject socialLink = (BasicDBObject) socialLinkObj; BasicDBObject idFedLink = new BasicDBObject(); idFedLink.put("userName", socialLink.get("socialUsername")); idFedLink.put("userId", socialLink.get("socialUserId")); idFedLink.put("identityProvider", socialLink.get("socialProvider")); federatedIdentities.add(idFedLink); } // Remove obsolete keys and save user user.remove("socialLinks"); users.save(user); if (log.isTraceEnabled()) { log.tracev("Social links of user {0} converted to identity links", user.get("_id")); } } } } finally { usersCursor.close(); } log.debug("Social links of users converted to identity links"); } private void addAccessCodeLoginTimeout() { DBCollection realms = db.getCollection("realms"); DBCursor realmsCursor = realms.find(); try { while (realmsCursor.hasNext()) { BasicDBObject realm = (BasicDBObject) realmsCursor.next(); realm.put("accessCodeLifespanLogin", 1800); realms.save(realm); } } finally { realmsCursor.close(); } } private void addNewAdminRoles() { DBCollection realms = db.getCollection("realms"); String adminRealmName = Config.getAdminRealm(); DBCursor realmsCursor = realms.find(); try { while (realmsCursor.hasNext()) { BasicDBObject realm = (BasicDBObject) realmsCursor.next(); if (adminRealmName.equals(realm.get("name"))) { addNewAdminRolesToMasterRealm(realm); } else { addNewAdminRolesToRealm(realm); } } } finally { realmsCursor.close(); } } private void addNewAdminRolesToMasterRealm(BasicDBObject adminRealm) { DBCollection realms = db.getCollection("realms"); DBCollection applications = db.getCollection("applications"); DBCollection roles = db.getCollection("roles"); DBCursor realmsCursor = realms.find(); try { while (realmsCursor.hasNext()) { BasicDBObject currentRealm = (BasicDBObject) realmsCursor.next(); String masterAdminAppName = currentRealm.getString("name") + "-realm"; BasicDBObject masterAdminApp = (BasicDBObject) applications.findOne(new BasicDBObject().append("realmId", adminRealm.get("_id")).append("name", masterAdminAppName)); String viewIdProvidersRoleId = insertApplicationRole(roles, AdminRoles.VIEW_IDENTITY_PROVIDERS, masterAdminApp.getString("_id")); String manageIdProvidersRoleId = insertApplicationRole(roles, AdminRoles.MANAGE_IDENTITY_PROVIDERS, masterAdminApp.getString("_id")); BasicDBObject adminRole = (BasicDBObject) roles.findOne(new BasicDBObject().append("realmId", adminRealm.get("_id")).append("name", AdminRoles.ADMIN)); BasicDBList adminCompositeRoles = (BasicDBList) adminRole.get("compositeRoleIds"); adminCompositeRoles.add(viewIdProvidersRoleId); adminCompositeRoles.add(manageIdProvidersRoleId); roles.save(adminRole); log.debugv("Added roles {0} and {1} to application {2}", AdminRoles.VIEW_IDENTITY_PROVIDERS, AdminRoles.MANAGE_IDENTITY_PROVIDERS, masterAdminAppName); } } finally { realmsCursor.close(); } } private void addNewAdminRolesToRealm(BasicDBObject currentRealm) { DBCollection applications = db.getCollection("applications"); DBCollection roles = db.getCollection("roles"); BasicDBObject adminApp = (BasicDBObject) applications.findOne(new BasicDBObject().append("realmId", currentRealm.get("_id")).append("name", "realm-management")); String viewIdProvidersRoleId = insertApplicationRole(roles, AdminRoles.VIEW_IDENTITY_PROVIDERS, adminApp.getString("_id")); String manageIdProvidersRoleId = insertApplicationRole(roles, AdminRoles.MANAGE_IDENTITY_PROVIDERS, adminApp.getString("_id")); BasicDBObject adminRole = (BasicDBObject) roles.findOne(new BasicDBObject().append("applicationId", adminApp.get("_id")).append("name", AdminRoles.REALM_ADMIN)); BasicDBList adminCompositeRoles = (BasicDBList) adminRole.get("compositeRoleIds"); adminCompositeRoles.add(viewIdProvidersRoleId); adminCompositeRoles.add(manageIdProvidersRoleId); roles.save(adminRole); log.debugv("Added roles {0} and {1} to application realm-management of realm {2}", AdminRoles.VIEW_IDENTITY_PROVIDERS, AdminRoles.MANAGE_IDENTITY_PROVIDERS, currentRealm.get("name")); } private void addDefaultProtocolMappers(KeycloakSession session) { addDefaultMappers(session, db.getCollection("applications")); addDefaultMappers(session, db.getCollection("oauthClients")); } private void addDefaultMappers(KeycloakSession session, DBCollection clients) { DBCursor clientsCursor = clients.find(); try { while (clientsCursor.hasNext()) { BasicDBObject currentClient = (BasicDBObject) clientsCursor.next(); BasicDBList dbProtocolMappers = new BasicDBList(); currentClient.put("protocolMappers", dbProtocolMappers); Object claimMask = currentClient.get("allowedClaimsMask"); MigrationProvider migrationProvider = session.getProvider(MigrationProvider.class); List<ProtocolMapperRepresentation> protocolMappers = migrationProvider.getMappersForClaimMask((Long) claimMask); for (ProtocolMapperRepresentation protocolMapper : protocolMappers) { BasicDBObject dbMapper = new BasicDBObject(); dbMapper.put("id", KeycloakModelUtils.generateId()); dbMapper.put("protocol", protocolMapper.getProtocol()); dbMapper.put("name", protocolMapper.getName()); dbMapper.put("consentRequired", protocolMapper.isConsentRequired()); dbMapper.put("consentText", protocolMapper.getConsentText()); dbMapper.put("protocolMapper", protocolMapper.getProtocolMapper()); Map<String, String> config = protocolMapper.getConfig(); BasicDBObject dbConfig = MapMapper.convertMap(config, null); dbMapper.put("config", dbConfig); dbProtocolMappers.add(dbMapper); } // Remove obsolete keys from client currentClient.remove("allowedClaimsMask"); log.debugv("Added default mappers to application {1}", currentClient.get("name")); clients.save(currentClient); } } finally { clientsCursor.close(); } } private String insertApplicationRole(DBCollection roles, String roleName, String applicationId) { BasicDBObject role = new BasicDBObject(); String roleId = KeycloakModelUtils.generateId(); role.append("_id", roleId); role.append("name", roleName); role.append("applicationId", applicationId); role.append("nameIndex", applicationId + "//" + roleName); roles.insert(role); return roleId; } }