Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Table of Contents


Overview

The ModuleConfiguration page discusses the general idea behind IdP Modules and how they're used by deployers. This page describes the concept technically, explains how the system's built-in modules are laid out, and explains how to expose them from third-party plugins, which is very straightforward.

An IdPModule is an implementation of the titular Java interface that exposes information about a module to the system and provides very basic operations to enable and disable the module. The CLI uses the interface to perform that work and the information returned to report results.

...

An IdPModule is found through the Java Services API, which relies on a special file in META-INF to identify the possible implementations of an interface. The tools that operate on IdPModules use the ServiceLoader class to locate the implementations and instantiate the interface to perform work. There are no other inherent restrictions on how modules may be implemented, but there are classes provided that simplify the work involved to simply defining a few properties and embedding various files in a jar on the IdP's classpath.

...

For a Module derived from the AbstractIdPModule class, the following outline describes what happens for example.xml during enable (updates are the same):

  1. If noreplace:

    1. If the file already exists:

      1. If the old content is the same as the new content, nothing happens.

      2. Else the new content is copied to example.xml.idpnew (previous versions of example.xml.idpnew are overwritten).

    2. Else the new content is copied to example.xml

  2. Else

    1. If the file already exists:

      1. If the old content is the same as the new content, nothing happens.

      2. Else the new content is copied to example.xml and the old content is copied to example.xml.idpsave (failing the enable operation if this file exists).

For disable:

  1. If the file exists:

    1. If the clean option is supplied or the old content is the same as the default content, then the file is removed.

    2. Else the old file is copied to example.xml.idpsave (overwriting previous versions).

  2. Else nothing happens.

The basis for comparison is a SHA-1 hash of the content.

...

To expose a module, at least one new jarfile must be incorporated into the IdP's classpath containing an implementation of the IdPModule interface and the necessary services file identifying it in META-INF/services/net.shibboleth.idp.module.IdPModule

That's technically all that is required in absolute terms. Practically speaking, most modules will be based on the PropertyDrivenIdPModule API class and will be implemented via a very short Java class, a module.properties file, and any additional resources the module manages.

Property Reference

When using the PropertyDrivenIdPModule class to implement modules, all of the module description takes the form of a Java properties file. The "root" property for a module has the name of the implementation class of the module, and the value is the module's ID, or unique key. Module naming should rely on Java package syntax for uniqueness, but need not match actual Java packages or classes.

All other property names are prefixed by the module ID, followed by a period (.), and then a property suffix. The following suffixes are supported. Only "name" is required.

Suffix

Description

name

A human-readable but brief name

desc

A longer, human-readable description

url

A URL for more information or documentation

postenable

A message to display to a deployer that enables the module

postdisable

A message to display to a deployer that disables the module

n.src

Classpath or HTTP/HTTPS resource location for resource N managed by the module

n.dest

Filesystem location relative to idp.home for resource N to be placed when enabled

n.replace

A true/false value indicating whether a resource should directly overwrite an existing copy of itself. Default is false.

n.optional

A true/false value indicating whether the absence of a resource should influence whether the module is enabled or not. Default is false. This is useful to allow deployers to remove a file without the module thinking it's then disabled.

n.exec

A true/false value indicating whether a file should be marked executable on POSIX systems. Default is false.

The final 5 properties are a repeating pair (src/dest) for each resource managed by the module, with the others being optional. Resources are numbered starting at 1 and increasing atomically up to the last resource managed (no gaps allowed). Sources are generally classpath-based and should be absolute to ensure proper lookup. Destinations are filesystem paths relative to the IdP's install tree.

...

The following approach and layout is strongly suggested.

text
Code Block
language
Expand
titleSuggested JAR Layout
Code Block
languagetext
META-INF/
	services/
		net.shibboleth.idp.module.IdPModule (property file)
org/
	example/
		module/
			impl/
				Example.java (module implementation)
				module.properties (property file)
			conf/
				example.xml (a Spring configuration file, optional)
			views/
				example.vm (a Velocity view, optional)
			edit-webapp/
				example.jsp (a JSP page, optional)

Given the above example, the required files have content as follows:

textcollapsetrue
Code Block
language
Expand
titleMETA-INF/services/net.shibboleth.idp.module.IdPModule
Code Block
language
text
org.example.module.impl.Example
javacollapsetrue
Code Block
language
Expand
titleorg/example/module/impl/Example.java
Code Block
language
java
package org.example.module.impl;

import java.io.IOException;

import net.shibboleth.idp.module.IdPModule;
import net.shibboleth.idp.module.ModuleException;
import net.shibboleth.idp.module.PropertyDrivenIdPModule;

/**
 * {@link IdPModule} implementation.
 */
public final class Example extends PropertyDrivenIdPModule {

    /**
     * Constructor.
     *  
     * @throws ModuleException on error
     * @throws IOException on error
     */
    public Example() throws IOException, ModuleException {
        super(Example.class);
    }
}

Assuming the (optional) resources noted above in the original layout, the module definition properties would be:

textcollapsetrue
Code Block
language
Expand
titleorg/example/module/impl/module.properties
Code Block
language
text
# You can assign a shorter module ID to use independent of the class.
org.example.module.impl.Example = org.example.Example

org.example.Example.name = Example Module
org.example.Example.desc = Feature that does an example thing
org.example.Example.url = https://wiki.example.org/docs/ExampleModule
org.example.Example.1.src = /org/example/module/conf/example.xml
org.example.Example.1.dest = conf/example-config.xml
org.example.Example.2.src = /org/example/module/views/example.vm
org.example.Example.2.dest = views/example.vm
org.example.Example.3.src = /org/example/module/edit-webapp/example.jsp
org.example.Example.3.dest = edit-webapp/example.jsp
org.example.Example.postenable = Customize edit-webapp/example.jsp and rebuild war to deploy.

Core IdP Modules

The IdP modules that are part of the core software release are implemented inside of the idp-conf-impl Maven module as subtypes of the CoreIdPModule implementation class. This allows the module "url" property to be relative to the proper IdP wiki space (IDP4 initially). All modules are implemented in classes in impl packages and are assigned IDs that are prefixed with "idp.", further subdivided by functional area. The layout is as follows:

...

Modules packaged within plugins produced by the Shibboleth Project should implement them based on the PluginIdPModule implementation class, a special case of depending on an implementation class in a separate module. This is strictly to "hide" the class from third parties. This allows the module "url" property to be relative to the proper wiki space (IDPPLUGINS).