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