Short version:

I have setup a small maven web project (JDK 1.8.0, Source: 1.8, JavaEE7) to test the JDBCRealm in Glassfish 4.1 (build 13). It consists of two Entities: RealmUser und RealmGroup and a JAX-RS Service to insert, update and delete these Entities.

I defined the JDBCResource in glassfish-resources.xml, configured the realm via Glassfish Admin Console, and setup web.xml with login-config (BASIC) only.

When using a WebFilter to activate authentication it works fine.

But when i setup a security constraint in the web.xml instead, i get the following exception whenever i try to access the protected resource (Full Stacktrace and details below):

Schwerwiegend:   jdbcrealm.invaliduser
Fine:   Cannot validate user
javax.security.auth.login.LoginException: Unable to connect to datasource java:app/jdbc/sampleresource for database user null.
...
Caused by: javax.naming.NamingException: Lookup failed for 'java:app/jdbc/sampleresource' in SerialContext[myEnv={com.sun.enterprise.connectors.jndisuffix=__nontx, java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NamingException: Invocation exception: Got null ComponentInvocation ]
...
Caused by: javax.naming.NamingException: Invocation exception: Got null ComponentInvocation 
...

Your help is greatly appreciated!


Step by Step:

I created a Derby Database (SampleDB, user: testuser, password: pw) and defined a JDBC resource via glassfish-resources.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <jdbc-resource enabled="true" jndi-name="java:app/jdbc/sampleresource" object-type="user" pool-name="samplepool">
        <description/>
    </jdbc-resource>
    <jdbc-connection-pool datasource-classname="org.apache.derby.jdbc.ClientDataSource40" name="samplepool" res-type="javax.sql.DataSource">
        <property name="URL" value="jdbc:derby://localhost:1527/SampleDB"/>
        <property name="serverName" value="localhost"/>
        <property name="portNumber" value="1527"/>
        <property name="databaseName" value="SampleDB"/>
        <property name="User" value="testuser"/>
        <property name="Password" value="pw"/>
        <property name="driverClass" value="org.apache.derby.jdbc.ClientDriver"/>
    </jdbc-connection-pool>    
</resources>

I created the persistence.xml with jta-data-source set to java:app/jdbc/sampleresource:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="SampleRealmPU" transaction-type="JTA">
    <jta-data-source>java:app/jdbc/sampleresource</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="create"/>
    </properties>
  </persistence-unit>
</persistence>

On Startup the Application adds a default user (admin, pw) and default group (Administrator), and assigns admin to the Administrator group.

Then i created the JDBC Realm using the Admin Console, and pointed the Realm to java:app/jdbc/sampleresource.

Note:

  • I added Database username and password entries although they should be redundant.
  • Default Principal To Role Mapping is Enabled.

enter image description here

I implemented two services:

  • GET on .../webresources/UserService/users returns the list of all users
  • GET on .../webresources/UserService/groups return the list of all groups

Now to activate authentication for accessing groups i created a very simple web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>SampleRealm</realm-name>
    </login-config>
</web-app>

and a WebFilter:

@WebFilter("/webresources/UserService/groups/*")
public class Authenticator implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            if (req.authenticate(resp)) {
                chain.doFilter(req, resp);
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
    @Override
    public void destroy() {
    }
}

So far it works! I have to provide my default user credentials to access the groups.


Now instead of using the Webfilter i want to use the web.xml to define the same authentication constraint on groups. I commented the whole WebFilter and modified the web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <security-constraint>
        <display-name>GroupConstraint</display-name>
        <web-resource-collection>
            <web-resource-name>UserService groups</web-resource-name>
            <description/>
            <url-pattern>/webresources/UserService/groups/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description>requires auth</description>
            <role-name>Administrator</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>SampleRealm</realm-name>
    </login-config>
    <security-role>
        <description/>
        <role-name>Administrator</role-name>
    </security-role>
</web-app>

With this setup i can access the users resource (i.e. database is there) but when i try to access the groups resource i get HTTP Status 401 - Unauthorized and Glassfish logs:

Fine:   [Web-Security] Setting Policy Context ID: old = null ctxID = samples-realm-web/samples-realm-web
Fine:   [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/UserService/groups" "GET")
Fine:   [Web-Security] hasUserDataPermission isGranted: true
Fine:   [Web-Security] Policy Context ID was: samples-realm-web/samples-realm-web
Fine:   [Web-Security] Generating a protection domain for Permission check.
Fine:   [Web-Security] Codesource with Web URL: file:/samples-realm-web/samples-realm-web
Fine:   [Web-Security] Checking Web Permission with Principals : null
Fine:   [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/webresources/UserService/groups" "GET")
Finest:   JACC Policy Provider: PolicyWrapper.implies, context (samples-realm-web/samples-realm-web)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/webresources/UserService/groups" "GET"))
Fine:   [Web-Security] hasResource isGranted: false
Fine:   [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/UserService/groups" "GET")
Finest:   Processing login with credentials of type: class com.sun.enterprise.security.auth.login.common.PasswordCredential
Fine:   Logging in user [admin] into realm: SampleRealm using JAAS module: jdbcRealm
Fine:   Login module initialized: class com.sun.enterprise.security.ee.auth.login.JDBCLoginModule
Schwerwiegend:   jdbcrealm.invaliduser
Fine:   Cannot validate user
javax.security.auth.login.LoginException: Unable to connect to datasource java:app/jdbc/sampleresource for database user null.
    at com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.getConnection(JDBCRealm.java:585)
    at com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.isUserValid(JDBCRealm.java:408)
    at com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.authenticate(JDBCRealm.java:324)
    at com.sun.enterprise.security.ee.auth.login.JDBCLoginModule.authenticate(JDBCLoginModule.java:78)
    at com.sun.enterprise.security.auth.login.PasswordLoginModule.authenticateUser(PasswordLoginModule.java:116)
    at com.sun.enterprise.security.BasePasswordLoginModule.login(BasePasswordLoginModule.java:145)
    at sun.reflect.GeneratedMethodAccessor52.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
    at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
    at javax.security.auth.login.LoginContext.login(LoginContext.java:587)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:383)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:241)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:154)
    at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:695)
    at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:636)
    at org.apache.catalina.authenticator.BasicAuthenticator.authenticate(BasicAuthenticator.java:166)
    at com.sun.web.security.RealmAdapter.invokeAuthenticateDelegate(RealmAdapter.java:1524)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:606)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:702)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:415)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:282)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:201)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:175)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:561)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
    at java.lang.Thread.run(Thread.java:744)
Caused by: javax.naming.NamingException: Lookup failed for 'java:app/jdbc/sampleresource' in SerialContext[myEnv={com.sun.enterprise.connectors.jndisuffix=__nontx, java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [Root exception is javax.naming.NamingException: Invocation exception: Got null ComponentInvocation ]
    at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:491)
    at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:438)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at org.glassfish.resourcebase.resources.naming.ResourceNamingService.lookup(ResourceNamingService.java:236)
    at com.sun.enterprise.connectors.service.ConnectorResourceAdminServiceImpl.lookup(ConnectorResourceAdminServiceImpl.java:224)
    at com.sun.enterprise.connectors.ConnectorRuntime.lookupNonTxResource(ConnectorRuntime.java:553)
    at com.sun.enterprise.connectors.ConnectorRuntime.lookupNonTxResource(ConnectorRuntime.java:538)
    at com.sun.enterprise.security.auth.realm.jdbc.JDBCRealm.getConnection(JDBCRealm.java:573)
    ... 48 more
Caused by: javax.naming.NamingException: Invocation exception: Got null ComponentInvocation 
    at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.getComponentId(GlassfishNamingManagerImpl.java:842)
    at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:714)
    at com.sun.enterprise.naming.impl.JavaURLContext.lookup(JavaURLContext.java:167)
    at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:471)
    ... 56 more

Fine:   JAAS authentication aborted.
Finest:   doPasswordLogin fails
javax.security.auth.login.LoginException: Security Exception
    at javax.security.auth.login.LoginContext.invoke(LoginContext.java:840)
    at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682)
    at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
    at javax.security.auth.login.LoginContext.login(LoginContext.java:587)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:383)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:241)
    at com.sun.enterprise.security.auth.login.LoginContextDriver.login(LoginContextDriver.java:154)
    at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:695)
    at com.sun.web.security.RealmAdapter.authenticate(RealmAdapter.java:636)
    at org.apache.catalina.authenticator.BasicAuthenticator.authenticate(BasicAuthenticator.java:166)
    at com.sun.web.security.RealmAdapter.invokeAuthenticateDelegate(RealmAdapter.java:1524)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:606)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:702)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:415)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:282)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:201)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:175)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:561)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:565)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:545)
    at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.SecurityException
    at javax.security.auth.login.LoginContext.invoke(LoginContext.java:841)
    ... 39 more

Warnung:   WEB9102: Web Login Failed: com.sun.enterprise.security.auth.login.common.LoginException: Login failed: Security Exception

I tried several things to solve this including:

  • renaming the jdbc resource
  • leaving/adding the java:app namespace at several points
  • creating a completly new project to test
  • added Role Mappings (despite having default Role mapping enabled)

Example of RoleMappings using glassfish-web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMSSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/h2ee web-app_2_4.xsd">
  <security-role-mapping>
    <role-name>Administrator</role-name>
    <group-name>Administrator</group-name>
  </security-role-mapping>
</glassfish-web-app>

Your help is greatly appreciated!

1

There are 1 answers

0
Cynfeal On

your password Encryption is set to SHA-256... Make it AES

USE SHA-256 as the digest Algo not the encryption... try using Hex as the Encoding