Chapter 4. Creating Custom Authentication Providers with Maven

In this chapter we will learn how to implement a custom provider that integrates some of our legacy SSO systems.

Developing a provider consists of the following tasks:

  • Creating and configuring a Maven project
  • Writing our MBean delegate
  • Developing a JAAS LoginModule that interacts with our SSO and returns Principals to WebLogic

As we shall see, the hardest work will be configuring Maven to have a reproducible and industry-ready project that can create the MBean JAR file for us.

The Maven project

There is no WebLogic MBeanMaker plugin in our application and also the existing tool is not really Maven friendly.

Tip

WebLogic MBeanMaker

This is a command-line utility that generates all the files you need to form an MBean type, from partial Java classes to contract interfaces and some custom files used by WebLogic itself to introspect the MBean once it is deployed in JAR inside the system class loader.

What we will do is an integration of the existing technologies into Maven using the maven-antrun-plugin plugin as a bridge between these two worlds. These technologies are so invasive that we will have to disable some standard and common Maven plugins such as maven-jar-plugin and maven-install-plugin. In a sense, the work of the compile plugin will be done by this piece of ancient BEA technology.

But all of this makes sense if we want to have a piece of software that can be integrated into modern build systems, and if we want to have a good development environment where we can work in a write-deploy-run lifecycle.

Creating the Maven project

We will start simple, with the shortest and simplest Maven POM we can have, as shown in the following code snippet:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>net.lucamasini.security</groupId>
    <artifactId>chapter-4-auth-provider</artifactId>
    <version>1.0-SNAPSHOT</version>

</project>

Here, we didn't specify a parent POM and we left the standard JAR packaging as it is—even if this is not managed by Maven—because it will be done directly by WebLogic MBeanMaker. We are not going to specify, here, all the properties that are needed because there are too many and they will be introduced progressively as we proceed with this chapter.

Dependencies

Our projects need some dependencies from the WebLogic binaries to compile. The different binaries that need to be added are explained in the following steps:

  1. First we need to add the JAR containing the custom WebLogic Security API of our MBean, as shown in the following code snippet:
    <dependency>
      <groupId>com.bea.core</groupId>
       <artifactId>commons.security.api</artifactId>
       <version>1.1.0.0_6-2-0-0</version>
       <scope>system</scope>
       <systemPath>
        ${middleware.home}/modules/
        com.bea.core.common.security.api_1.1.0.0_6-2-0-0.jar
      </systemPath>
    </dependency>
  2. Then, we need to add a JAR containing classes that we will use in our LoginModule (WLSUser and WLSGroup), as shown in the following code snippet:
    <dependency>
      <groupId>com.bea.core</groupId>
       <artifactId>weblogic.security</artifactId>
       <version>1.1.0.0_6-2-0-0</version>
       <scope>system</scope>
       <systemPath>
        ${middleware.home}/modules/
        com.bea.core.weblogic.security_1.1.0.0_6-2-0-0.jar
      </systemPath>
    </dependency>
  3. Finally we need the WebLogic mega JAR where most of the used classes are located; it can be added using the following code:
    <dependency>
      <groupId>oracle</groupId>
       <artifactId>weblogic</artifactId>
       <version>${weblogic.version}</version>
       <scope>system</scope>
       <systemPath>
        ${middleware.home}/wlserver/server/lib/weblogic.jar
      </systemPath>
    </dependency>
  4. As can be seen from this first piece of POM, we need to add two properties; one of them points to WebLogic installation, as shown in the following code:
    <middleware.home>/path/to/wls1211_dev</middleware.home>
  5. The other is the version we are developing on, as shown in the following code:
    <weblogic.version>12.1.1.0</weblogic.version>

Reconfiguring standard plugins

Another easy step is to reconfigure some common Maven plugins, such as compile and resources. Inside the <build> tag, we add the following code:

<plugins>
    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.0.2</version>
        <configuration>
            <encoding>UTF-8</encoding>
            <source>${maven.compiler.source}</source>
            <target>${maven.compiler.target}</target>
        </configuration>
    </plugin>
   <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <encoding>UTF-8</encoding>
        </configuration>
        <executions>
            <execution>
                <id>default-install</id>
                <phase>install</phase>
                <goals>
                    <goal>copy-resources</goal>
                </goals>
                <configuration>
                    <outputDirectory>
                    ${domain.dir}/lib/mbeantypes
              </outputDirectory>
                    <resources>
                        <resource>
                            <directory>
                    ${project.build.directory}
                   </directory>
                            <includes>
                                <include>
                    ${project.build.finalName}.jar
                      </include>
                            </includes>
                        </resource>
                    </resources>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>

Here, we configure UTF-8 as standard encoding so that it is platform independent (remember to configure your source editor) and we set source/target version for the javac compiler. Of course, we need to define the following two new properties:

<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>

As already explained, the WebLogic MBeanMaker takes care of packaging the created artifact, so we need to disable the standard maven-jar-plugin plugin. Moreover, the out-of-the-box install goal does not make any sense in this environment, so we configure an ad hoc execution of maven-resources-plugin that moves the generated JAR file inside the correct folder, because of which we can also disable the standard maven-install-plugin plugin, as shown in the following code snippet:

<plugin>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <executions>
        <execution>
            <id>default-jar</id>
            <phase>none</phase>
        </execution>
    </executions>
</plugin>
<plugin>
    <artifactId>maven-install-plugin</artifactId>
    <version>2.3.1</version>
    <executions>
        <execution>
            <id>default-install</id>
            <phase>none</phase>
        </execution>
    </executions>
</plugin>

We can see that in order to disable one of the standard Maven plugins, all we need to do is bind its internal execution ID to the none execution phase.

The install plugin is replaced by the default-install execution of maven-resources-plugin, where we tell it to move the generated JAR inside the WebLogic domain's lib/mbeantype folder, which is the default folder for custom Providers. For that we need to define a new property, as shown in the following code snippet:

<domain.dir>/path/to/your/domain</domain.dir>

The path should point to the folder where we created the development domain.

Now another plugin, this time a custom plugin from Codehaus' Mojo project, one that does something that Maven should do on its own—add another source folder.

Quite often you have more than one place where sources are placed because one of them was written by a developer and the others are autogenerated. This kind of configuration is not possible using the standard set of Maven plugins. Luckily, this simple plugin that does a lot of other interesting things, allows us to add other folders as source folders. This plugin is used in the following code snippet:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.5</version>
    <executions>
        <execution>
            <id>add-source</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>add-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>${generated.sources.dir}</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

The execution of the add-source goal is bound to the generate-sources phase so that everything is consistent within this POM configuration. What is ${generated.sources.dir}? It is a new property, defined as follows:

<generated.sources.dir>
  ${project.build.directory}/generated-source
</generated.sources.dir>

It is the destination where we will tell WebLogic MBeanMaker to write its custom generated classes.

The last simple task we will do inside this POM is to enable resource filtering. Again inside the <build> tag, we add the following code:

<resources>
    <resource>
        <filtering>true</filtering>
        <directory>src/main/resources</directory>
    </resource>
</resources>

Adding WebLogic MBeanMaker to the POM

WebLogic's MBean is an old BEA-patented technology and is based on the following:

  • An XML MBean definition file
  • A set of APIs
  • A generator that—in two steps—generates the MBean that executes our LoginModule and then packages it for deployment under WebLogic as an Authentication Provider.

That said, it is a really old piece of software and it's tied to WebLogic and its custom development environment, based on Ant and proprietary APIs. Integration with Maven is possible in the following two ways:

  • The main road: Writing a custom plugin that uses Oracle's utility and also configures the execution phase
  • Let it think: Deceive MBeanMaker to think it is running inside Ant using the mave-antrun-plugin plugin

Of course, the former is a better solution that can spare us a lot of time configuring the POM, but you need to have some time to write and maintain it over an extended period of time and over different WebLogic versions.

Using the latter solution instead is far less elegant because we need to write some old Ant XML configuration. But this way it's really easy to integrate it with Maven.

That said, we will explore the second solution and we will configure Ant to execute the generator for us. The first thing to do is to configure the plugin and its dependencies, as shown in the following code snippet:

<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.3</version>
    <dependencies>
        <dependency>
            <groupId>weblogic</groupId>
            <artifactId>weblogic</artifactId>
            <version>${weblogic.version}</version>
            <scope>system</scope>
            <systemPath>
        ${middleware.home}/wlserver/server/lib/weblogic.jar
          </systemPath>
        </dependency>
    </dependencies>
    <executions>
  …
  …

Then, we will code the two execution tags. First, the MBean definition file is read and then the intermediary files are created, as shown in the following code snippet:

<execution>
    <id>generate-mbean</id>
    <phase>process-resources</phase>
    <goals>
        <goal>run</goal>
    </goals>
    <configuration>
        <tasks>
            <java fork="true" classname="weblogic.management.commo.WebLogicMBeanMaker" classpathref="maven.plugin.classpath">
              <jvmarg 
          value="-DMDF=${project.build.outputDirectory}/
                PacktSiteUsersAuthentication.xml" />
              <jvmarg 
          value="-Dfiles=${project.build.outputDirectory}" />
              <jvmarg value="-DcreateStubs=true" />
              <jvmarg value="-Dverbose=true" />
            </java>
        </tasks>
    </configuration>
</execution>

Here, we launch the WebLogic MBeanMaker telling it to parse the XML file inside the output folder. This works because we linked this execution to the process-resources and so we can be sure that maven-resources-plugin has filtered our resources and placed them inside the configured output folder. We also tell it to place the intermediate files inside the output folder and to eventually overwrite existing stubs (not in our case because we are using a generated folder). Finally, we enable the verbose mode to display any important information in case we need them.

In the second execution, the intermediary files and developer code is compiled and packaged as an MBean, as shown in the following code snippet:

<execution>
    <id>generate-jar</id>
    <phase>compile</phase>
    <goals>
        <goal>run</goal>
    </goals>
    <configuration>
        <tasks>
            <java fork="true"
 classname="weblogic.management.commo.WebLogicMBeanMaker"
 classpathref="maven.plugin.classpath">
                <jvmarg value="-DMJF=${jar.file}" />
                <jvmarg value="-Dfiles=${project.build.outputDirectory}" />
                <jvmarg value="-DcreateStubs=true" />
                <jvmarg value="-DpreserveStubs=true" />
                <jvmarg value="-Dverbose=true" />
                <arg value="-preserveStubs" />
            </java>
            <move 
          todir="${generated.sources.dir}/${package.dir}" 
          file="${project.build.outputDirectory}/
              PacktSiteUsersAuthenticationImpl.java" />
            <move todir="${generated.sources.dir}">
                <fileset 
              dir="${project.build.outputDirectory}">
                    <include name="**/*.java" />
                </fileset>
            </move>
        </tasks>
    </configuration>
</execution>

Of course, here we need to define two new Maven properties; the first points to the JAR file that we want to be generated, as shown in the following code snippet:

<jar.file>
${project.build.directory}/${project.build.finalName}.jar
</jar.file>

The second is used to preserve package structure during the move task, as shown in the following code:

<package.dir>
net/lucamasini/security
</package.dir>

Maven configuration is now completed. This POM can be used as a template for every Authentication Provider we need to do, and we can proceed to the core implementation of the MBean, starting with its XML definition.

Defining the MBean with an MDF File

The central point of our development iteration is the MDF file, where we define the MBean that is a wrapper of LoginModule, which we will implement. This is a custom XML and you need the commo.dtd file that can be found inside the WebLogic installation (under the $MW_HOME/wl_server/server/lib folder) and copy it inside the src/main/resources folder of your project, because from now on it will be referenced using the SYSTEM document type, as shown in the following code snippet:

<?xml version="1.0" ?>
<!DOCTYPE MBeanType SYSTEM "commo.dtd">

Of course, the main tag is named MBeanType and defines how the MBean class will be generated; the MBeanType is defined as follows:

<MBeanType
Name = "PacktSiteUsersAuthentication"
DisplayName = "PacktSiteUsersAuthentication"
Package = "net.lucamasini.security"
Extends =
"weblogic.management.security.authentication.Authenticator"
PersistPolicy = "OnUpdate"
>

Every attribute of this tag is very important, starting with the name that will be used to define a new XML schema type for the security namespace inside the WebLogic's config.xml file, as defined in the following code snippet:

<sec:authentication-provider
xmlns:ext="http://xmlns.oracle.com/weblogic/security/extension" 
xsi:type="ext:packt-site-users-authenticationType">
  <sec:name>packt</sec:name>
  <sec:control-flag>OPTIONAL</sec:control-flag>
</sec:authentication-provider>

Here, we can see that xsi:type is the MBean name lowered, with a - between lowercase letters and with Type as a suffix.

The DisplayName attribute is instead used inside the WebLogic console and that is what we see in the drop-down menu when we add a new Authentication Provider.

Package is the Java package of the generated artifacts and Extends is the standard MBean we decided to extend—weblogic.management.security.authentication.Authenticator—when we develop an Authentication Provider.

The last attribute—PersistPolicy = "OnUpdate"—tells to generate an MBean that will write itself in the storage file (usually the config.xml) every time one of its attributes is modified.

Finally, we can run an mvn install to generate our Authentication Provider, as shown in the following command:

mvn install

This provider is not yet a working provider, but we can catch a glimpse of what we are going to build.

It can be installed under the WebLogic console, but then WebLogic will refuse to start with a [Security:097533]SecurityProvider service class name for PackProvider is not specified error message because we haven't yet configured the MDF, and nor have we written the implementation of our MBean. But apart from this, WebLogic knows what we have just generated and tries to use it (if you are panicking about your WebLogic domain, just delete the sec: section inside the config.xml file).

Peering inside the target folder, we can notice a special class under the weblogic.management.security package; in our sample it will be named CHAPTER4_AUTH_PROVIDER_1_0_SNAPSHOT1345106773809855000BeanInfoFactory. It is named with the name of the MBean JAR file along with the current time in milliseconds, which is different every time we do the install (for that always remember to do a clean before install). This class is a factory that, given the interface, references the standard JavaBean's BeanInfo class of our MBean implementation.

We can proceed with writing our MDF and adding the configuration for ProviderClassName as follows:

<MBeanAttribute
Name = "ProviderClassName"
Type = "java.lang.String"
Writeable = "false"
Default = "&quot;net.lucamasini.security.PacktAuthProviderImpl&quot;"
/>

Please note that we need to use the &quot; XML entity because the ProviderClassName attribute needs a value between quotes, but these are now used by the XML file itself.

If not, when we relaunch the install and start WebLogic, we will get a completely different error message—[Security:097534]Failed to obtain an instance of class net.lucamasini.security.PacktAuthProviderImpl. This is because we've now specified which class will be our MBean implementation and WebLogic tries to create a new instance of a class that doesn't exist yet.

The next two attributes that we are going to add are those that the WebLogic administrator will see when he/she will configures the provider; these attributes are as follows:

<MBeanAttribute
Name = "Description"
Type = "java.lang.String"
Writeable = "false"
Default = "&quot;WebLogic Packt Authentication Provider&quot;"
/>

<MBeanAttribute
Name = "Version"
Type = "java.lang.String"
Writeable = "false"
Default = "&quot;1.0&quot;"
/>

In description and version, we can add whatever we prefer; these are two informative strings and we can check this in the MBeanImplBeanInfo class by looking for these two properties.

Finally, we add a real configuration property, the URL that will be used by our provider to interact with our legacy SSO system, as shown in the following code:

<MBeanAttribute
Name = "URL"
Type = "java.lang.String"
Writeable = "true"
Default = "&quot;${authentication.services.url}&quot;"
/>

In a different manner from the other attributes, this can also be written using the console (or directly into the config.xml file) by our system administrator. We are not hardcoding the URL inside the MDF file, but using Maven's resource filtering so that we can configure this parameter inside our POM—maybe with different values between our environments (development, stage, and production).

Of course, our POM must be enriched with the following new property:

<authentication.services.url>
   http://localhost:8080/sso.jsp
</authentication.services.url>

Our MDF file configuration is completed. We can now code the MBean's delegate implementation class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.179.85