Проблема с подключением IBM MQ с использованием внешних учетных данных пользователя - Spring Boot + JMS + IBM MQ 8.0.0.9 - PullRequest
0 голосов
/ 22 января 2019

Мне нужна помощь для заголовка темы. Запросите ваше предложение здесь.

Я использую Spring Boot Framework для получения сообщений от IBM MQ 8.0.0.9. Прилагаемая программа соответствует основным ожиданиям. Тем не менее, он всегда использует учетные данные ОС (в частности, учетные данные для входа в Windows) для подключения к IBM MQ. Но я бы хотел использовать учетные данные, указанные в файле свойств. Даже если я намеренно введу неверные учетные данные в файлах свойств, программа успешно подключится к IBM MQ (используя учетные данные для входа в Windows, которые также имеют доступ к IBM MQ).

Вот подробности MQ - MQ версия 8.0.0.9, QM версия 8.0.0.9, КОННАУТ - Не установлено, ХЛОУТ - инвалид, QMGR CONNAUTH - не установлено, CHCKCLNT - ДОПОЛНИТЕЛЬНО, AUTHINFO - SYS.DEFAULT.AUTHINFO.IDPWOS

Не могли бы вы подсказать, что я делаю не так, здесь, в программе присоединения. Я также попробовал закомментированную строку кода.

@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 голосов
/ 24 января 2019

На основе обновлений в ваших комментариях:

  • Ваше приложение использует классы IBM MQ для JMS из IBM MQ v8.0.0.9
  • Ваше приложение подключается кIBM MQ queue manager также работает под управлением v8.0.0.9.
    • Для диспетчера очереди отключено CONNAUTH [QMGR CONNAUTH('')]
    • Для диспетчера очереди отключено CHLAUTH [`QMGR CHLAUTH (DISABLED) '].

В вашей конфигурации показан следующий компонент:

@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);
        */

С классами IBM MQ для JMS v8.0 и позже значение по умолчанию для параметра WMQConstants.USER_AUTHENTICATION_MQCSP составляет FALSE.Это означает, что клиент должен работать в режиме совместимости, это означает, что клиент MQ работает так же, как и в версии 7.5 и ниже, MQCSP не существовал в этих более старых версиях, а указанные имя пользователя и пароль были отправлены в некоторые поля с именем RemoteUserIdentifier иRemotePassword и были ограничены 12 символами.

В MQ v8 и выше классы IBM MQ для JMS теперь поддерживают новый способ отправки имени пользователя и пароля, это структура MQCSP.Это имеет некоторые преимущества, например, это могут пароли длиной более 12 символов.Если WMQConstants.USER_AUTHENTICATION_MQCSP равно TRUE, то имя пользователя и пароль будут отправлены в структуре MQCSP, а RemoteUserIdentifier, используемый в режиме совместимости, вместо этого будет заполнен именем пользователя, под которым выполняется процесс, а поле RemotePassword будетоставлено пустым.

Я не могу найти ничего, что могло бы заставить меня поверить, что бин userCredentialsConnectionFactoryAdapter делает что-то с настройкой WMQConstants.USER_AUTHENTICATION_MQCSP, так что это заставит меня поверить, что он должен посылать вам имя пользователя и пароль.указывается в полях с именами RemoteUserIdentifier и RemotePassword.Если вместо этого вы использовали закомментированный код, он отправит имя пользователя и пароль, указанные вами в MQCSP, а ваш идентификатор входа в Windows, на котором выполняется процесс, будет отправлен в поле RemoteUserIdentifier.


Aадминистратор очередей в v8 с указанной конфигурацией полностью игнорирует все в структуре MQCSP и просматривает только поле RemoteUserIdentifier.Вы также сказали, что CHLAUTH ОТКЛЮЧЕН, так что это означает, что нет никаких правил CHLAUTH, которые бы ограничивали или изменяли имя пользователя, которое отправляет клиент.Если на канале SVRCONN указан пустой MCAUSER, то идентификатор пользователя, отправленный в поле RemoteUserIdentifier, будет использоваться для проверки авторизации очереди.

Я подозреваю, что когда вы заметили, что ваши "учетные данные для входа в Windows" встречаются садминистратор очередей это было, когда вы установили WMQConstants.USER_AUTHENTICATION_MQCSP на TRUE.Установив для этого значение FALSE, вы можете указать любой идентификатор, который хотите отправить в MQ, и из-за конфигурации администратора очередей он примет этот идентификатор и будет использовать его, пароль не проверен.

ПосколькуMQ не проверяет пароль, не имеет значения, какое значение, если вы укажете пароль, сможет подключиться следующее, отправив указанное имя пользователя.

mqQueueConnectionFactory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, FALSE);
mqQueueConnectionFactory.setStringProperty(WMQConstants.USERID, userName); 

Примечания о администраторе очередейsetup

Поскольку CONNAUTH не настроен и CHLAUTH также ОТКЛЮЧЕН, вы можете подключиться к администратору очередей и указать идентификатор mqm (если администратор очередей в Unix) или идентификатор MUSR_MQADMIN (если очередьв Windows), и у вас будут все полномочия MQ для всех очередей в администраторе очередей.

Текущая конфигурация не обеспечивает безопасности, чтобы предотвратить доступ любого пользователя, имеющего доступ, по сети к хосту и порту диспетчера очереди.доступ к любым ресурсам, доступным администратору очередей, в большинстве случаев это также можноveraged для выполнения всего, что вы хотите, на сервере, где работает администратор очередей.

...