Friday 9 February 2018

Weblogic 12c + SAML2: publish your metadata over an URL

This week I got to do a SAML2 implementation again for APEX against ADFS. Actually the same setup as last year. One pitfall I fell into with open eyes, was the Redirect URI on the 'Web SSO Partner Provider'. I entered /ords/f*, but it had to be with out the wild-card: /ords/f. But that aside.

At one step in the setup of a SAML2 configuration is that you have to publish the metadata, by clicking a button. Some SAML2 capabable middleware solutions can publish the metadata over an URL. ADFS does support a URL to get the metadata from the Service Provider, being Weblogic12c servicing your application. This prevents that you need to hand over the xml file every time you change/update your configuration. For instance because of expired certificates. How nice would it be if Weblogic supported this?

Well, actually, you can! Sort of... Weblogic does support to service a document-folder, like the htdocs folder of Apache. To do so, you need to create a war file, with only a weblogic.xml file that couples a context-root to a certain folder. And apparently Glassfish can do so too!

When you install ORDS on Weblogic, following the steps, you generate an i.war that is actually the example for this post. You could extract that file and adapt it for this purpose. But I wanted to be able to generate it. Doing so I could reuse this for several other purposes if I would need to.

So I started with a new Saml2MetaData project folder and created a src folder, with a WEB-INF folder beneath it.
Then I copied the three deployment descriptors:
  • sun-web.xml
  • web.xml
  • weblogic.xml
 The sun-web.xml (not being the travel company):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD GlassFish Application Server 3.0 Servlet 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-web-app_3_0-0.dtd">
<sun-web-app>
 <!-- This element specifies the context path the static resources are served from --> 
 <context-root>${samlMetaData.contextRoot}</context-root>
 <!-- This element specifies the location on disk where the static resources are located -->
 <property name="alternatedocroot_1" value="from=/* dir=${samlMetaData.home}"/>
</sun-web-app>

As you can see I placed the ${samlMetaData.contextRoot} the property in the context-root-tag and the property named alternatedocroot_1 got the directory reference containing the ${samlMetaData.home}.

The web.xml is there for completeness, but does not contain a directory reference:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_3.dtd">
<web-app>
 <!-- This Web-App leverages the alternate doc-root functionality in WebLogic and GlassFish to serve static content 
      For WebLogic refer to the weblogic.xml file in this folder
      For GlassFish refer to the sun-web.xml file in this folder
  -->
</web-app>

And then the weblogic.xml: including the same properties referencing the context-root and folder:
<weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app">
 <!-- This element specifies the context path the static resources are served from -->
 <context-root>${samlMetaData.contextRoot}</context-root>
 <virtual-directory-mapping>
  <!-- This element specifies the location on disk where the static resources are located -->
  <local-path>${samlMetaData.home}</local-path>
  <url-pattern>/*</url-pattern>
 </virtual-directory-mapping>
</weblogic-web-app>

Then I need an ANT build file that copies these files replacing the properties. I would have done it with WLST if I had found a way to wrap the lot into a war file, that quickly. But ANT does the job well. First I need a build.properties file, that denotes the properties values:
build.dir=${basedir}/build
dist.dir=${basedir}/dist
src.dir=${basedir}/src
samlMetaData.home=c:\\certs\\saml2
samlMetaData.contextRoot=/samlMetaData


And then the ANT build.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project name="SamlMetaData" basedir="." default="build">
   <property file="build.properties" />
   <!-- Clean & Init -->
   <target name="clean">
      <echo>Delete build and dist folder</echo>
      <delete dir="${build.dir}" />
      <delete dir="${dist.dir}" />
   </target>
   <target name="init" depends="clean">
      <echo>Create build and dist folder</echo>
      <mkdir dir="${build.dir}" />
      <mkdir dir="${dist.dir}" />
   </target>
   <!-- war the project -->
   <target name="war">
      <property name="war.dir" value="${dist.dir}/${ant.project.name}" />
      <property name="war.file" value="${war.dir}/${ant.project.name}.war" />
      <echo>Create war file ${war.file} from ${build.dir}</echo>
      <mkdir dir="${war.dir}" />
      <jar destfile="${war.file}" basedir="${build.dir}">
         <manifest />
      </jar>
   </target>
   <!-- Build the war file -->
   <target name="build" depends="init">
      <echo>Copy ${src.dir} to  ${build.dir}, expanding properties</echo>
      <copy todir="${build.dir}">
         <fileset dir="${src.dir}" />
         <filterchain>
            <expandproperties />
         </filterchain>
      </copy>
      <ant target="war" />
   </target>
</project>

Run this with ANT andit will create a build and a dist  folder with the war file.
This can be deployed to Weblogic that results in a context root as configured in the build.properties. Everything placed in the folder as configured in the samlMetaData.home folder can be fetched through Weblogic.

So just publish your metadata to that folder and the IdentityProvider can get it auto-magically.
And of course you can use this for any other static file provisioning through Weblogic.

No comments :