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 @Override
47 public void discardPlugin(Plugin plugin) throws PluginException
48 {
49 if (!(plugin instanceof UnloadablePlugin))
50 {
51 super.discardPlugin(plugin);
52 }
53 else
54 {
55 logger.debug("Detected an unloadable plugin '{}', so skipping discard", plugin.getKey());
56 }
57 }
58
59 private final class CheckPluginPermissionFunction implements Function<Plugin, Plugin>
60 {
61 @Override
62 public Plugin apply(Plugin p)
63 {
64
65 if (p.hasAllPermissions())
66 {
67 return p;
68 }
69
70 if (p instanceof PluginArtifactBackedPlugin)
71 {
72 return checkPlugin((PluginArtifactBackedPlugin) p);
73 }
74 return p;
75 }
76
77 private Plugin checkPlugin(PluginArtifactBackedPlugin p)
78 {
79 final PluginArtifact pluginArtifact = p.getPluginArtifact();
80
81 if (pluginArtifact.containsJavaExecutableCode() && !p.getActivePermissions().contains(Permissions.EXECUTE_JAVA))
82 {
83 UnloadablePlugin unloadablePlugin = new UnloadablePlugin(
84 "Plugin doesn't require '" + Permissions.EXECUTE_JAVA + "' permission yet references some java executable code. " +
85 "This could be either embedded java classes, embedded java libraries, spring context files or bundle activator.");
86 unloadablePlugin.setKey(p.getKey());
87 unloadablePlugin.setName(p.getName());
88
89 logger.warn("Plugin '{}' only requires permission {} which doesn't include '{}', yet has some java code " +
90 "(classes, libs, spring context, etc), making it un-loadable.",
91 new Object[]{p.getKey(), p.getActivePermissions(), Permissions.EXECUTE_JAVA});
92
93
94 discardPlugin(p);
95
96 return unloadablePlugin;
97 }
98 else if (hasSystemModules(p) && !p.getActivePermissions().contains(Permissions.CREATE_SYSTEM_MODULES))
99 {
100 UnloadablePlugin unloadablePlugin = new UnloadablePlugin(
101 "Plugin doesn't require '" + Permissions.CREATE_SYSTEM_MODULES + "' permission yet declared " +
102 "modules use the 'system' attribute. ");
103 unloadablePlugin.setKey(p.getKey());
104 unloadablePlugin.setName(p.getName());
105
106 logger.warn("Plugin '{}' only requires permission {} which doesn't include '{}', yet has system modules " +
107 ", making it un-loadable.",
108 new Object[]{p.getKey(), p.getActivePermissions(), Permissions.CREATE_SYSTEM_MODULES});
109
110
111 discardPlugin(p);
112
113 return unloadablePlugin;
114 }
115 else
116 {
117 return p;
118 }
119 }
120
121 private boolean hasSystemModules(PluginArtifactBackedPlugin plugin)
122 {
123 for (ModuleDescriptor descriptor : plugin.getModuleDescriptors())
124 {
125 if (descriptor.isSystemModule())
126 {
127 return true;
128 }
129 }
130 return false;
131 }
132 }
133 }