Skip to main content

On This Page

Building Morpheus Plugins: A Practical Workflow for Engineers

3 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

Building a Morpheus Plugin A Practical Walkthrough

The Morpheus hybrid cloud management platform provides an SDK with over fifty provider types for extending cloud integrations and UI components. This guide demonstrates building an MFA enforcement utility to close a security gap where appliance-wide 2FA is not natively supported.

Why This Matters

While the SDK is documented in pieces, the practical transition from idea to a running shadow JAR on an appliance is often undocumented. Technical reality requires managing Gradle 7.x/JDK 11 compatibility while targeting Java 8, and failing to account for Content-Security-Policy (CSP) through nonce helpers results in silent UI failures that are difficult to debug.

Key Insights

  • The SDK exposes 50+ provider types like CloudProvider and GlobalUIComponentProvider to hook into specific lifecycle moments.
  • Local clones of morpheus-plugin-core and morpheus-openapi are essential for high-speed grepping of 600+ endpoint files and 650+ schemas.
  • The shadow plugin must be updated to com.github.johnrengelman.shadow version 7.1.2 for compatibility with Gradle 7.x and JDK 11.
  • Using compileOnly for the plugin API and Groovy is mandatory to prevent NoSuchMethodError at runtime caused by classpath conflicts.
  • GlobalUIComponentProvider allows HTML injection via Handlebars but requires the {{nonce}} helper to bypass Morpheus strict security headers.

Working Examples

Setting up reference material for local grepping.

git clone --depth 1 --branch v1.2.x https://github.com/HewlettPackard/morpheus-plugin-core.git
git clone --depth 1 https://github.com/HewlettPackard/morpheus-docs.git
git clone --depth 1 https://github.com/HewlettPackard/morpheus-openapi.git

Minimal build.gradle configuration for a Morpheus shadow JAR.

plugins {
  id 'java'
  id 'groovy'
  id 'com.github.johnrengelman.shadow' version '7.1.2'
}
group = 'com.morpheusdata'
version = '1.0.0'
sourceCompatibility = '11'
targetCompatibility = '11'
repositories { mavenCentral() }
dependencies {
  compileOnly 'com.morpheusdata:morpheus-plugin-api:0.15.4'
  compileOnly 'org.codehaus.groovy:groovy-all:3.0.11'
  compileOnly 'io.reactivex.rxjava3:rxjava:3.1.5'
  compileOnly 'org.slf4j:slf4j-api:1.7.26'
}
shadowJar {
  manifest {
    attributes(
      'Plugin-Class' : 'com.example.myplugin.MyPlugin',
      'Plugin-Version': archiveVersion.get()
    )
  }
}

The Plugin class serves as the entry point for registration.

class MfaEnforcerPlugin extends Plugin {
  @Override String getCode() { 'morpheus-mfa-enforcer-plugin' }
  @Override void initialize() {
    setName("MFA Enforcer")
    def provider = new MfaEnforcerProvider(this, morpheus)
    pluginProviders.put(provider.code, provider)
  }
}

Handlebars template using the nonce helper to satisfy CSP requirements.

<div id="mfa-shield" role="dialog" aria-modal="true">
<style nonce="{{nonce}}">
#mfa-shield {
  position: fixed; inset: 0; z-index: 2147483647;
  background: rgba(15, 23, 42, 0.75);
  display: flex; align-items: center; justify-content: center;
}
</style>
<div class="card">
  <h1>Two-Factor Authentication Required</h1>
  <a class="cta" href="{{userSettingsUrl}}" target="_top">
    Go to User Settings -> Enable 2FA
  </a>
</div>
</div>

Practical Applications

  • Use Case: Implementing appliance-wide MFA enforcement using GlobalUIComponentProvider to intercept users post-login. Pitfall: Performing uncached database lookups on every page render, which creates latency and InnoDB lock contention.
  • Use Case: Adding custom detail tabs via InstanceTabProvider or AppTabProvider. Pitfall: Implementing bare interfaces instead of extending AbstractProvider, which leads to missing Handlebars helpers and classpath prefix errors.
  • Use Case: Hardening security via password complexity rules or IP-based access restrictions. Pitfall: Relying on browser session cookies for internal API calls, which require OAuth2 bearer tokens for /api/* endpoints.

References:

Continue reading

Next article

Automating Accessibility with the CSS contrast-color() Function

Related Content