Reputation: 33
I need a help for the captioned subject. Request your suggestion here.
I am using spring boot framework to get the messages from IBM MQ 8.0.0.9. The attached program meets the basic expectation. However, It always uses the OS credential (in specifically Windows Login credential) to connect to the IBM MQ. But I would like it to use the credential this is given in property file. Even if, I intentionally give wrong credential in the property files, the program happily connects with the IBM MQ (using windows login credential which has access to the IBM MQ as well).
Here is the MQ Details - MQ Version 8.0.0.9, QM Version 8.0.0.9, CONNAUTH - Not Set, CHLAUTH - Disabled, QMGR CONNAUTH - Not Set, CHCKCLNT - OPTIONAL, AUTHINFO - SYS.DEFAULT.AUTHINFO.IDPWOS
Could you suggest what I am doing wrong here in the attach program. I have tried the commented line of code as well.
@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 {
...
}
}
}
Upvotes: 3
Views: 4098
Reputation: 10672
Based on the updates in your comments:
QMGR CONNAUTH('')
]In your configuration you show the following 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;
}
You also have the following commented out code:
/*
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);
*/
With IBM MQ classes for JMS v8.0 and later the default for the setting WMQConstants.USER_AUTHENTICATION_MQCSP
is FALSE
. This denotes that the client should work in compatibility mode, this means the MQ client works as it did in version 7.5 and lower, MQCSP did not exist in those older versions and the username and password specified were sent in some fields called RemoteUserIdentifier
and RemotePassword
and were limited to 12 characters.
With MQ v8 and higher the IBM MQ classes for JMS now support a new way to send the username and password, this is the MQCSP struction. This has some benefits for example it can passwords that are longer than 12 characters. If WMQConstants.USER_AUTHENTICATION_MQCSP
is TRUE
the username and password specified will be sent in the MQCSP structure and the RemoteUserIdentifier
that is used in compatibility mode is instead filled in with the username the process is running under and the RemotePassword
field is left blank.
I can't find anything that leads me to believe that the userCredentialsConnectionFactoryAdapter
bean does anything with the WMQConstants.USER_AUTHENTICATION_MQCSP
setting so this would lead me to believe it should be sending the username and password you specified in the fields called RemoteUserIdentifier
and RemotePassword
. If you used the commented out code instead it would send the username and password you specified in the MQCSP and your windows login id that is running the process would be sent in the RemoteUserIdentifier
field.
A queue manager at v8 with the configuration you have specified will completely disregard anything in the MQCSP structure and will only look at the RemoteUserIdentifier
field. You also said CHLAUTH is DISABLED, so this means that there are no CHLAUTH rules in place that would restrict or change the username that the client sends. If the SVRCONN
channel has a blank MCAUSER, then the userid sent in the RemoteUserIdentifier
field will be used for queue authorization checks.
I suspect that when you noted your "windows login credential" coming across to the queue manager it was when you had WMQConstants.USER_AUTHENTICATION_MQCSP
set to TRUE
. By setting this to FALSE
you can specify any ID you want to be sent to MQ and because of the configuration of the queue manager it will accept that ID and use it, the password is not verified.
Since the password is not checked by MQ it does not matter what value if any you specify for the password, the following would be able to connect sending the specified username.
mqQueueConnectionFactory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, FALSE);
mqQueueConnectionFactory.setStringProperty(WMQConstants.USERID, userName);
Because CONNAUTH is not configured and CHLAUTH is also DISABLED you can connect to the queue manager and specify the mqm
id (if the queue manager is on Unix) or the MUSR_MQADMIN
id (if the queue manager is on Windows) and you would have full MQ authority over all queues on the queue manager.
The current configuration provides no security to prevent anyone that has access connect over the network to the queue manager's host and port from accessing any resources the queue manager has available, in most cases this could also be leveraged to execute anything you want on the server where the queue manager runs.
Upvotes: 2