Jakarta ee 使用WildFly:javax.JMS.JMSSecurityException:HQ119032:User:null没有权限=在地址{2}上发送

Jakarta ee 使用WildFly:javax.JMS.JMSSecurityException:HQ119032:User:null没有权限=在地址{2}上发送,jakarta-ee,jms,wildfly,jaas,hornetq,Jakarta Ee,Jms,Wildfly,Jaas,Hornetq,使用WildFly 9.0.2 final,部分在standalone full.xml中定义如下 像、和这样的部分被完全省略,因为我没有对它们进行任何更改 项目领域 真的 102400 它定义了一个名为destinationFactory的连接工厂,它使用http连接器和一个名为userStatusQueue的队列,该队列绑定到嵌套的元素中列出的JNDI名称 它还定义了一个安全域 ProjectRealm 使用以下命令启用(默认)安全性: true 在这种情况下,它会引发以下异常 15

使用WildFly 9.0.2 final,
部分在
standalone full.xml
中定义如下

这样的部分被完全省略,因为我没有对它们进行任何更改


项目领域
真的
102400
它定义了一个名为
destinationFactory
的连接工厂,它使用
http连接器
和一个名为
userStatusQueue
的队列,该队列绑定到嵌套的
元素中列出的JNDI名称

它还定义了一个安全域

ProjectRealm
使用以下命令启用(默认)安全性:

true
在这种情况下,它会引发以下异常

15:49:28,093 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (default task-2) java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}: javax.el.ELException: java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
    at com.sun.el.parser.AstValue.invoke(AstValue.java:296)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:149)
    at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
    at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:814)
    at javax.faces.component.UICommand.broadcast(UICommand.java:300)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
    at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:658)
    at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:130)
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:78)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at io.undertow.websockets.jsr.JsrWebSocketFilter.doFilter(JsrWebSocketFilter.java:151)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at org.omnifaces.facesviews.FacesViewsForwardingFilter.filterExtensionLess(FacesViewsForwardingFilter.java:128)
    at org.omnifaces.facesviews.FacesViewsForwardingFilter.doFilter(FacesViewsForwardingFilter.java:89)
    at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at filter.LoginNocacheFilter.doFilter(LoginNocacheFilter.java:32)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at org.omnifaces.filter.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:122)
    at org.omnifaces.filter.HttpFilter.doFilter(HttpFilter.java:108)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
    at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.security.handlers.AuthenticationConstraintHandler.handleRequest(AuthenticationConstraintHandler.java:51)
    at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.servlet.handlers.security.ServletSecurityConstraintHandler.handleRequest(ServletSecurityConstraintHandler.java:56)
    at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
    at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
    at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
    at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:80)
    at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:172)
    at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
    at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:774)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
    at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:219)
    at io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:108)
    at com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:643)
    at admin.bean.SignInCheck.signIn(SignInCheck.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:292)
    ... 64 more
Caused by: javax.jms.JMSSecurityRuntimeException: HQ119032: User: null doesnt have permission=SEND on address {2}
    at org.hornetq.jms.client.JmsExceptionUtils.convertToRuntimeException(JmsExceptionUtils.java:76)
    at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:112)
    at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:135)
    at filter.SecurityCheck.sendMessageToDestination(SecurityCheck.java:54)
    at filter.SecurityCheck.doAfterProcessing(SecurityCheck.java:107)
    at filter.SecurityCheck.doFilter(SecurityCheck.java:161)
    at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
    at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
    at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
    at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:263)
    at io.undertow.servlet.handlers.ServletInitialHandler.dispatchToPath(ServletInitialHandler.java:198)
    at io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:195)
    ... 72 more
Caused by: javax.jms.JMSSecurityException: HQ119032: User: null doesnt have permission=SEND on address {2}
    at org.hornetq.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:399)
    at org.hornetq.core.client.impl.ClientProducerImpl.sendRegularMessage(ClientProducerImpl.java:334)
    at org.hornetq.core.client.impl.ClientProducerImpl.doSend(ClientProducerImpl.java:304)
    at org.hornetq.core.client.impl.ClientProducerImpl.send(ClientProducerImpl.java:135)
    at org.hornetq.jms.client.HornetQMessageProducer.doSendx(HornetQMessageProducer.java:524)
    at org.hornetq.jms.client.HornetQMessageProducer.send(HornetQMessageProducer.java:210)
    at org.hornetq.jms.client.HornetQMessageProducer.send(HornetQMessageProducer.java:200)
    at org.hornetq.jms.client.HornetQJMSProducer.send(HornetQJMSProducer.java:107)
    ... 87 more
Caused by: HornetQSecurityException[errorType=SECURITY_EXCEPTION message=HQ119032: User: null doesnt have permission=SEND on address {2}]
    ... 95 more
当给
一个
false
值时,消息通过定义的队列(由消息驱动Bean(MDB)接收)发送。但是,我只需要具有预定义权限/角色的用户(
role\u ADMIN
role\u USER
)来创建队列并跨队列发送消息

如上所示使用
的方法失败,出现上述异常

我尝试在
/standalone/configuration/application roles.properties
中添加角色,与中使用的
ProjectRealm.properties
文件中的定义完全相同


内部
,但也没有帮助

admins=ROLE_ADMIN
users=ROLE_USER
在通过队列发送消息之前,还需要做哪些工作来验证用户


附加:

JAAS安全管理器使用以下域使用JDBC领域(XA数据源)对用户进行身份验证和授权。这已经很好了


队列被注入到身份验证Servlet过滤器中,
JMSContext
使用该过滤器在用户成功进行身份验证和授权后通过队列发送消息

@WebFilter(filterName = "SecurityCheck", urlPatterns = {"/WEB-INF/jaas/*"}, dispatcherTypes = {DispatcherType.FORWARD})
public final class SecurityCheck implements Filter {

    @Resource(lookup = "java:/jms/destination")
    private Queue queue;

    @Inject
    @JMSConnectionFactory("java:jboss/exported/jms/destinationFactory")
    private JMSContext context;
    // jms/destinationFactory is expected to work here but it only works using the fully qualified namespace as above.

    public SecurityCheck() {}

    private void sendMessageToDestination(String message) throws JMSException {
        context.createProducer().send(queue, message);
    }

    private void doBeforeProcessing(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        String userName = request.getParameter("userName");
        request.login(userName.trim(), request.getParameter("password"));
    }

    private void doAfterProcessing(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException, JMSException {

        if (request.isUserInRole("ROLE_ADMIN")) {
            sendMessageToDestination("Message");
            // Redirect to a secure area.
        } else if (request.isUserInRole("ROLE_USER")) {
            sendMessageToDestination("Message");
            // Redirect to a secure area.
        }

        //...
    }

    //...
}
我使用自签名SSL证书纯粹是为了测试。因此,它使用
https://localhost:8443/ContextPath
用于访问安全的web资源

web.xml中的
机密


更新:

使用消息的消息驱动Bean:

@JMSDestinationDefinition(name = "destination", interfaceName = "javax.jms.Queue", resourceAdapter = "jmsra", destinationName = "destination")
@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/destination"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = "connectionFactoryLookup", propertyValue = "java:jboss/exported/jms/destinationFactory"),
    @ActivationConfigProperty(propertyName = "messagingType", propertyValue = "javax.jms.MessageListener"),
    @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jms/destination"),
    @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true")
})
public class UserStatusMessageBean implements MessageListener {

    public UserStatusMessageBean() {}

    @Resource
    private MessageDrivenContext messageDrivenContext;
    @EJB
    private UserStatusService userStatusService;

    @Override
    public void onMessage(Message message) {

        try {
            if (message instanceof TextMessage) {
                TextMessage textMessage = (TextMessage) message;
                String text = textMessage.getText();

                if (StringUtils.isNotBlank(text)) {
                    userStatusService.addHost(text);
                } else {
                    System.out.println("No message found.");
                }
            } else {
                System.out.println("Message is of wrong type : " + message.getClass().getName());
            }
        } catch (JMSException e) {
            messageDrivenContext.setRollbackOnly();
            System.out.println(e);
        } catch (Throwable e) {
            System.out.println(e);
        }
    }
}
有一个远程EJB被注入到上述MDB中,它需要定义的权限

@Stateless
@DeclareRoles(value = {"ROLE_ADMIN", "ROLE_USER"})
@RolesAllowed(value = {"ROLE_ADMIN", "ROLE_USER"})
public class UserStatusBean implements UserStatusService {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void addHost(String hostName) {
        // Insert or update via JPA.
    }
}
部署应用程序时,服务器将继续递归地抛出以下异常,除非中给出了
false

false

我在WildFly 9.0.2上复制了相同的问题(使用RESTEJB资源而不是Servlet)

为了修复它,我做了以下操作:

@Resource(mappedName = "java:jboss/exported/jms/destinationFactory")
ConnectionFactory factory;

private void sendMessageToDestination(String message, String user) throws JMSException {
    try (Connection connection = factory.createConnection(user,"hardcodedPassword");
         Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer producer = session.createProducer(queue)) {

        TextMessage textMessage = session.createTextMessage(message);

        producer.send(textMessage);
    }
}
正如您所看到的,在连接创建期间,我提供了一个有效的用户名和密码。此用户与在hornetq服务器安全设置中配置的用户具有相同的角色

我没有使用与您当时完全相同的安全域(我使用自己的代码来重现您的问题)。 如果您的工作不正常,请参阅:




  • 已经进行了这些更改。此异常在部署时发生:
    17:17:31687错误[org.hornetq.ra](默认线程-1)HQ154003:无法重新连接org.hornetq.ra.inflow.HornetQActivationSpec(ra=org.hornetq.ra。HornetQResourceAdapter@a0f08fdestination=jms/destination destinationType=javax.jms.Queue ack=Auto-acknowledge-dustable=false-clientID=null-user=null-maxSession=15):HornetQSecurityException[errorType=SECURITY\u异常消息=HQ119032:用户:null没有权限=在地址{2}上消费]
    …在队列有机会在运行时发送消息之前,除非在
    true
    中给出了
    false
    值,并且
    中的所有
    角色
    属性都重置为
    guest
    。目标消息驱动Bean(MDB)向EJB注入权限:
    @RolesAllowed(value={“ROLE\u ADMIN”,“ROLE_USER”}
    导致抛出
    javax.ejb.ejbaccesexception
    。请注意,当我遇到与您相同的异常时,“USER:null没有权限”",这是在执行sendMessageToDestination方法期间,在创建连接时添加任何用户和密码信息之前,解决了此问题。部署对我来说很好,但我没有任何MDB,因为我想重现您的消息发送错误。由于MDB期间出现另一个异常,您到底更改了什么立即启动(消费)?如果您可以将您的项目源共享到github或其他平台,这会有所帮助。我已经更新了问题。除了更新之外,还对
    sendMessageToDestination()
    方法进行了更改。
    23:31:22,138 ERROR [io.undertow.request] (default task-7) UT005023: Exception handling request to /jeeshop-admin/rs/users/administrators: org.jboss.resteasy.spi.UnhandledException: javax.jms.JMSSecurityException: HQ119032: User: null doesnt have permission=SEND on address {2}
        at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:76)
    
    @Resource(mappedName = "java:jboss/exported/jms/destinationFactory")
    ConnectionFactory factory;
    
    private void sendMessageToDestination(String message, String user) throws JMSException {
        try (Connection connection = factory.createConnection(user,"hardcodedPassword");
             Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
             MessageProducer producer = session.createProducer(queue)) {
    
            TextMessage textMessage = session.createTextMessage(message);
    
            producer.send(textMessage);
        }
    }
    
    @MessageDriven(activationConfig = {
            @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
            @ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true"),
            @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:jboss/exported/jms/destination"),
            @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
    public class TestMDB implements MessageListener {
    
        @Override
        @PermitAll
        public void onMessage(Message message) {
    
            if (message instanceof TextMessage) {
                try {
                    System.out.println(((TextMessage) message).getText());
                } catch (JMSException e) {
                    // propagate for transaction rollback
                    throw new IllegalArgumentException(e);
                }
            }
    
        }
    }