1

I am trying to deploy an enterprise application EAR consisting of:

  • an EJB 3.1 module containing stateless session beans
  • a web module containing servlets

to Apache Geronimo V3.0 (packaged as a WebSphere Community 3.0.0.4 Server).

The beans are exposed through the @LocalBean annotation and injected into the servlets using the @EJB annotation.

Without any application security settings defined, everything works flawlessly. But, as soon as I define even the simplest security setup, injection fails with the message:

java.lang.IllegalArgumentException: Invalid method interface: LocalBean javax.security.jacc.EJBMethodPermission$MethodSpec.checkMethodInterface(EJBMethodPermission.java:303) javax.security.jacc.EJBMethodPermission$MethodSpec.(EJBMethodPermission.java:209) javax.security.jacc.EJBMethodPermission.(EJBMethodPermission.java:90) org.apache.geronimo.openejb.GeronimoSecurityService.isCallerAuthorized(GeronimoSecurityService.java:100) org.apache.openejb.core.stateless.StatelessContainer.invoke(StatelessContainer.java:159) org.apache.openejb.core.ivm.EjbObjectProxyHandler.synchronizedBusinessMethod(EjbObjectProxyHandler.java:255) org.apache.openejb.core.ivm.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:235) org.apache.openejb.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:92) org.apache.openejb.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler.java:284) com.sun.proxy.$Proxy117.getSysTime(Unknown Source) dk.danicon.servlet.Systime.doGet(Systime.java:43) javax.servlet.http.HttpServlet.service(HttpServlet.java:575) javax.servlet.http.HttpServlet.service(HttpServlet.java:668)

The security configuration works perfectly and prompts for credentials on servlets defined with an annotation like the one below, if they don't try to inject an EJB:

@ServletSecurity(@HttpConstraint(rolesAllowed={"admin"}))

I can make the injection work by removing the @LocalBean and implementing a @Local interface instead. But, from what I have been able to read on the subject, this should work with no-interface views as well - and I would like to avoid the added overhead from the interface.

I am attaching the relevant configuration files below and hope someone can tell me what I'm missing here?

application.xml (EAR module):

<?xml version="1.0" encoding="UTF-8"?>
<application id="Application_ID" version="6" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd">
 <display-name>TestEar</display-name>
 <module id="Module_1383740442312">
    <web>
        <web-uri>TestWeb.war</web-uri>
        <context-root>test</context-root>
    </web>
 </module>
 <module id="Module_1383741874882">
    <ejb>TestEjb.jar</ejb>
 </module> 
</application> 

geronimo-application.xml (EAR module):

<?xml version="1.0" encoding="UTF-8"?>
<app:application xmlns:app="http://geronimo.apache.org/xml/ns/j2ee/application-2.0" application-name="TestEar" xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:client="http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0" xmlns:conn="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2" xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2" xmlns:ejb="http://openejb.apache.org/xml/ns/openejb-jar-2.2" xmlns:jaspi="http://geronimo.apache.org/xml/ns/geronimo-jaspi" xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-2.0" xmlns:name="http://geronimo.apache.org/xml/ns/naming-1.2" xmlns:pers="http://java.sun.com/xml/ns/persistence" xmlns:pkgen="http://openejb.apache.org/xml/ns/pkgen-2.1" xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0" xmlns:web="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1">
<dep:environment>
    <dep:moduleId>
        <dep:groupId>dk.danicon</dep:groupId>
        <dep:artifactId>application</dep:artifactId>
        <dep:version>1.0</dep:version>
        <dep:type>car</dep:type>
    </dep:moduleId>
    <dep:dependencies>
        <dep:dependency>
            <dep:groupId>org.apache.geronimo.framework</dep:groupId>
            <dep:artifactId>j2ee-security</dep:artifactId>
            <dep:type>car</dep:type>
        </dep:dependency>
        <dep:dependency>
            <dep:groupId>console.dbpool</dep:groupId>
            <dep:artifactId>jdbc_ssodb</dep:artifactId>
            <dep:version>1.0</dep:version>
            <dep:type>car</dep:type>
        </dep:dependency>
    </dep:dependencies>
</dep:environment>
<sec:security>
    <sec:role-mappings>
        <sec:role role-name="admin">
            <sec:principal class="org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" name="ADMIN"/>
        </sec:role>
    </sec:role-mappings>
</sec:security>
<dep:gbean class="org.apache.geronimo.security.realm.GenericSecurityRealm" name="webrealm">
    <dep:attribute name="realmName">webrealm</dep:attribute>
    <dep:reference name="ServerInfo">
        <dep:name>ServerInfo</dep:name>
    </dep:reference>
    <dep:xml-reference name="LoginModuleConfiguration">
        <log:loginConfig>
            <log:login-module control-flag="REQUIRED" wrap-principals="false">
                <log:login-domain-name>webrealm</log:login-domain-name>
                <log:login-module-class>org.apache.geronimo.security.realm.providers.SQLLoginModule</log:login-module-class>
                <log:option name="dataSourceName">jdbc/ssodb</log:option>
                <log:option name="userSelect">SELECT username, password FROM v4.app_users WHERE username = ?</log:option>
                <log:option name="groupSelect">SELECT username, group_name FROM v4.app_users WHERE username = ?</log:option>
                <log:option name="digest"/>
                <log:option name="encoding"/>
            </log:login-module>
        </log:loginConfig>
    </dep:xml-reference>
</dep:gbean>
</app:application>

ejb-jar.xml (EJB module):

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar version="3.1" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
  <display-name>TestEjb </display-name> 
</ejb-jar>

openejb-jar.xml (EJB module):

<?xml version="1.0" encoding="UTF-8"?>
<ejb:openejb-jar xmlns:ejb="http://openejb.apache.org/xml/ns/openejb-jar-2.2" xmlns:app="http://geronimo.apache.org/xml/ns/j2ee/application-2.0" xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:client="http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0" xmlns:conn="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2" xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2" xmlns:jaspi="http://geronimo.apache.org/xml/ns/geronimo-jaspi" xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-2.0" xmlns:name="http://geronimo.apache.org/xml/ns/naming-1.2" xmlns:pers="http://java.sun.com/xml/ns/persistence" xmlns:pkgen="http://openejb.apache.org/xml/ns/pkgen-2.1" xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0" xmlns:web="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1">
<dep:environment>
    <dep:moduleId>
        <dep:groupId>dk.danicon</dep:groupId>
        <dep:artifactId>ejbmodule</dep:artifactId>
        <dep:version>1.0</dep:version>
        <dep:type>car</dep:type>
    </dep:moduleId>
</dep:environment>
</ejb:openejb-jar>

web.xml (WEB module):

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>TestWeb</display-name>
<welcome-file-list>
    <welcome-file>index.html</welcome-file>
</welcome-file-list>
<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>webrealm</realm-name>
</login-config>
</web-app>

geronimo-web.xml (WEB module):

<?xml version="1.0" encoding="UTF-8"?>
<web:web-app xmlns:web="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1" xmlns:app="http://geronimo.apache.org/xml/ns/j2ee/application-2.0" xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:client="http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0" xmlns:conn="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2" xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2" xmlns:ejb="http://openejb.apache.org/xml/ns/openejb-jar-2.2" xmlns:jaspi="http://geronimo.apache.org/xml/ns/geronimo-jaspi" xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-2.0" xmlns:name="http://geronimo.apache.org/xml/ns/naming-1.2" xmlns:pers="http://java.sun.com/xml/ns/persistence" xmlns:pkgen="http://openejb.apache.org/xml/ns/pkgen-2.1" xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0">
<dep:environment>
    <dep:moduleId>
        <dep:groupId>dk.danicon</dep:groupId>
        <dep:artifactId>webmodule</dep:artifactId>
        <dep:version>1.0</dep:version>
        <dep:type>car</dep:type>
    </dep:moduleId>
</dep:environment>
<web:context-root>/test</web:context-root>
<web:security-realm-name>webrealm</web:security-realm-name>
</web:web-app>

Sample EJB:

package dk.danicon.ejb;

import javax.annotation.security.RolesAllowed;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;

@Stateless
@LocalBean
@RolesAllowed({"admin"})
public class SysTime {

    public SysTime() {
    }

    public long getSysTime() {
        return System.currentTimeMillis();
    }
}

Sample servlet:

package dk.danicon.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import dk.danicon.ejb.SysTime;

@WebServlet("/testsystime")
@ServletSecurity(@HttpConstraint(rolesAllowed={"admin"}))
public class TestSystime extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @EJB
    SysTime systime;

    public TestSystime() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            PrintWriter pw = response.getWriter();
            pw.println("<html><body><h3>Systime</h3>");
            pw.println("<p>System time: " + systime.getSysTime() + " - " + systime.getClass().getName() +  "</p>");
            if(request.getUserPrincipal() != null)
               pw.println("<p>Principal: " + request.getUserPrincipal().getName() + "</p>");
            pw.println("</body></html>");
    }
}

1 Answers1

0

This appears to be an OpenEJB bug since there is no such LocalBean method interface type. That said, I am somewhat surprised that EJBMethodPermission is throwing an exception since the javadoc for that class says that implementations should be flexible enough to support unknown method interface types.

Brett Kail
  • 33,593
  • 2
  • 85
  • 90
  • You're correct, there is no such interface, because the @LocalBean implies a no-interface EJB as per the EJB 3.1 specification JSR-318 - and OpenEJB should recognize this. – danishrulez Nov 11 '13 at 16:15
  • @user2960650 I'm not sure if you're agreeing or disagreeing. To reiterate, OpenEJB is correct to identify this as a no-interface view, but it (or Geronimo?) is wrong to pass the "LocalBean" string to EJBMethodPermission rather than "Local". – Brett Kail Nov 12 '13 at 12:54
  • I think I misunderstood your original post. I agree, it must be a bug, but I am unsure if it's in OpenEJB or Geronimo. – danishrulez Nov 13 '13 at 12:18