2

SpringJmsSecurityExceptionJmsTemplate. 厄介な部分は、Spring 以外の同等のコードを使用して正常に公開できることです。

以下は、スローされる例外です (宛先が であると仮定QUEUE.IN)。

org.springframework.jms.JmsSecurityException: Access denied to resource: type=<jms>, application=DistQueue-Module, destinationType=queue, resource=QUEUE.IN, action=send; nested exception is weblogic.jms.common.JMSSecurityException: Access denied to resource: type=<jms>, application=DistQueue-Module, destinationType=queue, resource=QUEUE.IN, action=send
        at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:291)
        at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:168)
        at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:469)
        at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:534)
        at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:526)
        at com.company.jms.publisher.service.impl.JmsServiceImpl.sendMessage(JmsServiceImpl.java:34)
        at com.company.jms.publisher.service.impl.JmsServiceImpl.publish(JmsServiceImpl.java:29)
        at com.company.jms.publisher.controller.MainController.postIt(MainController.java:74)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
        at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
        at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:401)
        at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
        at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
        at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
        at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450)
        at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
        at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
        at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
        at org.mortbay.jetty.Server.handle(Server.java:326)
        at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
        at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:945)
        at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
        at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
        at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
        at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
        at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
2013-11-07 19:26:56.506:WARN::Nested in org.springframework.jms.JmsSecurityException: Access denied to resource: type=<jms>, application=DistQueue-Module, destinationType=queue, resource=QUEUE.IN, action=send; nested exception is weblogic.jms.common.JMSSecurityException: Access denied to resource: type=<jms>, application=DistQueue-Module, destinationType=queue, resource=QUEUE.IN, action=send:
weblogic.jms.common.JMSSecurityException: Access denied to resource: type=<jms>, application=DistQueue-Module, destinationType=queue, resource=QUEUE.IN, action=send
        at weblogic.jms.common.JMSSecurityHelper.checkPermission(JMSSecurityHelper.java:162)
        at weblogic.jms.backend.BEDestinationSecurityImpl.checkSendPermission(BEDestinationSecurityImpl.java:74)
        at weblogic.jms.backend.BEDestinationImpl.checkPermission(BEDestinationImpl.java:2513)
        at weblogic.jms.backend.BEDestinationImpl.sendInitialize(BEDestinationImpl.java:1565)
        at weblogic.jms.backend.BEDestinationImpl.send(BEDestinationImpl.java:2079)
        at weblogic.jms.backend.BEDestinationImpl.wrappedSend(BEDestinationImpl.java:2051)
        at weblogic.jms.backend.BEDestinationImpl.invoke(BEDestinationImpl.java:1539)
        at weblogic.messaging.dispatcher.Request.wrappedFiniteStateMachine(Request.java:961)
        at weblogic.messaging.dispatcher.DispatcherImpl.dispatchAsyncInternal(DispatcherImpl.java:140)
        at weblogic.messaging.dispatcher.DispatcherImpl.dispatchAsync(DispatcherImpl.java:116)
        at weblogic.messaging.dispatcher.Request.dispatchAsync(Request.java:1304)
        at weblogic.jms.dispatcher.Request.dispatchAsync(Request.java:97)
        at weblogic.jms.frontend.FEProducer.doDispatch(FEProducer.java:900)
        at weblogic.jms.frontend.FEProducer.sendRetryDestination(FEProducer.java:1033)
        at weblogic.jms.frontend.FEProducer.send(FEProducer.java:1435)
        at weblogic.jms.frontend.FEProducer.invoke(FEProducer.java:1496)
        at weblogic.messaging.dispatcher.Request.wrappedFiniteStateMachine(Request.java:961)
        at weblogic.messaging.dispatcher.DispatcherServerRef.invoke(DispatcherServerRef.java:276)
        at weblogic.messaging.dispatcher.DispatcherServerRef.handleRequest(DispatcherServerRef.java:141)
        at weblogic.messaging.dispatcher.DispatcherServerRef.access$000(DispatcherServerRef.java:34)
        at weblogic.messaging.dispatcher.DispatcherServerRef$2.run(DispatcherServerRef.java:112)
        at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
        at weblogic.work.ExecuteThread.run(ExecuteThread.java:178)

未加工のデバッグ用にすべてのプーリング コードを削除したという事実を無視して、メッセージを送信するために標準の JmsTemplate で次の構成を使用しています。

<beans:bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <beans:property name="environment">
        <beans:props>
            <beans:prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</beans:prop>
            <beans:prop key="java.naming.provider.url">${jms.connectionUrl}</beans:prop>
            <beans:prop key="java.naming.security.principal">${jms.username}</beans:prop>
            <beans:prop key="java.naming.security.credentials">${jms.password}</beans:prop>
        </beans:props>
    </beans:property>
</beans:bean>

<beans:bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <beans:property name="jndiTemplate" ref="jndiTemplate" />
    <beans:property name="jndiName" value="${jms.connectionFactoryName}" />
</beans:bean>

<beans:bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean">
    <beans:property name="jndiTemplate" ref="jndiTemplate" />
    <beans:property name="jndiName" value="${jms.destinationName}" />
</beans:bean>

<beans:bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <beans:property name="connectionFactory" ref="connectionFactory" />
    <beans:property name="defaultDestination" ref="destination" />

    <beans:property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE" />
    <beans:property name="sessionTransacted" value="false" />
</beans:bean>

正常に公開される非 Spring コードの同等のビットを以下に示します。

Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
environment.put(Context.PROVIDER_URL, prop("jms.connectionUrl"));
environment.put(Context.SECURITY_PRINCIPAL, prop("jms.username"));
environment.put(Context.SECURITY_CREDENTIALS, prop("jms.password"));

Context context = new InitialContext(environment);
ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup(prop("jms.connectionFactoryName"));

Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

Destination destination = (Destination) context.lookup(prop("jms.destinationName"));
MessageProducer producer = session.createProducer(destination);
connection.start();

TextMessage tm = session.createTextMessage(UUID.randomUUID().toString());
producer.send(tm);

例外メッセージから判断すると、資格情報が重要な場所で提供されていないと思われます。JNDI ルックアップは成功し、すべてのプロパティ (資格情報を含む) を無効な値に変更すると、公開を試行するずっと前に、初期化中に明確なエラーがスローされます。

UserCredentialsConnectionFactoryAdapter最初は、作成時に資格情報が提供されていることを確認することで問題を解決できると思っていましたが、同じエラーが発生しました。さらに、上記の単純な例ではこれを使用する必要はありません。

完全を期すために、ここに jmsTemplate のコードのビットを示します。

public void sendMessage(final String message) throws JmsException {
    jmsTemplate.send(new MessageCreator() {
        public Message createMessage(Session session) throws JMSException {
            TextMessage textMessage = session.createTextMessage(message);
            return textMessage;
        }
    });
}

最後になりましたが、パブリッシュ先の WebLogic インスタンスを制御したりアクセスしたりすることはできません。重要な手がかりがあるかどうかを確認するためにログを確認する担当者がいますが、かなり時間がかかる可能性があります。

4

1 に答える 1

1

同様の Spring バグ レポートをさらに調査した結果、この問題の (非直感的な) 回避策を発見しました。質問を削除するのではなく、これを回答として投稿することにしました。これが将来他の誰かに役立つことを願っています。

具体的には、 2008 年からSPR-4720に遭遇しました。John Bakar は、まったく何もしないように見える修正を推奨していますが、実際には上記の問題を解決しています。

私のプロジェクトに適用すると、修正は次のようになります。

public class UserCredentialsConnectionFactoryAdapter extends org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter {

    private JndiTemplate jndiTemplate;

    public void setJndiTemplate(JndiTemplate jndiTemplate) {
        this.jndiTemplate = jndiTemplate;
    }

    @Override
    protected Connection doCreateConnection(String username, String password) throws JMSException {
        wlFix();
        return super.doCreateConnection(username, password);
    }

    /**
     * Associate JNDI variables (user and password) with this thread for the
     * benefit of the WL drivers.
     */
    protected void wlFix() {
        try {
            @SuppressWarnings("unused")
            InitialContext initialContext = new InitialContext(jndiTemplate.getEnvironment());
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

}

変ですよね?

全体として、他の人の参考のために、私の Spring 構成は次のようになります。

<beans:bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <beans:property name="environment">
        <beans:props>
            <beans:prop key="java.naming.factory.initial">${jms.jndiFactory}</beans:prop>
            <beans:prop key="java.naming.provider.url">${jms.connectionUrl}</beans:prop>
            <beans:prop key="java.naming.security.principal">${jms.username}</beans:prop>
            <beans:prop key="java.naming.security.credentials">${jms.password}</beans:prop>
        </beans:props>
    </beans:property>
</beans:bean>

<beans:bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <beans:property name="jndiTemplate" ref="jndiTemplate" />
    <beans:property name="jndiName" value="${jms.connectionFactoryName}" />
</beans:bean>

<beans:bean id="connectionFactoryAdapter" class="com.company.jms.publisher.UserCredentialsConnectionFactoryAdapter">
    <beans:property name="jndiTemplate" ref="jndiTemplate" />
    <beans:property name="targetConnectionFactory" ref="connectionFactory" />
    <beans:property name="username" value="${jms.username}" />
    <beans:property name="password" value="${jms.password}" />
</beans:bean>

<beans:bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
    <beans:property name="targetConnectionFactory" ref="connectionFactoryAdapter" />
    <beans:property name="sessionCacheSize" value="10" />
</beans:bean>

<beans:bean id="destinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
    <beans:property name="jndiTemplate" ref="jndiTemplate" />
</beans:bean>

<beans:bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <beans:property name="connectionFactory" ref="cachingConnectionFactory" />
    <beans:property name="destinationResolver" ref="destinationResolver" />
    <beans:property name="defaultDestinationName" value="${jms.publish.destinationName}" />

    <beans:property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE" />
    <beans:property name="sessionTransacted" value="false" />
</beans:bean>

InitialContextダミーを作成して何もしないことで WLS に資格情報が適切に提供されないという問題が解決される理由を正式に (憶測ではなく) 説明できる人なら誰にでも報奨金を提供したいと思います。

于 2013-11-10T00:55:05.473 に答える