JDBCRealm身份验证与Servlet @WebFilter一起使用,但在web.xml中使用安全性约束时会抛出NamingEcception

时间:2014-11-27 13:20:16

标签: glassfish web.xml restful-authentication java-ee-7 jdbcrealm

简短版本:

我已经设置了一个小型的maven web项目(JDK 1.8.0,源代码:1.8,JavaEE7)来测试Glassfish 4.1(build 13)中的JDBCRealm。它由两个实体组成:RealmUser和RealmGroup以及用于插入,更新和删除这些实体的JAX-RS服务。

我在glassfish-resources.xml中定义了JDBCResource,通过Glassfish管理控制台配置了域,并仅使用login-config(BASIC)设置web.xml。

使用 WebFilter 激活身份验证时,可以正常运行

但是,当我在web.xml中设置安全约束时,每当我尝试访问受保护资源时,我都会收到以下异常(完整Stacktrace及以下详细信息) ):

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 
...

非常感谢您的帮助!


一步一步:

我创建了一个Derby数据库(SampleDB,用户:testuser,密码:pw)并通过glassfish-resources.xml定义了一个JDBC资源:

<?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>

我创建了persistence.xml,其中jta-data-source设置为 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>

在启动时,应用程序会添加默认用户(admin,pw)和默认组(Administrator),并将admin分配给Administrator组。

然后我使用管理控制台创建了JDBC领域,并将领域指向 java:app / jdbc / sampleresource

注意:

  • 我添加了数据库用户名和密码条目,尽管它们应该是多余的。
  • 默认主体到角色映射已启用

enter image description here

我实施了两项服务:

    ... / webresources / UserService / users 上的
  • GET 返回所有用户的列表
  • ... / webresources / UserService / groups 上的
  • GET 返回所有群组的列表

现在要激活访问组的身份验证,我创建了一个非常简单的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>

和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() {
    }
}

到目前为止一切正常!我必须提供默认用户凭据才能访问这些群组。


现在而不是使用Webfilter 我想使用 web.xml在组上定义相同的身份验证约束。我评论了整个WebFilter并修改了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>

通过此设置,我可以访问用户资源(即数据库在那里)但是当我尝试访问组资源时,我得到 HTTP状态401 - 未经授权和Glassfish日志:

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

我尝试了几件事来解决这个问题,包括:

  • 重命名jdbc资源
  • 在几个点上留下/添加java:app命名空间
  • 创建一个完整的新项目进行测试
  • 添加了角色映射(尽管已启用默认角色映射)

使用glassfish-web.xml的RoleMappings示例:

<?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>

非常感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

您的密码加密设置为SHA-256 ...将其设为AES

使用SHA-256作为摘要Algo而不是加密...尝试使用Hex作为编码