使用外部用户凭证连接IBM MQ的问题-Spring Boot + JMS + IBM MQ 8.0.0.9

时间:2019-01-22 16:19:50

标签: spring-boot jms ibm-mq spring-jms

我需要为字幕主题提供帮助。在此处请求您的建议。

我正在使用Spring Boot框架从IBM MQ 8.0.0.9获取消息。附带的程序符合基本要求。但是,它始终使用OS凭证(特别是Windows登录凭证)连接到IBM MQ。但是我希望它使用属性文件中提供的凭据。即使我故意在属性文件中提供了错误的凭证,该程序也很高兴与IBM MQ连接(使用Windows登录凭证,该凭证也可以访问IBM MQ)。

以下是MQ详细信息- MQ版本8.0.0.9, QM版本8.0.0.9, CONNAUTH-未设置, CHLAUTH-残疾人, QMGR CONNAUTH-未设置, CHCKCLNT-可选, AUTHINFO-SYS.DEFAULT.AUTHINFO.IDPWOS

您能否在Attach程序中建议我在做什么错。我也尝试过注释的代码行。

@EnableJms
@Configuration
@EnableTransactionManagement
public class JmsConfig {
    @Value("${ibm.mq.host}")
    private String host;
    @Value("${ibm.mq.port}")
    private Integer port;
    @Value("${ibm.mq.queueManager}")
    private String queueManager;
    @Value("${ibm.mq.channel}")
    private String channel;
    @Value("${ibm.mq.responseQueue}")
    private String responseQueue;
    @Value("${ibm.mq.userName}")
    private String userName;
    @Value("${ibm.mq.password}")
    private String password;
    @Value("${ibm.mq.receiveTimeout}")
    private long timeout;

    @Autowired(required=true)
    @Qualifier(value="responseListener")
    MessageListener  responseListener;

    @Bean (name="queueConnectionFactory")
    public MQQueueConnectionFactory mqQueueConnectionFactory() {
        MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();

        try {
            mqQueueConnectionFactory.setHostName(host);
            mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
            mqQueueConnectionFactory.setChannel(channel);
            mqQueueConnectionFactory.setPort(port);
            mqQueueConnectionFactory.setQueueManager(queueManager);
            mqQueueConnectionFactory.setCCSID(819);
            /*
            mqQueueConnectionFactory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
            mqQueueConnectionFactory.setStringProperty(WMQConstants.USERID, userName);
            mqQueueConnectionFactory.setStringProperty(WMQConstants.PASSWORD, password);
            mqQueueConnectionFactory.setStringProperty(CMQC.USER_ID_PROPERTY, userName);
            mqQueueConnectionFactory.setStringProperty(CMQC.PASSWORD_PROPERTY, password);
            */
        } catch (JMSException e) {
            log.error("Error occured: " + e);
        }

        return mqQueueConnectionFactory;
    }

    @Primary
    @Bean (name="userCredentialsConnectionFactoryAdapter")
    @DependsOn(value = { "queueConnectionFactory" })
    UserCredentialsConnectionFactoryAdapter getUserCredentialsConnectionFactoryAdapter(
            MQQueueConnectionFactory mqQueueConnectionFactory) {
        UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
        userCredentialsConnectionFactoryAdapter.setUsername(userName);
        userCredentialsConnectionFactoryAdapter.setPassword(password);
        userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
        return userCredentialsConnectionFactoryAdapter;
    }

    @Bean (name="simpleMessageListenerContainer")
    @DependsOn(value = { "userCredentialsConnectionFactoryAdapter" })
    public SimpleMessageListenerContainer queueResponseContainer(ConnectionFactory userCredentialsConnectionFactoryAdapter) {
        SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer();
        simpleMessageListenerContainer.setConnectionFactory(userCredentialsConnectionFactoryAdapter);
        simpleMessageListenerContainer.setConnectLazily(true);
        simpleMessageListenerContainer.setDestinationName(responseQueue);
        simpleMessageListenerContainer.setMessageListener(responseListener);
        return simpleMessageListenerContainer;
    }

    @Bean
    public JmsOperations jmsOperations(ConnectionFactory userCredentialsConnectionFactoryAdapter) {
        JmsTemplate jmsTemplate = new JmsTemplate(userCredentialsConnectionFactoryAdapter);
        jmsTemplate.setReceiveTimeout(timeout);
        return jmsTemplate;
    }
}

====================

@Component(value="responseListener")
public class ResponseListener implements MessageListener {

    public void onMessage(Message message) {    
        ...
    }
}

===================

@Component
public class ContainerChecker {

    @Autowired
    SimpleMessageListenerContainer  queueContainer;

    @Scheduled(fixedRate = 300000)
    public void reportContainerStatus() throws ServiceException{
        if(!queueContainer.isActive()) {
            ...
        } else {
            ...
        }
    }
}

1 个答案:

答案 0 :(得分:0)

根据您评论中的更新:

  • 您的应用程序正在使用IBM MQ v8.0.0.9中用于JMS的IBM MQ类
  • 您的应用程序正在连接到同时运行v8.0.0.9的IBM MQ队列管理器。
    • 队列管理器已禁用CONNAUTH [QMGR CONNAUTH('')]
    • 队列管理器已禁用CHLAUTH ['QMGR CHLAUTH(DISABLED)']。

在您的配置中,显示以下bean:

@Bean (name="userCredentialsConnectionFactoryAdapter")
@DependsOn(value = { "queueConnectionFactory" })
UserCredentialsConnectionFactoryAdapter getUserCredentialsConnectionFactoryAdapter(
        MQQueueConnectionFactory mqQueueConnectionFactory) {
    UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
    userCredentialsConnectionFactoryAdapter.setUsername(userName);
    userCredentialsConnectionFactoryAdapter.setPassword(password);
    userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
    return userCredentialsConnectionFactoryAdapter;
}

您还具有以下注释掉的代码:

        /*
        mqQueueConnectionFactory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, true);
        mqQueueConnectionFactory.setStringProperty(WMQConstants.USERID, userName);
        mqQueueConnectionFactory.setStringProperty(WMQConstants.PASSWORD, password);
        mqQueueConnectionFactory.setStringProperty(CMQC.USER_ID_PROPERTY, userName);
        mqQueueConnectionFactory.setStringProperty(CMQC.PASSWORD_PROPERTY, password);
        */

对于JMS v8.0和更高版本的IBM MQ类,设置WMQConstants.USER_AUTHENTICATION_MQCSP的默认值为FALSE。这表示客户机应该在兼容模式下工作,这意味着MQ客户机可以像7.5及更低版本中的工作一样,MQCSP在那些较早的版本中不存在,并且指定的用户名和密码在名为{{1} }和RemoteUserIdentifier,最多12个字符。

在MQ v8和更高版本中,JMS的IBM MQ类现在支持一种新的发送用户名和密码的方式,这就是MQCSP指令。这有一些好处,例如,它可以输入超过12个字符的密码。如果RemotePasswordWMQConstants.USER_AUTHENTICATION_MQCSP,则指定的用户名和密码将以MQCSP结构发送,并且在兼容模式下使用的TRUE会填充用户名,进程将在和下运行。 RemoteUserIdentifier字段留空。

我找不到任何让我相信RemotePassword bean使用userCredentialsConnectionFactoryAdapter设置进​​行任何操作的东西,因此这使我相信它应该发送您在中指定的用户名和密码。称为WMQConstants.USER_AUTHENTICATION_MQCSPRemoteUserIdentifier的字段。如果您使用注释掉的代码,它将发送您在MQCSP中指定的用户名和密码,而正在运行该进程的Windows登录ID将在RemotePassword字段中发送。


v8上具有您指定的配置的队列管理器将完全忽略MQCSP结构中的任何内容,而只会查看RemoteUserIdentifier字段。您还说过CHLAUTH已被禁用,因此这意味着没有适当的CHLAUTH规则会限制或更改客户端发送的用户名。如果RemoteUserIdentifier通道的MCAUSER为空,则在SVRCONN字段中发送的用户ID将用于队列授权检查。

我怀疑当您注意到您的“ Windows登录凭据”进入队列管理器时,是您将RemoteUserIdentifier设置为WMQConstants.USER_AUTHENTICATION_MQCSP的时候。通过将此设置为TRUE,您可以指定要发送给MQ的任何ID,并且由于队列管理器的配置,它将接受并使用该ID,因此不会验证密码。

由于MQ不会检查密码,因此,如果您为密码指定了什么值,则无所谓,以下内容将能够连接以发送指定的用户名。

FALSE

关于队列管理器设置的注意事项

因为未配置CONNAUTH并且CHLAUTH也被禁用,所以您可以连接到队列管理器并指定mqQueueConnectionFactory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, FALSE); mqQueueConnectionFactory.setStringProperty(WMQConstants.USERID, userName); id(如果队列管理器在Unix上)或mqm id(如果队列)管理器在Windows上),您将对队列管理器上的所有队列具有完全的MQ权限。

当前配置无法提供安全性,以防止通过网络连接到队列管理器的主机和端口的任何人访问队列管理器可用的任何资源,在大多数情况下,这也可以用来执行您想要执行的任何操作队列管理器运行的服务器。