Plugin Tutorial : Creating a SSOPlugin for Vertical Site 4.2
A common scenario for many larger-scale companies is to implement some sort of identity management system. The rationale for implementing such a system is to ensure a unified policy for authentication and authorization across all corporate intranets and extranets, often with a complex infrastructure. So where does Vertical Site fit in, in this scenario? When implementing a security framework you leave all your authentication and authorization concerns to the service. So when the http-request hits Vertical Site, the user and request has already passed clearance. That means that Vertical Site doesn’t have to do it. So your first step would be to get rid of the existing Vertical Site login and then implement a SSOPlugin. The plugin then automatically logs in the user into Vertical Site when certain rules are met. In this tutorial this is the presence of a valid http request header. In our example we’ll assume that we are using IBM Tivoli Access Manager/WebSeal, so the header we are looking for is named “iv-user”. But first, a brief description of how WebSeal works: WebSEAL normally acts as a reverse Web proxy by receiving HTTP/HTTPS requests from a Web browser and delivering content from its own Web server or from junctioned back-end Web application servers. Requests passing through WebSEAL are evaluated by the Tivoli Access Manager authorization service to determine whether the user is authorized to access the requested resource Source: IBM Tivoli Access Manager & WebSEAL So let’s get started.
Create the pom.xml
The first thing we do is to create the Maven configuration - pom.xml.
The directory layout follows the standard Maven recommendation.
The dependencies are all but one, commonly available, but notice the last one - “com.enonic.cms”.
To be able to compile you must add this dependency to your local repository, follow these steps.
- Find you Vertical Site 4.2.x release zip file (or under Downloads on the Community web).
- Unzip this file, and find cms.war under the /webapps folder
- Unzip cms.war.
- Under WEB-INF/lib, you’ll find cms-core-4.2.x.jar.
- Open a command window and CD to the directory where cms-core-4.2.x jar is located.
- Run the following Maven command
(replace 4.2.x with the correct version number you have downloaded/are running)
mvn install:install-file -DgroupId=com.enonic.cms -DartifactId=cms-core -Dversion=4.2.x -Dpackaging=jar -Dfile=cms-core-4.2.x.jar
There you go, the cms-core dependency should now be in your local repository. The pom.xml
The pom.xml - See attached file.
Attachment file
pom.xml (1 KB)
Create the test class
Ok, we will implement 3 test methods.For setting up the http request, we use the MockHttpServletRequest from the Spring mock framework. With this mock request we can simulate the http header that we expect WebSeal to pass on.
Here are the tests.
getAuthenticatedUser
Tests the SSOPlugin with a valid username - we expect the username to be returned, since it is valid.
getAuthenticatedUserWithIgnoredUser
When WebSeal passes on un-authenticated requests, e.g. user has not logged in, instead of sending a empty header or not setting the header at all, WebSeal passes on “Unauthenticated”. So to handle this situation we will code our plugin to handle these special cases.
A list of special usernames that should be ignored will be configured in the SSOPlugin configuration. This will make the plugin generic for all header-value SSO-identification.
This test assures that these special/reserved usernames are handled correctly.
getAuthenticatedUserWithNoHeaderKey
The plugin need to know which key to use to lookup the header value. If this key is not set, an exception is expected to be thrown.
The test code:
package com.enonic.tutorial.sso;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import com.enonic.vertical.presentation.sso.SSOException;
import com.enonic.vertical.presentation.sso.SSOPlugin;
public class HeaderSSOPluginTest {
private static final String HEADER_WEBSEAL_KEY = "iv-user";
private SSOPlugin headerSSOPlugin;
@Before
public void setupSSOPlugin() {
headerSSOPlugin = new HeaderSSOPlugin();
headerSSOPlugin.setParameter(HeaderSSOPlugin.HEADER_LOOKUP_KEY, HEADER_WEBSEAL_KEY);
headerSSOPlugin.setParameter(HeaderSSOPlugin.IGNORE_KEY, "anonymous&unauthenticated");
}
@Test
public void getAuthenticatedUser() throws SSOException {
final String testUser = "ren";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader(HEADER_WEBSEAL_KEY, testUser);
assertEquals("SSOPlugin should return user : " + testUser,
testUser, headerSSOPlugin.getAuthenticatedUser(request));
}
@Test
public void getAuthenticatedUserWithIgnoredUser() throws SSOException {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader(HEADER_WEBSEAL_KEY, "anonymous");
assertNull("SSOPlugin should NOT return user",
headerSSOPlugin.getAuthenticatedUser(request));
new MockHttpServletRequest();
request.addHeader(HEADER_WEBSEAL_KEY, "unauthenticated");
assertNull("SSOPlugin should NOT return user",
headerSSOPlugin.getAuthenticatedUser(request));
}
@Test (expected = SSOException.class)
public void getAuthenticatedUserWithNoHeaderKey() throws SSOException {
SSOPlugin invalidHeaderSSOPlugin = new HeaderSSOPlugin();
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader(HEADER_WEBSEAL_KEY, "anonymous");
invalidHeaderSSOPlugin.getAuthenticatedUser(request);
}
}
Create the plugin class
Ok, so we have created the test class.Now we need to create the plugin class.
Important stuff:
The class need to implement:
- com.enonic.vertical.presentation.sso.SSOPlugin;
- public String getAuthenticatedUser(final HttpServletRequest request)
- public void setParameter(final String key, final String value)
getAuthenticatedUser: When there is a valid http header passed in, identifying the user, just return this value. This will login the user into Vertical Site. In all other cases, return “null”.
Less important stuff.
The class need to implement
- public boolean logInUser(final String userId, final HttpSession session)
- public boolean logOutUser(final String userId, final HttpSession session)
The plugin code:
package com.enonic.tutorial.sso;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.enonic.vertical.presentation.sso.SSOException;
import com.enonic.vertical.presentation.sso.SSOPlugin;
public class HeaderSSOPlugin implements SSOPlugin {
protected static final String HEADER_LOOKUP_KEY = "headerLookupKey";
protected static final String IGNORE_KEY = "ignore";
private Map parameters = new HashMap();
/**
* {@inheritDoc}
* @see com.enonic.vertical.presentation.sso.SSOPlugin#getAuthenticatedUser(javax.servlet.http.HttpServletRequest)
*/
public String getAuthenticatedUser(final HttpServletRequest request)
throws SSOException {
String headerKey = parameters.get(HEADER_LOOKUP_KEY);
if (headerKey == null || headerKey.equals("")) {
throw new SSOException("Unable to find user as header value: Header key for lookup is NULL");
}
String user = request.getHeader(headerKey);
if (user != null && !user.equals("")) {
String ignores = parameters.get(IGNORE_KEY);
if (ignores != null && !ignores.equals("")) {
StringTokenizer ignoreTokens = new StringTokenizer(ignores, "&");
while (ignoreTokens.hasMoreElements()) {
String ignore = (String) ignoreTokens.nextElement();
if (user.equalsIgnoreCase(ignore)) {
return null;
}
}
}
return user;
}
return null;
}
/**
* {@inheritDoc}
* @see com.enonic.vertical.presentation.sso.SSOPlugin#logInUser(java.lang.String, javax.servlet.http.HttpSession)
*/
public boolean logInUser(final String userId, final HttpSession session)
throws SSOException {
return false;
}
/**
* {@inheritDoc}
* @see com.enonic.vertical.presentation.sso.SSOPlugin#logOutUser(java.lang.String, javax.servlet.http.HttpSession)
*/
public boolean logOutUser(final String userId, final HttpSession session)
throws SSOException {
return false;
}
/**
* {@inheritDoc}
* @see com.enonic.vertical.presentation.sso.SSOPlugin#setParameter(java.lang.String, java.lang.String)
*/
public void setParameter(final String key, final String value) {
parameters.put(key, value);
}
}
Creating the configuration
Add these lines to you site-x.properties under your $CMS_HOME/config directory.sso.plugin=com.enonic.tutorial.sso.HeaderSSOPlugin
sso.forceLogin=true
sso.parameters=headerLookupKey=iv-user,ignore=anonymous&unauthenticated
Deploying the plugin
Run mvn package to create the jar file. Now that you have "sso-plugin.jar” we can deploy it to the server. The jar file must be placed under the $CMS_HOME/plugins directory. Make sure you have added the configuration to site-x.properties and restart the application and the SSO-plugin will be available.Using the plugin
To test the plugin on a live site, open up your website in Firefox. (the website must be able to differentiate between logged-in/logged-out states - i.e. display logged-in-state if user is logged in). If you haven’t already installed it, install the “Modify headers” add-on. (https://addons.mozilla.org/en-US/firefox/addon/967). This will make you able to set the iv-user header in your browser and test the different scenarios. Things to test:- Set iv-user to valid username (must be present i Vertical Site userstore) - the user should automatically be logged in
- Set iv-user to unauthenticad - the user should be logged of.
- Set iv-user back to valid user, forcing a login, the try to remove iv-user header completely. The user should again be logged off.
- Play around!




Comments
If you want to comment on this article you need to be logged in.