001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * François Maturel 016 */ 017 018package org.nuxeo.ecm.platform.ui.web.keycloak; 019 020import java.io.IOException; 021import java.io.InputStream; 022import java.lang.reflect.Constructor; 023import java.lang.reflect.InvocationTargetException; 024import java.lang.reflect.Method; 025 026import org.codehaus.jackson.map.ObjectMapper; 027import org.keycloak.adapters.KeycloakDeployment; 028import org.keycloak.adapters.KeycloakDeploymentBuilder; 029import org.keycloak.representations.adapters.config.AdapterConfig; 030import org.keycloak.util.SystemPropertiesJsonParserFactory; 031 032/** 033 * This class is developed to overcome a Jackson version problem between Nuxeo and Keycloak.<br> 034 * Nuxeo uses Jackson version 1.8.x where Keycloak uses 1.9.x<br> 035 * Sadly the {@link ObjectMapper#setSerializationInclusion} method is not in 1.8.x<br> 036 * Then {@link KeycloakNuxeoDeployment} is the same class as {@link KeycloakDeploymentBuilder}, rewriting static method 037 * {@link KeycloakDeploymentBuilder#loadAdapterConfig} to avoid the use of 038 * {@link ObjectMapper#setSerializationInclusion} 039 * 040 * @since 7.4 041 */ 042public class KeycloakNuxeoDeployment { 043 044 /** 045 * Invokes KeycloakDeploymentBuilder.internalBuild with reflection to avoid rewriting source code 046 * 047 * @param is the configuration file {@link InputStream} 048 * @return the {@link KeycloakDeployment} corresponding to the configuration file 049 */ 050 public static KeycloakDeployment build(InputStream is) { 051 AdapterConfig adapterConfig = loadAdapterConfig(is); 052 053 try { 054 Constructor<KeycloakDeploymentBuilder> constructor = KeycloakDeploymentBuilder.class.getDeclaredConstructor(); 055 constructor.setAccessible(true); 056 KeycloakDeploymentBuilder builder = constructor.newInstance(); 057 058 Method method = KeycloakDeploymentBuilder.class.getDeclaredMethod("internalBuild", AdapterConfig.class); 059 method.setAccessible(true); 060 return (KeycloakDeployment) method.invoke(builder, adapterConfig); 061 } catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) { 062 throw new RuntimeException(e); 063 } 064 } 065 066 public static AdapterConfig loadAdapterConfig(InputStream is) { 067 ObjectMapper mapper = new ObjectMapper(new SystemPropertiesJsonParserFactory()); 068 AdapterConfig adapterConfig; 069 try { 070 adapterConfig = mapper.readValue(is, AdapterConfig.class); 071 } catch (IOException e) { 072 throw new RuntimeException(e); 073 } 074 return adapterConfig; 075 } 076 077}