/** * Reads the value of the now-deprecated "auth-provider" property from guacamole.properties, * returning the corresponding AuthenticationProvider class. If no authentication provider could * be read, or the property is not present, null is returned. * * <p>As this property is deprecated, this function will also log warning messages if the property * is actually specified. * * @return The value of the deprecated "auth-provider" property, or null if the property is not * present. */ @SuppressWarnings( "deprecation") // We must continue to use this property until it is truly no longer supported private Class<AuthenticationProvider> getAuthProviderProperty() { // Get and bind auth provider instance, if defined via property try { // Use "auth-provider" property if present, but warn about deprecation Class<AuthenticationProvider> authenticationProvider = environment.getProperty(BasicGuacamoleProperties.AUTH_PROVIDER); if (authenticationProvider != null) logger.warn( "The \"auth-provider\" and \"lib-directory\" properties are now deprecated. Please use the \"extensions\" and \"lib\" directories within GUACAMOLE_HOME instead."); return authenticationProvider; } catch (GuacamoleException e) { logger.warn( "Value of deprecated \"auth-provider\" property within guacamole.properties is not valid: {}", e.getMessage()); logger.debug("Error reading authentication provider from guacamole.properties.", e); } return null; }
/** * Returns the classloader that should be used as the parent classloader for all extensions. If * the GUACAMOLE_HOME/lib directory exists, this will be a classloader that loads classes from * within the .jar files in that directory. Lacking the GUACAMOLE_HOME/lib directory, this will * simply be the classloader associated with the ExtensionModule class. * * @return The classloader that should be used as the parent classloader for all extensions. * @throws GuacamoleException If an error occurs while retrieving the classloader. */ private ClassLoader getParentClassLoader() throws GuacamoleException { // Retrieve lib directory File libDir = new File(environment.getGuacamoleHome(), LIB_DIRECTORY); // If lib directory does not exist, use default class loader if (!libDir.isDirectory()) return ExtensionModule.class.getClassLoader(); // Return classloader which loads classes from all .jars within the lib directory return DirectoryClassLoader.getInstance(libDir); }
/** * Loads all extensions within the GUACAMOLE_HOME/extensions directory, if any, adding their * static resource to the given resoure collections. * * @param javaScriptResources A modifiable collection of static JavaScript resources which may * receive new JavaScript resources from extensions. * @param cssResources A modifiable collection of static CSS resources which may receive new CSS * resources from extensions. */ private void loadExtensions( Collection<Resource> javaScriptResources, Collection<Resource> cssResources) { // Retrieve and validate extensions directory File extensionsDir = new File(environment.getGuacamoleHome(), EXTENSIONS_DIRECTORY); if (!extensionsDir.isDirectory()) return; // Retrieve list of all extension files within extensions directory File[] extensionFiles = extensionsDir.listFiles( new FileFilter() { @Override public boolean accept(File file) { return file.isFile() && file.getName().endsWith(EXTENSION_SUFFIX); } }); // Verify contents are accessible if (extensionFiles == null) { logger.warn( "Although GUACAMOLE_HOME/" + EXTENSIONS_DIRECTORY + " exists, its contents cannot be read."); return; } // Sort files lexicographically Arrays.sort(extensionFiles); // Load each extension within the extension directory for (File extensionFile : extensionFiles) { logger.debug("Loading extension: \"{}\"", extensionFile.getName()); try { // Load extension from file Extension extension = new Extension(getParentClassLoader(), extensionFile); // Validate Guacamole version of extension if (!isCompatible(extension.getGuacamoleVersion())) { logger.debug( "Declared Guacamole version \"{}\" of extension \"{}\" is not compatible with this version of Guacamole.", extension.getGuacamoleVersion(), extensionFile.getName()); throw new GuacamoleServerException( "Extension \"" + extension.getName() + "\" is not " + "compatible with this version of Guacamole."); } // Add any JavaScript / CSS resources javaScriptResources.addAll(extension.getJavaScriptResources().values()); cssResources.addAll(extension.getCSSResources().values()); // Attempt to load all authentication providers bindAuthenticationProviders(extension.getAuthenticationProviderClasses()); // Add any translation resources serveLanguageResources(extension.getTranslationResources()); // Add all HTML patch resources patchResourceService.addPatchResources(extension.getHTMLResources().values()); // Add all static resources under namespace-derived prefix String staticResourcePrefix = "/app/ext/" + extension.getNamespace() + "/"; serveStaticResources(staticResourcePrefix, extension.getStaticResources()); // Serve up the small favicon if provided if (extension.getSmallIcon() != null) serve("/images/logo-64.png").with(new ResourceServlet(extension.getSmallIcon())); // Serve up the large favicon if provided if (extension.getLargeIcon() != null) serve("/images/logo-144.png").with(new ResourceServlet(extension.getLargeIcon())); // Log successful loading of extension by name logger.info("Extension \"{}\" loaded.", extension.getName()); } catch (GuacamoleException e) { logger.error( "Extension \"{}\" could not be loaded: {}", extensionFile.getName(), e.getMessage()); logger.debug("Unable to load extension.", e); } } }