ibm-messaging / mq-jms-spring

Components to assist MQ JMS integration with Spring frameworks
Apache License 2.0
186 stars 102 forks source link

Connection Failure where ID is in CommentInsert2or3, failing on user running the app instead of config #81

Closed aholtmart closed 1 year ago

aholtmart commented 2 years ago

Runnning

com.ibm.mq mq-jms-spring-boot-starter 2.3.4

Queue Manager log: If you look below you can see CommentInsert1 has the user that is running the java app and SVC is the service account from auto config in CommentInsert2 11/18/21 13:10:44 - Process(1025171.5659530) User(mqs*) Program(amqrmppa) Host(MQS-**) Installation(MQAppliance) VRMF(9.2.0.3) QMgr(M*4) Time(2021-11-18T18:10:44.434Z) ArithInsert1(2) ArithInsert2(2035) CommentInsert1(tdev*) CommentInsert2(SVC**) CommentInsert3(tdev*)

AMQ9557E: Queue Manager User ID initialization failed for 'tdev***'.

Has anyone seen this before? is there a queue manager rule/setting that we need to add/adjust to make this work?

Thanks,*

Please include the following information in your ticket.

ibmmqmet commented 2 years ago

You've not really provided a lot of information to go on. What is the configuration both for the app and the qmgr, what is the actual error, what is the program doing? There are many things that affect how authentication is done by the qmgr, including qm.ini settings, AUTHREC and AUTHINFO settings. It's impossible to say what to "adjust" without knowing what the current situation is.

Some examples of application programs using userid/password with Spring can be found at https://github.com/ibm-messaging/mq-dev-patterns/tree/master/Spring-JMS. Since the little you have given suggests there is an MQ Appliance involved, then make sure you've read and understood https://www.ibm.com/docs/en/mq-appliance/9.2?topic=security-types-user-how-they-are-authenticated

aholtmart commented 2 years ago

it is this same issue. https://github.com/ibm-messaging/mq-jms-spring/issues/48

aholtmart commented 2 years ago

I use this to configure my connection. What we are finding is my windows user is being sent. I can see it in a wireshark trace and am not able to find where the user/password are being sent from my app.

@Configuration @ComponentScan @Slf4j public class NotifyFinancialGatewayListenerJmsConfig {

@Value("${mq.notifyfinancialgateway.listener.connName}")
private String host;

@Value("${mq.notifyfinancialgateway.listener.queueManager}")
private String queueManager;

@Value("${mq.notifyfinancialgateway.listener.channel}")
private String channel;

@Value("${mq.notifyfinancialgateway.listener.user}")
private String username;

@Value("${mq.notifyfinancialgateway.listener.password}")
private String password;

@Value("${mq.notifyfinancialgateway.listener.port}")
private int port;

@Value("${jms.receive.timeout}")
private long RECEIVETIMEOUT;

/* UTF-8 encoding */
private final int ENCODING = 1208;

@Value("${session.cache.size}")
private int SESSION_CACHE_SIZE;

@Bean(name = "NotifyFinancialGatewayListenerConnectionFactory")
public MQQueueConnectionFactory mqQueueConnectionFactory(){
    MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
    mqQueueConnectionFactory.setHostName(host);
    try{
        mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
        mqQueueConnectionFactory.setCCSID(ENCODING);
        mqQueueConnectionFactory.setChannel(channel);
        mqQueueConnectionFactory.setQueueManager(queueManager);
        mqQueueConnectionFactory.setPort(port);
    }catch(Exception e){
        log.error(e.getMessage());
    }
    return mqQueueConnectionFactory;
}

@Bean(name = "NotifyFinancialGatewayListenerConnectionFactoryAdapter")
public UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter(@Qualifier("NotifyFinancialGatewayListenerConnectionFactory")MQQueueConnectionFactory mqQueueConnectionFactory) {
    UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
    userCredentialsConnectionFactoryAdapter.setUsername(username);
    userCredentialsConnectionFactoryAdapter.setPassword(password);
    userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
    return userCredentialsConnectionFactoryAdapter;
}

@Bean(name = "NotifyFinancialGatewayListenerCachingConnectionFactory")
public CachingConnectionFactory cachingConnectionFactory(@Qualifier("NotifyFinancialGatewayListenerConnectionFactoryAdapter") UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
    CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
    cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
    cachingConnectionFactory.setSessionCacheSize(SESSION_CACHE_SIZE);
    cachingConnectionFactory.setReconnectOnException(true);
    return cachingConnectionFactory;
}

@Bean(name = "NotifyFinancialGatewayListenerJmsOperation")
public JmsOperations jmsOperations(@Qualifier("NotifyFinancialGatewayListenerCachingConnectionFactory") CachingConnectionFactory cachingConnectionFactory) {
    JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
    jmsTemplate.setReceiveTimeout(RECEIVETIMEOUT);
    return jmsTemplate;
}

@Bean(name="NotifyFinancialGatewayListenerContainerFactory")
public JmsListenerContainerFactory<?> receiveReplyFromGppFactory(@Qualifier("NotifyFinancialGatewayListenerCachingConnectionFactory") CachingConnectionFactory connectionFactory,
                                                                 DefaultJmsListenerContainerFactoryConfigurer configurer) {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    return factory;
}

}

ibmmqmet commented 2 years ago

I don't know how the UserCredentialAdapter bean gets wired into the CF creation and configuration - that would likely be a question to be raised on one of the Spring projects directly. But applying properties to the CF itself works for passing over the authentication info. For example,

mqQueueConnectionFactory.setStringProperty(WMQConstants.USERID,username);
mqQueueConnectionFactory.setStringProperty(WMQConstants.PASSWORD,password);
// The next line isn't needed with latest levels of MQ as it's the default setting now, but for completeness...
mqQueueConnectionFactory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP,true);
ibmmqmet commented 2 years ago

This also works, writing it as straight-line code instead of splitting into multiple beans:

JmsTemplate jmsTemplate = new JmsTemplate();
UserCredentialsConnectionFactoryAdapter adapter = new UserCredentialsConnectionFactoryAdapter();
adapter.setTargetConnectionFactory(mqQueueConnectionFactory);
adapter.setUsername(username);
adapter.setPassword(password);
jmsTemplate.setConnectionFactory(adapter);