View Javadoc

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              // we don't need to check if all permissions are allowed
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                  // This will go via super to the delegate
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                 // This will go via super to the delegate
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 }