Tomcat

This is a quick start for integrating a Tomcat Web application with JOSSO. JOSSO integration relies on an SSO agent component installed in the container. Atricore provides agents for a wide variety of platforms:

  • All JEE Container: Tomcat, JBoss, Weblogic, Wepbsphere, Jetty, Liferay

  • Apache Server 2.2

  • Internet Information Server: ISAPI filter, ASPX, .NET

  • PHP

Other platforms like Python, React, etc. can use standard APIs like OpenID connect as well.

The goal of the SSO agent is to simplify SSO integration for the developers. Applications relying on JEE security may require minimal to no changes to be integrated. This process describes how to configure your JEE web application to rely on JOSSO for user identity. We call this process Jossifying your application.

Prerequisites

  • JOSSO Server configured and running (in any platform).

  • A Java Web/EJB Application.

Installing the SSO Agent

There are two ways to install the agent: one is by running the activation from within the JOSSO console, the other is manually installing the artifacts and making configuration changes.

Manual Activation

Activating the agent is basically installing SSO components into Tomcat. There are three objects that are provided in order to enable SSO support in the container:

  • JOSSO Agent Valve: Valves are Tomcat internal filters; we provide a valve that will intercept HTTP requests.

  • JOSSO Realm: Realms are also Tomcat plugins used to provide information about users to the container.

  • JOSSO JAAS Login Module: Login modules are JEE plugins for the Java Authentication and Authorization service.

Copying Required Artifacts

The following libaries are needed by the compoments mentioned above. These can be found in $JOSSO_HOME/dist/agents/lib/ folder. Or downloaded directly as a bundle. The only library that is specific to the Tomcat version is josso-tomcat85-agent-1.8.11-SNAPSHOT.jar. You need to chose one of these josso-tomcat70-agent-1.8.13-SNAPSHOT.jar, josso-tomcat80-agent-1.8.13-SNAPSHOT.jar, josso-tomcat85-agent-1.8.13-SNAPSHOT.jar, josso-tomcat90-agent-1.8.13-SNAPSHOT.jar

Copy these files into $CATALINA_HOME/lib folder.

  • josso-tomcat85-agent-1.8.13-SNAPSHOT.jar

  • josso-agent-shared-1.8.13-SNAPSHOT.jar

  • josso-agents-bin-1.8.13-SNAPSHOT-jaxws.jar

  • spring-aop-2.5.5.jar

  • spring-beans-2.5.5.jar

  • spring-context-2.5.5.jar

  • spring-core-2.5.5.jar

  • xbean-spring-3.4.3.jar

  • commons-beanutils-1.6.1.jar

  • commons-lang-2.0.jar

  • commons-logging-api-1.0.4.jar

  • commons-logging-1.1.1.jar

  • commons-digester-1.5.jar

  • commons-collections-3.0.jar

  • commons-httpclient-3.1.jar

  • commons-discovery-0.2.jar

  • commons-codec-1.3.jar

  • commons-modeler-1.1.jar

Configuring Tomcat: Valve and Realm

We need to enable the components we mentioned before. To enable the Valve and the Realm we need to modify Tomcat’s server.xml file. This file is located in $CATALINA_HOME/conf folder.

There are two changes we need to perform.

  1. Replace the current Realm with the new one.

  2. Add a new Valve at the end of the Host element.

This snippet should help you understand the changes.

server.xml

<Server>
    <Engine defaultHost="localhost" name="Catalina">

        ....

        <!-- ================================================== -->
        <!--   JOSSO JAAS Realm, configuration automatially generated by JOSSO Installer -->
        <Realm appName="josso" className="org.josso.tc85.agent.jaas.CatalinaJAASRealm" debug="1"
            roleClassNames="org.josso.gateway.identity.service.BaseRoleImpl"
            userClassNames="org.josso.gateway.identity.service.BaseUserImpl">

        </Realm>

        <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">

            ....

            <!-- ================================================== -->
            <!--   JOSSO Agent Valve, configuration automatially generated by JOSSO Installer -->
            <Valve appName="josso" className="org.josso.tc85.agent.SSOAgentValve" debug="1"/>
            <!-- ================================================== -->
        </Host>
    </Engine>
</Server>
Configuring Tomcat: JAAS Module

JAAS Modules are included by Tomcat using system properties. First we need to create a JAAS configuration file and install it in $CATALINA_HOME/conf. We should name it jaas.conf

jaas.conf

josso {
  org.josso.tc85.agent.jaas.SSOGatewayLoginModule required debug=true;
};

Then we can modify Tomcat’s setenv.sh or setenv.bat (depending on the server) and include the new property. You can create or find these files in $CATALINA_HOME/bin

setenv.bat

set JAVA_OPTS=%JAVA_OPTS% -Djava.security.auth.login.config=%CATALINA_HOME%\conf\jaas.conf

setenv.sh

JAVA_OPTS="$JAVA_OPTS -Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.conf"

If you start Tomcat as a Windows service, make sure to add the property to the service settings, including the full path to the jaas.conf file. You can do this using Tomcat’s service configuration tool.

Install the Agent Configuration

The last step is to copy the SSO agent configuration file josso-agent-config.xml. You can download the file from Atricore’s Web Console. Open your identity appliance model and select the element that represents your Tomcat server. Go to the Activation section and click the agent configuration button. You can save the file to your computer and copy it to the Tomcat server.

It may be required to make changes to this file. One common change is the agent’s endpoint. This is the URL that the agent will use to contact the SSO server. If Tomcat and JOSSO are running in the same server, or even in a local network, it may be better to replace Tomcat’s public domain from the endpoint, and even switch from HTTPS to HTTP.

        <property name="endpoint">
            <value>localhost:8081</value>
        </property>

If the endpoint is NOT using HTTPS, you need to remove the transportSecurity property as well.

If you are copying the agent configuration from another server, you need to modify the following properties. Make sure to udpate (if needed) protocol, server domain/port, appliance name (IDA-TEST) and Tomcat element name (TC85).

josso-agent-config.xm

<beans ...>

    <bean class="org.josso.tc85.agent.CatalinaSSOAgent" name="josso-tc85-agent">

    ...

    <property name="gatewayLoginUrl">
        <value>http://localhost:8081/IDBUS/IDA-TEST/TC85/JOSSO/SSO/REDIR</value>
    </property>
    <property name="gatewayLogoutUrl">
        <value>http://localhost:8081/IDBUS/IDA-TEST/TC85/JOSSO/SLO/REDIR</value>
    </property>

    ...
        <property name="automaticLoginStrategies">
            <list>
                <bean class="org.josso.agent.http.DefaultAutomaticLoginStrategy">
                    <property name="mode">
                        <value>REQUIRED</value>
                    </property>
                    <property name="ignoredReferrers">
                        <list>
                            <value>http://localhost:8081/IDBUS/</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>

    ...

    </bean>
</beans>

Configure the Web Application

Set up the partner application

The SSO agent needs to know which Tomcat applications are SSO Partner applications. If you exported your agent config from JOSSO, you already have the proper entries in the josso-agent-config.xml file. Let’s take a look at this definition:

...
<property name="ssoPartnerApps">
    <list>
        <bean class="org.josso.agent.SSOPartnerAppConfig">
            <property name="id">
                <value>sp-1</value>
            </property>
            <property name="vhost">
                <value>localhost</value>
            </property>
            <property name="context">
                <value>/partnerapp</value>
            </property>
        </bean>
    </list>
</property>
....

The only required properties are id and context, the vhost is optional, but if defined it must match the server hostname received in HTTP requests. You can have multiple application definitions if you are integrating different apps into JOSSO.

The id MUST match the name of the service provider as defined in the Identity Appliance Model. The context must be the Web Application context running in Tomcat. It can be the root context (/).

Set up JEE Security

A Web application that uses security requires the user to log in, in order to access some of its resources. The user’s credentials are verified against a security realm and, once authenticated, access will be granted only to specified resources within the Web application.

Security in a Web application is configured using three elements:

The <login-config> element specifies how the user is prompted to log in and the location of the security realm. If this element is present, the user must be authenticated in order to access any resource that is constrained by a <security-constraint> defined in the Web application.

A <security-constraint> is used to define the access privileges to a collection of resources via their URL mapping. A <security-role> element represents a group or principal in the realm. This security role name is used in the <security-constraint>. element and can be linked to an alternative role name used in servlet code via the <security-role-ref> element. See JEE specification for more information.

Let's look at the complete web.xml file of your partner web application:

web.xml

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web
Application 2.3//EN " " http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
    <display-name> JOSSO Partner Application </display-name>
    <welcome-file-list id= "WelcomeFileList" >
        <welcome-file> index.jsp </welcome-file>
    </welcome-file-list>

    <security-constraint>

        <!-- Sample Security Constraint -->
        <web-resource-collection>
            <web-resource-name>administrator-resources</web-resource-name>
            <url-pattern>/administrator/* </url-pattern>
            <http-method>HEAD </http-method>
            <http-method>GET </http-method>
            <http-method>POST </http-method>
            <http-method>PUT </http-method>
            <http-method>DELETE </http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>Administrator</role-name>
        </auth-constraint>

        <user-data-constraint>
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>

    </security-constraint>

    <!-- JOSSO interna JSP page, you MUST use this setup -->
    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login-redirect.jsp</form-login-page>
            <form-error-page>/login-redirect.jsp</form-error-page>
        </form-login-config>
    </login-config>

    <security-role >
        <description> The Administrator Role</description>
        <role-name>Administrator</role-name>
    </security-role>

</web-app>

You can have as many constraints as needed, even none. A constraint may also have no roles, if all users may access it.

Add Agent Resources

The following resources must be added to your web application:

  • login-redirect.jsp: This is referenced from the web.xml descriptor. You can copy the login-redirect.jsp page provided by josso to your application resources directory, or simply create a new one. The content is very simple:

login-redirect.jsp

<%@page contentType= "text/html; charset=iso-8859-1" language= "java" session= "true" %>
<% response.sendRedirect(request.getContextPath() + "/josso_login/" ); %>
  • josso-agent-shared-1.8.13-SNAPSHOT.jar (optional, version may vary): This is only needed if you want to obtain user properties within your application. Unfortunately JEE specification does not allow for user properties, all you can get is the principal name, and verify if a role is associated to the current user. We will see examples below. The file can be found in Tomcat’s lib folder if the agent was already installed.

Developing

Agent Paths

The agent handles a special set of paths in your application that can be used to trigger specific functions. For example, if you access the path /josso_login. The login process will start, the SSO Agent will redirect the user to the SSO server, while storing the page that requested the login so users can be sent back to the original resource.

If you access the /josso_logout path, the logout will be triggered.

Accessing User Information in your Code

If you want to check if a user has logged in, you can use JEE API to do so. Let’s take a look at an example that shows how to identify the current user, how to verify if the user has a particular role, and how to get properties provided by the SSO server.

Sample JSP Page

<%@ page import="org.josso.gateway.identity.SSOUser" %>
<%@ page contentType="text/html; charset=UTF-8" language="java" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es" lang="es">

<head>

      <title>JOSSO - Java Open Single SignOn</title><!-- Edit -->

      <meta name="Title" content="Atricore, Inc" />
      <meta name="Keywords" content="JOSSO Sample Partner Application" />
      <meta name="Description" content="This is a JOSSO partner application." />

      <meta name="Robots" content="index,follow" />
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

</head>

<body>

<%
// JEE API call to get current user.
if (request.getUserPrincipal() == null) {
%>
      <p>You are an anonymous user.</p>
      <a href="<%=request.getContextPath()%>/josso_login/" >Click here to login</a>
<%

}  else {

%>

    <p>You are logged in as <%=request.getUserPrincipal().getName()%>.</p>
    <a href="<%=request.getContextPath()%>/josso_logout/" >Click here to logout</a>

<%
    if (request.getUserPrincipal() != null) {

        // Unfortunately JEE API does not provide this option.
        // Cast the principal to a josso specific user, and iterate over its properties.
        SSOUser ssoUser = (SSOUser) request.getUserPrincipal();

        // getProperties() Returns an array of SSONameValuePair instances
        // You can look for a specific user property.
        for (int i = 0 ; i < ssoUser.getProperties().length ; i++) {
            ssoUser.getProperties()[i].getName();
            ssoUser.getProperties()[i].getValue();
        }
    }
}
%>

</body>
</html>

Getting username and user principal

HttpServletRequest request = ....;

String username = request.getRemotePrincipal();

// This can be casted to an SSOUser instnace.
Principal principal = request.getPrincipal();
SSOUser ssoUser = (SSOUser) principal;

Verify a specific role

HttpServletRequest request = ....;

boolean isAdmin = request.isUserInRole("Administrator");

Get user properties

HttpServletRequest request = ....;

SSOUser ssoUser = (SSOUser) request.getPrincipal();

SSONameValuePair[] properties = ssoUser.getProperties();
Last Updated:
Contributors: Sebastian