Plugin Security Architecture in OmegaT

This section explains the plugin security architecture in OmegaT, fundamental for understanding and working with its plugin system.


Understanding ClassLoaders and Security

What is a ClassLoader?

A ClassLoader in Java is responsible for loading classes into memory. Think of it as a gatekeeper that controls which classes your code can see and use. Each ClassLoader creates an isolated namespace—classes loaded by one ClassLoader cannot directly access classes loaded by another unless explicitly permitted.

Why ClassLoaders Matter for Security

Consider the following scenarios:

  1. Single Application ClassLoader:

Application ClassLoader
├── Plugin A classes
├── Plugin B classes  
└── Plugin C classes
  • In this setup, Plugin A can access and interfere with Plugin B’s classes.

  1. Per-Plugin ClassLoaders:

Application ClassLoader
├── Plugin A ClassLoader
│   └── Plugin A classes
├── Plugin B ClassLoader  
│   └── Plugin B classes
└── Plugin C ClassLoader
└── Plugin C classes
  • Here, each plugin is isolated, preventing interference.


Current Implementation

OmegaT Design Approach

Code snippet:

EnumMap<PluginType, MainClassLoader> MAINCLASSLOADERS;
  • Assigns one ClassLoader per plugin type:

    • Theme plugins share a ClassLoader.

    • Language plugins share a ClassLoader.

    • Filter plugins share a ClassLoader.

    • …and so on.

For the formal decision and architectural background on this approach, see ADR: Plugin Security Architecture and ClassLoader Isolation.

Security Implications

  1. Intra-Type Interference: Plugins of the same type (e.g., themes) can access each other’s classes.

  2. Dependency Conflicts: Different plugins using incompatible library versions can cause runtime conflicts.

  3. Fault Propagation: A bug or memory leak in one plugin can affect all plugins of the same type.


Theoretical Best Practice: Per-Plugin ClassLoader Isolation

Industry Standard Approach

There is a best practice of the software industry standard. It is “Per-Plugin” classloader isolation.

Here is a code snippet to explain.

public class PluginUtils {
    Map<String, ClassLoader> pluginClassLoaders = new ConcurrentHashMap<>();

    public void loadPlugins() {
        // ... several initializations
        // During plugin loading:
        for (PluginManifest manifest : manifests) {
            ClassLoader pluginClassLoader = new URLClassLoader(
                    manifest.getClasspathUrls(), getClass().getClassLoader()
            );
            pluginClassLoaders.put(manifest.getPluginId(), pluginClassLoader);
        }
    }
}

Benefits

  1. Complete Isolation: Plugins cannot interfere with one another.

  2. Dependency Safety: Plugins can use distinct library versions.

  3. Fault Containment: Failures in one plugin don’t affect others.

  4. Security Boundaries: Malicious plugins are isolated.

  5. Resource Management: Memory leaks are contained per ClassLoader.


Industry Best Practices

  • OSGi Framework: Each bundle (plugin) gets its own ClassLoader

  • Eclipse Plugin System: Plugins are isolated by default

  • IntelliJ IDEA: Plugins run in separate ClassLoaders

  • NetBeans: Module system provides ClassLoader isolation

These systems all choose security over simplicity because plugin isolation is critical for stability and security.


Why Per-Plugin ClassLoaders Won’t Work for OmegaT

OmegaT has specific requirements that make per-plugin ClassLoader isolation impractical.

Constraint 1: Language Module Resource Sharing

  • Problem: Language modules must share resources like dictionaries with the core library.

  • Issue with Isolation:

    • Resources in Plugin A’s ClassLoader are invisible to the core or other plugins.

  • Required Solution:

    • A shared ClassLoader for language plugins ensures resource accessibility.

Constraint 2: Swing UIManager Registration

  • Problem: Theme plugins must register Look-and-Feel (LaF) classes with UIManager.

  • Issue with Isolation:

    • UIManager requires global visibility to LaF classes, which isolated ClassLoaders cannot provide.

  • Required Solution:

    • A shared ClassLoader for theme plugins allows LnF classes to be registered and used globally.


Conclusion

The current design represents the optimal solution for OmegaT’s constraints. It enhances security within reasonable functional limits while maintaining a clean code structure and flexibility for future development.