Thanks for looking into this David.
We're building everything ourselves as we have minor hacks to the
Geronimo code.
I'll try to give it another shot sometime later this week, but right
now I have to focus on other things. The Jetty6 build is working for
us. I'll let you know what I find when I try again. Also see
comments to your inline comments.
Trygve
On Wed, Jun 3, 2009 at 1:55 AM, David Jencks
<david_jen...@yahoo.com> wrote:
I made a couple comments inline however I strongly suspect your
problems are caused by a jetty bug I had a hand in creating :-) that
could cause the FormAuthenticator to not recognize that the request
is the data from the login page.
https://bugs.eclipse.org/bugs/show_bug.cgi?id=278887
I'm not sure how quickly jetty snapshots are getting pushed ---
probably daily. Also you may want to wait until g. snapshots are
available again.... but if you build everything yourself you might
find it's started working again!
thanks
david jencks
On Jun 1, 2009, at 9:55 AM, Trygve Hardersen wrote:
Hello
We have been building a relatively large and complex system using
Geronimo-2.2 for some time. We're now getting close to finishing
the project, and it's encouraging to see that the release of
Geronimo 2.2 is getting closer, and that branching is around the
corner.
However the latest Geronimo updates, I'm pretty sure it's the
switch to Jetty7, broke our security model. I've been trying to get
make it work again for some time, but with no luck. Hence this mail.
First we have a realm and credential store plugin that is used by
all other parts of the application:
# plan.xml
<?xml version="1.0" encoding="UTF-8"?>
<dep:module
xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2"
xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.2"
xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-2.0"
xmlns:cs="http://geronimo.apache.org/xml/ns/credentialstore-1.0">
<dep:gbean name="jotta-realm"
class="org.apache.geronimo.security.realm.GenericSecurityRealm">
<dep:attribute name="realmName">jotta-realm</dep:attribute>
<dep:attribute name="global">true</dep:attribute>
<dep:xml-reference name="LoginModuleConfiguration">
<log:login-config>
<!-- Allow administrator logins -->
<log:login-module control-flag="SUFFICIENT" wrap-
principals="false">
<log:login-domain-name>jotta-admin</log:login-
domain-name>
<log:login-module-
class
>
org
.apache
.geronimo.security.realm.providers.PropertiesFileLoginModule</
log:login-module-class>
<log:option name="usersURI">var/security/
users.properties</log:option>
<log:option name="groupsURI">var/security/
groups.properties</log:option>
</log:login-module>
<!-- Then check the user DBs -->
<log:login-module control-flag="REQUIRED" wrap-
principals="false">
<log:login-domain-name>jotta-users</log:login-
domain-name>
<log:login-module-
class>no.jotta.backup.security.server.JottaLoginModule</log:login-
module-class>
</log:login-module>
</log:login-config>
</dep:xml-reference>
<dep:reference name="ServerInfo">
<dep:name>ServerInfo</dep:name>
</dep:reference>
</dep:gbean>
<dep:gbean name="JottaCredentialStore"
class
=
"org
.apache.geronimo.security.credentialstore.SimpleCredentialStoreImpl">
<dep:xml-attribute name="credentialStore">
<cs:credential-store>
<cs:realm name="jotta-realm">
<cs:subject>
<cs:id>anonymous</cs:id>
<cs:credential>
<
cs:type
>org.apache.geronimo.security.credentialstore.NameCallbackHandler</
cs:type>
<cs:value>anonymous</cs:value>
</cs:credential>
<cs:credential>
<
cs:type
>
org
.apache.geronimo.security.credentialstore.PasswordCallbackHandler</
cs:type>
<cs:value>${geronimoPasswd}</cs:value>
</cs:credential>
</cs:subject>
<cs:subject>
<cs:id>system</cs:id>
<cs:credential>
<
cs:type
>org.apache.geronimo.security.credentialstore.NameCallbackHandler</
cs:type>
<cs:value>system</cs:value>
</cs:credential>
<cs:credential>
<
cs:type
>
org
.apache.geronimo.security.credentialstore.PasswordCallbackHandler</
cs:type>
<cs:value>${geronimoPasswd}</cs:value>
</cs:credential>
</cs:subject>
</cs:realm>
</cs:credential-store>
</dep:xml-attribute>
<dep:reference name="Realms">
<dep:name>jotta-realm</dep:name>
</dep:reference>
<dep:dependency>
<dep:name>jotta-realm</dep:name>
</dep:dependency>
</dep:gbean>
</dep:module>
I can use this security configuration later from other EJB modules,
also deployed as plugins:
# plan.xml
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://geronimo.apache.org/xml/ns/j2ee/application-2.0
"
xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2"
xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.2"
xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0">
<module>
<ejb>crm-ejb-${jottaVersion}.jar</ejb>
<openejb-jar xmlns="http://openejb.apache.org/xml/ns/openejb-jar-2.2
">
<dep:environment>
<dep:moduleId>
<dep:groupId>no.jotta.backup.crm</dep:groupId>
<dep:artifactId>crm-ejb</dep:artifactId>
<dep:version>${jottaVersion}</dep:version>
<dep:type>ejb</dep:type>
</dep:moduleId>
<dep:dependencies>
<dep:dependency>
<dep:groupId>no.jotta.backup.security</
dep:groupId>
<dep:artifactId>security-ejb</dep:artifactId>
<dep:version>${jottaVersion}</dep:version>
<dep:type>ejb</dep:type>
</dep:dependency>
</dep:dependencies>
</dep:environment>
<security use-context-handler="false">
<sec:credential-store-ref>
<dep:name>JottaCredentialStore</dep:name>
</sec:credential-store-ref>
<sec:role-mappings>
<sec:role role-name="admin">
<sec:principal name="admin"
class
=
"org
.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" />
</sec:role>
<sec:role role-name="anonymous">
<sec:principal name="anonymous"
class
=
"org
.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" />
</sec:role>
<sec:role role-name="customer">
<sec:principal name="customer"
class
=
"org
.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" />
</sec:role>
<sec:role role-name="system">
<sec:run-as-subject>
<sec:description>Allow internal
components to run as system</sec:description>
<sec:realm>jotta-realm</sec:realm>
<sec:id>system</sec:id>
</sec:run-as-subject>
<sec:login-domain-principal
name="system"
domain-name="jotta-admin"
class
=
"org
.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" />
You don't need the principal above, anything it maps to the "system"
role the principal below will also map.
I did try a lot of different configurations but I think I only tried
removing the principal below, not the one above. Will test without
the principal above.
<sec:principal
name="system"
class
=
"org
.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" />
</sec:role>
</sec:role-mappings>
</security>
<enterprise-beans>
<session>
<ejb-name>jotta.crm.CustomerService</ejb-name>
<ejb-ref>
<!-- Reference to security service -->
<nam:ref-
name>no.jotta.backup.crm.ejb.CustomerServiceImpl/userService</
nam:ref-name>
<nam:pattern>
<nam:artifactId>security-ejb</
nam:artifactId>
<nam:name>jotta.security.UserService</
nam:name>
</nam:pattern>
</ejb-ref>
</session>
</enterprise-beans>
</openejb-jar>
</module>
</application>
When the "jotta.crm.CustomerService" EJB calls the
"jotta.security.UserService" it always runs as the "system" role,
which is what it is supposed to do. I also have a testsuite using
remote EJB, and from it I can log in manually using either the
PropertiesFileLoginModule or the JottaLoginModule. In other words
the security configuration works as I expect it to.
The problem comes when using this security setup from a WAR module.
I have a very simple web application that has a single servlet
responsible for gather the email addresses of interested customers.
This servlet is supposed to run as "system":
# web.xml
<web-app version="2.5" 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_2_5.xsd
"
metadata-complete="false">
<description>
Web application resposible for providing the Web Beta
for customers of Jotta Backup.
</description>
<display-name>Jotta Web Beta</display-name>
<!-- Can be run in a cluster, but does not require session
replication -->
<distributable/>
<welcome-file-list>
<welcome-file>welcome</welcome-file>
</welcome-file-list>
.....
<servlet>
<description>Servlet providing interested customer
functionality</description>
<display-name>Interested Customer Servlet</display-name>
<servlet-name>InterestedCustomerServlet</servlet-name>
<servlet-
class
>no.jotta.backup.web.gui.pub..servlets.InterestedCustomerServlet</
servlet-class>
<run-as>
<description>Runs as system</description>
<role-name>system</role-name>
</run-as>
</servlet>
<servlet-mapping>
<servlet-name>InterestedCustomerServlet</servlet-name>
<url-pattern>/welcome</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>InterestedCustomerServlet</servlet-name>
<url-pattern>/welcome/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>InterestedCustomerServlet</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>InterestedCustomerServlet</servlet-name>
<url-pattern>/register/</url-pattern>
</servlet-mapping>
<!-- EJB Mappings -->
<ejb-local-ref>
<description>Reference to the Customer Service</description>
<ejb-ref-name>customerService</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>no.jotta.backup.crm.intf.CustomerServiceLocal</local>
</ejb-local-ref>
<security-role>
<role-name>anonymous</role-name>
</security-role>
<security-role>
<role-name>system</role-name>
</security-role>
</web-app>
Now I've been trying a lot of different plan.xml configurations to
make this work, but the one that we've been using for quite some
time looked like this:
# plan.xml
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://geronimo.apache.org/xml/ns/j2ee/application-2.0
"
xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2"
xmlns:nam="http://geronimo.apache.org/xml/ns/naming-1.2"
xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0">
<module>
<web>web-beta.war</web>
<web-app xmlns="http://geronimo.apache.org/xml/ns/j2ee/web/jetty-2.0.2
">
<context-root>/beta</context-root>
<security-realm-name>jotta-realm</security-realm-name>
<security use-context-handler="false">
<sec:credential-store-ref>
<dep:name>JottaCredentialStore</dep:name>
</sec:credential-store-ref>
<sec:default-subject>
<sec:realm>jotta-realm</sec:realm>
<sec:id>anonymous</sec:id>
</sec:default-subject>
<sec:role-mappings>
<sec:role role-name="anonymous">
<sec:login-domain-principal
name="anonymous" domain-name="jotta-admin"
class
=
"org
.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" />
</sec:role>
<sec:role role-name="system">
<sec:run-as-subject>
<sec:description>Allow internal
components to run as system</sec:description>
<sec:realm>jotta-realm</sec:realm>
<sec:id>system</sec:id>
</sec:run-as-subject>
<sec:login-domain-principal name="system"
domain-name="jotta-admin"
class
=
"org
.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" />
As with the ejb configuration, you don't need the first principal
here, anything it maps to the "system" role will also be mapped by
the next principal.
<sec:principal name="system"
class
=
"org
.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal" />
</sec:role>
</sec:role-mappings>
</security>
</web-app>
</module>
</application>
This used to work but no longer so. The servlet does not run as
"system" and access to the EJB is denied:
The default subject for the web app is anonymous, and there are no
security constraints, so the only possiblilty AFAICT is that the
user identity inside the servlet would be "anonymous". The run-as
role controls what identity is used to call the ejb... which ought
to be system, as the run-as-role for the servlet is actually
system. I suspect this is what you meant and that I'm nitpicking :-)
Yes, I tried to remove the "default anonymous" role in case it was
overriding the "run-as system" role. I found it was not. I did not
actually check which, if any, role the servlet actually ran under.
Will check that as well.
javax.ejb.EJBAccessException: Unauthorized Access by Principal Denied
at
org
.apache
.openejb
.core.stateless.StatelessContainer.invoke(StatelessContainer.java:
153)
at
org
.apache
.openejb
.core
.ivm
.EjbObjectProxyHandler.businessMethod(EjbObjectProxyHandler.java:217)
at
org
.apache
.openejb
.core.ivm.EjbObjectProxyHandler._invoke(EjbObjectProxyHandler.java:
77)
at
org
.apache
.openejb
.core.ivm.BaseEjbProxyHandler.invoke(BaseEjbProxyHandler..java:281)
The Geronimo source I'm running against is trunk from sometime on
Thursday last week (28th). I'm unable to build the current Geronimo
trunk because of the following error:
[INFO]
------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO]
------------------------------------------------------------------------
[INFO] Error assembling WAR: Deployment descriptor: /home/jotta/
dailybuild/geronimo/trunk/server_clean/plugins/activemq/activemq-
webconsole/target/activemq-webconsole-2.2-SNAPSHOT/WEB-INF/web.xml
does not exist.
Does anyone have an idea what is going wrong here, or how I can
make this work again? I'll try to create a simple application that
illustrates the webapp run-as problem. Our application is rather
complex and many things can go wrong. It's probably also possible
to switch back to Jetty6, any idea if that would help?
Your help and work is much appreciated!
Trygve Hardersen
Jotta AS