9.4.4. Securing Access to JNDI with a Read-Only Unsecured Context

Another feature available for the JNDI/HTTP naming service is the ability to define a context that can be accessed by unauthenticated users in read-only mode. This can be important for services used by the authentication layer. For example, the SRPLoginModule needs to lookup the SRP server interface used to perform authentication. The rest of this section explains how read-only works in JBoss Enterprise Application Platform.
First, the ReadOnlyJNDIFactory is declared in invoker.sar/WEB-INF/web.xml. It will be mapped to /invoker/ReadOnlyJNDIFactory.
<servlet>
    <servlet-name>ReadOnlyJNDIFactory</servlet-name>
    <description>A servlet that exposes the JBoss JNDI Naming service stub
          through http, but only for a single read-only context. The return content 
          is serialized MarshalledValue containing the org.jnp.interfaces.Naming 
          stub.
    </description>
    <servlet-class>org.jboss.invocation.http.servlet.NamingFactoryServlet</servlet-class>
    <init-param>
        <param-name>namingProxyMBean</param-name>
        <param-value>jboss:service=invoker,type=http,target=Naming,readonly=true</param-value>
    </init-param>
    <init-param>
        <param-name>proxyAttribute</param-name>
        <param-value>Proxy</param-value>
    </init-param>
    <load-on-startup>2</load-on-startup>
</servlet>

<!-- ... -->
                        
<servlet-mapping>
    <servlet-name>ReadOnlyJNDIFactory</servlet-name>
    <url-pattern>/ReadOnlyJNDIFactory/*</url-pattern>
</servlet-mapping>
The factory only provides a JNDI stub which needs to be connected to an invoker. Here the invoker is jboss:service=invoker,type=http,target=Naming,readonly=true. This invoker is declared in the http-invoker.sar/META-INF/jboss-service.xml file.
   <mbean code="org.jboss.invocation.http.server.HttpProxyFactory"
      name="jboss:service=invoker,type=http,target=Naming,readonly=true">
      <attribute name="InvokerName">jboss:service=Naming</attribute>
      <attribute name="InvokerURLPrefix">http://</attribute>
      <attribute name="InvokerURLSuffix">:8080/invoker/readonly/JMXInvokerServlet</attribute>
      <attribute name="UseHostName">true</attribute>
      <attribute name="ExportedInterface">org.jnp.interfaces.Naming</attribute>
      <attribute name="JndiName"></attribute>
      <attribute name="ClientInterceptors">
          <interceptors>
             <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor>
             <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
             <interceptor>org.jboss.naming.interceptors.ExceptionInterceptor</interceptor>
             <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor>
          </interceptors>
      </attribute>
   </mbean>
The proxy on the client side needs to talk back to a specific invoker servlet on the server side. The configuration here has the actual invocations going to /invoker/readonly/JMXInvokerServlet. This is actually the standard JMXInvokerServlet with a read-only filter attached.
  <filter>
     <filter-name>ReadOnlyAccessFilter</filter-name>
     <filter-class>org.jboss.invocation.http.servlet.ReadOnlyAccessFilter</filter-class>
     <init-param>
         <param-name>readOnlyContext</param-name>
         <param-value>readonly</param-value>
         <description>The top level JNDI context the filter will enforce
             read-only access on. If specified only Context.lookup operations
             will be allowed on this context. Another other operations or
             lookups on any other context will fail. Do not associate this
             filter with the JMXInvokerServlets if you want unrestricted
             access. </description>
     </init-param>
     <init-param>
         <param-name>invokerName</param-name>
         <param-value>jboss:service=Naming</param-value>
         <description>The JMX ObjectName of the naming service mbean </description>
     </init-param>
 </filter>
 
 <filter-mapping>
     <filter-name>ReadOnlyAccessFilter</filter-name>
     <url-pattern>/readonly/*</url-pattern>
 </filter-mapping>

 <!-- ... -->
 <!-- A mapping for the JMXInvokerServlet that only allows invocations 
         of lookups under a read-only context. This is enforced by the
         ReadOnlyAccessFilter 
         -->
 <servlet-mapping>
     <servlet-name>JMXInvokerServlet</servlet-name>
     <url-pattern>/readonly/JMXInvokerServlet/*</url-pattern>
 </servlet-mapping>
The readOnlyContext parameter is set to readonly which means that when you access JBoss through the ReadOnlyJNDIFactory, you will only be able to access data in the readonly context. Here is a code fragment that illustrates the usage:
Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, 
                "org.jboss.naming.HttpNamingContextFactory");
env.setProperty(Context.PROVIDER_URL, 
                "http://localhost:8080/invoker/ReadOnlyJNDIFactory");

Context ctx2 = new InitialContext(env);
Object data = ctx2.lookup("readonly/data");
Attempts to look up any objects outside of the readonly context will fail. Note that JBoss does not ship with any data in the readonly context, so the readonly context will not be bound usable unless you create it.