1 package com.atlassian.plugin.loaders;
2
3 import com.atlassian.plugin.*;
4 import com.atlassian.plugin.impl.UnloadablePlugin;
5 import com.google.common.base.Function;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8
9 import static com.google.common.collect.ImmutableList.copyOf;
10 import static com.google.common.collect.Iterables.transform;
11
12 public final class PermissionCheckingPluginLoader extends ForwardingPluginLoader
13 {
14 private static final Logger logger = LoggerFactory.getLogger(PermissionCheckingPluginLoader.class);
15
16 public PermissionCheckingPluginLoader(PluginLoader delegate)
17 {
18 super(delegate);
19 }
20
21 @Override
22 public Iterable<Plugin> loadAllPlugins(ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
23 {
24 return copyOf(transform(delegate().loadAllPlugins(moduleDescriptorFactory), new CheckPluginPermissionFunction()));
25 }
26
27 @Override
28 public Iterable<Plugin> loadFoundPlugins(ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
29 {
30 return copyOf(transform(delegate().loadFoundPlugins(moduleDescriptorFactory), new CheckPluginPermissionFunction()));
31 }
32
33 @Override
34 public void removePlugin(Plugin plugin) throws PluginException
35 {
36 if (!(plugin instanceof UnloadablePlugin))
37 {
38 super.removePlugin(plugin);
39 }
40 else
41 {
42 logger.debug("Detected an unloadable plugin '{}', so skipping removal", plugin.getKey());
43 }
44 }
45
46 private static final class CheckPluginPermissionFunction implements Function<Plugin, Plugin>
47 {
48 @Override
49 public Plugin apply(Plugin p)
50 {
51
52 if (p.hasAllPermissions())
53 {
54 return p;
55 }
56
57 if (p instanceof PluginArtifactBackedPlugin)
58 {
59 return checkPlugin((PluginArtifactBackedPlugin) p);
60 }
61 return p;
62 }
63
64 private Plugin checkPlugin(PluginArtifactBackedPlugin p)
65 {
66 final PluginArtifact pluginArtifact = p.getPluginArtifact();
67
68 if (pluginArtifact.containsJavaExecutableCode() && !p.getActivePermissions().contains(Permissions.EXECUTE_JAVA))
69 {
70 UnloadablePlugin unloadablePlugin = new UnloadablePlugin(
71 "Plugin doesn't require '" + Permissions.EXECUTE_JAVA + "' permission yet references some java executable code. " +
72 "This could be either embedded java classes, embedded java libraries, spring context files or bundle activator.");
73 unloadablePlugin.setKey(p.getKey());
74 unloadablePlugin.setName(p.getName());
75
76 logger.warn("Plugin '{}' only requires permission {} which doesn't include '{}', yet has some java code " +
77 "(classes, libs, spring context, etc), making it un-loadable.",
78 new Object[]{p.getKey(), p.getActivePermissions(), Permissions.EXECUTE_JAVA});
79
80 return unloadablePlugin;
81 }
82 else if (hasSystemModules(p) && !p.getActivePermissions().contains(Permissions.CREATE_SYSTEM_MODULES))
83 {
84 UnloadablePlugin unloadablePlugin = new UnloadablePlugin(
85 "Plugin doesn't require '" + Permissions.CREATE_SYSTEM_MODULES + "' permission yet declared " +
86 "modules use the 'system' attribute. ");
87 unloadablePlugin.setKey(p.getKey());
88 unloadablePlugin.setName(p.getName());
89
90 logger.warn("Plugin '{}' only requires permission {} which doesn't include '{}', yet has system modules " +
91 ", making it un-loadable.",
92 new Object[]{p.getKey(), p.getActivePermissions(), Permissions.CREATE_SYSTEM_MODULES});
93
94 return unloadablePlugin;
95 }
96 else
97 {
98 return p;
99 }
100 }
101
102 private boolean hasSystemModules(PluginArtifactBackedPlugin plugin)
103 {
104 for (ModuleDescriptor descriptor : plugin.getModuleDescriptors())
105 {
106 if (descriptor.isSystemModule())
107 {
108 return true;
109 }
110 }
111 return false;
112 }
113 }
114 }