├── .classpath ├── .gitignore ├── .project ├── .settings ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.core.prefs └── org.eclipse.m2e.core.prefs ├── LICENSE.txt ├── README.txt ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── mcafee │ │ ├── AMQOps.java │ │ ├── JmsAuthentication.java │ │ ├── JmsDestination.java │ │ ├── JmsDiggerException.java │ │ ├── JmsDumpDestination.java │ │ ├── JmsDurableSubscriberManipulator.java │ │ ├── JmsHelper.java │ │ ├── JmsInitialContextFactory.java │ │ ├── JmsLoginInfo.java │ │ ├── JmsMessageContentGenerator.java │ │ ├── JmsMsgType.java │ │ ├── JmsPasswordOps.java │ │ ├── JmsWriter.java │ │ ├── MessageCountUpdater.java │ │ └── gui │ │ ├── AmqOpsTab.java │ │ ├── JMSDiggerAboutTab.java │ │ ├── JmsAuthenticationTab.java │ │ ├── JmsConfig.java │ │ ├── JmsConfigTab.java │ │ ├── JmsDiggerFrame.java │ │ ├── JmsDumpDestinationTab.java │ │ ├── JmsDurableSubscriberTab.java │ │ ├── JmsGuiCommon.java │ │ └── ProgressInfo.java └── resources │ ├── fs_icon_32.png │ └── log4j.properties └── test └── java └── com └── mcafee ├── AMQOpsTest.java ├── FuzzAMQOps.java ├── IdGeneratorTest.java ├── JmsAuthenticationTest.java ├── JmsDumpDestinationTest.java ├── JmsDurableSubscriberManipulatorTest.java ├── JmsHelperTest.java ├── JmsInitialContextFactoryTest.java ├── JmsLoginInfoTest.java └── JmsPasswordOpsTest.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | jmsdigger 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | net.sourceforge.metrics.builder 15 | 16 | 17 | 18 | 19 | org.eclipse.m2e.core.maven2Builder 20 | 21 | 22 | 23 | 24 | 25 | org.eclipse.jdt.core.javanature 26 | org.eclipse.m2e.core.maven2Nature 27 | net.sourceforge.metrics.nature 28 | 29 | 30 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/main/resources=UTF-8 4 | encoding//src/test/java=UTF-8 5 | encoding/=UTF-8 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 3 | org.eclipse.jdt.core.compiler.compliance=1.5 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.5 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | 204 | ======================================== 205 | Copyright (c) 2013, Gursev Singh Kalra (McAfee, Inc - Foundstone Professional Services) 206 | All rights reserved. 207 | 208 | Redistribution and use in source and binary forms, with or without 209 | modification, are permitted provided that the following conditions are 210 | met: 211 | 212 | * Redistributions of source code must retain the above copyright 213 | notice, this list of conditions and the following disclaimer. 214 | * Redistributions in binary form must reproduce the above 215 | copyright notice, this list of conditions and the following 216 | disclaimer in the documentation and/or other materials provided 217 | with the distribution. 218 | * Neither the name of the Gursev Singh Kalra nor the names of its 219 | contributors may be used to endorse or promote products derived 220 | from this software without specific prior written permission. 221 | 222 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 223 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 224 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 225 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 226 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 227 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 228 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 229 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 230 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 231 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 232 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | JMSDigger is an Enterprise Messaging Application assessment tool. 2 | The current release primarily focuses on ActiveMQ. 3 | 4 | Copyright (c) 2014, Gursev Singh Kalra - gursev.kalra@foundstone.com 5 | (McAfee, Inc - Foundstone Professional Services) 6 | 7 | Licensing 8 | ======================================================================= 9 | JMSDigger license information is available in the file named "LICENSE.txt" 10 | in this directory. The license applies to all source code and resources 11 | contained in the JMSDigger tool. -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.mcafee 6 | jmsdigger 7 | 0.1.1.0-SNAPSHOT 8 | jar 9 | 10 | jmsdigger 11 | https://github.com/OpenSecurityResearch/jmsdigger 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | org.apache.activemq 20 | activemq-all 21 | 5.6.0 22 | 23 | 24 | junit 25 | junit 26 | 4.11 27 | test 28 | 29 | 30 | org.apache.directory.studio 31 | org.apache.commons.codec 32 | 1.6 33 | 34 | 35 | 36 | org.slf4j 37 | slf4j-api 38 | 1.7.2 39 | 40 | 41 | org.jasypt 42 | jasypt 43 | 1.9.0 44 | 45 | 46 | xstream 47 | xstream 48 | 1.2.2 49 | 50 | 51 | commons-lang 52 | commons-lang 53 | 20030203.000129 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-jar-plugin 61 | 2.2 62 | 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-assembly-plugin 67 | 2.2-beta-4 68 | 69 | 70 | jar-with-dependencies 71 | 72 | 73 | 74 | com.mcafee.gui.JmsDiggerFrame 75 | 76 | 77 | 78 | 79 | 80 | package 81 | 82 | single 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | McAfee, Inc. 91 | 92 | 93 | Gursev Singh Kalra 94 | 95 | JMSDigger is JMS API based Enterprise Messaging Application assessment tool. 96 | 97 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/AMQOps.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import java.util.ArrayList; 4 | 5 | import javax.jms.Connection; 6 | import javax.jms.Destination; 7 | import javax.jms.JMSException; 8 | import javax.jms.MapMessage; 9 | import javax.jms.Message; 10 | import javax.jms.MessageConsumer; 11 | import javax.jms.MessageProducer; 12 | import javax.jms.Queue; 13 | import javax.jms.Session; 14 | import javax.jms.Topic; 15 | import javax.naming.InitialContext; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | 20 | /** 21 | * Based on explanation and code example from ActiveMQ tutorials hosted at 22 | * http://activemq.apache.org/statisticsplugin.html 23 | * @author Gursev Singh Kalra @ McAfee, Inc. 24 | */ 25 | public class AMQOps { 26 | private static final Logger LOG = LoggerFactory.getLogger(AMQOps.class); 27 | private static final int TIMEOUT = 1000; // Time to wait for the Queue or Topic status to return since the query is typically blocking. 28 | private InitialContext ctx; 29 | private JmsLoginInfo loginInfo; 30 | private String cfName; 31 | ArrayList dstStats = new ArrayList(); 32 | private Connection connection; // Connection to the broker to last for the entire querying cycle 33 | private Session session; // Session created for the connection. This may or may not change between different request 34 | private Queue replyToQueue; // to connect status responses 35 | private Message message; // message to be sent and initialized during init call 36 | private MessageConsumer messageConsumer; // To consumer receive incoming messages containing stats 37 | private MessageProducer messageProducer; // To send messages to the destination 38 | private boolean statsGenerated = false; 39 | 40 | 41 | boolean initialized = false; 42 | 43 | public AMQOps(InitialContext ctx, String connFactName, JmsLoginInfo loginInfo) { 44 | this.ctx = ctx; 45 | this.loginInfo = loginInfo; 46 | this.cfName = connFactName; 47 | } 48 | 49 | public AMQOps(InitialContext ctx, String connFactName) { 50 | this(ctx, connFactName, null); 51 | } 52 | 53 | /** 54 | * The init method initializes the object so it can be later used. It performs following actions
55 | * 1. Creates a new connection and corresponding session
56 | * 2. Creates a temporary queue to receive user response
57 | * 3. Sets a message Consumer
58 | * 4. Sets the message JMSReplyTo header to the temporary queue
59 | * 5. Starts the connection and sets the initialized instance variable to true
60 | * @throws JmsDiggerException 61 | */ 62 | public void init() throws JmsDiggerException { 63 | LOG.debug("Entering init"); 64 | if(ctx == null || JmsHelper.isStringNullOrEmpty(cfName)) 65 | throw JmsHelper.buildJmsDiggerException("Null value for InitialContext or Connection Factory Name"); 66 | 67 | connection = JmsHelper.createConnection(ctx, cfName, loginInfo); 68 | 69 | try { 70 | session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 71 | replyToQueue = session.createTemporaryQueue(); 72 | messageConsumer = session.createConsumer(replyToQueue); 73 | message = session.createMessage(); 74 | message.setJMSReplyTo(replyToQueue); 75 | messageProducer = session.createProducer(null); 76 | connection.start(); 77 | } catch (JMSException ex) { 78 | LOG.info("Error occured while initializing AMQStats", ex); 79 | throw JmsHelper.buildJmsDiggerException("Error occured while initializing AMQStats", ex); 80 | } 81 | 82 | initialized = true; 83 | LOG.debug("Leaving init"); 84 | } 85 | 86 | /** 87 | * This method returns the obtained statistics as String. 88 | * @return String 89 | * @throws JmsDiggerException 90 | */ 91 | public String getStatsAsString() throws JmsDiggerException { 92 | if(!initialized) 93 | throw new IllegalArgumentException("No stats available"); 94 | 95 | if(!statsGenerated) 96 | throw new IllegalStateException("No stats available"); 97 | 98 | StringBuilder sb = new StringBuilder(); 99 | sb.append(""); 100 | for(MapMessage mm : dstStats) { 101 | sb.append(JmsHelper.mapMessageToString(mm)); 102 | sb.append("\n=================================\n\n"); 103 | } 104 | return sb.toString(); 105 | } 106 | 107 | /** 108 | * Returns statistics of an ActiveMQ broker 109 | * @return ArrayList 110 | * @throws JmsDiggerException 111 | */ 112 | public ArrayList getBrokerStats() throws JmsDiggerException { 113 | return getDestinationStats("ActiveMQ.Statistics.Broker", false, true); 114 | } 115 | 116 | /** 117 | * Returns statistics of a Subscription 118 | * @return ArrayList 119 | * @throws JmsDiggerException 120 | */ 121 | public ArrayList getSubscriptionsStats() throws JmsDiggerException { 122 | return getDestinationStats("ActiveMQ.Statistics.Subscription", false, true); 123 | 124 | } 125 | 126 | /** 127 | * Returns status of Queue with given name. It optionally allows 128 | * you to query Queue status with or without ActiveMQ.Statistics.Destination prefix to the name 129 | * 130 | * @param qName Queue name 131 | * @param prepend - Prepends ActiveMQ.Statistics.Destination. to the Queue name if true, else the qName is queried raw 132 | * @return ArrayList 133 | * @throws JmsDiggerException 134 | */ 135 | 136 | public ArrayList getQueueStats(String qName, boolean prepend) throws JmsDiggerException { 137 | return getDestinationStats(qName, prepend, true); 138 | } 139 | 140 | /** 141 | * Returns status of Topic with given name. It optionally allows 142 | * you to query Topic status with or without ActiveMQ.Statistics.Destination. 143 | * 144 | * @param tName - Topic name 145 | * @param prepend - Prepends ActiveMQ.Statistics.Destination. to the topic name if true, else the tName is queried raw 146 | * @return ArrayList 147 | * @throws JmsDiggerException 148 | */ 149 | 150 | public ArrayList getTopicStats(String tName, boolean prepend) throws JmsDiggerException { 151 | return getDestinationStats(tName, prepend, false); 152 | } 153 | 154 | /** 155 | * This is the main (private) method to query the status and return to the caller. 156 | * @param qName - Queue Name 157 | * @param prepend - Boolean value that decides if ActiveMQ.Statistics.Destination. should be prepended to the qName 158 | * @param isQueue - the destination is a Queue if true, else it is a Topic 159 | * @return - ArrayList 160 | * @throws JmsDiggerException 161 | */ 162 | private ArrayList getDestinationStats(String qName, boolean prepend, boolean isQueue) throws JmsDiggerException { 163 | 164 | statsGenerated = false; // set to false before every attempt to get status 165 | if(qName == null) 166 | throw new IllegalArgumentException("null Destination name passed to getDestinationStats"); 167 | 168 | assertInitialization(); 169 | 170 | if(prepend) 171 | qName = "ActiveMQ.Statistics.Destination." + qName; 172 | 173 | dstStats = new ArrayList(); 174 | 175 | try { 176 | if(isQueue) { 177 | Queue queue = session.createQueue(qName); 178 | messageProducer.send(queue, message); 179 | } else { 180 | Topic topic = session.createTopic(qName); 181 | messageProducer.send(topic, message); 182 | } 183 | MapMessage stats; 184 | while((stats = (MapMessage) messageConsumer.receive(TIMEOUT)) != null) { 185 | dstStats.add(stats); 186 | } 187 | statsGenerated = true; 188 | return dstStats; 189 | } catch (JmsDiggerException ex) { 190 | throw ex; 191 | } catch (JMSException ex) { 192 | LOG.info("An error occured in getDestinationStats", ex); 193 | throw JmsHelper.buildJmsDiggerException("An error occured in getDestinationStats", ex); 194 | } 195 | } 196 | 197 | public void assertInitialization() { 198 | if(!initialized) 199 | throw new IllegalArgumentException(this.getClass().getName().toString() + "'s object is not initialized"); 200 | } 201 | 202 | /** 203 | * Main method to create a Queue or Topic on the target ActiveMQ broker 204 | * @param dstName - Name of the destination 205 | * @param isQueue - Boolean value indicating that the destination is a Queue (when true) or a Topic (when false) 206 | * @return - Destination object 207 | * @throws JmsDiggerException 208 | */ 209 | 210 | private Destination createDestination(String dstName, boolean isQueue) throws JmsDiggerException { 211 | if(JmsHelper.isStringNullOrEmpty(dstName)) 212 | throw JmsHelper.buildJmsDiggerException("Invalid destination name parameter"); 213 | 214 | assertInitialization(); 215 | 216 | try { 217 | if(isQueue) { 218 | Queue q = session.createQueue(dstName); 219 | messageProducer.send(q, message); 220 | return q; 221 | } else { 222 | Topic t = session.createTopic(dstName); 223 | messageProducer.send(t, message); 224 | return t; 225 | } 226 | } catch (JMSException ex) { 227 | LOG.info("Destination " + dstName + " could not be created", ex); 228 | throw JmsHelper.buildJmsDiggerException("Destination " + dstName + " could not be created", ex); 229 | } 230 | } 231 | 232 | /** 233 | * Creates a Queue on ActiveMQ broker 234 | * @param queueName - Name of the queue 235 | * @return - Queue object 236 | * @throws JmsDiggerException 237 | */ 238 | 239 | public Queue createQueue(String queueName) throws JmsDiggerException { 240 | return (Queue) createDestination(queueName, true); 241 | } 242 | 243 | /** 244 | * Creates a Topic on ActiveMQ broker 245 | * @param topicName - Name of the topic 246 | * @return - Topic object 247 | * @throws JmsDiggerException 248 | */ 249 | public Topic createTopic(String topicName) throws JmsDiggerException { 250 | return (Topic) createDestination(topicName, false); 251 | } 252 | 253 | public void close() { 254 | try { 255 | messageProducer.close(); 256 | messageConsumer.close(); 257 | session.close(); 258 | connection.close(); 259 | } catch (JMSException e) { 260 | LOG.info("AMQOps done failed"); 261 | } 262 | 263 | } 264 | 265 | } 266 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsAuthentication.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import javax.jms.Connection; 4 | import javax.jms.ConnectionFactory; 5 | import javax.jms.JMSException; 6 | import javax.naming.InitialContext; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | /** 12 | * This class allows you to check if a Messaging broker supports 13 | * anonymous authentication and also helps validated user credentials 14 | * @author Gursev Singh Kalra @ McAfee, Inc. 15 | * 16 | */ 17 | public class JmsAuthentication { 18 | private static final Logger LOG = LoggerFactory.getLogger(JmsAuthentication.class); 19 | private InitialContext initialContext; 20 | private String cfName; //Connection Factory Name 21 | private JMSException exception; 22 | 23 | public JMSException getException() { 24 | return exception; 25 | } 26 | 27 | public JmsAuthentication(InitialContext initialContext, String cfName) throws JmsDiggerException { 28 | if(initialContext == null) 29 | throw new JmsDiggerException("InitialContext was null"); 30 | this.initialContext = initialContext; 31 | this.cfName = cfName; 32 | } 33 | 34 | /** 35 | * Checks if the provided loginInfo (username/password) is valid. 36 | * IMPORTANT: When anonymous authentication is enabled, any username and password combination allows 37 | * access. 38 | * @param loginInfo 39 | * @return boolean 40 | * @throws JMSException 41 | */ 42 | public boolean isLoginInfoValid(JmsLoginInfo loginInfo) throws JmsDiggerException 43 | { 44 | LOG.debug("Entering isLoginInfoValid method"); 45 | return chkAuthBool(loginInfo); 46 | } 47 | 48 | 49 | /** 50 | * Checks if the initialContext allows anonymous authentication 51 | * @return boolean 52 | * @throws JMSException 53 | */ 54 | public boolean isAnonymousAuthAlowed() throws JmsDiggerException 55 | { 56 | LOG.debug("Entering isAnonymousAuthAlowed method"); 57 | return chkAuthBool(null); 58 | } 59 | 60 | /** 61 | * This is the main method that performs all the lifting and validates user credentials or the 62 | * anonymous authentication support. The return value is true or false. 63 | * @param loginInfo 64 | * @return boolean 65 | * @throws JmsDiggerException 66 | */ 67 | private boolean chkAuthBool(JmsLoginInfo loginInfo) throws JmsDiggerException 68 | { 69 | LOG.debug("Entering chkAuth method"); 70 | boolean authStatus = false; 71 | ConnectionFactory connFact = null; 72 | Connection conn = null; 73 | 74 | connFact = JmsHelper.getConnectionFactory(initialContext, cfName); 75 | //ConnectionFactory cf = jConnFact.getConnectionFactory(cfName, result) 76 | 77 | try 78 | { 79 | if(loginInfo == null) 80 | { 81 | //Attempt an anonymous connection 82 | conn = connFact.createConnection(); 83 | } 84 | else 85 | { 86 | //Attempt an connection with username and password 87 | conn = connFact.createConnection(loginInfo.getUsername(), loginInfo.getPassword()); 88 | } 89 | conn.start(); 90 | // It was also observed that JMSSecurityException was not thrown as suggested by the API documentation. 91 | // But, JMSException was thrown (generated by java.lang.SecurityException). 92 | authStatus = true; 93 | } 94 | catch(JMSException ex) // JmsSecurityException inherits from JmsException. 95 | { 96 | exception = ex; 97 | if(loginInfo == null) 98 | LOG.info("Anonymous authentication was rejected", ex); 99 | else 100 | LOG.info("Invalid " + loginInfo, ex); 101 | authStatus = false; 102 | } 103 | finally 104 | { 105 | if(conn != null) 106 | { 107 | try{ 108 | conn.close(); 109 | } 110 | catch(JMSException ex){ 111 | LOG.debug("Connection could not be closed", ex); 112 | } 113 | } 114 | } 115 | 116 | LOG.debug("Leaving chkAuth method"); 117 | return authStatus; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsDestination.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | /** 4 | * Defines the type of JMS destination 5 | * @author Gursev Singh Kalra @ McAfee, Inc. 6 | * 7 | */ 8 | public enum JmsDestination { 9 | QUEUE, 10 | TOPIC, 11 | CONNECTIONFACTORY, 12 | DURABLESUBSCRIBER, 13 | BROKER, 14 | SUBSCRIPTION 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsDiggerException.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import javax.jms.JMSException; 4 | 5 | /** 6 | * This is the main exception class for the JMSDigger Tool 7 | * @author Gursev Singh Kalra @ McAfee, Inc. 8 | * 9 | */ 10 | public class JmsDiggerException extends JMSException { 11 | 12 | private static final long serialVersionUID = 1L; 13 | 14 | public JmsDiggerException(String msg) { 15 | super(msg); 16 | } 17 | 18 | public JmsDiggerException(String msg, String errCode) { 19 | super(msg, errCode); 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsDumpDestination.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.IOException; 5 | import java.util.Enumeration; 6 | 7 | import javax.jms.Connection; 8 | import javax.jms.ConnectionFactory; 9 | import javax.jms.Destination; 10 | import javax.jms.InvalidSelectorException; 11 | import javax.jms.JMSException; 12 | import javax.jms.Message; 13 | import javax.jms.MessageListener; 14 | import javax.jms.Queue; 15 | import javax.jms.QueueBrowser; 16 | import javax.jms.QueueSession; 17 | import javax.jms.Session; 18 | import javax.jms.Topic; 19 | import javax.jms.TopicSession; 20 | import javax.jms.TopicSubscriber; 21 | import javax.naming.InitialContext; 22 | import javax.naming.NamingException; 23 | 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | /** 28 | * This class writes the contents of a JMS destination (Queue, Topic and DurableSubscribers) \ 29 | * to the local file system using the JMSWriter object. 30 | * @author Gursev Singh Kalra @ McAfee, Inc. 31 | * 32 | */ 33 | 34 | public class JmsDumpDestination implements MessageListener { 35 | private static final Logger LOG = LoggerFactory.getLogger(JmsDumpDestination.class); 36 | private static String filenameIdentifier = "qDump"; 37 | private static final int TIMEOUT = 2000; // 2 second timeout for synchronously receiving messages 38 | 39 | private int msgCountToDump = 0; 40 | private JmsLoginInfo loginInfo; 41 | private boolean initialized; 42 | private JmsDestination dstType; 43 | 44 | private JmsWriter jmsWriter; 45 | private InitialContext ctx; 46 | 47 | private String msgSelector; 48 | private String dstName; 49 | private String targetDirectory; 50 | 51 | private ConnectionFactory connFact; 52 | private String connFactName; 53 | private Connection connection; 54 | private Destination dst; 55 | private int msgsWritten = 0; 56 | private int msgsTraversed = 0; 57 | private boolean dumpComplete; 58 | 59 | // For durable subscriber dumps 60 | private String durableSubscriberName; 61 | private String clientId; 62 | private MessageCountUpdater messageCountUpdater; 63 | 64 | /** 65 | * Main constructor the initialize the JMS Destination dumps 66 | * @param ctx - Initial Context 67 | * @param dstName - Destination name 68 | * @param connFactName - Name of the connection factory 69 | * @param msgSelector - Message selector 70 | * @param loginInfo - Login Info 71 | */ 72 | public JmsDumpDestination(InitialContext ctx, String dstName, String connFactName, String msgSelector, JmsLoginInfo loginInfo) 73 | { 74 | if(ctx == null || dstName == null || connFactName == null) 75 | throw new IllegalArgumentException("Unexpected null object passed to JmsDumpQueue constructor"); 76 | this.ctx = ctx; 77 | this.dstName = dstName; 78 | this.msgSelector = msgSelector; 79 | this.connFactName = connFactName; 80 | this.loginInfo = loginInfo; 81 | this.initialized = false; 82 | this.dumpComplete = false; 83 | } 84 | 85 | public void setTargetDirectory(String targetDirectory) { 86 | this.targetDirectory = targetDirectory; 87 | } 88 | 89 | public boolean isDumpComplete() { 90 | return this.dumpComplete; 91 | } 92 | 93 | public void setMessageCountUpdater(MessageCountUpdater messageCountUpdater) { 94 | this.messageCountUpdater = messageCountUpdater; 95 | } 96 | /** 97 | * Initialize JMS destination dump with anonymous authentication and no message selector 98 | * @param ctx - Initial Context 99 | * @param dstName - Destination name 100 | * @param connFactName - Connection factory name 101 | * @throws NamingException 102 | * @throws JMSException 103 | */ 104 | public JmsDumpDestination(InitialContext ctx, String dstName, String connFactName) 105 | { 106 | this(ctx, dstName, connFactName, null, null); 107 | } 108 | 109 | /** 110 | * Initialize JMS destination dump with anonymous authentication and a message selector 111 | * @param ctx 112 | * @param dstName 113 | * @param connFactName 114 | * @param msgSelector 115 | */ 116 | public JmsDumpDestination(InitialContext ctx, String dstName, String connFactName, String msgSelector) 117 | { 118 | this(ctx, dstName, connFactName, msgSelector, null); 119 | } 120 | 121 | /** 122 | * Set only when you want your client to use a client Id. The value cannot be null. 123 | * @param clientId 124 | */ 125 | public void setClientId(String clientId) { 126 | if(clientId == null) { 127 | LOG.info("Null client ID provided"); 128 | throw new IllegalArgumentException("Null client ID provided"); 129 | } 130 | this.clientId = clientId; 131 | } 132 | 133 | 134 | /** 135 | * Set only when you want to dump a durable subscriber. Both clientID and Durable subscriber name must 136 | * be set for the durable subscriber dump functionality to work. If not, an exception will be thrown 137 | * during the initialization phased with init. 138 | * @param durableSubscriberName 139 | */ 140 | public void setDurableSubscriberName(String durableSubscriberName) { 141 | if(durableSubscriberName == null) { 142 | LOG.info("Null durable subscriber name provided provided"); 143 | throw new IllegalArgumentException("Null durable subscriber name provided"); 144 | } 145 | this.durableSubscriberName = durableSubscriberName; 146 | } 147 | 148 | 149 | 150 | 151 | /** 152 | * The init method initiates three types of processing 153 | * 1. Queue Dump - Via Queue Browsers 154 | * 2. Topic Dumps 155 | * 3. Durable Subscriber Dumps 156 | * 157 | * For a Topic, the algorithm to choose a destination when dst is a Topic instance 158 | * is as follows based on "clientId" and "durableSubscriberName" values 159 | * 160 | *
161 | * -------------------------------------------------------------
162 | * clientId | durableSubscriberName | LookFor |
163 | * -------------------------------------------------------------
164 | * null/empty | null/empty | Topic |
165 | * null/empty | value | Throw Error |
166 | * value | null/empty | Topic |
167 | * value | value | Dump Durable Subscriber |
168 | * --------------------------------------------------------------
169 | */ 170 | 171 | public void init() throws JmsDiggerException { 172 | LOG.debug("Entering init method"); 173 | try { 174 | dst = (Destination) ctx.lookup(dstName); 175 | 176 | if(dst == null) 177 | throw new IllegalArgumentException(dstName + " not found in JNDI"); 178 | 179 | if(dst instanceof Queue) { 180 | dstType = JmsDestination.QUEUE; 181 | filenameIdentifier = "queue-" + dstName; 182 | } 183 | else { 184 | if(dst instanceof Topic) { 185 | if(JmsHelper.isStringNullOrEmpty(durableSubscriberName)) { 186 | dstType = JmsDestination.TOPIC; 187 | filenameIdentifier = "topic-" + dstName; 188 | } else { 189 | if(JmsHelper.isStringNullOrEmpty(clientId)) { 190 | LOG.info("clientId cannot be null when durableSubscriberName has a value"); 191 | throw new IllegalArgumentException("clientId cannot be null when durableSubscriberName has a value"); 192 | } else { 193 | dstType = JmsDestination.DURABLESUBSCRIBER; 194 | filenameIdentifier = "durableSubscriber-" + dstName; 195 | } 196 | } 197 | } else { 198 | throw new IllegalArgumentException(dstName + " is neither a Queue nor a Topic"); 199 | } 200 | } 201 | 202 | connFact = (ConnectionFactory) ctx.lookup(this.connFactName); 203 | 204 | jmsWriter = new JmsWriter(targetDirectory, filenameIdentifier); 205 | if(loginInfo == null) 206 | connection = (Connection) connFact.createConnection(); 207 | else 208 | connection = (Connection) connFact.createConnection(loginInfo.getUsername(), loginInfo.getPassword()); 209 | 210 | // Set clientId - This is very important for durable subscriber identification 211 | if(clientId != null) 212 | connection.setClientID(clientId); 213 | } catch (JmsDiggerException e) { 214 | throw e; 215 | } catch (NamingException e) { 216 | LOG.info("Either a Queue or Destination name not found", e); 217 | throw JmsHelper.buildJmsDiggerException("Either a Queue or Destination name not found", e); 218 | } catch (JMSException e) { 219 | LOG.info("Could not create a connection", e); 220 | throw JmsHelper.buildJmsDiggerException("Could not create a connection", e); 221 | } 222 | 223 | msgsWritten = 0; 224 | initialized = true; 225 | LOG.debug("Leaving init method"); 226 | 227 | } 228 | 229 | /** 230 | * Initializes the number of messages that objects of this class will 231 | * attempt to dump to the local filesystem. If value of count paramter is 232 | * less than 0, the value is left unchanged. 233 | * @param count 234 | */ 235 | public void setMsgCountToDump(int count) { 236 | LOG.debug("Entering setMsgCountToDump method"); 237 | if(count >= 0) 238 | msgCountToDump = count; 239 | LOG.debug("Leaving setMsgCountToDump method"); 240 | 241 | } 242 | 243 | public int getMsgsWritten() { 244 | return msgsWritten; 245 | } 246 | 247 | /** 248 | * Dumps contents of a Queue. Creates a QueueBrowser, gets the enumeration and writes messages. 249 | * @throws FileNotFoundException 250 | * @throws IOException 251 | * @throws JmsDiggerException 252 | * @throws InterruptedException 253 | */ 254 | private void initQueueDump() throws FileNotFoundException, IOException, JmsDiggerException, InterruptedException { 255 | LOG.debug("Entering initQueueDump method"); 256 | 257 | QueueSession qSession = null; 258 | QueueBrowser qBrowser = null; 259 | Enumeration qEnum = null; 260 | jmsWriter.init(); 261 | 262 | try { 263 | qSession = (QueueSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 264 | if(msgSelector == null) 265 | qBrowser = qSession.createBrowser((Queue)dst); 266 | else 267 | qBrowser = qSession.createBrowser((Queue)dst, msgSelector); 268 | connection.start(); 269 | boolean breakout = false; 270 | while(msgsTraversed <= msgCountToDump || msgCountToDump == 0) { 271 | qEnum = qBrowser.getEnumeration(); 272 | if(!qEnum.hasMoreElements()) { 273 | Thread.sleep(2 * 1000); // Wait and try to get more elements 274 | continue; 275 | } 276 | Message msg = null; 277 | while(qEnum.hasMoreElements()) { 278 | msg = (Message) qEnum.nextElement(); 279 | try { 280 | jmsWriter.writeMsg(msg); 281 | msgsWritten++; 282 | 283 | /** 284 | * Update the count in GUI 285 | */ 286 | if(messageCountUpdater != null) { 287 | messageCountUpdater.setCount(msgsWritten); 288 | Thread t = new Thread(messageCountUpdater); 289 | t.start(); 290 | } 291 | } catch(JmsDiggerException ex) { 292 | //Swallow exceptions for failed write messages 293 | } 294 | msgsTraversed++; 295 | if(msgsTraversed >= msgCountToDump && msgCountToDump != 0) { 296 | breakout = true; // never break out when msgCountToDump is 0 297 | dumpComplete = true; 298 | break; // break from inner while loop 299 | } 300 | } 301 | if(breakout) 302 | break; // break from outer while loop 303 | } 304 | } catch (InvalidSelectorException ex) { 305 | LOG.info("Message selector exception encountered", ex); 306 | throw JmsHelper.buildJmsDiggerException("Message selector exception encountered", ex); 307 | } catch (JMSException ex) { 308 | LOG.info("A JMSException occured while creating a QueueBrowser", ex); 309 | throw JmsHelper.buildJmsDiggerException("A JMSException occured while creating a QueueBrowser", ex); 310 | } 311 | 312 | 313 | 314 | try { 315 | qBrowser.close(); 316 | qSession.close(); 317 | } catch (JMSException e) { 318 | LOG.info("qBroswer or qSession close failed ", e); 319 | //Swallow the exception on close. 320 | } 321 | 322 | if(msgsTraversed > msgsWritten) { 323 | LOG.info("Messages Traversed " + msgsTraversed, ", Messages Written: " + msgsWritten); 324 | throw JmsHelper.buildJmsDiggerException("Not all messages were written. Check log for more details"); 325 | } 326 | LOG.debug("Leaving initQueueDump method"); 327 | } 328 | 329 | 330 | /** 331 | * Write one message at a time. The object of this class is set as a message listener for Topics 332 | * Every message is received by this method is in turn written unless the number of messages 333 | * written exceeds the target. 334 | */ 335 | public void onMessage(Message msg){ 336 | LOG.debug("Entering onMessage method"); 337 | if(msgCountToDump == 0 || msgsTraversed < msgCountToDump) { 338 | msgsTraversed++; 339 | try { 340 | jmsWriter.writeMsg(msg); 341 | msgsWritten++; 342 | /** 343 | * Update the count in GUI 344 | */ 345 | if(messageCountUpdater != null) { 346 | messageCountUpdater.setCount(msgsWritten); 347 | Thread t = new Thread(messageCountUpdater); 348 | t.start(); 349 | } 350 | } catch (JmsDiggerException e) { 351 | LOG.info("Message write failed", e); 352 | } 353 | } else { 354 | this.dumpComplete = true; 355 | } 356 | LOG.debug("Leaving onMessage method"); 357 | } 358 | 359 | /** 360 | * Dump contents of a topic. 361 | * @throws JmsDiggerException 362 | * @throws FileNotFoundException 363 | * @throws IOException 364 | */ 365 | private void initTopicDump() throws JmsDiggerException, FileNotFoundException, IOException { 366 | LOG.debug("Entering initTopicDump method"); 367 | TopicSession tSession; 368 | TopicSubscriber tSubscriber; 369 | jmsWriter.init(); 370 | 371 | try { 372 | tSession = (TopicSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 373 | tSubscriber = tSession.createSubscriber((Topic)dst); 374 | 375 | //Set the current object as message listener. All messages will be sent to onMessage method 376 | tSubscriber.setMessageListener(this); 377 | connection.start(); // start the connection - very important 378 | } catch (JMSException e) { 379 | LOG.info("Failure while initiating a Topic Dump", e); 380 | throw JmsHelper.buildJmsDiggerException("Failure while initiating a Topic Dump", e); 381 | } 382 | 383 | //IMPORTANT: The subscriber and session must not be closed as closing them will cause the 384 | // onMessage listener to be dysfunctional and no messages will be received. 385 | LOG.debug("Leaving initTopicDump method"); 386 | } 387 | 388 | 389 | /** 390 | * Dump contents of a durable subscriber. The reads are synchronous and block for duration specified 391 | * in the TIMEOUT (milliseconds) static variable. 392 | * @throws FileNotFoundException 393 | * @throws IOException 394 | * @throws JmsDiggerException 395 | */ 396 | 397 | private void initDurableSubscriberDump() throws FileNotFoundException, IOException, JmsDiggerException { 398 | // Lot of duplicate code between initTopicDump and initDurableSubscriberDump. 399 | //TODO: Potentially combine these functions -- REVIEW and DECIDE. 400 | 401 | LOG.debug("Entering initDurableSubscriberDump method"); 402 | Message msg; 403 | TopicSession tSession; 404 | TopicSubscriber tSubscriber; 405 | jmsWriter.init(); 406 | 407 | try { 408 | tSession = (TopicSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 409 | tSubscriber = tSession.createDurableSubscriber((Topic)dst, durableSubscriberName); 410 | connection.start(); 411 | while(true) { 412 | msg = tSubscriber.receive(TIMEOUT); //Synchronous read, returns null when no message is received during TIMEOUT time 413 | 414 | //Ensure that null message is not passed to JmsWriter as it will throw an IllegalArgumentException 415 | if(msg == null) { 416 | continue; 417 | } 418 | if(msgCountToDump == 0 || msgsTraversed < msgCountToDump) { 419 | try { 420 | jmsWriter.writeMsg(msg); 421 | msgsWritten++; 422 | /** 423 | * Update the count in GUI 424 | */ 425 | if(messageCountUpdater != null) { 426 | messageCountUpdater.setCount(msgsWritten); 427 | Thread t = new Thread(messageCountUpdater); 428 | t.start(); 429 | } 430 | } catch (JmsDiggerException ex) { 431 | LOG.info("Message write failed ", ex); 432 | //Swallow single message write failure exception 433 | } 434 | 435 | msgsTraversed++; 436 | } else { 437 | this.dumpComplete = true; 438 | break; 439 | } 440 | } 441 | } catch (JMSException e) { 442 | LOG.info("Failure while performing a Durable Subscriber Dump", e); 443 | throw JmsHelper.buildJmsDiggerException("Failure while performing a Durable Subscriber Dump", e); 444 | } 445 | 446 | try { 447 | tSubscriber.close(); 448 | tSession.close(); 449 | } catch (JMSException ex) { 450 | //Swallow the close exception 451 | } 452 | 453 | LOG.debug("Leaving initDurableSubscriberDump method"); 454 | } 455 | 456 | /** 457 | * The public method that initiates the message dump from different types of destinations based on the 458 | * destination type determined by the init call. 459 | * @throws IllegalAccessException 460 | * @throws JmsDiggerException 461 | * @throws FileNotFoundException 462 | * @throws IOException 463 | * @throws InterruptedException 464 | */ 465 | 466 | public void dump() throws IllegalAccessException, JmsDiggerException, FileNotFoundException, IOException, InterruptedException 467 | { 468 | LOG.debug("Entering dump method"); 469 | if(!initialized) 470 | throw new IllegalAccessException("dump method called without initializing"); 471 | 472 | if(dstType == JmsDestination.QUEUE) 473 | initQueueDump(); 474 | else { 475 | if(dstType == JmsDestination.TOPIC) 476 | initTopicDump(); 477 | else { 478 | if(dstType == JmsDestination.DURABLESUBSCRIBER) 479 | initDurableSubscriberDump(); 480 | else { 481 | LOG.info(dstName + "is neither a Queue nor Topic or a Durable Subscriber"); 482 | throw new IllegalArgumentException(dstName + "is neither a Queue nor Topic or a Durable Subscriber"); 483 | } 484 | } 485 | } 486 | LOG.debug("Leaving dump method"); 487 | } 488 | 489 | /** 490 | * Important to call the close method to close all the file handles 491 | * for the jmsWriter and also close the JMS connection. 492 | * @throws JMSException 493 | * @throws IOException 494 | */ 495 | 496 | public void close() throws JMSException, IOException 497 | { 498 | LOG.debug("Entering close method"); 499 | jmsWriter.close(); 500 | connection.close(); 501 | LOG.debug("Leaving close method"); 502 | 503 | } 504 | 505 | } 506 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsDurableSubscriberManipulator.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import java.util.ArrayList; 4 | 5 | import javax.jms.Connection; 6 | import javax.jms.InvalidDestinationException; 7 | import javax.jms.JMSException; 8 | import javax.jms.Session; 9 | import javax.jms.Topic; 10 | import javax.jms.TopicSubscriber; 11 | import javax.naming.InitialContext; 12 | import javax.naming.NamingException; 13 | 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | /** 18 | * This class provides capability to perform various operations related to durable subscribers. 19 | * Given a Topic name, credentials (optional), durable subscriber name, the class can be used to perform the following actions: 20 | * 1. Create random and named durable subscribers 21 | * 2. Erase durable subscribers 22 | * 3. Create large number of durable subscribers with random names 23 | * @author Gursev Singh Kalra @ McAfee, Inc. 24 | * 25 | */ 26 | public class JmsDurableSubscriberManipulator { 27 | private static final Logger LOG = LoggerFactory.getLogger(JmsDurableSubscriberManipulator.class); 28 | private InitialContext ctx; 29 | private Topic topic = null; 30 | private JmsLoginInfo loginInfo; 31 | private String cfName; 32 | private String topicName; 33 | private Connection connection; // Connection to the broker to last for the entire querying cycle 34 | private Session session; // Session created for the connection. This may or may not change between different request 35 | private boolean initialized = false; 36 | 37 | private void assertInitialization() { 38 | if(!initialized) 39 | throw new IllegalArgumentException(this.getClass().getName().toString() + "'s object is not initialized"); 40 | } 41 | 42 | public JmsDurableSubscriberManipulator(InitialContext ctx, String topicName, String connFactName) { 43 | this(ctx, topicName, connFactName, null); 44 | 45 | } 46 | 47 | public JmsDurableSubscriberManipulator(InitialContext ctx, String topicName, String connFactName, JmsLoginInfo loginInfo) { 48 | this.ctx = ctx; 49 | this.loginInfo = loginInfo; 50 | this.cfName = connFactName; 51 | this.topicName = topicName; 52 | } 53 | 54 | public void init() throws JmsDiggerException { 55 | init(null); 56 | } 57 | 58 | /** 59 | * Creates a connection, session and starts the connection. 60 | * clientId is set if provided. This is typically used for creating a durable subscriber. 61 | * @param clientId 62 | * @throws JmsDiggerException 63 | */ 64 | public void init(String clientId) throws JmsDiggerException { 65 | LOG.debug("Entering init"); 66 | if(ctx == null || JmsHelper.isStringNullOrEmpty(cfName)) 67 | throw JmsHelper.buildJmsDiggerException("Null value for InitialContext or Connection Factory Name"); 68 | 69 | if(clientId == null) 70 | connection = JmsHelper.createConnection(ctx, cfName, loginInfo ); 71 | else 72 | connection = JmsHelper.createConnection(ctx, cfName, loginInfo, clientId); 73 | 74 | try { 75 | topic = (Topic) ctx.lookup(topicName); 76 | session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 77 | connection.start(); 78 | } catch (JMSException ex) { 79 | LOG.info("Error occured while initializing", ex); 80 | throw JmsHelper.buildJmsDiggerException("Error occured while initializing AMQStats", ex); 81 | } catch (NamingException ex) { 82 | LOG.info(topicName + " not found ", ex); 83 | throw JmsHelper.buildJmsDiggerException(topicName + " not found", ex); 84 | } 85 | 86 | initialized = true; 87 | LOG.debug("Leaving init"); 88 | } 89 | 90 | /** 91 | * Creates "count" number of subscribers for a Topic. Typically to be used during DoS 92 | * by file system exhaustion. The attack may work like this: 93 | * 1. Connect to a Topic 94 | * 2. Create durable subscribers 95 | * 3. Continue to Send large PERSISTENT messages with longer expiry time to the topic. 96 | * 97 | * @param count - number of TopicSubscribers to create 98 | * @return ArrayList - An arraylist of all TopicSubscribers created 99 | * @throws JmsDiggerException 100 | */ 101 | public ArrayList createDurableSubscribers(int count) throws JmsDiggerException { 102 | ArrayList aList = new ArrayList(); 103 | if(count <= 0) 104 | throw new IllegalArgumentException("Count cannot be negative"); 105 | 106 | for(int i = 0; i < count; i++) { 107 | TopicSubscriber ts = createDurableSubscriber(JmsHelper.getRandomString()); 108 | aList.add(ts); 109 | } 110 | return aList; 111 | } 112 | 113 | /** 114 | * Creates a durable topic subscriber with a random name. 115 | * @return TopicSubscriber 116 | * @throws JmsDiggerException 117 | */ 118 | public TopicSubscriber createRandDurableSubscriber() throws JmsDiggerException { 119 | return createDurableSubscriber(JmsHelper.getRandomString()); 120 | } 121 | 122 | /** 123 | * Creates a durable subscriber with a specified name. 124 | * The durable subscriber created can be connected to later on to retrieve content. 125 | * @param name - Name of the topic subscriber 126 | * @return TopicSubscriber - The topic subscriber object 127 | * @throws JmsDiggerException 128 | */ 129 | 130 | public TopicSubscriber createDurableSubscriber(String name) throws JmsDiggerException { 131 | return createDurableSubscriber(name, "", false); 132 | } 133 | 134 | /** 135 | * A Wrapper around createDurableSubscriber with three arguments. 136 | * The noLocal is set to false for every call. 137 | * @param durableSubscriberName 138 | * @param messageSelector 139 | * @return 140 | * @throws JmsDiggerException 141 | */ 142 | public TopicSubscriber createDurableSubscriber(String durableSubscriberName, String messageSelector) throws JmsDiggerException { 143 | return createDurableSubscriber(durableSubscriberName, messageSelector, false); 144 | } 145 | 146 | /** 147 | * This call creates a Durable Subscriber for a topic. It is mandatory to initialize 148 | * with init before making this call. If not, the call will fail. 149 | * @param durableSubscriberName - Name of the durable subscriber 150 | * @param messageSelector - The message selector. Can be null, blank or contain a valid value 151 | * @param noLocal - Enable or disable messages generated from same host 152 | * @return TopicSubscriber - Returns the topic subscriber created 153 | * @throws JmsDiggerException - Throws for any errors 154 | */ 155 | public TopicSubscriber createDurableSubscriber(String durableSubscriberName, String messageSelector, boolean noLocal) throws JmsDiggerException { 156 | LOG.debug("Entering createDurableSubscriber"); 157 | assertInitialization(); 158 | 159 | if(JmsHelper.isStringNullOrEmpty(durableSubscriberName)) 160 | throw new IllegalArgumentException("Durable subscriber name cannot be null or blank"); 161 | 162 | try { 163 | return session.createDurableSubscriber(topic, durableSubscriberName, messageSelector, noLocal); 164 | } catch (JMSException ex) { 165 | LOG.info("An error has occured while creating durable subscriber", ex); 166 | throw JmsHelper.buildJmsDiggerException("An error has occured while creating durable subscriber", ex); 167 | } 168 | } 169 | 170 | /** 171 | * Erases a durable subscriber. 172 | * @param durableSuscriberName 173 | * @throws JmsDiggerException 174 | */ 175 | public void eraseDurableSubscriber(String durableSuscriberName) throws JmsDiggerException { 176 | LOG.debug("Entering eraseDurableSubscriber"); 177 | assertInitialization(); 178 | try { 179 | session.unsubscribe(durableSuscriberName); 180 | } catch (InvalidDestinationException ex) { 181 | LOG.info("No durable subscriber exists with name " + durableSuscriberName); 182 | throw JmsHelper.buildJmsDiggerException("No durable subscriber exists with name " + durableSuscriberName); 183 | } catch (JMSException ex) { 184 | LOG.info("Error occured while erasing a durable subscriber", ex); 185 | throw JmsHelper.buildJmsDiggerException("Error occured while erasing a durable subscriber", ex); 186 | } 187 | LOG.debug("Leaving eraseDurableSubscriber"); 188 | } 189 | 190 | /** 191 | * Close the JMS session and the connection 192 | */ 193 | public void close() { 194 | try { 195 | session.close(); 196 | connection.close(); 197 | } catch (JMSException e) { 198 | LOG.info("AMQOps done failed"); 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsHelper.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | import java.io.StringWriter; 6 | import java.math.BigInteger; 7 | import java.util.Enumeration; 8 | import java.util.Random; 9 | 10 | import javax.jms.Connection; 11 | import javax.jms.ConnectionFactory; 12 | import javax.jms.Destination; 13 | import javax.jms.JMSException; 14 | import javax.jms.MapMessage; 15 | import javax.jms.Session; 16 | //import javax.naming.Context; 17 | import javax.naming.InitialContext; 18 | import javax.naming.NamingException; 19 | 20 | import org.apache.commons.codec.binary.Hex; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | /** 25 | * This is a helper class that offers various functionalities:
26 | * 1. Creates random strings with getRandomString method
27 | * 2. Obtain a destination object with getDestination
28 | * 3. Converts byte array to hex String with byteArrayToHexString
29 | * 4. Converts a MapMessage to string with mapMessageToString method
30 | * 5. Creates a JMS connection and returns the connection object with createConnection method
31 | * 6. Breaks a string to character array with stringToCharArrayString
32 | * 7. Build JmsDiggerException with two overloaded methods with name buildJmsDiggerException
33 | * 8. Creates a connection factory from initial context and connection factory name with getConnectionFactory method
34 | * 9. Creates ActiveMQ's initial context with getActiveMQInitialContext method
35 | * @author Gursev Singh Kalra @ McAfee, Inc. 36 | * 37 | */ 38 | public class JmsHelper { 39 | 40 | private static final Logger LOG = LoggerFactory.getLogger(JmsHelper.class); 41 | private static Random random = new Random(); 42 | 43 | /** 44 | * Generates and returns a random string 45 | * @return String 46 | */ 47 | public static String getRandomString() { 48 | return new BigInteger(64, random).toString(16); 49 | } 50 | 51 | /** 52 | * Converts exception's stack trace to a string for easy printing and consumption 53 | * @param ex 54 | * @return 55 | */ 56 | public static String exceptionStacktraceToString(Exception ex) { 57 | StringWriter sWriter = new StringWriter(); 58 | PrintWriter pWriter = new PrintWriter(sWriter); 59 | ex.printStackTrace(pWriter); 60 | String result = sWriter.toString(); 61 | pWriter.close(); 62 | try { 63 | sWriter.close(); 64 | } catch (IOException e) { 65 | // Eating it up 66 | } 67 | return result; 68 | } 69 | 70 | /** 71 | * Obtains a Destination object. Any generated exception is added to the cause. 72 | * @param ctx - InitialContext 73 | * @param destName - Destination Name 74 | * @return - Destination Object 75 | * @throws JmsDiggerException 76 | */ 77 | public static Destination getDestination(InitialContext ctx, String destName) throws JmsDiggerException 78 | { 79 | LOG.debug("Entering getDestination method"); 80 | Destination dest = null; 81 | if(ctx == null || isStringNullOrEmpty(destName)) 82 | { 83 | LOG.info("Either InitialContext or Destination Name is null"); 84 | throw new JmsDiggerException("Either InitialContext or Destination Name is null"); 85 | } 86 | 87 | try 88 | { 89 | dest = (Destination)(ctx.lookup(destName)); 90 | } 91 | catch(ClassCastException ex) 92 | { 93 | LOG.info("The returned object for name " + destName + " was not of type Destination", ex); 94 | throw buildJmsDiggerException("The returned object for name " + destName + " was not of type Destination", ex); 95 | } 96 | catch(NamingException ne) 97 | { 98 | LOG.info("No destination found with name " + destName, ne); 99 | throw buildJmsDiggerException("No destination found with name " + destName, ne); 100 | } 101 | 102 | LOG.debug("Leaving getDestination method"); 103 | return dest; 104 | 105 | } 106 | 107 | /** 108 | * Convert a byte array to hex string 109 | * Converts a byte array to string representation of hex digits 110 | * Example conversion -> { 0x12, 0x23, 0x32, 0xA5 } 111 | * @param b 112 | * @return 113 | */ 114 | public static String byteArrayToHexString(byte[] b) { 115 | 116 | StringBuilder sb = new StringBuilder(); 117 | if (b.length == 0) 118 | return "{ }"; 119 | 120 | String str = Hex.encodeHexString(b); 121 | String[] twoCharArray = str.split("(?<=\\G.{2})"); 122 | 123 | sb.append("{ "); 124 | for (String s : twoCharArray) 125 | sb.append("0x" + s + ", "); 126 | 127 | sb.deleteCharAt(sb.length() - 2); 128 | sb.append("}"); 129 | return sb.toString(); 130 | } 131 | 132 | /** 133 | * Convers a map message to a string with a custom header 134 | * @param msg - The MapMessage 135 | * @return string representation of the message 136 | * @throws JmsDiggerException 137 | */ 138 | public static String mapMessageToString(MapMessage msg) throws JmsDiggerException { 139 | return mapMessageToString(msg, null); 140 | } 141 | 142 | /** 143 | * Convers a map message to a string with a custom header 144 | * @param msg - The MapMessage 145 | * @param customHdr - The header to be used for separating message 146 | * @return string representation of the message 147 | * @throws JmsDiggerException 148 | */ 149 | public static String mapMessageToString(MapMessage msg, String customHdr) throws JmsDiggerException { 150 | Enumeration e = null; 151 | StringBuilder sb = new StringBuilder(); 152 | String name; 153 | Object value; 154 | 155 | try { 156 | e = ((MapMessage) msg).getMapNames(); 157 | 158 | if (e.hasMoreElements()) { 159 | if(customHdr != null) 160 | sb.append(customHdr + "\n"); 161 | 162 | while (e.hasMoreElements()) { 163 | name = e.nextElement().toString(); 164 | sb.append("\t" + name + " : "); 165 | value = msg.getObject(name); 166 | if (value instanceof byte[]) 167 | sb.append(JmsHelper.byteArrayToHexString((byte[]) value) + "\n"); 168 | else 169 | sb.append(value + "\n"); 170 | } 171 | } 172 | } catch(JMSException ex) { 173 | throw buildJmsDiggerException("An exception occured while creating String representation of MapMessage"); 174 | } 175 | return sb.toString(); 176 | } 177 | 178 | 179 | /** 180 | * This method returns a connection or null if connection could not be generated. 181 | * @param ctx - Initial Context 182 | * @param cfName - ConnectionFactory name 183 | * @param loginInfo - JmsLoginInfo object with username and password 184 | * @param clientId - Client ID to be used 185 | * @return 186 | * @throws JmsDiggerException 187 | */ 188 | public static Connection createConnection(InitialContext ctx, String cfName, JmsLoginInfo loginInfo, String clientId) throws JmsDiggerException { 189 | LOG.debug("Entering getConnection method"); 190 | Connection conn = null; 191 | ConnectionFactory connFact = getConnectionFactory(ctx, cfName); 192 | 193 | try 194 | { 195 | if(loginInfo == null) 196 | conn = connFact.createConnection(); 197 | else 198 | conn = connFact.createConnection(loginInfo.getUsername(), loginInfo.getPassword()); 199 | //conn.setClientID(getRandomString()); 200 | if(clientId != null) 201 | conn.setClientID(clientId); 202 | // A new session is created as ActiveMQ does not initiate a new connection unless session creation is attempted. 203 | // The connection is valid and usable only if it allows session creation. 204 | Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); 205 | 206 | //Close the session if it gets created as it is not needed. 207 | if(sess != null) 208 | sess.close(); 209 | } 210 | catch(JMSException e) 211 | { 212 | LOG.info("Connection to the broker failed", e); 213 | throw buildJmsDiggerException("Connection to the broker failed", e); 214 | } 215 | 216 | LOG.debug("Leaving getConnection method"); 217 | return conn; 218 | } 219 | 220 | 221 | /** 222 | * Convert a string to its character representation 223 | * @param str 224 | * @return 225 | */ 226 | public static String stringToCharArrayString(String str) { 227 | StringBuilder sb = new StringBuilder(); 228 | if(str == null) 229 | throw new IllegalArgumentException("String cannot be null"); 230 | if(isStringNullOrEmpty(str)) 231 | return ""; 232 | 233 | sb.append("{"); 234 | char[] c = str.toCharArray(); 235 | for(char chr : c) { 236 | sb.append("\""+chr+"\""); 237 | sb.append("=> "); 238 | sb.append((int)chr); 239 | sb.append(", "); 240 | } 241 | sb.append("}"); 242 | return sb.toString(); 243 | 244 | } 245 | 246 | public static Connection createConnection(InitialContext ctx, String cfName, JmsLoginInfo loginInfo) throws JmsDiggerException { 247 | return createConnection(ctx, cfName, loginInfo, null); 248 | } 249 | 250 | /** 251 | * This belongs to Unit tests. TODO move it to unit test code 252 | * @return 253 | * @throws JmsDiggerException 254 | */ 255 | public static InitialContext getActiveMQInitialContextForUnitTest() throws JmsDiggerException 256 | { 257 | JmsInitialContextFactory contextFactory = new JmsInitialContextFactory("org.apache.activemq.jndi.ActiveMQInitialContextFactory", "vm://localhost?broker.persistent=false"); 258 | contextFactory.addConnectionFactory("ConnectionFactory"); 259 | contextFactory.addQueue("submissions", "jms.submissions"); 260 | InitialContext ctx = contextFactory.getInitialContext(); 261 | return ctx; 262 | } 263 | 264 | /** 265 | * Returns InitialContext for ActiveMQ 266 | * @return InitialContext 267 | * @throws JmsDiggerException 268 | */ 269 | public static InitialContext getActiveMQInitialContext() throws JmsDiggerException 270 | { 271 | JmsInitialContextFactory contextFactory = new JmsInitialContextFactory("org.apache.activemq.jndi.ActiveMQInitialContextFactory", "tcp://192.168.127.130:61616"); 272 | contextFactory.addConnectionFactory("ConnectionFactory"); 273 | contextFactory.addQueue("submissions", "jms.submissions"); 274 | InitialContext ctx = contextFactory.getInitialContext(); 275 | return ctx; 276 | } 277 | 278 | 279 | /** 280 | * This method returns connection created with anonymous authentication. 281 | * @param ctx - Initial Context 282 | * @param cfName - ConnectionFactory name 283 | * @param result - JmsResposne object, primarily a DAO to carry back details on failure. 284 | * @return 285 | * @throws JmsDiggerException 286 | */ 287 | public static Connection createConnection(InitialContext ctx, String cfName) throws JmsDiggerException 288 | { 289 | return createConnection(ctx, cfName, null); 290 | } 291 | 292 | /** 293 | * Build a JMSDiggerException when another exception has occured and we want to wrap 294 | * that exception with JMSDiggerException 295 | * @param msg - The message 296 | * @param cause - Cause exception 297 | * @return 298 | */ 299 | public static JmsDiggerException buildJmsDiggerException(String msg, Throwable cause) { 300 | JmsDiggerException je = new JmsDiggerException(msg); 301 | je.initCause(cause); 302 | return je; 303 | 304 | } 305 | 306 | /** 307 | * Build a JMSDiggerException when another exception has occured and we want to wrap 308 | * that exception with JMSDiggerException 309 | * @param msg - The message 310 | * @return 311 | */ 312 | public static JmsDiggerException buildJmsDiggerException(String msg) { 313 | JmsDiggerException je = new JmsDiggerException(msg); 314 | return je; 315 | } 316 | 317 | /** 318 | * This method returns a connection factory from initial context and connection factory name 319 | * @param ctx - Initial Context 320 | * @param cfName - Connection factory name 321 | * @return - ConnectionFactory 322 | * @throws JmsDiggerException 323 | */ 324 | public static ConnectionFactory getConnectionFactory(InitialContext ctx, String cfName) throws JmsDiggerException 325 | { 326 | LOG.debug("Entering getConnectionFactory method"); 327 | if(ctx == null) 328 | { 329 | throw new JmsDiggerException("InitialContext parameter was null"); 330 | } 331 | 332 | //Doing this because of the way ActiveMQ handles local resolution of Connection Factory names 333 | if(isStringNullOrEmpty(cfName)) 334 | { 335 | cfName = "ConnectionFactory"; 336 | } 337 | 338 | ConnectionFactory cf = null; 339 | try 340 | { 341 | cf = (ConnectionFactory)(ctx.lookup(cfName)); 342 | } 343 | catch(ClassCastException ex) 344 | { 345 | LOG.info(cfName + " is not of type ConnectionFactory", ex); 346 | //The returned object can be of type Destination 347 | throw buildJmsDiggerException(cfName + " is not of type ConnectionFactory", ex); 348 | } 349 | catch(NamingException ne) 350 | { 351 | LOG.info("No Connection Factory with name " + cfName + " identified", ne); 352 | throw buildJmsDiggerException("No Connection Factory with name " + cfName + " identified", ne); 353 | } 354 | 355 | LOG.debug("Leaving getConnectionFactory method"); 356 | return cf; 357 | } 358 | 359 | /** 360 | * String value is checked against null or with spaces 361 | * @param str 362 | * @return true or false 363 | */ 364 | public static boolean isStringNullOrEmpty(String str) 365 | { 366 | if(str == null || str.trim().equals("")) 367 | return true; 368 | return false; 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsInitialContextFactory.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | import java.util.Properties; 3 | 4 | //import javax.naming.Context; 5 | import javax.naming.InitialContext; 6 | import javax.naming.NamingException; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * This class enables generation of InitailContexts. It does not use username or password from 12 | * the environment but relies on programmatically providing these values. 13 | * If someone wants to add username and password the following properties can be added 14 | * via addRawPropertyToEnv method. 15 | * 16 | * java.naming.security.principal -- for username 17 | * java.naming.security.credentials -- for password 18 | * @author Gursev Singh Kalra @ McAfee, Inc. 19 | * 20 | */ 21 | 22 | public class JmsInitialContextFactory { 23 | private static final Logger LOG = LoggerFactory.getLogger(JmsInitialContextFactory.class); 24 | 25 | private boolean editable; 26 | private Properties env = new Properties(); 27 | private String connectionFactoryName; 28 | 29 | public JmsInitialContextFactory() { 30 | editable = true; 31 | } 32 | 33 | /** 34 | * This constructor initializes the environment with InitialContextFactory name and the provider URL. 35 | * These are mandatory parameters as there is no point initializing if these values are not available 36 | * 37 | * @param initialContextFactory 38 | * @param providerUrl 39 | */ 40 | public JmsInitialContextFactory(String initialContextFactory, String providerUrl) 41 | { 42 | env.setProperty("java.naming.factory.initial", initialContextFactory); 43 | env.setProperty("java.naming.provider.url", providerUrl); 44 | editable = true; 45 | } 46 | 47 | public String getConnectionFactoryName() { 48 | return connectionFactoryName; 49 | } 50 | 51 | /** 52 | * This method takes two parameters to add a new Queue to the Context Environment. 53 | * The topicName parameter takes the name of the Queue, prepends it with "queue." before populating it in the environment. 54 | * This is required because that is how the destination name resolution happens. Queues must be prepended by "queue.". 55 | * The displayName is the name that gets displayed when connection is established. 56 | * @param queueName 57 | * @param displayName 58 | */ 59 | public void addQueue(String queueName, String displayName) { 60 | if(this.editable == false) 61 | return; 62 | env.setProperty("queue." + queueName, displayName); 63 | } 64 | 65 | 66 | /** 67 | * This method allows more control over what gets added. 68 | * One can choose to not use "topic." or "queue." prependers when adding to the environment variable env 69 | * @param destination 70 | * @param displayName 71 | */ 72 | public void addRawPropertyToEnv(String property, String displayName) { 73 | if(this.editable == false) 74 | return; 75 | env.setProperty(property, displayName); 76 | } 77 | 78 | /** 79 | * This method takes two parameters to add a new Topic to the Context Environment. 80 | * The topicName parameter takes the name of the Topic, prepends it with "topic." before populating it in the environment. 81 | * This is required because that is how the resolution happens. Queues must be prepended by "queue.". 82 | * The displayName is the name that gets displayed when connection is established. 83 | * @param topicName 84 | * @param displayName 85 | */ 86 | 87 | public void addTopic(String topicName, String displayName) { 88 | if(this.editable == false) 89 | return; 90 | env.setProperty("topic." + topicName, displayName); 91 | } 92 | 93 | /** 94 | * This method adds connectionFactoryNames to the initial context. 95 | * For connection factory lookup to work, the name must be registered here. If no registration is performed, 96 | * "ConnectionFactory" is the default name that can be used to access the ConnectionFactory from the JNDI service 97 | * @param connectionFactoryName 98 | */ 99 | public void addConnectionFactory(String connectionFactoryName) 100 | { 101 | if(this.editable == false) 102 | return; 103 | this.connectionFactoryName = connectionFactoryName; 104 | env.setProperty("connectionFactoryNames", connectionFactoryName); 105 | } 106 | 107 | 108 | /** 109 | * This method generates an Initial context, marks the InitialContextFactory object as non-editable before returning the 110 | * InitialContext 111 | * @param result 112 | * @return 113 | * @throws JmsDiggerException 114 | */ 115 | public InitialContext getInitialContext() throws JmsDiggerException { 116 | LOG.debug("Entering getInitialContext"); 117 | 118 | InitialContext ctx = null; 119 | 120 | // Default "connectionFactoryNames" to "ConnectionFactory" if not initialized 121 | // "ConnectionFactory" is overwritten when the value of "connectionFactoryNames" is set previously. So if a program 122 | // tries to access "ConnectionFactory" after "connectionFactoryNames" is set to something, javax.naming.NameNotFoundException 123 | // is thrown 124 | if(env.getProperty("connectionFactoryNames") == null) 125 | { 126 | this.connectionFactoryName = "ConnectionFactory"; 127 | env.setProperty("connectionFactoryNames", "ConnectionFactory"); 128 | } 129 | 130 | try 131 | { 132 | ctx = new InitialContext(this.env); 133 | } 134 | catch (NamingException ne) 135 | { 136 | LOG.info("Initial Context could not be created", ne); 137 | throw JmsHelper.buildJmsDiggerException("Initial Context could not be created", ne); 138 | } 139 | 140 | this.editable = false; 141 | LOG.debug("Leaving getInitialContext"); 142 | return ctx; 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsLoginInfo.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | /** 4 | * 5 | * @author Gursev Singh Kalra @ McAfee, Inc. 6 | * 7 | */ 8 | public class JmsLoginInfo { 9 | private String username; 10 | private String password; 11 | public String getUsername() { 12 | return username; 13 | } 14 | public void setUsername(String username) { 15 | this.username = username; 16 | } 17 | public String getPassword() { 18 | return password; 19 | } 20 | public void setPassword(String password) { 21 | this.password = password; 22 | } 23 | public JmsLoginInfo(String username, String password) { 24 | super(); 25 | this.username = username; 26 | this.password = password; 27 | } 28 | 29 | public String toString() 30 | { 31 | String uname; 32 | String passwd; 33 | 34 | uname = (username == null)? "null":username; 35 | passwd = (password == null)? "null":password; 36 | return "Username: \"" +uname+"\", Password: \"" +passwd + "\""; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsMessageContentGenerator.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.util.Hashtable; 5 | import java.util.Random; 6 | 7 | /** 8 | * 9 | * @author Gursev Singh Kalra @ McAfee, Inc. 10 | * 11 | */ 12 | class Person { 13 | private String name; 14 | private int age; 15 | 16 | 17 | public Person(String name, int age) { 18 | super(); 19 | this.name = name; 20 | this.age = age; 21 | } 22 | 23 | public String getName() { 24 | return name; 25 | } 26 | 27 | public int getAge() { 28 | return age; 29 | } 30 | 31 | } 32 | 33 | /** 34 | * This class generates content for JMS messages. 35 | * @author Gursev Singh Kalra 36 | * 37 | */ 38 | public class JmsMessageContentGenerator { 39 | 40 | private static final char[] printable = { 41 | 'a','b','c','d','e','f','g','h','i','j', 42 | 'k','l','m','n','o','p','q','r','s','t', 43 | 'u','v','w','x','y','z','A','B','C','D', 44 | 'E','F','G','H','I','J','K','L','M','N', 45 | 'O','P','Q','R','S','T','U','V','W','X', 46 | 'Y','Z','0','1','2','3','4','5','6','7', 47 | '8','9','`','!','@','#','$','%','^','&', 48 | '*','(',')','-','=','_','+','[',']','\\', 49 | '|','}','{',';','\'',':','"','/','.','\'', 50 | '<','>','?','~' 51 | }; 52 | 53 | private static final char[] alnum = { 54 | 'a','b','c','d','e','f','g','h','i','j', 55 | 'k','l','m','n','o','p','q','r','s','t', 56 | 'u','v','w','x','y','z','A','B','C','D', 57 | 'E','F','G','H','I','J','K','L','M','N', 58 | 'O','P','Q','R','S','T','U','V','W','X', 59 | 'Y','Z','0','1','2','3','4','5','6','7', 60 | '8','9' 61 | }; 62 | 63 | private static final Random random = new Random(); 64 | private static final int LEN = 50; 65 | private int max_value = 256; 66 | 67 | /** 68 | * Generate and return alphanumeric string 69 | * @return 70 | */ 71 | public String getAlnumString() { 72 | return getPrintableString(random.nextInt(LEN)); // do not want to return zero length strings 73 | } 74 | 75 | public void setMaxValue(int i) { 76 | max_value = i; 77 | } 78 | 79 | /** 80 | * Get alphanumeric string with a particular length 81 | * @param length 82 | * @return 83 | */ 84 | public String getAlnumString(int length) { 85 | int plen = alnum.length; 86 | StringBuilder sb = new StringBuilder(); 87 | for(int i = 0 ; i < length; i++) { 88 | sb.append(alnum[random.nextInt(plen)]); 89 | } 90 | return sb.toString(); 91 | } 92 | 93 | 94 | /** 95 | * generates String with length upto 50 characters. 96 | * For longer Strings, use getPrintableString(int length) method 97 | * @return 98 | */ 99 | public String getPrintableString() { 100 | return getPrintableString(random.nextInt(LEN)); // do not want to return zero length strings 101 | } 102 | 103 | /** 104 | * Create a printable string 105 | * @param length 106 | * @return 107 | */ 108 | public String getPrintableString(int length) { 109 | int plen = printable.length; 110 | StringBuilder sb = new StringBuilder(); 111 | for(int i = 0 ; i < length; i++) { 112 | sb.append(printable[random.nextInt(plen)]); 113 | } 114 | return sb.toString(); 115 | } 116 | 117 | 118 | public String getString() { 119 | return getString(random.nextInt(LEN) + 1); 120 | 121 | } 122 | 123 | /** 124 | * Creates a string with all characters less than max_value 125 | * @param length 126 | * @return 127 | */ 128 | public String getString(int length) { 129 | StringBuilder sb = new StringBuilder(); 130 | for(int i = 0 ; i < length; i++) { 131 | sb.append((char)(random.nextInt(max_value))); 132 | } 133 | return sb.toString(); 134 | } 135 | 136 | 137 | /** 138 | * Create a byte array with random length 139 | * @return 140 | */ 141 | public byte[] getByteAray() { 142 | return getByteAray(random.nextInt(LEN) + 1); 143 | } 144 | 145 | /** 146 | * Create a byte array with length 147 | * @param length - length of the byte array 148 | * @return 149 | */ 150 | public byte[] getByteAray(int length) { 151 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 152 | for(int i = 0 ; i < length; i++) { 153 | baos.write(random.nextInt(256)); 154 | } 155 | return baos.toByteArray(); 156 | } 157 | 158 | /** 159 | * Creates a Person object and returns 160 | * @return 161 | */ 162 | public Object getObject() { 163 | return new Person(getPrintableString(), random.nextInt(LEN)); 164 | 165 | } 166 | 167 | /** 168 | * creates a HashTable object of random length 169 | * @return HashTable 170 | */ 171 | public Hashtable getMap() { 172 | return getMap(random.nextInt(LEN)); 173 | } 174 | 175 | /** 176 | * creates a HashTable object of specified length 177 | * @param size - size of the HashTable 178 | * @return HashTable 179 | */ 180 | public Hashtable getMap(int size) { 181 | Hashtable map = new Hashtable(); 182 | for(int i = 0 ; i < size; i ++) 183 | map.put(getPrintableString(), getString()); 184 | return map; 185 | } 186 | 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsMsgType.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | /** 4 | * 5 | * @author Gursev Singh Kalra @ McAfee, Inc. 6 | * 7 | */ 8 | public enum JmsMsgType { 9 | BYTES, 10 | TEXT, 11 | STREAM, 12 | MAP, 13 | OBJECT, 14 | MESSAGE 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsPasswordOps.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import java.util.ArrayList; 4 | import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; 5 | import org.jasypt.exceptions.EncryptionOperationNotPossibleException; 6 | 7 | /** 8 | * 9 | * @author Gursev Singh Kalra @ McAfee, Inc. 10 | * 11 | */ 12 | public class JmsPasswordOps { 13 | private ArrayList passwords = new ArrayList(); 14 | private StandardPBEStringEncryptor decryptor = new StandardPBEStringEncryptor(); 15 | 16 | public void addPassword(String password) { 17 | if(password == null) 18 | throw new IllegalArgumentException("Password cannot be null"); 19 | this.passwords.add(password); 20 | } 21 | 22 | public void addPasswordList(ArrayList passwords) { 23 | if(passwords == null || passwords.size() == 0) 24 | throw new IllegalArgumentException("Password ArrayList cannot be null or of zero length"); 25 | 26 | //Perform a deep copy 27 | for(String pass: passwords) { 28 | if(pass != null) 29 | this.passwords.add(pass); 30 | } 31 | } 32 | 33 | public void clearPasswords() { 34 | this.passwords.clear(); 35 | } 36 | 37 | 38 | public String decryptOne(String encPassword, String key) { 39 | String result = null; 40 | if(JmsHelper.isStringNullOrEmpty(encPassword) || key == null || key.equals("")) { 41 | throw new IllegalArgumentException("EncryptedText or password cannot be null or empty"); 42 | } 43 | 44 | decryptor = new StandardPBEStringEncryptor(); 45 | 46 | try { 47 | decryptor.setPassword(key); 48 | result = decryptor.decrypt(encPassword); 49 | } catch (EncryptionOperationNotPossibleException ex) { 50 | //Absorb this exception 51 | } 52 | return result; 53 | } 54 | 55 | public String decrypt(String encryptedText) { 56 | String result = null; 57 | if(encryptedText == null) 58 | throw new IllegalArgumentException("Encrypted text cannot be null"); 59 | 60 | if(passwords.size() == 0) 61 | throw new IllegalArgumentException("No password list provided"); 62 | 63 | for(String pass : passwords) { 64 | //New object is required for each decryption attempt 65 | decryptor = new StandardPBEStringEncryptor(); 66 | try { 67 | decryptor.setPassword(pass); 68 | result = decryptor.decrypt(encryptedText); 69 | } catch (EncryptionOperationNotPossibleException ex) { 70 | //Absorb this exception to be able to run through a large number of passwords 71 | } 72 | } 73 | // A null value for the result indicates that encrypted 74 | // text could not be decrypted with the provided passwords 75 | return result; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/JmsWriter.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.PrintWriter; 8 | import java.util.Date; 9 | 10 | import javax.jms.BytesMessage; 11 | import javax.jms.JMSException; 12 | import javax.jms.MapMessage; 13 | import javax.jms.Message; 14 | import javax.jms.MessageEOFException; 15 | import javax.jms.ObjectMessage; 16 | import javax.jms.StreamMessage; 17 | import javax.jms.TextMessage; 18 | 19 | import org.apache.commons.codec.binary.Hex; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import com.thoughtworks.xstream.XStream; 24 | 25 | /** 26 | * Objects of this class write Message and its data to flat files. It determines 27 | * the type of message and then writes data as per different headers. Types of 28 | * messages supported are:
29 | * 1. Message
30 | * 2. TextMessage
31 | * 3. ObjectMessage
32 | * 4. BytesMessage
33 | * 5. Stream Message
34 | * 6. MapMessage
35 | * 36 | * @author Gursev Singh Kalra @ McAfee, Inc. 37 | * 38 | */ 39 | 40 | public class JmsWriter { 41 | 42 | private static final Logger LOG = LoggerFactory.getLogger(JmsWriter.class); 43 | 44 | private static String fileSeparator; 45 | private String targetDir; 46 | private boolean targetDirExists; 47 | private static String msgSeparator; // used as a separator between messages 48 | // being dumped 49 | private String msgDumpFilePath; 50 | private PrintWriter msgDumpFileHandle; 51 | 52 | private XStream jmsXstream; 53 | 54 | private int textMsgsWritten = 0; 55 | private int bytesMsgsWritten = 0; 56 | private int objMsgsWritten = 0; 57 | private int streamMsgsWritten = 0; 58 | private int mapMsgsWritten = 0; 59 | private int msgsWritten = 0; 60 | 61 | private String identifier; 62 | 63 | static { 64 | msgSeparator = "\n~-~-~-~-~-~-~-~-~-~~-~-~-~-~-~-~-~-~-~" + (new Date()).getTime() + "\n"; 65 | } 66 | 67 | public JmsWriter(String targetDir, String identifier) throws JmsDiggerException { 68 | this.targetDir = targetDir; 69 | targetDirExists = false; 70 | fileSeparator = System.getProperty("file.separator"); 71 | try { 72 | (new File(targetDir)).mkdirs(); 73 | } catch (Exception ex) { 74 | LOG.error("Target directory could not be created", ex); 75 | throw JmsHelper.buildJmsDiggerException("Target directory could not be created"); 76 | } 77 | jmsXstream = new XStream(); 78 | this.identifier = identifier; 79 | } 80 | 81 | public void init() throws FileNotFoundException, IOException { 82 | LOG.debug("Entering init"); 83 | initFileHandles(); 84 | LOG.debug("Leaving init"); 85 | } 86 | 87 | private void initFileHandles() throws FileNotFoundException, IOException { 88 | // time in seconds since epoch 89 | LOG.debug("Entering initFileHandles"); 90 | long dt = ((new Date()).getTime()); 91 | msgDumpFilePath = targetDir + fileSeparator + identifier + "-MessageDump-" + dt + ".txt"; 92 | 93 | try { 94 | msgDumpFileHandle = new PrintWriter(new FileOutputStream(msgDumpFilePath), true); 95 | msgDumpFileHandle.println("#########################################################################\nJMS Destination message dump generated by JMSDigger\n#########################################################################\n"); 96 | } catch (FileNotFoundException ex) { 97 | LOG.error("Output file handle could not be creatd", ex); 98 | throw ex; 99 | } 100 | 101 | LOG.debug("Leaving initFileHandles"); 102 | } 103 | 104 | private String byteArrayToHexString(byte[] b) { 105 | LOG.debug("Entering byteArrayToHexString"); 106 | // Converts a byte array to string representation of hex digits 107 | // { 0x12, 0x23, 0x32, 0xA5 } 108 | StringBuilder sb = new StringBuilder(); 109 | if (b.length == 0) 110 | return "{ }"; 111 | 112 | String str = Hex.encodeHexString(b); 113 | String[] twoCharArray = str.split("(?<=\\G.{2})"); 114 | 115 | sb.append("{ "); 116 | for (String s : twoCharArray) 117 | sb.append("0x" + s + ", "); 118 | 119 | sb.deleteCharAt(sb.length() - 2); 120 | sb.append("}"); 121 | LOG.debug("Leaving byteArrayToHexString"); 122 | return sb.toString(); 123 | } 124 | 125 | private String getBytesMessageContentAsString(BytesMessage msg) throws JmsDiggerException { 126 | LOG.debug("Entering writeBytesMessage"); 127 | int len = -1; 128 | byte[] body; 129 | 130 | try { 131 | len = (int) msg.getBodyLength(); 132 | if (len == 0) { 133 | return "{ }"; 134 | } 135 | 136 | body = new byte[len]; 137 | msg.readBytes(body); 138 | } catch (JMSException ex) { 139 | LOG.info("An error occured while retreving content from ByteMessage", ex); 140 | throw JmsHelper.buildJmsDiggerException("An error occured while retreving content from ByteMessage", ex); 141 | } 142 | LOG.debug("Leaving writeBytesMessage"); 143 | return byteArrayToHexString(body); 144 | 145 | } 146 | 147 | private String getStreamMessageContentAsString(StreamMessage msg) throws JmsDiggerException { 148 | LOG.debug("Entering writeStreamMessage"); 149 | StringBuilder sb = new StringBuilder(); 150 | sb.append("{ "); 151 | Object o; 152 | 153 | try { 154 | while (true) { 155 | o = msg.readObject(); 156 | if (o instanceof byte[]) 157 | sb.append(byteArrayToHexString((byte[]) o)); 158 | else 159 | sb.append(o); 160 | sb.append(", "); 161 | } 162 | } catch (MessageEOFException ex) { 163 | sb.deleteCharAt(sb.length() - 2); 164 | // Do nothing. End of StreamMessage content has reached. 165 | } catch (JMSException ex) { 166 | LOG.info("An error occured while reading Object from StreamMessage", ex); 167 | throw JmsHelper.buildJmsDiggerException("An error occured while reading Object from StreamMessage", ex); 168 | } 169 | 170 | sb.append("}"); 171 | LOG.debug("Leaving writeStreamMessage"); 172 | return sb.toString(); 173 | } 174 | 175 | private String getMapMessageContentAsString(MapMessage msg) throws JmsDiggerException { 176 | LOG.debug("Entering writeMapMessage"); 177 | try { 178 | return(JmsHelper.mapMessageToString(msg, "[+] MapMessage name-value pairs : ")); 179 | } catch (JMSException ex) { 180 | LOG.info("An error occured while reading MapMessage", ex); 181 | throw JmsHelper.buildJmsDiggerException("An error occured while reading MapMessage", ex); 182 | } 183 | } 184 | 185 | 186 | /** 187 | * Analyze the message type against all the JMS message types supported and 188 | * write metadata as per the message type 189 | * 190 | * @param msg 191 | * @param result 192 | * @throws JmsDiggerException 193 | * @throws IOException 194 | */ 195 | public void writeMsg(Message msg) throws JmsDiggerException { 196 | LOG.debug("Entering writeMsg"); 197 | if (msg == null) 198 | throw new IllegalArgumentException("Message parameter is null"); 199 | 200 | JmsMsgType type = null; 201 | StringBuilder messageContent = new StringBuilder(); 202 | 203 | try { 204 | if (msg instanceof BytesMessage) { 205 | LOG.debug("Message Type : BytesMessage"); 206 | type = JmsMsgType.BYTES; 207 | messageContent.append("[+] Message Type : BytesMessage"); 208 | messageContent.append("\n"); 209 | messageContent.append("[+] Message Bytes as an Array: \n"); 210 | messageContent.append(getBytesMessageContentAsString((BytesMessage) msg)); 211 | messageContent.append("\n"); 212 | bytesMsgsWritten++; 213 | } 214 | 215 | if (type == null && msg instanceof TextMessage) { 216 | LOG.debug("Message Type : TextMessage"); 217 | type = JmsMsgType.TEXT; 218 | messageContent.append("[+] Message Type : TextMessage"); 219 | messageContent.append("\n"); 220 | messageContent.append("[+] Extracted Text\n"); 221 | messageContent.append(((TextMessage)msg).getText()); 222 | messageContent.append("\n"); 223 | textMsgsWritten++; 224 | } 225 | 226 | if (type == null && msg instanceof StreamMessage) { 227 | LOG.debug("Message Type : StreamMessage"); 228 | type = JmsMsgType.STREAM; 229 | messageContent.append("[+] Message Type : StreamMessage"); 230 | messageContent.append("\n"); 231 | messageContent.append("[+] Extracted Stream\n"); 232 | messageContent.append(getStreamMessageContentAsString((StreamMessage) msg)); 233 | messageContent.append("\n"); 234 | streamMsgsWritten++; 235 | } 236 | 237 | if (type == null && msg instanceof MapMessage) { 238 | LOG.debug("Message Type : MapMessage"); 239 | type = JmsMsgType.MAP; 240 | messageContent.append("[+] Message Type : MapMessage"); 241 | messageContent.append("\n"); 242 | messageContent.append(getMapMessageContentAsString((MapMessage) msg)); 243 | messageContent.append("\n"); 244 | mapMsgsWritten++; 245 | } 246 | 247 | if (type == null && msg instanceof ObjectMessage) { 248 | LOG.debug("Message Type : ObjectMessage"); 249 | type = JmsMsgType.OBJECT; 250 | messageContent.append("[+] Message Type : ObjectMessage"); 251 | messageContent.append("\n"); 252 | objMsgsWritten++; 253 | } 254 | 255 | if (type == null && msg instanceof Message) { 256 | LOG.debug("Message Type : Message"); 257 | type = JmsMsgType.MESSAGE; 258 | messageContent.append("[+] Message Type : Message"); 259 | messageContent.append("\n"); 260 | } 261 | 262 | messageContent.append("[+] Message Properties in XML (including binary dump in content/data element)\n"); 263 | messageContent.append(jmsXstream.toXML(msg)); 264 | messageContent.append("\n"); 265 | messageContent.append(msgSeparator); 266 | msgDumpFileHandle.println(messageContent.toString()); 267 | msgsWritten++; 268 | } catch (JMSException ex) { 269 | LOG.info("A JMS operation failed", ex); 270 | throw JmsHelper.buildJmsDiggerException("A JMS operation failed", ex); 271 | } 272 | LOG.debug("Leaving writeMsg"); 273 | } 274 | 275 | private String getWriteCountBreakup() { 276 | StringBuilder sb = new StringBuilder(); 277 | sb.append("ObjectMessages written: " + objMsgsWritten + ", "); 278 | sb.append("BytesMessages written: " + bytesMsgsWritten + ", "); 279 | sb.append("StreamMessages written: " + streamMsgsWritten + ", "); 280 | sb.append("MapMessages written: " + mapMsgsWritten + ", "); 281 | sb.append("TextMessages written: " + textMsgsWritten); 282 | return sb.toString(); 283 | } 284 | 285 | public void close() throws IOException { 286 | LOG.debug("Entering close"); 287 | if (msgsWritten == 0) 288 | msgDumpFileHandle.println("No messages were written"); 289 | 290 | msgDumpFileHandle.flush(); 291 | msgDumpFileHandle.close(); 292 | 293 | LOG.debug(getWriteCountBreakup()); 294 | LOG.debug("Leaving close"); 295 | } 296 | 297 | } -------------------------------------------------------------------------------- /src/main/java/com/mcafee/MessageCountUpdater.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | import java.awt.EventQueue; 3 | import javax.swing.JLabel; 4 | 5 | /** 6 | * 7 | * @author Gursev Singh Kalra @ McAfee, Inc. 8 | * 9 | */ 10 | public class MessageCountUpdater implements Runnable { 11 | private JLabel progressLabel; 12 | private int count; 13 | 14 | 15 | 16 | public MessageCountUpdater(JLabel progressLabel) { 17 | this.progressLabel = progressLabel; 18 | } 19 | 20 | public void setCount(int count) { 21 | this.count = count; 22 | } 23 | 24 | public void run() { 25 | EventQueue.invokeLater(new Runnable() { 26 | public void run() { 27 | progressLabel.setText(Integer.toString(count)); 28 | } 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/JMSDiggerAboutTab.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | import java.awt.GridBagConstraints; 4 | import java.awt.GridBagLayout; 5 | 6 | import javax.swing.BorderFactory; 7 | import javax.swing.JPanel; 8 | import javax.swing.JTextArea; 9 | import javax.swing.border.Border; 10 | import javax.swing.border.EtchedBorder; 11 | 12 | public class JMSDiggerAboutTab extends JPanel{ 13 | 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = 1L; 18 | private String title; 19 | 20 | public String getTitle() { 21 | return this.title; 22 | } 23 | public JMSDiggerAboutTab() { 24 | this.title = "About"; 25 | JPanel aboutPanel = new JPanel(new GridBagLayout()); 26 | Border border = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); 27 | aboutPanel.setBorder(border); 28 | JTextArea aboutTextArea = new JTextArea("\n JMSDigger is an Enterprise Messaging Application Assessment tool. \n\n Author: Gursev Singh Kalra (gursev.kalra@foundstone.com)\n McAfee, Inc - Foundstone Professional Services. \n\n Source code: \n https://github.com/OpenSecurityResearch/jmsdigger\n "); 29 | aboutTextArea.setEditable(false); 30 | GridBagConstraints gbc = new GridBagConstraints(); 31 | gbc.gridx = 0; 32 | gbc.gridy = 0; 33 | aboutPanel.add(aboutTextArea, gbc); 34 | this.add(aboutPanel); 35 | } 36 | 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/JmsAuthenticationTab.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | import java.awt.Dimension; 4 | import java.awt.GridBagConstraints; 5 | import java.awt.GridBagLayout; 6 | import java.awt.Insets; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | import java.io.File; 10 | import java.io.FileInputStream; 11 | import java.io.FileNotFoundException; 12 | import java.util.ArrayList; 13 | import java.util.Enumeration; 14 | import java.util.List; 15 | import java.util.Scanner; 16 | import java.util.concurrent.ExecutionException; 17 | 18 | import javax.naming.InitialContext; 19 | import javax.swing.BorderFactory; 20 | import javax.swing.DefaultListModel; 21 | import javax.swing.JButton; 22 | import javax.swing.JFileChooser; 23 | import javax.swing.JLabel; 24 | import javax.swing.JList; 25 | import javax.swing.JPanel; 26 | import javax.swing.JProgressBar; 27 | import javax.swing.JScrollPane; 28 | import javax.swing.JTextArea; 29 | import javax.swing.JTextField; 30 | import javax.swing.SwingWorker; 31 | import javax.swing.border.Border; 32 | import javax.swing.border.EtchedBorder; 33 | 34 | import org.slf4j.Logger; 35 | import org.slf4j.LoggerFactory; 36 | 37 | import com.mcafee.JmsAuthentication; 38 | import com.mcafee.JmsDiggerException; 39 | import com.mcafee.JmsHelper; 40 | import com.mcafee.JmsLoginInfo; 41 | 42 | /** 43 | * 44 | * @author Gursev Singh Kalra @ McAfee, Inc. 45 | * 46 | */ 47 | public class JmsAuthenticationTab extends JPanel { 48 | 49 | private static final Logger LOG = LoggerFactory.getLogger(JmsAuthenticationTab.class); 50 | private static int space = 5; 51 | private String title; 52 | private JFileChooser fileChooser; 53 | 54 | public String getTitle() { 55 | return title; 56 | } 57 | 58 | /** 59 | * 60 | */ 61 | private static final long serialVersionUID = 1L; 62 | private JTextField singleUserInput ; 63 | private JTextField singlePassInput; 64 | private JButton goSingleUser; 65 | private JList usernameList; 66 | private JButton loadUserIdsButton; 67 | private JButton clearUserIdsButton; 68 | private JList passwordList; 69 | private JButton loadPasswordsButton; 70 | private JButton clearPasswordsButton; 71 | private JButton goBruteforceButton; 72 | private JTextArea outputArea; 73 | private JProgressBar progressBar; 74 | private JmsConfigTab jmsConfigTab; 75 | private AuthenticationWorker authenticationWorker; 76 | 77 | 78 | public JmsAuthenticationTab(JmsConfigTab jmsConfigTab) { 79 | this.jmsConfigTab = jmsConfigTab; 80 | UsernamePasswordListManipulator usernamePasswordListManipulatorObject = new UsernamePasswordListManipulator(); 81 | TriggerAuthenticationWorker triggerAuthenticationWorkerObject = new TriggerAuthenticationWorker(); 82 | 83 | JLabel blankLabel = new JLabel("\n"); 84 | Insets inset = new Insets(space, space, space, space); 85 | Insets masterInset = new Insets(space * 2, space *2 , space*2, space*2); 86 | GridBagLayout masterGbl = new GridBagLayout(); 87 | GridBagConstraints masterGbc = new GridBagConstraints(); 88 | this.setLayout(masterGbl); 89 | this.title = "Authentication"; 90 | 91 | JPanel singleUserPanel = new JPanel(new GridBagLayout()); 92 | JLabel singleUserLabel = new JLabel("Username: "); 93 | singleUserLabel.setHorizontalAlignment(JLabel.RIGHT); 94 | JLabel singlePassLabel = new JLabel("Password: "); 95 | singlePassLabel.setHorizontalAlignment(JLabel.RIGHT); 96 | singlePassInput = new JTextField(20); 97 | goSingleUser = new JButton("Go"); 98 | goSingleUser.addActionListener(triggerAuthenticationWorkerObject); 99 | GridBagConstraints gbc = new GridBagConstraints(); 100 | Border border = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); 101 | Border singleUserBorder = BorderFactory.createTitledBorder(border, "Credential Check"); 102 | Border fuzzBorder = BorderFactory.createTitledBorder(border, "Credential Brute Force"); 103 | 104 | 105 | gbc.insets = inset; 106 | gbc.gridx = 0; 107 | gbc.gridy = 0; 108 | singleUserPanel.add(singleUserLabel, gbc); 109 | gbc.gridx = 1; 110 | gbc.gridy = 0; 111 | gbc.gridwidth = 2; 112 | singleUserInput = new JTextField(20); 113 | //gbc.weightx = 1.0; 114 | //gbc.fill = GridBagConstraints.HORIZONTAL; 115 | singleUserPanel.add(singleUserInput, gbc); 116 | gbc.gridx = 0; 117 | gbc.gridy = 1; 118 | gbc.gridwidth = 1; 119 | gbc.weightx = 0.0; 120 | gbc.fill = GridBagConstraints.NONE; 121 | singleUserPanel.add(singlePassLabel, gbc); 122 | gbc.gridx = 1; 123 | gbc.gridy = 1; 124 | gbc.gridwidth = 2; 125 | //gbc.weightx = 1.0; 126 | //gbc.fill = GridBagConstraints.HORIZONTAL; 127 | singleUserPanel.add(singlePassInput, gbc); 128 | 129 | 130 | 131 | JPanel buttonPanel = new JPanel(); 132 | buttonPanel.add(goSingleUser); 133 | gbc.gridx = 0; 134 | gbc.gridy = 2; 135 | gbc.gridwidth = 3; 136 | singleUserPanel.add(buttonPanel, gbc); 137 | singleUserPanel.setBorder(singleUserBorder); 138 | 139 | masterGbc.gridx = 0; 140 | masterGbc.gridy = 0; 141 | masterGbc.anchor = GridBagConstraints.LINE_START; 142 | this.add(singleUserPanel, masterGbc); 143 | 144 | masterGbc.gridx = 0; 145 | masterGbc.gridy = 1; 146 | this.add(blankLabel, masterGbc); 147 | 148 | 149 | 150 | /* 151 | * Panel to accomodate controls for username and password lists 152 | */ 153 | JPanel loginFuzzPanel = new JPanel(new GridBagLayout()); 154 | Dimension userPasswdListSize = new Dimension(275,70); 155 | gbc = new GridBagConstraints(); 156 | //gbc.insets = inset; 157 | 158 | /* 159 | * Build the USERNAME, Jlist and corresponding load and clear buttons 160 | */ 161 | JPanel usernamePanel = new JPanel(new GridBagLayout()); 162 | JLabel userIdLabel = new JLabel("Usernames"); 163 | gbc.gridx = 0; 164 | gbc.gridy = 0; 165 | usernamePanel.add(userIdLabel, gbc); 166 | 167 | usernameList = new JList(); 168 | DefaultListModel usernameModel = new DefaultListModel(); 169 | usernameList.setModel(usernameModel); 170 | usernameList.setBorder(border); 171 | gbc.gridx = 0; 172 | gbc.gridy = 1; 173 | JScrollPane userPane = new JScrollPane(usernameList); 174 | userPane.setPreferredSize(userPasswdListSize); 175 | usernamePanel.add(userPane, gbc); 176 | 177 | JPanel usernameLoadClearPanel = new JPanel(); 178 | loadUserIdsButton = new JButton("Load"); 179 | usernameLoadClearPanel.add(loadUserIdsButton); 180 | loadUserIdsButton.addActionListener(usernamePasswordListManipulatorObject); 181 | clearUserIdsButton = new JButton("Clear"); 182 | usernameLoadClearPanel.add(clearUserIdsButton); 183 | clearUserIdsButton.addActionListener(usernamePasswordListManipulatorObject); 184 | gbc.gridx = 0; 185 | gbc.gridy = 2; 186 | usernamePanel.add(usernameLoadClearPanel, gbc); 187 | 188 | gbc.gridx = 0; 189 | gbc.gridy = 0; 190 | loginFuzzPanel.add(usernamePanel, gbc); 191 | 192 | /* 193 | * Build the PASSWORD, Jlist and corresponding load and clear buttons 194 | */ 195 | JPanel passwordPanel = new JPanel(new GridBagLayout()); 196 | JLabel passwordsLabel = new JLabel("Passwords"); 197 | gbc.gridx = 0; 198 | gbc.gridy = 0; 199 | passwordPanel.add(passwordsLabel, gbc); 200 | 201 | passwordList = new JList(); 202 | DefaultListModel passwordModel = new DefaultListModel(); 203 | passwordList.setModel(passwordModel); 204 | //passwordList.setPreferredSize(userPasswdListSize); 205 | passwordList.setBorder(border); 206 | gbc.gridx = 0; 207 | gbc.gridy = 1; 208 | JScrollPane passPane = new JScrollPane(passwordList); 209 | passPane.setPreferredSize(userPasswdListSize); 210 | passwordPanel.add(passPane, gbc); 211 | 212 | 213 | /** 214 | * CODE BEGIN - Load and clear passwords 215 | */ 216 | JPanel passwordLoadClearPanel = new JPanel(); 217 | loadPasswordsButton = new JButton("Load"); 218 | passwordLoadClearPanel.add(loadPasswordsButton); 219 | loadPasswordsButton.addActionListener(usernamePasswordListManipulatorObject); 220 | clearPasswordsButton = new JButton("Clear"); 221 | passwordLoadClearPanel.add(clearPasswordsButton); 222 | clearPasswordsButton.addActionListener(usernamePasswordListManipulatorObject); 223 | gbc.gridx = 0; 224 | gbc.gridy = 2; 225 | passwordPanel.add(passwordLoadClearPanel, gbc); 226 | 227 | gbc.gridx = 1; 228 | gbc.gridy = 0; 229 | loginFuzzPanel.add(passwordPanel, gbc); 230 | /** 231 | * CODE ENDS - Load and clear passwords 232 | */ 233 | 234 | 235 | /* 236 | * Create the go button and stick it to the end of the Fuzzing 237 | */ 238 | JPanel goBruteforcePanel = new JPanel(new GridBagLayout()); 239 | goBruteforceButton = new JButton("Go"); 240 | goBruteforceButton.addActionListener(triggerAuthenticationWorkerObject); 241 | goBruteforcePanel.add(goBruteforceButton); 242 | gbc.gridx = 0; 243 | gbc.gridy = 0; 244 | goBruteforcePanel.add(goBruteforceButton, gbc); 245 | gbc.gridx = 0; 246 | gbc.gridy = 1; 247 | gbc.gridwidth = 2; 248 | loginFuzzPanel.add(goBruteforcePanel, gbc); 249 | 250 | masterGbc.gridx = 0; 251 | masterGbc.gridy = 2; 252 | loginFuzzPanel.setBorder(fuzzBorder); 253 | this.add(loginFuzzPanel, masterGbc); 254 | 255 | 256 | /* 257 | * Add a text box to display results and exception details 258 | */ 259 | JPanel outputBoxPanel = new JPanel(new GridBagLayout()); 260 | outputArea = new JTextArea(15, 50); 261 | outputArea.setEditable(false); 262 | 263 | gbc.fill = GridBagConstraints.BOTH; 264 | gbc.gridx = 0; 265 | gbc.gridy = 0; 266 | outputBoxPanel.add(new JScrollPane(outputArea), gbc); 267 | Border authBorder = BorderFactory.createTitledBorder(border, "Results"); 268 | outputBoxPanel.setBorder(authBorder); 269 | masterGbc.gridx = 0; 270 | masterGbc.gridy = 3; 271 | this.add(outputBoxPanel, masterGbc); 272 | 273 | 274 | /* 275 | * Pane to display progress 276 | */ 277 | JPanel progressPanel = new JPanel(new GridBagLayout()); 278 | JLabel progressLabel = new JLabel("Progress > "); 279 | gbc.gridx = 0; 280 | gbc.gridy = 0; 281 | gbc.fill = GridBagConstraints.NONE; 282 | progressPanel.add(progressLabel, gbc); 283 | 284 | 285 | progressBar = new JProgressBar(); 286 | gbc.fill = GridBagConstraints.HORIZONTAL; 287 | gbc.gridx = 2; 288 | gbc.gridy = 0; 289 | gbc.weightx = 1.0; 290 | progressPanel.add(progressBar, gbc); 291 | 292 | masterGbc.gridx = 0; 293 | masterGbc.gridy = 4; 294 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 295 | masterGbc.insets = masterInset; 296 | this.add(progressPanel, masterGbc); 297 | 298 | 299 | } 300 | 301 | class UsernamePasswordListManipulator implements ActionListener { 302 | 303 | public void actionPerformed(ActionEvent event) { 304 | DefaultListModel usernamePasswordListModel = new DefaultListModel(); 305 | if(event.getSource() == clearUserIdsButton) { 306 | usernameList.setModel(usernamePasswordListModel); 307 | return; 308 | } 309 | else { 310 | if(event.getSource() == clearPasswordsButton) { 311 | passwordList.setModel(usernamePasswordListModel); 312 | return; 313 | } 314 | } 315 | 316 | 317 | fileChooser = new JFileChooser(); 318 | fileChooser.setCurrentDirectory(new File(".")); 319 | Scanner fileScanner; 320 | 321 | int result = fileChooser.showOpenDialog(null); 322 | if(result == JFileChooser.APPROVE_OPTION) { 323 | File file = fileChooser.getSelectedFile(); 324 | try { 325 | fileScanner = new Scanner(new FileInputStream(file)); 326 | while(fileScanner.hasNextLine()) { 327 | usernamePasswordListModel.addElement(fileScanner.nextLine()); 328 | } 329 | fileScanner.close(); 330 | } catch (FileNotFoundException e) { 331 | LOG.info("An error has occured with the file Scanner", e); 332 | JmsGuiCommon.showErrorAndLogMessage("An error occured with the file Scanner."); 333 | } 334 | if(event.getSource() == loadUserIdsButton) 335 | usernameList.setModel(usernamePasswordListModel); 336 | else 337 | if(event.getSource() == loadPasswordsButton) 338 | passwordList.setModel(usernamePasswordListModel); 339 | } 340 | } 341 | } 342 | 343 | class TriggerAuthenticationWorker implements ActionListener { 344 | 345 | public void actionPerformed(ActionEvent event) { 346 | outputArea.setText(""); 347 | progressBar.setValue(0); 348 | DefaultListModel userIdModel = (DefaultListModel)(usernameList.getModel()); 349 | DefaultListModel passwordModel = (DefaultListModel)(passwordList.getModel()); 350 | 351 | ArrayList usernameArrayList = new ArrayList(); 352 | ArrayList passwordArrayList = new ArrayList(); 353 | 354 | if(event.getSource() == goSingleUser) { 355 | usernameArrayList.add(singleUserInput.getText()); 356 | passwordArrayList.add(singlePassInput.getText()); 357 | } else { 358 | if(event.getSource() == goBruteforceButton) { 359 | 360 | if(passwordModel.getSize() == 0) 361 | passwordArrayList.add(""); 362 | else { 363 | Enumeration e = passwordModel.elements(); 364 | while(e.hasMoreElements()) 365 | passwordArrayList.add(e.nextElement()); 366 | } 367 | 368 | if(userIdModel.getSize() == 0) 369 | usernameArrayList.add(""); 370 | else { 371 | Enumeration e = userIdModel.elements(); 372 | while(e.hasMoreElements()) 373 | usernameArrayList.add(e.nextElement()); 374 | } 375 | } 376 | } 377 | try { 378 | authenticationWorker = new AuthenticationWorker(jmsConfigTab.getJmsConfig(), usernameArrayList, passwordArrayList); 379 | } catch (JmsDiggerException e) { 380 | LOG.info("An error has occured while creating an AuthenticationWorker", e); 381 | JmsGuiCommon.showErrorAndLogMessage("An error has occured while creating an AuthenticationWorker"); 382 | } 383 | authenticationWorker.execute(); 384 | disableAllButtons(); 385 | } 386 | 387 | private void disableAllButtons() { 388 | goSingleUser.setEnabled(false); 389 | goBruteforceButton.setEnabled(false); 390 | loadPasswordsButton.setEnabled(false); 391 | loadUserIdsButton.setEnabled(false); 392 | clearPasswordsButton.setEnabled(false); 393 | clearUserIdsButton.setEnabled(false); 394 | } 395 | } 396 | 397 | class ProgressInfo { 398 | private String accessResult; 399 | private int percentage; 400 | 401 | public String getAccessResult() { 402 | return accessResult; 403 | } 404 | 405 | public int getPercentage() { 406 | return percentage; 407 | } 408 | 409 | public ProgressInfo(String accessResult, int percentage) { 410 | this.accessResult = accessResult; 411 | this.percentage = percentage; 412 | } 413 | } 414 | 415 | class AuthenticationWorker extends SwingWorker { 416 | 417 | private ArrayList usernameArrayList; 418 | private ArrayList passwordArrayList; 419 | 420 | private JmsConfig jmsConfig; 421 | private InitialContext initialContext; 422 | private JmsLoginInfo loginInfo; 423 | private JmsAuthentication jmsAuthn; 424 | private boolean boolResult; 425 | 426 | public AuthenticationWorker(JmsConfig jmsConfig, ArrayList usernameArrayList, ArrayList passwordArrayList) { 427 | this.jmsConfig = jmsConfig; 428 | this.usernameArrayList = usernameArrayList; 429 | this.passwordArrayList = passwordArrayList; 430 | } 431 | 432 | @Override 433 | public String doInBackground() throws JmsDiggerException { 434 | StringBuilder testResults; 435 | StringBuilder workingCreds = new StringBuilder(); 436 | workingCreds.append("\n\n###########################################################\nWorking Credentials:\n"); 437 | // contextFactory = new JmsInitialContextFactory(jmsConfig.getCtxFactoryClass(), jmsConfig.getProviderUrl()); 438 | // contextFactory.addConnectionFactory(jmsConfig.getConnFactName()); 439 | // ctx = contextFactory.getInitialContext(); 440 | initialContext = jmsConfig.buildInitialContext(); 441 | jmsAuthn = new JmsAuthentication(initialContext, jmsConfig.getConnFactName()); 442 | int userPasswordCombinations = usernameArrayList.size() * passwordArrayList.size(); 443 | int count = 0; 444 | for(String username: usernameArrayList) { 445 | for(String password: passwordArrayList) { 446 | testResults = new StringBuilder(); 447 | loginInfo = new JmsLoginInfo(username, password); 448 | 449 | testResults.append("###########################################################\nTrying => " 450 | +loginInfo 451 | +"\n" 452 | +"Result: "); 453 | count++; 454 | 455 | boolResult = jmsAuthn.isLoginInfoValid(loginInfo); 456 | if(boolResult == false) { 457 | testResults.append("Failed\n"); 458 | testResults.append(JmsHelper.exceptionStacktraceToString(jmsAuthn.getException())); 459 | } else { 460 | testResults.append("Success\n"); 461 | workingCreds.append(loginInfo + "\n"); 462 | } 463 | 464 | publish(new ProgressInfo(testResults.toString(), count*100/userPasswordCombinations)); 465 | } 466 | } 467 | return workingCreds.toString(); 468 | } 469 | 470 | @Override 471 | public void process(List progressInfo) { 472 | progressBar.setValue(progressInfo.get(progressInfo.size() - 1).getPercentage()); 473 | for(ProgressInfo p : progressInfo) { 474 | outputArea.append("\n" + p.getAccessResult()); 475 | } 476 | } 477 | 478 | @Override 479 | public void done() { 480 | //outputArea.append(); 481 | try { 482 | outputArea.append(get()); 483 | } catch (InterruptedException e) { 484 | LOG.info("An error has occured while appending to the outputArea", e); 485 | } catch (ExecutionException e) { 486 | LOG.info("An error has occured while appending to the outputArea", e); 487 | } 488 | enableAllButtons(); 489 | } 490 | 491 | private void enableAllButtons() { 492 | //Thread.sleep(3* 1000); 493 | goSingleUser.setEnabled(true); 494 | goBruteforceButton.setEnabled(true); 495 | loadPasswordsButton.setEnabled(true); 496 | loadUserIdsButton.setEnabled(true); 497 | clearPasswordsButton.setEnabled(true); 498 | clearUserIdsButton.setEnabled(true); 499 | } 500 | 501 | } 502 | 503 | } 504 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/JmsConfig.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | import javax.naming.InitialContext; 4 | 5 | import com.mcafee.JmsDiggerException; 6 | import com.mcafee.JmsInitialContextFactory; 7 | import com.mcafee.JmsLoginInfo; 8 | 9 | /** 10 | * 11 | * @author Gursev Singh Kalra @ McAfee, Inc. 12 | * 13 | */ 14 | public class JmsConfig { 15 | private InitialContext initialContext; 16 | private JmsInitialContextFactory contextFactory; 17 | private String ctxFactoryClass; 18 | private String connFactName; 19 | private String providerUrl; 20 | private String username; 21 | private String password; 22 | private JmsLoginInfo loginInfo; 23 | private boolean finalInitContext; 24 | 25 | public JmsConfig(String ctxFactoryClass, String connFactName, String providerUrl, String username, String password) throws JmsDiggerException { 26 | this.ctxFactoryClass = ctxFactoryClass; 27 | this.connFactName = connFactName; 28 | this.providerUrl = providerUrl; 29 | this.username = username; 30 | this.password = password; 31 | contextFactory = new JmsInitialContextFactory(this.getCtxFactoryClass(), this.getProviderUrl()); 32 | contextFactory.addConnectionFactory(this.getConnFactName()); 33 | loginInfo = new JmsLoginInfo(this.username, this.password); 34 | finalInitContext = false; 35 | } 36 | 37 | public InitialContext buildInitialContext() throws JmsDiggerException { 38 | //Delaying Initial Context initialization until it is retrieved. 39 | if(!finalInitContext) 40 | initialContext = contextFactory.getInitialContext(); 41 | return initialContext; 42 | } 43 | 44 | public void addTopic(String topicName) { 45 | if(!finalInitContext) 46 | contextFactory.addTopic(topicName, "jms."+topicName); 47 | } 48 | 49 | public void addQueue(String queueName) { 50 | if(!finalInitContext) 51 | contextFactory.addQueue(queueName, "jms."+queueName); 52 | } 53 | 54 | public String getCtxFactoryClass() { 55 | return ctxFactoryClass; 56 | } 57 | 58 | public String getConnFactName() { 59 | return connFactName; 60 | } 61 | 62 | public String getProviderUrl() { 63 | return providerUrl; 64 | } 65 | 66 | public String getUsername() { 67 | return username; 68 | } 69 | 70 | public String getPassword() { 71 | return password; 72 | } 73 | 74 | public JmsLoginInfo getLoginInfo() { 75 | return loginInfo; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/JmsConfigTab.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | import java.awt.EventQueue; 4 | import java.awt.GridBagConstraints; 5 | import java.awt.GridBagLayout; 6 | import java.awt.Insets; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | 10 | import javax.naming.InitialContext; 11 | import javax.swing.JButton; 12 | import javax.swing.JLabel; 13 | import javax.swing.JOptionPane; 14 | import javax.swing.JPanel; 15 | import javax.swing.JPasswordField; 16 | import javax.swing.JTextField; 17 | 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | import com.mcafee.JmsAuthentication; 22 | import com.mcafee.JmsDiggerException; 23 | import com.mcafee.JmsHelper; 24 | import com.mcafee.JmsInitialContextFactory; 25 | import com.mcafee.JmsLoginInfo; 26 | 27 | /** 28 | * This panel contains all the configuration related items 29 | * @author Gursev Singh Kalra @ McAfee, Inc. 30 | * 31 | */ 32 | 33 | public class JmsConfigTab extends JPanel { 34 | 35 | /** 36 | * 37 | */ 38 | private static final Logger LOG = LoggerFactory.getLogger(JmsConfigTab.class); 39 | private static final long serialVersionUID = 1L; 40 | private String title; 41 | private static int space = 5; 42 | 43 | private JTextField ctxFactoryClassInput; 44 | private JTextField providerUrlInput; 45 | private JTextField usernameInput; 46 | private JPasswordField passwordInput; 47 | private JTextField connFactNameInput; 48 | private JButton testConfigButton; 49 | 50 | 51 | public String getTitle() { 52 | return title; 53 | } 54 | 55 | public JmsConfig getJmsConfig() throws JmsDiggerException { 56 | if(JmsHelper.isStringNullOrEmpty(connFactNameInput.getText()) 57 | || JmsHelper.isStringNullOrEmpty(ctxFactoryClassInput.getText()) 58 | || JmsHelper.isStringNullOrEmpty(providerUrlInput.getText())) 59 | { 60 | JOptionPane.showMessageDialog(null, "One of Connection Factory, Provider URL or Context Factory Name is or empty", "Error", JOptionPane.ERROR_MESSAGE); 61 | return null; 62 | } 63 | JmsConfig jmsConfig = new JmsConfig( 64 | ctxFactoryClassInput.getText(), 65 | connFactNameInput.getText(), 66 | providerUrlInput.getText(), 67 | usernameInput.getText(), 68 | new String(passwordInput.getPassword()) 69 | ); 70 | return jmsConfig; 71 | } 72 | 73 | public JmsConfigTab () { 74 | Insets inset = new Insets(space, space, space, space); 75 | GridBagConstraints gbc = new GridBagConstraints(); 76 | gbc.insets = inset; 77 | JPanel configPanel = new JPanel(new GridBagLayout()); 78 | 79 | JLabel ctxFactoryClassLabel = new JLabel("Initial Context Factory Class"); 80 | ctxFactoryClassInput = new JTextField(30); 81 | ctxFactoryClassInput.setText("org.apache.activemq.jndi.ActiveMQInitialContextFactory"); 82 | ctxFactoryClassInput.setEditable(false); 83 | ctxFactoryClassLabel.setHorizontalAlignment(JLabel.RIGHT); 84 | 85 | JLabel connFactNameLabel = new JLabel("Connection Factory Name"); 86 | connFactNameInput = new JTextField(); 87 | connFactNameInput.setEditable(false); 88 | connFactNameInput.setText("ConnectionFactory"); 89 | connFactNameLabel.setHorizontalAlignment(JLabel.RIGHT); 90 | 91 | JLabel providerUrlLabel = new JLabel("Provider URL"); 92 | providerUrlInput = new JTextField(); 93 | providerUrlLabel.setHorizontalAlignment(JLabel.RIGHT); 94 | 95 | JLabel usernameLabel = new JLabel("Username"); 96 | usernameInput = new JTextField(); 97 | usernameLabel.setHorizontalAlignment(JLabel.RIGHT); 98 | 99 | JLabel passwordLabel = new JLabel("Password"); 100 | passwordInput = new JPasswordField(); 101 | passwordLabel.setHorizontalAlignment(JLabel.RIGHT); 102 | 103 | JPanel testConfigPanel = new JPanel(); 104 | testConfigButton = new JButton("Test Configuration"); 105 | testConfigButton.addActionListener(new TestJmsConfiguration()); 106 | testConfigPanel.add(testConfigButton); 107 | 108 | gbc.gridx = 0; 109 | gbc.gridy = 0; 110 | gbc.weightx = 0.0; 111 | configPanel.add(ctxFactoryClassLabel, gbc); 112 | gbc.gridx = 1; 113 | gbc.gridy = 0; 114 | gbc.fill = GridBagConstraints.HORIZONTAL; 115 | gbc.weightx = 1.0; 116 | configPanel.add(ctxFactoryClassInput, gbc); 117 | gbc.gridx = 0; 118 | gbc.gridy = 1; 119 | gbc.weightx = 0.0; 120 | gbc.fill = GridBagConstraints.HORIZONTAL; 121 | configPanel.add(connFactNameLabel, gbc); 122 | gbc.gridx = 1; 123 | gbc.gridy = 1; 124 | gbc.weightx = 1.0; 125 | gbc.fill = GridBagConstraints.HORIZONTAL; 126 | configPanel.add(connFactNameInput, gbc); 127 | 128 | gbc.gridx = 0; 129 | gbc.gridy = 2; 130 | gbc.weightx = 0.0; 131 | gbc.fill = GridBagConstraints.HORIZONTAL; 132 | configPanel.add(providerUrlLabel, gbc); 133 | gbc.gridx = 1; 134 | gbc.gridy = 2; 135 | gbc.weightx = 1.0; 136 | gbc.fill = GridBagConstraints.HORIZONTAL; 137 | configPanel.add(providerUrlInput, gbc); 138 | 139 | gbc.gridx = 0; 140 | gbc.gridy = 3; 141 | gbc.weightx = 0.0; 142 | gbc.fill = GridBagConstraints.HORIZONTAL; 143 | configPanel.add(usernameLabel, gbc); 144 | gbc.gridx = 1; 145 | gbc.gridy = 3; 146 | gbc.weightx = 1.0; 147 | gbc.fill = GridBagConstraints.HORIZONTAL; 148 | configPanel.add(usernameInput, gbc); 149 | gbc.gridx = 0; 150 | gbc.gridy = 4; 151 | gbc.weightx = 0.0; 152 | gbc.fill = GridBagConstraints.HORIZONTAL; 153 | configPanel.add(passwordLabel, gbc); 154 | gbc.gridx = 1; 155 | gbc.gridy = 4; 156 | gbc.weightx = 1.0; 157 | gbc.fill = GridBagConstraints.HORIZONTAL; 158 | configPanel.add(passwordInput, gbc); 159 | 160 | 161 | gbc.gridx = 0; 162 | gbc.gridwidth = 2; 163 | gbc.gridy = 5; 164 | gbc.weightx = 1.0; 165 | gbc.fill = GridBagConstraints.HORIZONTAL; 166 | configPanel.add(testConfigPanel, gbc); 167 | 168 | GridBagConstraints masterGbc = new GridBagConstraints(); 169 | masterGbc.gridx = 0; 170 | masterGbc.gridy = 0; 171 | masterGbc.anchor = GridBagConstraints.NORTHWEST; 172 | 173 | this.add(configPanel, masterGbc); 174 | this.title = "JMS Config"; 175 | 176 | } 177 | 178 | class TestJmsConfiguration implements ActionListener { 179 | private String username; 180 | private String connFactName; 181 | private String ctxFactoryClass; 182 | private String providerUrl; 183 | private String password; 184 | private JmsConfigTestWorker jmsConfigTest; 185 | 186 | public TestJmsConfiguration() { 187 | 188 | } 189 | 190 | public void actionPerformed(ActionEvent e) { 191 | connFactName = connFactNameInput.getText(); 192 | ctxFactoryClass = ctxFactoryClassInput.getText(); 193 | providerUrl = providerUrlInput.getText(); 194 | username = usernameInput.getText(); 195 | username = usernameInput.getText(); 196 | char[] tpassword = passwordInput.getPassword(); 197 | password = new String(tpassword); 198 | 199 | if(JmsHelper.isStringNullOrEmpty(connFactName) 200 | || JmsHelper.isStringNullOrEmpty(ctxFactoryClass) 201 | || JmsHelper.isStringNullOrEmpty(providerUrl)) 202 | { 203 | JOptionPane.showMessageDialog(null, "One of Connection Factory, Provider URL or Context Factory Name is or empty", "Error", JOptionPane.ERROR_MESSAGE); 204 | return; 205 | } 206 | 207 | try { 208 | jmsConfigTest = new JmsConfigTestWorker(ctxFactoryClass, connFactName, providerUrl, username, password); 209 | Thread t = new Thread(jmsConfigTest); 210 | t.start(); 211 | } catch (JmsDiggerException ex) { 212 | String s = "An error has occured while creating a JmsConfigTestWorker"; 213 | LOG.info(s, ex); 214 | JmsGuiCommon.showErrorAndLogMessage(s); 215 | } 216 | 217 | } 218 | } 219 | 220 | 221 | class JmsConfigTestWorker implements Runnable { 222 | private JmsInitialContextFactory contextFactory; 223 | private InitialContext ctx; 224 | private JmsLoginInfo loginInfo; 225 | private JmsAuthentication jmsAuthn; 226 | private boolean result; 227 | 228 | 229 | 230 | public JmsConfigTestWorker(String ctxFactoryClass, String connFactName, String providerUrl, String username, String password) throws JmsDiggerException { 231 | contextFactory = new JmsInitialContextFactory(ctxFactoryClass, providerUrl); 232 | contextFactory.addConnectionFactory(connFactName); 233 | ctx = contextFactory.getInitialContext(); 234 | loginInfo = new JmsLoginInfo(username, password); 235 | jmsAuthn = new JmsAuthentication(ctx, connFactName); 236 | this.result = false; 237 | 238 | } 239 | 240 | public void run() { 241 | EventQueue.invokeLater(new Runnable() { 242 | public void run() { 243 | testConfigButton.setEnabled(false); 244 | } 245 | }); 246 | 247 | try { 248 | result = jmsAuthn.isLoginInfoValid(loginInfo); 249 | EventQueue.invokeLater(new Runnable() { 250 | public void run() { 251 | if(result == true) 252 | JOptionPane.showMessageDialog(null, "Configuration parameters OK!", "Success", JOptionPane.INFORMATION_MESSAGE); 253 | else 254 | JOptionPane.showMessageDialog(null, "Connection failed, please check logs for more details.", "Failure", JOptionPane.ERROR_MESSAGE); 255 | } 256 | }); 257 | 258 | 259 | } catch (JmsDiggerException e) { 260 | String errStr = "An error occured while checking login credentials"; 261 | LOG.info(errStr, e); 262 | JmsGuiCommon.showErrorAndLogMessage(errStr); 263 | } finally { 264 | EventQueue.invokeLater(new Runnable() { 265 | public void run() { 266 | testConfigButton.setEnabled(true); 267 | } 268 | }); 269 | } 270 | 271 | } 272 | 273 | } 274 | 275 | } 276 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/JmsDiggerFrame.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | import java.awt.BorderLayout; 4 | import java.awt.GridLayout; 5 | import java.awt.Image; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | 9 | import javax.imageio.ImageIO; 10 | import javax.swing.JFrame; 11 | import javax.swing.JPanel; 12 | import javax.swing.JTabbedPane; 13 | import javax.swing.SwingUtilities; 14 | 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import com.mcafee.JmsDiggerException; 19 | 20 | /** 21 | * 22 | * @author Gursev Singh Kalra @ McAfee, Inc. 23 | * 24 | */ 25 | class JmsDiggerFrame extends JFrame { 26 | 27 | private static final long serialVersionUID = 1L; 28 | private static final int WIDTH = 700; 29 | private static final int HEIGHT = 690; 30 | private static final Logger LOG = LoggerFactory.getLogger(JmsDiggerFrame.class); 31 | 32 | public JmsDiggerFrame() { 33 | 34 | } 35 | 36 | public JmsDiggerFrame(String name) throws IOException { 37 | super(name); 38 | } 39 | 40 | public String getString() { 41 | return "string"; 42 | } 43 | 44 | private static void createAndShowGUI() throws JmsDiggerException, IOException { 45 | JmsDiggerFrame jmsDiggerFrame = new JmsDiggerFrame("JMSDigger 0.1.1.0"); 46 | 47 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 48 | InputStream inputStream = classLoader.getResourceAsStream("fs_icon_32.png"); 49 | Image fsIcon = ImageIO.read(inputStream); 50 | jmsDiggerFrame.setIconImage(fsIcon); 51 | 52 | jmsDiggerFrame.setSize(WIDTH, HEIGHT); 53 | jmsDiggerFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 54 | 55 | JPanel jmsDiggerParentPanel = new JPanel(new GridLayout(1, 1)); 56 | JTabbedPane tabbedPane = new JTabbedPane(); 57 | tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); 58 | JmsConfigTab jmsConfigTab = new JmsConfigTab(); 59 | JmsAuthenticationTab authenticationTab = new JmsAuthenticationTab(jmsConfigTab); 60 | JmsDumpDestinationTab dumpTab = new JmsDumpDestinationTab(jmsConfigTab); 61 | JmsDurableSubscriberTab durableSubscriberTab = new JmsDurableSubscriberTab(jmsConfigTab); 62 | AmqOpsTab amqOpsTab = new AmqOpsTab(jmsConfigTab); 63 | JMSDiggerAboutTab aboutTab = new JMSDiggerAboutTab(); 64 | 65 | // All the tabs will be added here 66 | tabbedPane.add(jmsConfigTab.getTitle(), jmsConfigTab); 67 | tabbedPane.add(authenticationTab.getTitle(), authenticationTab); 68 | tabbedPane.add(amqOpsTab.getTitle(), amqOpsTab); 69 | tabbedPane.add(dumpTab.getTitle(), dumpTab); 70 | tabbedPane.add(durableSubscriberTab.getTitle(), durableSubscriberTab); 71 | tabbedPane.add(aboutTab.getTitle(), aboutTab); 72 | 73 | jmsDiggerParentPanel.add(tabbedPane); 74 | jmsDiggerFrame.add(jmsDiggerParentPanel, BorderLayout.NORTH); 75 | jmsDiggerFrame.setVisible(true); 76 | } 77 | 78 | 79 | /** 80 | * @param args 81 | */ 82 | public static void main(String[] args) { 83 | SwingUtilities.invokeLater(new Runnable() { 84 | public void run() { 85 | try { 86 | createAndShowGUI(); 87 | } catch (JmsDiggerException e) { 88 | String errStr = "An error occured while creating JMSDigger GUI"; 89 | LOG.info(errStr, e); 90 | JmsGuiCommon.showErrorAndLogMessage(errStr); 91 | } catch (IOException e) { 92 | String errStr = "An error occured while creating JMSDigger GUI"; 93 | LOG.info(errStr, e); 94 | JmsGuiCommon.showErrorAndLogMessage(errStr); 95 | } 96 | } 97 | }); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/JmsDumpDestinationTab.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | import java.awt.FlowLayout; 4 | import java.awt.GridBagConstraints; 5 | import java.awt.GridBagLayout; 6 | import java.awt.Insets; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | import javax.jms.JMSException; 13 | import javax.naming.InitialContext; 14 | import javax.naming.NamingException; 15 | import javax.swing.ButtonGroup; 16 | import javax.swing.JButton; 17 | import javax.swing.JFileChooser; 18 | import javax.swing.JLabel; 19 | import javax.swing.JOptionPane; 20 | import javax.swing.JPanel; 21 | import javax.swing.JRadioButton; 22 | import javax.swing.JSpinner; 23 | import javax.swing.JTextField; 24 | import javax.swing.SpinnerNumberModel; 25 | import javax.swing.SwingWorker; 26 | 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | import com.mcafee.JmsDestination; 31 | import com.mcafee.JmsDiggerException; 32 | import com.mcafee.JmsDumpDestination; 33 | import com.mcafee.JmsHelper; 34 | import com.mcafee.JmsLoginInfo; 35 | import com.mcafee.MessageCountUpdater; 36 | 37 | /** 38 | * 39 | * @author Gursev Singh Kalra @ McAfee, Inc. 40 | * 41 | */ 42 | public class JmsDumpDestinationTab extends JPanel { 43 | 44 | 45 | /** 46 | * 47 | */ 48 | private static final Logger LOG = LoggerFactory.getLogger(JmsDumpDestinationTab.class); 49 | private static final long serialVersionUID = 1L; 50 | private String title; 51 | private JmsConfigTab jmsConfigTab; 52 | private static int space = 5; 53 | private JLabel writtenMsgCountLabel; 54 | private JTextField durableSubsNameInput; 55 | private JTextField clientIdInput; 56 | private JTextField messageSelectorInput; 57 | private JTextField destNameInput; 58 | private JButton startButton; 59 | private JButton stopButton; 60 | private SpinnerNumberModel spinnerModel; 61 | private JSpinner msgCountSpinner; 62 | private JTextField outputDirPath; 63 | private JButton outputDirSelectorButton; 64 | private JRadioButton topicRadio; 65 | private JRadioButton queueRadio; 66 | private JRadioButton durableRadio; 67 | private ButtonGroup bg; 68 | private DestinationDumpWorker destinationDumpWorker; 69 | 70 | public String getTitle() { 71 | return title; 72 | } 73 | 74 | public void enableDisableInputs(boolean status) { 75 | clientIdInput.setEditable(status); 76 | durableSubsNameInput.setEditable(status); 77 | } 78 | 79 | public void enableInputs() { 80 | enableDisableInputs(true); 81 | } 82 | 83 | public void disableInputs() { 84 | enableDisableInputs(false); 85 | clientIdInput.setText(""); 86 | durableSubsNameInput.setText(""); 87 | } 88 | 89 | public JmsDumpDestinationTab(JmsConfigTab jmsConfigTab) { 90 | this.jmsConfigTab = jmsConfigTab; 91 | GridBagConstraints masterGbc = new GridBagConstraints(); 92 | JPanel dumpDestinationPanel = new JPanel(new GridBagLayout()); 93 | 94 | Insets inset = new Insets(space, space, space, space); 95 | masterGbc.insets = inset; 96 | GridBagConstraints gbc = new GridBagConstraints(); 97 | 98 | JLabel dstNameLabel = new JLabel("Destination Name"); 99 | destNameInput = new JTextField(); 100 | dstNameLabel.setHorizontalAlignment(JLabel.RIGHT); 101 | 102 | JLabel dstTypeLabel = new JLabel("Destination Type"); 103 | dstTypeLabel.setHorizontalAlignment(JLabel.RIGHT); 104 | topicRadio = new JRadioButton("Topic"); 105 | topicRadio.addActionListener(new ActionListener() { 106 | public void actionPerformed(ActionEvent e) { 107 | disableInputs(); 108 | } 109 | }); 110 | 111 | 112 | topicRadio.setSelected(true); 113 | queueRadio = new JRadioButton("Queue"); 114 | queueRadio.addActionListener(new ActionListener() { 115 | public void actionPerformed(ActionEvent e) { 116 | disableInputs(); 117 | } 118 | }); 119 | 120 | 121 | durableRadio = new JRadioButton("Durable Subscriber"); 122 | durableRadio.addActionListener(new ActionListener() { 123 | public void actionPerformed(ActionEvent e) { 124 | enableInputs(); 125 | } 126 | }); 127 | 128 | bg = new ButtonGroup(); 129 | bg.add(topicRadio); 130 | bg.add(queueRadio); 131 | bg.add(durableRadio); 132 | 133 | JPanel dumpRadioPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); 134 | gbc.gridx = 0; 135 | gbc.gridy = 0; 136 | dumpRadioPanel.add(topicRadio, gbc); 137 | gbc.gridx = 1; 138 | gbc.gridy = 0; 139 | dumpRadioPanel.add(queueRadio, gbc); 140 | gbc.gridx = 2; 141 | gbc.gridy = 0; 142 | dumpRadioPanel.add(durableRadio, gbc); 143 | 144 | 145 | JLabel messageSelectorLabel = new JLabel("Message Selector"); 146 | messageSelectorInput = new JTextField(); 147 | messageSelectorLabel.setHorizontalAlignment(JLabel.RIGHT); 148 | 149 | JLabel clientIdLabel = new JLabel("Client ID (for durable Subscribers)"); 150 | clientIdInput = new JTextField(); 151 | clientIdLabel.setHorizontalAlignment(JLabel.RIGHT); 152 | //JPasswordField confirmPasswordInput = new JPasswordField(); 153 | 154 | JLabel durableSubsNameLabel = new JLabel("Durable Subscriber Name"); 155 | durableSubsNameInput = new JTextField(); 156 | durableSubsNameLabel.setHorizontalAlignment(JLabel.RIGHT); 157 | 158 | durableSubsNameLabel.setHorizontalAlignment(JLabel.RIGHT); 159 | 160 | JLabel outputDirLabel = new JLabel("Output Directory"); 161 | outputDirLabel.setHorizontalAlignment(JLabel.RIGHT); 162 | outputDirSelectorButton = new JButton("Select"); 163 | outputDirSelectorButton.addActionListener(new ActionListener() { 164 | public void actionPerformed(ActionEvent e) { 165 | JFileChooser fileChooser = new JFileChooser(); 166 | fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 167 | fileChooser.setCurrentDirectory(new File("/")); 168 | boolean validDirectory = false; 169 | //Scanner fileScanner; 170 | 171 | while(validDirectory != true) { 172 | int result = fileChooser.showOpenDialog(null); 173 | if(result == JFileChooser.CANCEL_OPTION) 174 | return; 175 | if(result == JFileChooser.APPROVE_OPTION) { 176 | File file = fileChooser.getSelectedFile(); 177 | String filePath = file.getAbsolutePath(); 178 | File check = new File(filePath); 179 | if(!check.exists()) { 180 | JOptionPane.showMessageDialog(null, "Invalid directory path", "Failure", JOptionPane.ERROR_MESSAGE); 181 | 182 | } else { 183 | outputDirPath.setText(file.getAbsolutePath()); 184 | validDirectory = true; 185 | } 186 | } 187 | } 188 | 189 | } 190 | }); 191 | 192 | outputDirPath = new JTextField(); 193 | String separator = System.getProperty("file.separator"); 194 | outputDirPath.setText(System.getProperty("user.home")+separator+"jmsdigger"); 195 | 196 | outputDirPath.setEditable(false); 197 | //outputDirPath.setEditable(false); 198 | JPanel outputDirSelectorPanel = new JPanel(new GridBagLayout()); 199 | gbc = new GridBagConstraints(); 200 | gbc.gridx = 0; 201 | gbc.gridy = 0; 202 | gbc.fill = GridBagConstraints.HORIZONTAL; 203 | gbc.weightx = 1.0; 204 | 205 | outputDirSelectorPanel.add(outputDirPath, gbc); 206 | gbc = new GridBagConstraints(); 207 | gbc.gridx = 2; 208 | gbc.gridy = 0; 209 | outputDirSelectorPanel.add(outputDirSelectorButton, gbc); 210 | 211 | JLabel msgCountLabel = new JLabel("Messages to Dump (Count)"); 212 | msgCountLabel.setHorizontalAlignment(JLabel.RIGHT); 213 | spinnerModel = new SpinnerNumberModel(10, 0, 9999, 1); 214 | JPanel countStartStopPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); 215 | msgCountSpinner = new JSpinner(spinnerModel); 216 | startButton = new JButton("Start Dump"); 217 | startButton.addActionListener(new TriggerDestinationDump()); 218 | stopButton = new JButton("Stop Dump"); 219 | 220 | stopButton.setEnabled(false); 221 | gbc = new GridBagConstraints(); 222 | gbc.gridx = 0; 223 | gbc.gridy = 0; 224 | gbc.weightx = 0.0; 225 | gbc.fill = GridBagConstraints.NONE; 226 | 227 | countStartStopPanel.add(msgCountSpinner, gbc); 228 | 229 | gbc.weightx = 1.0; 230 | gbc.fill = GridBagConstraints.BOTH; 231 | 232 | gbc.gridx = 0; 233 | gbc.gridy = 1; 234 | countStartStopPanel.add(startButton, gbc); 235 | gbc.gridx = 0; 236 | gbc.gridy = 2; 237 | countStartStopPanel.add(stopButton, gbc); 238 | durableSubsNameLabel.setHorizontalAlignment(JLabel.RIGHT); 239 | 240 | JLabel writtenMsgLabel = new JLabel("Messages Written"); 241 | writtenMsgLabel.setHorizontalAlignment(JLabel.RIGHT); 242 | writtenMsgCountLabel = new JLabel("--"); 243 | writtenMsgCountLabel.setHorizontalAlignment(JLabel.LEFT); 244 | 245 | 246 | masterGbc.gridx = 0; 247 | masterGbc.gridy = 0; 248 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 249 | masterGbc.weightx = 0.0; 250 | dumpDestinationPanel.add(dstNameLabel, masterGbc); 251 | masterGbc.gridx = 1; 252 | masterGbc.gridy = 0; 253 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 254 | masterGbc.weightx = 1.0; 255 | dumpDestinationPanel.add(destNameInput, masterGbc); 256 | 257 | masterGbc.gridx = 0; 258 | masterGbc.gridy = 1; 259 | masterGbc.weightx = 0.0; 260 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 261 | dumpDestinationPanel.add(dstTypeLabel, masterGbc); 262 | masterGbc.gridx = 1; 263 | masterGbc.gridy = 1; 264 | masterGbc.weightx = 1.0; 265 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 266 | dumpDestinationPanel.add(dumpRadioPanel, masterGbc); 267 | 268 | masterGbc.gridx = 0; 269 | masterGbc.gridy = 2; 270 | masterGbc.weightx = 0.0; 271 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 272 | dumpDestinationPanel.add(messageSelectorLabel, masterGbc); 273 | masterGbc.gridx = 1; 274 | masterGbc.gridy = 2; 275 | masterGbc.weightx = 1.0; 276 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 277 | dumpDestinationPanel.add(messageSelectorInput, masterGbc); 278 | 279 | masterGbc.gridx = 0; 280 | masterGbc.gridy = 3; 281 | masterGbc.weightx = 0.0; 282 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 283 | dumpDestinationPanel.add(clientIdLabel, masterGbc); 284 | masterGbc.gridx = 1; 285 | masterGbc.gridy = 3; 286 | masterGbc.weightx = 1.0; 287 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 288 | dumpDestinationPanel.add(clientIdInput, masterGbc); 289 | 290 | masterGbc.gridx = 0; 291 | masterGbc.gridy = 4; 292 | masterGbc.weightx = 0.0; 293 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 294 | dumpDestinationPanel.add(durableSubsNameLabel, masterGbc); 295 | masterGbc.gridx = 1; 296 | masterGbc.gridy = 4; 297 | masterGbc.weightx = 0.0; 298 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 299 | dumpDestinationPanel.add(durableSubsNameInput, masterGbc); 300 | 301 | masterGbc.gridx = 0; 302 | masterGbc.gridy = 5; 303 | masterGbc.weightx = 0.0; 304 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 305 | dumpDestinationPanel.add(outputDirLabel, masterGbc); 306 | masterGbc.gridx = 1; 307 | masterGbc.gridy = 5; 308 | masterGbc.weightx = 1.0; 309 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 310 | dumpDestinationPanel.add(outputDirSelectorPanel, masterGbc); 311 | 312 | masterGbc.gridx = 0; 313 | masterGbc.gridy = 6; 314 | masterGbc.weightx = 0.0; 315 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 316 | dumpDestinationPanel.add(msgCountLabel, masterGbc); 317 | masterGbc.gridx = 1; 318 | masterGbc.gridy = 6; 319 | masterGbc.weightx = 1.0; 320 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 321 | dumpDestinationPanel.add(countStartStopPanel, masterGbc); 322 | 323 | masterGbc.gridx = 0; 324 | masterGbc.gridy = 7; 325 | masterGbc.weightx = 0.0; 326 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 327 | dumpDestinationPanel.add(writtenMsgLabel, masterGbc); 328 | masterGbc.gridx = 1; 329 | masterGbc.gridy = 7; 330 | masterGbc.weightx = 1.0; 331 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 332 | dumpDestinationPanel.add(writtenMsgCountLabel, masterGbc); 333 | 334 | masterGbc = new GridBagConstraints(); 335 | masterGbc.gridx = 0; 336 | masterGbc.gridy = 0; 337 | masterGbc.anchor = GridBagConstraints.NORTHWEST; 338 | this.add(dumpDestinationPanel, masterGbc); 339 | 340 | disableInputs(); 341 | this.title = "Dump Destinations"; 342 | 343 | } 344 | 345 | class TriggerDestinationDump implements ActionListener { 346 | 347 | public void actionPerformed(ActionEvent arg0) { 348 | JmsDestination destinationType = JmsDestination.TOPIC; 349 | if(JmsHelper.isStringNullOrEmpty(destNameInput.getText())) { 350 | JOptionPane.showMessageDialog(null, "Destination name is empty", "Error", JOptionPane.ERROR_MESSAGE); 351 | return; 352 | } 353 | 354 | if(durableRadio.isSelected()) { 355 | if(JmsHelper.isStringNullOrEmpty(clientIdInput.getText()) || JmsHelper.isStringNullOrEmpty(durableSubsNameInput.getText())) { 356 | JOptionPane.showMessageDialog(null, "Client ID or Durable subscriber name not present", "Error", JOptionPane.ERROR_MESSAGE); 357 | return; 358 | } 359 | destinationType = JmsDestination.DURABLESUBSCRIBER; 360 | } else { 361 | if(topicRadio.isSelected()) { 362 | destinationType = JmsDestination.TOPIC; 363 | } else { 364 | destinationType = JmsDestination.QUEUE; 365 | } 366 | } 367 | 368 | try { 369 | //System.out.println("here"); 370 | destinationDumpWorker = new DestinationDumpWorker(destinationType); 371 | for(ActionListener a : stopButton.getActionListeners()) { 372 | stopButton.removeActionListener(a); 373 | } 374 | stopButton.addActionListener(new ActionListener() { 375 | public void actionPerformed(ActionEvent arg0) { 376 | destinationDumpWorker.cancel(true); 377 | } 378 | }); 379 | destinationDumpWorker.execute(); 380 | writtenMsgCountLabel.setText("0"); 381 | disableButtons(); 382 | } catch (JmsDiggerException ex) { 383 | String errStr = "An execption occured while triggering destination dump"; 384 | LOG.info(errStr, ex); 385 | JmsGuiCommon.showErrorAndLogMessage(ex.getMessage()); 386 | } catch (NamingException ex) { 387 | String errStr = "An NamingException occured while triggering a destination dump"; 388 | LOG.info(errStr, ex); 389 | JmsGuiCommon.showErrorAndLogMessage(ex.getMessage()); 390 | } catch (JMSException ex) { 391 | LOG.info("", ex); 392 | JmsGuiCommon.showErrorAndLogMessage(ex.getMessage()); 393 | } 394 | 395 | } 396 | 397 | private void disableButtons() { 398 | startButton.setEnabled(false); 399 | outputDirSelectorButton.setEnabled(false); 400 | stopButton.setEnabled(true); 401 | } 402 | } 403 | 404 | class DestinationDumpWorker extends SwingWorker { 405 | private String destinationName; 406 | private JmsDestination destinationType; 407 | private String msgSelector; 408 | private String clientId; 409 | private String durableSubscriberName; 410 | private String outputDirectory; 411 | private int count; 412 | private JmsDumpDestination destinationDumper; 413 | private JmsConfig jmsConfig; 414 | private InitialContext initialContext; 415 | //private Connection connection; 416 | //private ConnectionFactory connFact; 417 | private MessageCountUpdater messageCountUpdateObject; 418 | private JmsLoginInfo loginInfo; 419 | 420 | 421 | public DestinationDumpWorker(JmsDestination destinationType) throws NamingException, JMSException { 422 | jmsConfig = jmsConfigTab.getJmsConfig(); 423 | String connectionFactoryName = jmsConfig.getConnFactName(); 424 | this.destinationName = destNameInput.getText(); 425 | this.destinationType = destinationType; 426 | this.msgSelector = messageSelectorInput.getText(); 427 | this.clientId = clientIdInput.getText(); 428 | this.durableSubscriberName = durableSubsNameInput.getText(); 429 | this.outputDirectory = outputDirPath.getText(); 430 | this.count = (Integer) msgCountSpinner.getValue(); 431 | 432 | if(this.destinationType == JmsDestination.QUEUE) 433 | jmsConfig.addQueue(this.destinationName); 434 | else 435 | jmsConfig.addTopic(this.destinationName); 436 | this.initialContext = jmsConfig.buildInitialContext(); 437 | this.loginInfo = jmsConfig.getLoginInfo(); 438 | //this.connFact = (ConnectionFactory) initialContext.lookup(connectionFactoryName); 439 | //connection = (Connection) connFact.createConnection(); 440 | messageCountUpdateObject = new MessageCountUpdater(writtenMsgCountLabel); 441 | destinationDumper = new JmsDumpDestination(this.initialContext, this.destinationName, connectionFactoryName, this.msgSelector, this.loginInfo); 442 | destinationDumper.setTargetDirectory(this.outputDirectory); 443 | destinationDumper.setClientId(this.clientId); 444 | destinationDumper.setDurableSubscriberName(this.durableSubscriberName); 445 | destinationDumper.setMsgCountToDump(count); 446 | destinationDumper.setMessageCountUpdater(messageCountUpdateObject); 447 | } 448 | 449 | private void enableButtons() { 450 | startButton.setEnabled(true); 451 | outputDirSelectorButton.setEnabled(true); 452 | stopButton.setEnabled(false); 453 | } 454 | 455 | @Override 456 | protected String doInBackground() throws Exception { 457 | // System.out.println("Doing in background"); 458 | //Thread.sleep(5*1000); 459 | destinationDumper.init(); 460 | destinationDumper.dump(); 461 | return null; 462 | } 463 | 464 | @Override 465 | public void done() { 466 | Thread t = new Thread( 467 | new Runnable() { 468 | public void run() { 469 | while(true) { 470 | if(!isCancelled()) { 471 | if(!destinationDumper.isDumpComplete()) { 472 | try { 473 | //System.out.println(destinationDumper.isDumpComplete() + "\tSleeping now ======================\t" + isCancelled()); 474 | Thread.sleep(1 * 1000); 475 | } catch (InterruptedException e) { 476 | LOG.info("The thread was interrupted", e); 477 | JmsGuiCommon.showErrorAndLogMessage(e.getMessage()); 478 | } 479 | continue; 480 | } 481 | } 482 | try { 483 | enableButtons(); 484 | destinationDumper.close(); 485 | break; 486 | } catch (JMSException ex) { 487 | LOG.info("Destination Dumper could not be closed", ex); 488 | JmsGuiCommon.showErrorAndLogMessage(ex.getMessage()); 489 | } catch (IOException ex) { 490 | LOG.info("An IOException has occured", ex); 491 | JmsGuiCommon.showErrorAndLogMessage(ex.getMessage()); 492 | } 493 | } 494 | } 495 | }); 496 | t.start(); 497 | } 498 | } 499 | } 500 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/JmsDurableSubscriberTab.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | import java.awt.FlowLayout; 4 | import java.awt.GridBagConstraints; 5 | import java.awt.GridBagLayout; 6 | import java.awt.Insets; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | import java.lang.reflect.Array; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.concurrent.ExecutionException; 13 | 14 | import javax.naming.InitialContext; 15 | import javax.swing.BorderFactory; 16 | import javax.swing.JButton; 17 | import javax.swing.JLabel; 18 | import javax.swing.JOptionPane; 19 | import javax.swing.JPanel; 20 | import javax.swing.JProgressBar; 21 | import javax.swing.JScrollPane; 22 | import javax.swing.JSpinner; 23 | import javax.swing.JTextArea; 24 | import javax.swing.JTextField; 25 | import javax.swing.SpinnerNumberModel; 26 | import javax.swing.SwingWorker; 27 | import javax.swing.border.Border; 28 | import javax.swing.border.EtchedBorder; 29 | 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | import com.mcafee.JmsDiggerException; 34 | import com.mcafee.JmsDurableSubscriberManipulator; 35 | import com.mcafee.JmsHelper; 36 | 37 | /** 38 | * 39 | * @author Gursev Singh Kalra @ McAfee, Inc. 40 | * 41 | */ 42 | public class JmsDurableSubscriberTab extends JPanel { 43 | 44 | /** 45 | * 46 | */ 47 | private static final long serialVersionUID = 1L; 48 | private String title; 49 | private int space = 5; 50 | private JmsConfigTab jmsConfigTab; 51 | private JTextField topicNameInput; 52 | private JTextField messageSelectorInput; 53 | private JSpinner durableSubsCountSpinner; 54 | private SpinnerNumberModel spinnerModel; 55 | private JButton createMultipleDurableSubsButton; 56 | private JProgressBar progressBar; 57 | private JTextField clientIdInput; 58 | private JTextField subsNameInput; 59 | private JButton createSingleSubsButton; 60 | private JButton eraseDurableSubsButton; 61 | private JTextArea outputArea; 62 | private JmsConfig jmsConfig; 63 | private InitialContext initialContext; 64 | private JmsDurableSubscriberManipulator manipulator ; 65 | private static final Logger LOG = LoggerFactory.getLogger(JmsDurableSubscriberTab.class); 66 | 67 | 68 | public String getTitle() { 69 | return title; 70 | } 71 | 72 | public JmsDurableSubscriberTab(JmsConfigTab jmsConfigTab) throws JmsDiggerException { 73 | this.jmsConfigTab = jmsConfigTab; 74 | //jmsConfig = this.jmsConfigTab.getJmsConfig(); 75 | /** 76 | * The following line is commented out to enable late Initial Context generation. 77 | * There are additional two lines of code added see comments beginning __LAZY__ below. 78 | * This mostly appears to be a workaround, but i will have to create a more robust library. 79 | */ 80 | //initialContext = jmsConfig.buildInitialContext(); 81 | JPanel masterPanel = new JPanel(new GridBagLayout()); 82 | title = "Durable Subscribers"; 83 | TriggerDurableSubscriberCreation trigger = new TriggerDurableSubscriberCreation(); 84 | 85 | JPanel nameFilterPanel = new JPanel(new GridBagLayout()); 86 | GridBagConstraints masterGbc = new GridBagConstraints(); 87 | GridBagConstraints gbc = new GridBagConstraints(); 88 | Border border = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); 89 | Insets inset = new Insets(space, space, space, space); 90 | Insets masterInset = new Insets(space * 2, space * 2, space * 2, space * 2); 91 | masterGbc.insets = masterInset; 92 | 93 | gbc.insets = inset; 94 | gbc.fill = GridBagConstraints.HORIZONTAL; 95 | 96 | JLabel topicNameLabel = new JLabel("Topic Name"); 97 | gbc.gridx = 0; 98 | gbc.gridy = 0; 99 | topicNameLabel.setHorizontalAlignment(JLabel.RIGHT); 100 | nameFilterPanel.add(topicNameLabel, gbc); 101 | topicNameInput = new JTextField(30); 102 | gbc.gridx = 1; 103 | gbc.gridy = 0; 104 | nameFilterPanel.add(topicNameInput, gbc); 105 | 106 | JLabel filterLabel = new JLabel("Message Selector"); 107 | gbc.gridx = 0; 108 | gbc.gridy = 1; 109 | filterLabel.setHorizontalAlignment(JLabel.RIGHT); 110 | nameFilterPanel.add(filterLabel, gbc); 111 | messageSelectorInput = new JTextField(30); 112 | gbc.gridx = 1; 113 | gbc.gridy = 1; 114 | nameFilterPanel.add(messageSelectorInput, gbc); 115 | 116 | masterGbc.gridx = 0; 117 | masterGbc.gridy = 0; 118 | masterGbc.anchor = GridBagConstraints.LINE_START; 119 | masterPanel.add(nameFilterPanel, masterGbc); 120 | 121 | 122 | 123 | JPanel randomCountPanel = new JPanel(new GridBagLayout()); 124 | Border singleUserBorder = BorderFactory.createTitledBorder(border, "Create Multiple Durable Subscribers"); 125 | 126 | spinnerModel = new SpinnerNumberModel(10, 1, 9999, 1); 127 | durableSubsCountSpinner = new JSpinner(spinnerModel); 128 | gbc = new GridBagConstraints(); 129 | gbc.insets = inset; 130 | gbc.gridx = 0; 131 | gbc.gridy = 0; 132 | randomCountPanel.add(durableSubsCountSpinner, gbc); 133 | createMultipleDurableSubsButton = new JButton("Create"); 134 | createMultipleDurableSubsButton.addActionListener(trigger); 135 | gbc.gridx = 1; 136 | gbc.gridy = 0; 137 | randomCountPanel.add(createMultipleDurableSubsButton, gbc); 138 | 139 | 140 | // JLabel progressLabel = new JLabel("Progress > "); 141 | // gbc.fill = GridBagConstraints.HORIZONTAL; 142 | // gbc.gridx = 0; 143 | // gbc.gridy = 1; 144 | // randomCountPanel.add(progressLabel, gbc); 145 | 146 | // progressBar = new JProgressBar(); 147 | // progressBar.setBounds(0, 0, 30, 100); 148 | // 149 | // gbc.gridx = 1; 150 | // gbc.gridy = 1; 151 | // gbc.gridwidth = 2; 152 | // randomCountPanel.add(progressBar, gbc); 153 | randomCountPanel.setBorder(singleUserBorder); 154 | 155 | masterGbc = new GridBagConstraints(); 156 | masterGbc.gridx = 0; 157 | masterGbc.gridy = 2; 158 | masterGbc.insets = inset; 159 | masterGbc.anchor = GridBagConstraints.LINE_START; 160 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 161 | masterPanel.add(randomCountPanel, masterGbc); 162 | 163 | 164 | 165 | 166 | 167 | JPanel singleSubsPanel = new JPanel(new GridBagLayout()); 168 | Border singleSubsBorder = BorderFactory.createTitledBorder(border, "Create/Erase A Durable Subscriber"); 169 | gbc = new GridBagConstraints(); 170 | 171 | JLabel clientIdLabel = new JLabel("Client ID"); 172 | clientIdLabel.setHorizontalAlignment(JLabel.RIGHT); 173 | gbc.fill = GridBagConstraints.HORIZONTAL; 174 | gbc.insets = inset; 175 | gbc.gridx = 0; 176 | gbc.gridy = 0; 177 | singleSubsPanel.add(clientIdLabel, gbc); 178 | 179 | clientIdInput = new JTextField(30); 180 | gbc.gridx = 1; 181 | gbc.gridy = 0; 182 | singleSubsPanel.add(clientIdInput, gbc); 183 | 184 | JLabel subsNameLabel = new JLabel("Durable Subscriber Name"); 185 | subsNameLabel.setHorizontalAlignment(JLabel.RIGHT); 186 | gbc.insets = inset; 187 | gbc.gridx = 0; 188 | gbc.gridy = 1; 189 | singleSubsPanel.add(subsNameLabel, gbc); 190 | 191 | subsNameInput = new JTextField(30); 192 | gbc.gridx = 1; 193 | gbc.gridy = 1; 194 | singleSubsPanel.add(subsNameInput, gbc); 195 | 196 | JPanel createButtonPanel = new JPanel(new GridBagLayout()); 197 | createSingleSubsButton = new JButton("Create"); 198 | createSingleSubsButton.addActionListener(trigger); 199 | gbc.gridx = 0; 200 | gbc.gridy = 0; 201 | createButtonPanel.add(createSingleSubsButton, gbc); 202 | 203 | eraseDurableSubsButton = new JButton("Erase"); 204 | eraseDurableSubsButton.addActionListener(trigger); 205 | gbc.gridx = 1; 206 | gbc.gridy = 0; 207 | createButtonPanel.add(eraseDurableSubsButton, gbc); 208 | 209 | gbc.gridx = 0; 210 | gbc.gridy = 2; 211 | gbc.gridwidth = 2; 212 | singleSubsPanel.add(createButtonPanel, gbc); 213 | singleSubsPanel.setBorder(singleSubsBorder); 214 | 215 | JPanel outputBoxPanel = new JPanel(new GridBagLayout()); 216 | outputArea = new JTextArea(15, 50); 217 | outputArea.setEditable(false); 218 | 219 | gbc.fill = GridBagConstraints.BOTH; 220 | gbc.gridx = 0; 221 | gbc.gridy = 0; 222 | outputBoxPanel.add(new JScrollPane(outputArea), gbc); 223 | Border outputBorder = BorderFactory.createTitledBorder(border, "Results"); 224 | outputBoxPanel.setBorder(outputBorder); 225 | masterGbc.gridx = 0; 226 | masterGbc.gridy = 3; 227 | masterPanel.add(outputBoxPanel, masterGbc); 228 | 229 | /* 230 | * Pane to display progress 231 | */ 232 | JPanel progressPanel = new JPanel(new GridBagLayout()); 233 | JLabel progressLabel = new JLabel("Progress > "); 234 | gbc.gridx = 0; 235 | gbc.gridy = 0; 236 | gbc.fill = GridBagConstraints.NONE; 237 | progressPanel.add(progressLabel, gbc); 238 | 239 | 240 | progressBar = new JProgressBar(); 241 | gbc.fill = GridBagConstraints.HORIZONTAL; 242 | gbc.gridx = 2; 243 | gbc.gridy = 0; 244 | gbc.weightx = 1.0; 245 | progressPanel.add(progressBar, gbc); 246 | 247 | masterGbc.gridx = 0; 248 | masterGbc.gridy = 4; 249 | masterGbc.fill = GridBagConstraints.HORIZONTAL; 250 | masterGbc.insets = inset; 251 | masterPanel.add(progressPanel, masterGbc); 252 | 253 | 254 | masterGbc.gridx = 0; 255 | masterGbc.gridy = 1; 256 | masterGbc.anchor = GridBagConstraints.LINE_START; 257 | masterGbc.insets = inset; 258 | masterPanel.add(singleSubsPanel, masterGbc); 259 | 260 | this.add(masterPanel, masterGbc); 261 | 262 | } 263 | 264 | class TriggerDurableSubscriberErase implements ActionListener { 265 | 266 | public void actionPerformed(ActionEvent arg0) { 267 | } 268 | 269 | } 270 | 271 | class TriggerDurableSubscriberCreation implements ActionListener { 272 | 273 | public void disableAllButtons() { 274 | createMultipleDurableSubsButton.setEnabled(false); 275 | createSingleSubsButton.setEnabled(false); 276 | eraseDurableSubsButton.setEnabled(false); 277 | } 278 | 279 | public void actionPerformed(ActionEvent event) { 280 | DurableSubscriberWorker durableSubscriberWorker; 281 | if(JmsHelper.isStringNullOrEmpty(topicNameInput.getText())) { 282 | JOptionPane.showMessageDialog(null, "Topic name cannot be empty or null", "Error", JOptionPane.ERROR_MESSAGE); 283 | return; 284 | } 285 | 286 | if(event.getSource() == eraseDurableSubsButton) { 287 | if(JmsHelper.isStringNullOrEmpty(subsNameInput.getText()) || JmsHelper.isStringNullOrEmpty(clientIdInput.getText())) { 288 | JOptionPane.showMessageDialog(null, "Erase function requires a Client ID and Durable Subscriber Name", "Error", JOptionPane.ERROR_MESSAGE); 289 | return; 290 | } 291 | } 292 | 293 | String topicName = topicNameInput.getText(); 294 | String messageSelector = messageSelectorInput.getText(); 295 | int count = 1; 296 | String clientId = clientIdInput.getText(); 297 | String subsName = subsNameInput.getText(); 298 | 299 | ArrayList durableSubscriberNames = new ArrayList(); 300 | if(JmsHelper.isStringNullOrEmpty(clientId)) { 301 | clientId = JmsHelper.getRandomString(); 302 | } 303 | 304 | if(event.getSource() == createSingleSubsButton) { 305 | if(JmsHelper.isStringNullOrEmpty(subsName)) { 306 | durableSubscriberNames.add(JmsHelper.getRandomString()); 307 | } 308 | else { 309 | durableSubscriberNames.add(subsName); 310 | } 311 | 312 | } else { 313 | if(event.getSource() == createMultipleDurableSubsButton) { 314 | count = (Integer) spinnerModel.getValue(); 315 | for(int i = 0; i < count; i++) { 316 | durableSubscriberNames.add(JmsHelper.getRandomString()); 317 | } 318 | } else if(event.getSource() == eraseDurableSubsButton) { 319 | durableSubscriberNames.add(subsName); 320 | } 321 | } 322 | 323 | disableAllButtons(); 324 | //durableSubscriberWorker = new DurableSubscriberWorker(topicName, messageSelector, clientIdList, durableSubscriberNames, (Integer) spinnerModel.getValue()); 325 | try { 326 | durableSubscriberWorker = new DurableSubscriberWorker(topicName, messageSelector, clientId, durableSubscriberNames, count); 327 | if(event.getSource() == eraseDurableSubsButton) { 328 | durableSubscriberWorker.setErase(true); 329 | } 330 | durableSubscriberWorker.execute(); 331 | } catch (JmsDiggerException e) { 332 | LOG.info("An error has occured while creating/executing a durableSubscriberWorker", e); 333 | JmsGuiCommon.showErrorAndLogMessage(e.getMessage()); 334 | } 335 | } 336 | 337 | } 338 | 339 | class DurableSubscriberWorker extends SwingWorker { 340 | 341 | String messageSelector; 342 | String topicName; 343 | ArrayList clientIdList; 344 | ArrayList durableSubscriberNames; 345 | String clientId; 346 | int count; 347 | boolean erase; 348 | 349 | public void setErase(boolean erase) { 350 | this.erase = erase; 351 | } 352 | 353 | //public DurableSubscriberWorker(String topicName, String messageSelector, ArrayList clientIdList, ArrayList durableSubscriberNames, int count) { 354 | public DurableSubscriberWorker(String topicName, String messageSelector, String clientId, ArrayList durableSubscriberNames, int count) throws JmsDiggerException { 355 | this.topicName = topicName; 356 | this.messageSelector = messageSelector; 357 | //this.clientIdList = clientIdList; 358 | this.clientId = clientId; 359 | this.durableSubscriberNames = durableSubscriberNames; 360 | this.count = count; 361 | this.erase = false; 362 | 363 | /** 364 | * __LAZY__ the addTopic call adds the topic to the initial context's environment 365 | * variables before building the initial context. Once initial context is built, it cannot be changed.
366 | * Initializing the jmsConfig here to ensure that a new configuration is generated for each button click 367 | * to accommodate for topic changes for a single run. 368 | */ 369 | jmsConfig = jmsConfigTab.getJmsConfig(); 370 | jmsConfig.addTopic(topicName); 371 | initialContext = jmsConfig.buildInitialContext(); 372 | } 373 | 374 | public boolean isErase() { 375 | return erase; 376 | } 377 | 378 | @Override 379 | protected ProgressInfo doInBackground() throws Exception { 380 | 381 | try { 382 | manipulator = new JmsDurableSubscriberManipulator(initialContext, topicName, jmsConfig.getConnFactName(), jmsConfig.getLoginInfo()); 383 | manipulator.init(clientId); 384 | } catch (JmsDiggerException ex) { 385 | LOG.info("DurableSubscriberManipulator initialization failed", ex); 386 | ProgressInfo i = new ProgressInfo(JmsHelper.exceptionStacktraceToString(ex), false, 0); 387 | return i; 388 | } 389 | 390 | //publish(new ProgressInfo("\n==================================================\n[+] Creating durable subscribers with clientID \"" + clientId+"\"" , true, 0)); 391 | try { 392 | for(int i = 0; i < durableSubscriberNames.size() ; i++) { 393 | try { 394 | if(!isErase()) { 395 | manipulator.createDurableSubscriber(durableSubscriberNames.get(i), messageSelector); 396 | publish(new ProgressInfo("\n[+] Created durable subscriber \"" + durableSubscriberNames.get(i) +"\"" ,true, i*100/count)); 397 | } else { 398 | manipulator.eraseDurableSubscriber(durableSubscriberNames.get(0)); 399 | publish(new ProgressInfo("\n[+] Erased durable subscriber \"" + durableSubscriberNames.get(i) +"\"" ,true, 100)); 400 | } 401 | } catch(JmsDiggerException ex) { 402 | if(!isErase()) 403 | publish(new ProgressInfo("\n[-] Could not create durable subscriber \"" + durableSubscriberNames.get(i) +"\"" ,true, i*100/count)); 404 | else 405 | publish(new ProgressInfo("\n[-] Could not erase durable subscriber \"" + durableSubscriberNames.get(i) +"\"" ,true, 100)); 406 | } 407 | } 408 | } finally { 409 | /** 410 | * Very important to close the connections as ActiveMQ allows only one active connection from one clientID. 411 | * If the connection is not closed, ActiveMQ throws an exception of the following type 412 | * Caused by: javax.jms.InvalidClientIDException: Broker: localhost - Client: already connected from tcp://ipadderss:port 413 | */ 414 | manipulator.close(); 415 | } 416 | 417 | 418 | return new ProgressInfo("Completed", true, 100); 419 | } 420 | 421 | @Override 422 | public void process(List progressInfo) { 423 | for(ProgressInfo pInfo : progressInfo) { 424 | outputArea.append(pInfo.getDescription()); 425 | } 426 | ProgressInfo pInfo = progressInfo.get(progressInfo.size()-1); 427 | progressBar.setValue(pInfo.getPercentage()); 428 | } 429 | 430 | 431 | @Override 432 | public void done() { 433 | try { 434 | ProgressInfo pInfo = get(); 435 | if(pInfo.isSuccessful() == false && pInfo.getPercentage() == 0) { 436 | outputArea.setText(pInfo.getDescription()); 437 | JOptionPane.showMessageDialog(null, "An error has occured while creating durable subscribers", "Error", JOptionPane.ERROR_MESSAGE); 438 | } else { 439 | progressBar.setValue(pInfo.getPercentage()); 440 | } 441 | } catch (InterruptedException ex) { 442 | LOG.info("", ex); 443 | JmsGuiCommon.showErrorAndLogMessage(ex.getMessage()); 444 | } catch (ExecutionException ex) { 445 | LOG.info("", ex); 446 | JmsGuiCommon.showErrorAndLogMessage(ex.getMessage()); 447 | } 448 | JOptionPane.showMessageDialog(null, "Done!", "", JOptionPane.INFORMATION_MESSAGE); 449 | enableAllButtons(); 450 | 451 | } 452 | 453 | public void enableAllButtons() { 454 | createMultipleDurableSubsButton.setEnabled(true); 455 | createSingleSubsButton.setEnabled(true); 456 | eraseDurableSubsButton.setEnabled(true); 457 | } 458 | } 459 | } 460 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/JmsGuiCommon.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | import java.awt.EventQueue; 4 | import java.awt.GridBagConstraints; 5 | 6 | import javax.swing.JOptionPane; 7 | 8 | /** 9 | * 10 | * @author Gursev Singh Kalra @ McAfee, Inc. 11 | * 12 | */ 13 | public class JmsGuiCommon { 14 | public static void resetGridBagConstraints(GridBagConstraints gbc) { 15 | // Defaults from http://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html 16 | gbc.gridx = GridBagConstraints.RELATIVE; 17 | gbc.gridy = GridBagConstraints.RELATIVE; 18 | gbc.gridwidth = 1; 19 | gbc.gridheight = 1; 20 | gbc.fill = GridBagConstraints.NONE; 21 | gbc.ipadx = 0; 22 | gbc.ipady = 0; 23 | gbc.anchor = GridBagConstraints.CENTER; 24 | gbc.weightx = 0; 25 | gbc.weighty = 0; 26 | gbc.insets.left = 0; 27 | gbc.insets.right = 0; 28 | gbc.insets.bottom = 0; 29 | gbc.insets.top = 0; 30 | } 31 | 32 | public static void showErrorAndLogMessage() { 33 | EventQueue.invokeLater(new Runnable() { 34 | public void run() { 35 | JOptionPane.showMessageDialog(null, "An error has occured, please check logs for more details.", "Error", JOptionPane.ERROR_MESSAGE); 36 | } 37 | }); 38 | } 39 | 40 | public static void showErrorAndLogMessage(final String str) { 41 | EventQueue.invokeLater(new Runnable() { 42 | public void run() { 43 | JOptionPane.showMessageDialog(null, str+"\nPlease see log files for more details", "Error", JOptionPane.ERROR_MESSAGE); 44 | } 45 | }); 46 | } 47 | 48 | public static void showDoneMessage() { 49 | EventQueue.invokeLater(new Runnable() { 50 | public void run() { 51 | JOptionPane.showMessageDialog(null, "Done!", "", JOptionPane.INFORMATION_MESSAGE); 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/mcafee/gui/ProgressInfo.java: -------------------------------------------------------------------------------- 1 | package com.mcafee.gui; 2 | 3 | /** 4 | * 5 | * @author Gursev Singh Kalra @ McAfee, Inc. 6 | * 7 | */ 8 | public class ProgressInfo { 9 | private String description; 10 | private boolean successful; 11 | private int percentage; 12 | 13 | public ProgressInfo() { 14 | 15 | } 16 | 17 | public ProgressInfo(String description, boolean successful, int percentage) { 18 | this.description = description; 19 | this.successful = successful; 20 | this.percentage = percentage ; 21 | } 22 | 23 | public void setDescription(String description) { 24 | this.description = description; 25 | } 26 | 27 | public void setSuccessful(boolean successful) { 28 | this.successful = successful; 29 | } 30 | 31 | public void setPercentage(int percentage) { 32 | this.percentage = percentage; 33 | } 34 | 35 | public String getDescription() { 36 | if(description == null) 37 | return ""; 38 | return description; 39 | } 40 | 41 | public boolean isSuccessful() { 42 | return successful; 43 | } 44 | 45 | public int getPercentage() { 46 | return percentage; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/resources/fs_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenSecurityResearch/jmsdigger/5e2793c2da728b00999662ae0ce6cf562ff5b436/src/main/resources/fs_icon_32.png -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | # Root logger option 2 | log4j.rootLogger=INFO, file, stdout 3 | #log4j.rootLogger=file, stdout 4 | 5 | # Direct log messages to a log file 6 | log4j.appender.file=org.apache.log4j.RollingFileAppender 7 | log4j.appender.file.File=${user.home}/jmsdigger/jmsdigger.log 8 | log4j.appender.file.MaxFileSize=1MB 9 | log4j.appender.file.MaxBackupIndex=10 10 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 11 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 12 | 13 | # Direct log messages to stdout 14 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 15 | log4j.appender.stdout.Target=System.err 16 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 17 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n -------------------------------------------------------------------------------- /src/test/java/com/mcafee/AMQOpsTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.ArrayList; 6 | 7 | import javax.jms.JMSException; 8 | import javax.jms.MapMessage; 9 | import javax.jms.Queue; 10 | import javax.jms.Topic; 11 | 12 | import org.junit.After; 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | 16 | /** 17 | * 18 | * @author Gursev Singh Kalra @ McAfee, Inc. 19 | * 20 | */ 21 | public class AMQOpsTest { 22 | 23 | private AMQOps opsTest; 24 | @Before 25 | public void setUp() throws Exception { 26 | opsTest = new AMQOps(JmsHelper.getActiveMQInitialContext(), "ConnectionFactory"); 27 | opsTest.init(); 28 | } 29 | 30 | @After 31 | public void tearDown() throws Exception { 32 | 33 | } 34 | 35 | @Test 36 | public void brokerStatusAndSubscriptionStatusTest() throws JmsDiggerException { 37 | ArrayList status = null; 38 | int expected = 1; 39 | status = opsTest.getBrokerStats(); 40 | System.out.println(JmsHelper.mapMessageToString(status.get(0), "================")); 41 | 42 | assertNotNull(status); 43 | assertEquals(expected, status.size()); 44 | 45 | status = null; 46 | status = opsTest.getSubscriptionsStats(); 47 | assertNotNull(status); 48 | assertEquals(expected, status.size()); 49 | 50 | } 51 | 52 | @Test 53 | public void amqstatsAndamqstatstTest() throws JmsDiggerException { 54 | String dName = null; 55 | ArrayListstatus = null; 56 | int expected = 1; 57 | 58 | dName = "jms.amqQueueStats"; 59 | status = opsTest.getQueueStats(dName, true); 60 | assertNotNull(status); 61 | assertEquals(expected, status.size()); 62 | 63 | status = null; 64 | 65 | dName = "jms.amqTopicStats"; 66 | status = opsTest.getTopicStats(dName, true); 67 | 68 | assertNotNull(status); 69 | assertEquals(expected, status.size()); 70 | 71 | status = null; 72 | expected = 0 ; 73 | 74 | dName = "aa"; 75 | status = opsTest.getTopicStats(dName, true); 76 | assertNotNull(status); 77 | assertEquals(0, status.size()); 78 | } 79 | 80 | @Test 81 | public void amqWildCardStatsTest() throws JmsDiggerException { 82 | String dName = null; 83 | ArrayList status = null; 84 | dName = "jms.*"; 85 | status = opsTest.getQueueStats(dName, true); 86 | 87 | assertNotNull(status); 88 | assertTrue(status.size() > 1); 89 | 90 | dName = "jms.*"; 91 | status = opsTest.getTopicStats(dName, true); 92 | assertNotNull(status); 93 | assertTrue(status.size() > 1); 94 | } 95 | 96 | @Test 97 | public void createQueueAndDestinationTest() throws JmsDiggerException { 98 | ArrayList aList; 99 | String dstName = "lsadf2342"; 100 | 101 | Queue q = opsTest.createQueue(dstName); 102 | int expected = 1; 103 | 104 | aList = opsTest.getQueueStats(dstName, true); 105 | assertNotNull(aList); 106 | assertEquals(expected, aList.size()); 107 | 108 | Topic t = opsTest.createTopic(dstName); 109 | aList = opsTest.getTopicStats(dstName, true); 110 | assertNotNull(aList); 111 | assertEquals(expected, aList.size()); 112 | 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/FuzzAMQOps.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import static org.junit.Assert.*; 6 | 7 | import java.util.ArrayList; 8 | 9 | import javax.jms.JMSException; 10 | import javax.jms.MapMessage; 11 | import javax.jms.Queue; 12 | import javax.jms.Topic; 13 | import javax.management.MalformedObjectNameException; 14 | import javax.management.ObjectName; 15 | 16 | import org.apache.activemq.broker.BrokerService; 17 | import org.junit.After; 18 | import org.junit.AfterClass; 19 | import org.junit.Before; 20 | import org.junit.BeforeClass; 21 | import org.junit.Test; 22 | 23 | /** 24 | * 25 | * @author Gursev Singh Kalra @ McAfee, Inc. 26 | * 27 | */ 28 | public class FuzzAMQOps { 29 | private static Logger LOG = LoggerFactory.getLogger(FuzzAMQOps.class); 30 | 31 | private AMQOps opsTest; 32 | private static BrokerService broker; 33 | 34 | @BeforeClass 35 | public static void setUpBeforeClass() throws Exception { 36 | broker = new BrokerService(); 37 | broker.setPersistent(false); 38 | broker.start(); 39 | } 40 | 41 | @AfterClass 42 | public static void tearDownAfterClass() throws Exception { 43 | broker.stop(); 44 | } 45 | 46 | @Before 47 | public void setUp() throws Exception { 48 | //opsTest = new AMQOps(JmsHelper.getActiveMQInitialContextForUnitTest(), "ConnectionFactory"); 49 | opsTest = new AMQOps(JmsHelper.getActiveMQInitialContext(), "ConnectionFactory"); 50 | opsTest.init(); 51 | } 52 | 53 | @After 54 | public void tearDown() throws Exception { 55 | 56 | } 57 | 58 | // @Test 59 | // public void brokerStatusAndSubscriptionStatusTest() throws JmsDiggerException { 60 | // ArrayList status = null; 61 | // int expected = 1; 62 | // status = opsTest.getBrokerStats(); 63 | // assertNotNull(status); 64 | // assertEquals(expected, status.size()); 65 | // 66 | // status = null; 67 | // status = opsTest.getSubscriptionsStats(); 68 | // assertNotNull(status); 69 | // assertEquals(expected, status.size()); 70 | // 71 | // } 72 | // 73 | @Test 74 | public void amqstatsAndamqstatstTest() throws JmsDiggerException { 75 | 76 | JmsMessageContentGenerator gen = new JmsMessageContentGenerator(); 77 | gen.setMaxValue((int)256); 78 | String dstName = null; 79 | ArrayListstatus; 80 | Topic q; 81 | char[] c; 82 | 83 | for(int i = 1 ; i < 10; i+=1) { 84 | try { 85 | System.out.println(i); 86 | dstName = gen.getString(100); 87 | LOG.info("Destination Name => " + dstName); 88 | LOG.info(JmsHelper.stringToCharArrayString(dstName)); 89 | status = opsTest.getQueueStats(dstName, false); 90 | if(status != null && status.size() > 0) 91 | for(MapMessage m: status) 92 | System.out.println(JmsHelper.mapMessageToString(m)); 93 | else 94 | System.out.println("Nothing returned for " + dstName); 95 | } catch (JmsDiggerException ex) { 96 | LOG.info("Error occured at i => " + i, ex); 97 | } catch (Throwable ex) { 98 | LOG.info("This caused error => " + dstName); 99 | LOG.info("Error occured at i => " + i, ex); 100 | } 101 | 102 | } 103 | 104 | 105 | // ArrayListstatus = null; 106 | // int expected = 1; 107 | // 108 | // dstName = "jms.amqQueueStats"; 109 | // status = opsTest.getQueueStats(dstName, true); 110 | // assertNotNull(status); 111 | // assertEquals(expected, status.size()); 112 | // 113 | // status = null; 114 | // 115 | // dstName = "jms.amqTopicStats"; 116 | // status = opsTest.getTopicStats(dstName, true); 117 | // 118 | // assertNotNull(status); 119 | // assertEquals(expected, status.size()); 120 | // 121 | // status = null; 122 | // expected = 0 ; 123 | // 124 | // dstName = "aa"; 125 | // status = opsTest.getTopicStats(dstName, true); 126 | // assertNotNull(status); 127 | // assertEquals(0, status.size()); 128 | } 129 | // 130 | // @Test 131 | // public void amqWildCardStatsTest() throws JmsDiggerException { 132 | // String dName = null; 133 | // ArrayList status = null; 134 | // dName = "jms.*"; 135 | // status = opsTest.getQueueStats(dName, true); 136 | // 137 | // assertNotNull(status); 138 | // assertTrue(status.size() > 1); 139 | // 140 | // dName = "jms.*"; 141 | // status = opsTest.getTopicStats(dName, true); 142 | // assertNotNull(status); 143 | // assertTrue(status.size() > 1); 144 | // } 145 | 146 | //@Test 147 | public void createLongQueueNames() throws JmsDiggerException, Exception { 148 | 149 | //tried all 65536 characters. None returned error 150 | JmsMessageContentGenerator gen = new JmsMessageContentGenerator(); 151 | gen.setMaxValue((int)256); 152 | String dstName = ""; 153 | Topic q; 154 | char[] c; 155 | 156 | for(int i = 1 ; i < 5000; i+=1) { 157 | try { 158 | System.out.println(i); 159 | dstName = gen.getString(5); 160 | dstName = "//*/" + dstName; 161 | LOG.info("Destination Name => " + dstName); 162 | LOG.info(JmsHelper.stringToCharArrayString(dstName)); 163 | q = opsTest.createTopic(dstName); 164 | } catch (JmsDiggerException ex) { 165 | LOG.info("Error occured at i => " + i, ex); 166 | } catch (Throwable ex) { 167 | LOG.info("This caused error => " + dstName); 168 | LOG.info("Error occured at i => " + i, ex); 169 | } 170 | 171 | } 172 | } 173 | 174 | //@Test 175 | public void testObjectName() throws MalformedObjectNameException, NullPointerException { 176 | ObjectName onm = new ObjectName("aaaaaaaaaaaaa.ddddd"); 177 | System.out.println(onm.toString()); 178 | } 179 | 180 | //@Test 181 | public void createQueueAndDestinationTest() throws JmsDiggerException { 182 | //tried all 65536 characters. None returned error 183 | ArrayList aList; 184 | String dstName; 185 | Queue q; 186 | 187 | for(int i = 55000 ; i < 65536; i ++) { 188 | try { 189 | System.out.println(i); 190 | dstName = "" + (char)i; 191 | q = opsTest.createQueue(dstName); 192 | } catch (JmsDiggerException ex) { 193 | LOG.info("Error occured at i => " + i, ex); 194 | } 195 | 196 | } 197 | // 198 | // aList = opsTest.getQueueStats(dstName, true); 199 | // assertNotNull(aList); 200 | // assertEquals(expected, aList.size()); 201 | // 202 | // Topic t = opsTest.createTopic(dstName); 203 | // aList = opsTest.getTopicStats(dstName, true); 204 | // assertNotNull(aList); 205 | // assertEquals(expected, aList.size()); 206 | 207 | } 208 | 209 | } 210 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/IdGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.apache.activemq.util.IdGenerator; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | /** 11 | * 12 | * @author Gursev Singh Kalra @ McAfee, Inc. 13 | * 14 | */ 15 | public class IdGeneratorTest { 16 | 17 | @Before 18 | public void setUp() throws Exception { 19 | } 20 | 21 | @After 22 | public void tearDown() throws Exception { 23 | for(int i = 0; i < 100; i++) 24 | System.out.println(new IdGenerator().generateId()); 25 | } 26 | 27 | @Test 28 | public void test() { 29 | 30 | fail("Not yet implemented"); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/JmsAuthenticationTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import javax.naming.InitialContext; 6 | 7 | import org.junit.After; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | /** 12 | * 13 | * @author Gursev Singh Kalra @ McAfee, Inc. 14 | * 15 | */ 16 | public class JmsAuthenticationTest { 17 | private JmsAuthentication jmsAuthn; 18 | private JmsInitialContextFactory contextFactory; 19 | private InitialContext ctx; 20 | private String connFact = "ConnectionFactory"; 21 | private JmsLoginInfo loginInfo; 22 | private boolean state; 23 | private boolean testingAnonymous; 24 | 25 | 26 | @Before 27 | public void setUp() throws JmsDiggerException { 28 | contextFactory = new JmsInitialContextFactory("org.apache.activemq.jndi.ActiveMQInitialContextFactory", "tcp://192.168.10.101:61626"); 29 | contextFactory.addConnectionFactory(connFact); 30 | ctx = contextFactory.getInitialContext(); 31 | jmsAuthn = new JmsAuthentication(ctx, connFact); 32 | // Make sure to change Messaging broker running configuration before changing this variable. 33 | testingAnonymous = true; 34 | } 35 | 36 | @After 37 | public void tearDown() throws Exception { 38 | 39 | } 40 | 41 | /** 42 | * only one of testIsLoginInfoValid 43 | * @throws JmsDiggerException 44 | */ 45 | @Test 46 | public void testValidUsernameInvalidPassword() throws JmsDiggerException { 47 | loginInfo = new JmsLoginInfo("system", "iNvAlIdPassword!"); 48 | state = jmsAuthn.isLoginInfoValid(loginInfo); 49 | if(testingAnonymous) 50 | assertEquals(true, state); 51 | else 52 | assertEquals(false, state); 53 | } 54 | 55 | /** 56 | * only one of testIsLoginInfoValid 57 | * @throws JmsDiggerException 58 | */ 59 | @Test 60 | public void testInvalidUsernameValidPassword() throws JmsDiggerException { 61 | loginInfo = new JmsLoginInfo("iNvAlId", "manager"); 62 | state = jmsAuthn.isLoginInfoValid(loginInfo); 63 | if(testingAnonymous) 64 | assertEquals(true, state); 65 | else 66 | assertEquals(false, state); 67 | } 68 | 69 | /** 70 | * only one of testIsLoginInfoValid 71 | * @throws JmsDiggerException 72 | */ 73 | @Test 74 | public void testSystemUsernameManagerPassword() throws JmsDiggerException { 75 | loginInfo = new JmsLoginInfo("\"", "pas"); 76 | state = jmsAuthn.isLoginInfoValid(loginInfo); 77 | if(!testingAnonymous) 78 | assertTrue(state); 79 | } 80 | 81 | @Test 82 | public void testIsAnonymousAuthAlowed() throws JmsDiggerException { 83 | state = jmsAuthn.isAnonymousAuthAlowed(); 84 | if(testingAnonymous) 85 | assertEquals(true, state); 86 | else 87 | assertEquals(false, state); 88 | } 89 | 90 | @Test 91 | public void testNullUsernameTest() throws JmsDiggerException { 92 | loginInfo = new JmsLoginInfo(null, "manager"); 93 | state = jmsAuthn.isLoginInfoValid(loginInfo); 94 | if(testingAnonymous) 95 | assertTrue(state); 96 | else 97 | assertFalse(state); 98 | } 99 | 100 | @Test 101 | public void testNullPasswordTest() throws JmsDiggerException { 102 | loginInfo = new JmsLoginInfo("system", null); 103 | state = jmsAuthn.isLoginInfoValid(loginInfo); 104 | if(testingAnonymous) 105 | assertTrue(state); 106 | else 107 | assertFalse(state); 108 | 109 | } 110 | 111 | @Test 112 | public void testNullUsernameAndNullPasswordTest() throws JmsDiggerException { 113 | loginInfo = new JmsLoginInfo(null, null); 114 | state = jmsAuthn.isLoginInfoValid(loginInfo); 115 | if(testingAnonymous) 116 | assertTrue(state); 117 | else 118 | assertFalse(state); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/JmsDumpDestinationTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.IOException; 6 | import java.io.Serializable; 7 | import java.util.Random; 8 | 9 | import javax.jms.BytesMessage; 10 | import javax.jms.ConnectionFactory; 11 | import javax.jms.JMSException; 12 | import javax.jms.MapMessage; 13 | import javax.jms.Message; 14 | import javax.jms.Connection; 15 | import javax.jms.MessageProducer; 16 | import javax.jms.ObjectMessage; 17 | import javax.jms.Queue; 18 | import javax.jms.QueueConnection; 19 | import javax.jms.QueueConnectionFactory; 20 | import javax.jms.QueueSession; 21 | import javax.jms.Session; 22 | import javax.jms.StreamMessage; 23 | import javax.jms.TextMessage; 24 | import javax.jms.Topic; 25 | import javax.naming.InitialContext; 26 | import javax.naming.NamingException; 27 | 28 | import org.apache.activemq.ScheduledMessage; 29 | import org.apache.activemq.util.IdGenerator; 30 | import org.junit.After; 31 | import org.junit.Before; 32 | import org.junit.Test; 33 | import org.apache.commons.lang.RandomStringUtils; 34 | 35 | class RandomPerson implements Serializable { 36 | private static Random random = new Random(); 37 | private String name; 38 | private int age; 39 | public RandomPerson() { 40 | name = RandomStringUtils.random(random.nextInt(15)); 41 | age = random.nextInt(20); 42 | } 43 | } 44 | 45 | /** 46 | * 47 | * @author Gursev Singh Kalra @ McAfee, Inc. 48 | * 49 | */ 50 | public class JmsDumpDestinationTest { 51 | private InitialContext ctx; 52 | 53 | private String dumpQueue11Msgs = "dumpQueue11Msgs"; 54 | private String dumpQueue00Msgs = "dumpQueue00Msgs"; 55 | private String dumpTopic00Msgs = "dumpTopic00Msgs"; 56 | private String dumpTopic11Msgs = "dumpTopic11Msgs"; 57 | private String topic4DurableSubscriber = "topic4DurableSubscriber"; 58 | private String durableSubscriberName = "durableSubscriberName"; 59 | private String connFactName = "ConnectionFactory"; 60 | 61 | private ConnectionFactory connFact; 62 | private JmsDumpDestination destDumper; 63 | private JmsDurableSubscriberManipulator durableSubsManipulator; 64 | private String clientId = "gursev"; 65 | 66 | //The "session" and "connection" are used to send messages to the test queues and topics. 67 | // They are never passed on to the JmsDumpDestination object 68 | private Session session; 69 | private Connection connection; 70 | 71 | 72 | private InitialContext getInitialContext() throws JmsDiggerException 73 | { 74 | JmsInitialContextFactory contextFactory = new JmsInitialContextFactory("org.apache.activemq.jndi.ActiveMQInitialContextFactory", "tcp://127.0.0.1:61616"); 75 | contextFactory.addConnectionFactory(connFactName); 76 | contextFactory.addQueue(dumpQueue11Msgs, "jms."+dumpQueue11Msgs); 77 | contextFactory.addQueue(dumpQueue00Msgs, "jms."+dumpQueue00Msgs); 78 | contextFactory.addTopic(dumpTopic00Msgs, "jms."+dumpTopic00Msgs); 79 | contextFactory.addTopic(dumpTopic11Msgs, "jms."+dumpTopic11Msgs); 80 | contextFactory.addTopic(topic4DurableSubscriber, "jms."+topic4DurableSubscriber); 81 | InitialContext ctxx = contextFactory.getInitialContext(); 82 | return ctxx; 83 | } 84 | 85 | 86 | @Before 87 | public void setUp() throws Exception { 88 | ctx = getInitialContext(); 89 | connFact = (ConnectionFactory) ctx.lookup(connFactName); 90 | connection = (Connection) connFact.createConnection(); 91 | } 92 | 93 | @After 94 | public void tearDown() throws Exception { 95 | if(destDumper != null) 96 | destDumper.close(); 97 | } 98 | 99 | // @Test 100 | // public void testDumpQueue00MsgsForNoMessage() throws JMSException, IOException, Exception { 101 | // String qName = dumpQueue00Msgs; 102 | // destDumper = new JmsDumpDestination(ctx, qName, connFactName); 103 | // destDumper.setMsgCountToDump(0); 104 | // destDumper.init(); 105 | // try { 106 | // destDumper.dump(); 107 | // } catch(Exception ex) { 108 | // //gobble it up 109 | // } 110 | // destDumper.close(); 111 | // assertEquals(0, destDumper.getMsgsWritten()); 112 | // } 113 | 114 | 115 | private void sendMessages(Session session, MessageProducer mp) throws NamingException, JMSException { 116 | byte[] b = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47}; 117 | Message msg = session.createMessage(); 118 | mp.send(msg); 119 | msg = session.createMessage(); 120 | mp.send(msg); 121 | 122 | TextMessage tmsg = (TextMessage) session.createTextMessage(); 123 | tmsg.setText("text message by gursev"); 124 | tmsg.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "* * * * *"); 125 | String s = new IdGenerator().generateId(); 126 | tmsg.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_ID, s); 127 | System.out.println(s); 128 | mp.send(tmsg); 129 | tmsg = (TextMessage) session.createTextMessage(); 130 | tmsg.setText("text message by gursev"); 131 | mp.send(tmsg); 132 | 133 | ObjectMessage omsg = (ObjectMessage) session.createObjectMessage(true); 134 | omsg.setObject(new RandomPerson()); 135 | mp.send(omsg); 136 | 137 | 138 | MapMessage mmsg = (MapMessage) session.createMapMessage(); 139 | mmsg.setBoolean("boolean", false); 140 | 141 | 142 | mmsg.setByte("byte", (byte) 0x44); 143 | mmsg.setChar("char", 'c'); 144 | mmsg.setFloat("float", (float) 4.444); 145 | mmsg.setInt("int", 33); 146 | mmsg.setBytes("bytes[]", b); 147 | mp.send(mmsg); 148 | mmsg = (MapMessage) session.createMapMessage(); 149 | mmsg.setBoolean("boolean", false); 150 | mmsg.setByte("byte", (byte) 0x44); 151 | mmsg.setChar("char", 'c'); 152 | mmsg.setFloat("float", (float) 4.444); 153 | mmsg.setInt("int", 33); 154 | mmsg.setBytes("bytes[]", b); 155 | mp.send(mmsg); 156 | 157 | 158 | BytesMessage bmsg = (BytesMessage) session.createBytesMessage(); 159 | bmsg.writeBytes(b); 160 | mp.send(bmsg); 161 | 162 | bmsg = (BytesMessage) session.createBytesMessage(); 163 | bmsg.writeBytes(b); 164 | mp.send(bmsg); 165 | 166 | StreamMessage smsg = (StreamMessage) session.createStreamMessage(); 167 | smsg.writeBoolean(true); 168 | smsg.writeByte((byte) 0x44); 169 | smsg.writeChar('c'); 170 | smsg.writeFloat((float) 4.444); 171 | smsg.writeInt(3333); 172 | smsg.writeBytes(b); 173 | mp.send(smsg); 174 | 175 | smsg = (StreamMessage) session.createStreamMessage(); 176 | smsg.writeBoolean(true); 177 | smsg.writeByte((byte) 0x44); 178 | smsg.writeChar('c'); 179 | smsg.writeFloat((float) 4.444); 180 | smsg.writeInt(3333); 181 | smsg.writeBytes(b); 182 | mp.send(smsg); 183 | } 184 | 185 | 186 | @Test 187 | public void testDumpTopic00MsgsForNoMessage() throws JMSException, IOException, Exception { 188 | String tName = dumpTopic00Msgs; 189 | destDumper = new JmsDumpDestination(ctx, tName, connFactName); 190 | destDumper.setTargetDirectory("/Users/Consultant/jmsdigger"); 191 | destDumper.init(); 192 | 193 | destDumper.dump(); 194 | 195 | //Sleep to ensure that every message is read 196 | Thread.sleep(5000); 197 | destDumper.close(); 198 | assertEquals(0, destDumper.getMsgsWritten()); 199 | } 200 | 201 | 202 | @Test 203 | public void testDumpTopic11MsgsFor11Messages() throws JMSException, IOException, Exception { 204 | Topic topic = (Topic) ctx.lookup(dumpTopic11Msgs); 205 | session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 206 | MessageProducer mp = session.createProducer(topic); 207 | 208 | destDumper = new JmsDumpDestination(ctx, dumpTopic11Msgs, connFactName); 209 | destDumper.setTargetDirectory("/Users/Consultant/jmsdigger"); 210 | 211 | destDumper.init(); 212 | 213 | //Initiating dump before sending messages. This ensures that onMessage has started listening before messages are sent 214 | destDumper.dump(); 215 | 216 | //Sending messages after initiating the dump process so messages are read 217 | sendMessages(session, mp); 218 | 219 | //Sleep to ensure that every message is read 220 | Thread.sleep(10000); 221 | destDumper.close(); 222 | assertEquals(11, destDumper.getMsgsWritten()); 223 | } 224 | 225 | 226 | @Test 227 | public void testDumpQueue11MsgsFor11Messages() throws JMSException, IOException, Exception { 228 | Queue queue = (Queue) ctx.lookup(dumpQueue11Msgs); 229 | session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 230 | MessageProducer mp = session.createProducer(queue); 231 | sendMessages(session, mp); 232 | 233 | destDumper = new JmsDumpDestination(ctx, dumpQueue11Msgs, connFactName); 234 | destDumper.setTargetDirectory("/Users/Consultant/jmsdigger"); 235 | destDumper.setMsgCountToDump(11); 236 | 237 | destDumper.init(); 238 | destDumper.dump(); 239 | destDumper.close(); 240 | assertEquals(11, destDumper.getMsgsWritten()); 241 | } 242 | 243 | /** 244 | * This test works with two classes 245 | * 1. Durable subscriber manipulation class 246 | * 2. Dump destination. 247 | * @throws NamingException 248 | * @throws JMSException 249 | * @throws InterruptedException 250 | * @throws IOException 251 | * @throws IllegalAccessException 252 | */ 253 | @Test 254 | public void testDurableSubscriberDump() throws NamingException, JMSException, InterruptedException, IOException, IllegalAccessException { 255 | Topic topic = (Topic) ctx.lookup(topic4DurableSubscriber); 256 | 257 | durableSubsManipulator = new JmsDurableSubscriberManipulator(ctx, topic4DurableSubscriber, connFactName); 258 | durableSubsManipulator.init(clientId); 259 | durableSubsManipulator.createDurableSubscriber(durableSubscriberName); 260 | durableSubsManipulator.close(); // Important to close as a only one connection can use a single client ID. 261 | 262 | session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 263 | MessageProducer mp = session.createProducer(topic); 264 | mp.setTimeToLive(0); 265 | sendMessages(session, mp); 266 | 267 | //Closing to ensure that dump method connectivity with same ID does not error out. 268 | session.close(); 269 | connection.close(); 270 | 271 | destDumper = new JmsDumpDestination(ctx, topic4DurableSubscriber, connFactName); 272 | destDumper.setTargetDirectory("/Users/Consultant/jmsdigger"); 273 | destDumper.setClientId(clientId); 274 | destDumper.setDurableSubscriberName(durableSubscriberName); 275 | destDumper.init(); 276 | destDumper.dump(); 277 | 278 | Thread.sleep(10000); 279 | destDumper.close(); 280 | assertEquals(11, destDumper.getMsgsWritten()); 281 | 282 | } 283 | 284 | @Test 285 | public void zSendMessagesToDurableSubscriber() throws NamingException, JMSException { 286 | Topic topic = (Topic) ctx.lookup(topic4DurableSubscriber); 287 | session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 288 | MessageProducer mp = session.createProducer(topic); 289 | for(int i = 0; i < 10; i ++) { 290 | //mp.setTimeToLive(0); 291 | sendMessages(session, mp); 292 | } 293 | session.close(); 294 | connection.close(); 295 | destDumper = null; 296 | } 297 | 298 | @Test 299 | public void zSendMessagesToTopic11Msgs() throws NamingException, JMSException { 300 | Topic topic = (Topic) ctx.lookup(dumpTopic11Msgs); 301 | session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 302 | MessageProducer mp = session.createProducer(topic); 303 | sendMessages(session, mp); 304 | destDumper = null; 305 | } 306 | 307 | @Test 308 | public void zSendMessagesToQueue() throws NamingException, JMSException { 309 | Queue queue = (Queue) ctx.lookup(dumpQueue11Msgs); 310 | session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 311 | MessageProducer mp = session.createProducer(queue); 312 | sendMessages(session, mp); 313 | destDumper = null; 314 | } 315 | 316 | 317 | } 318 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/JmsDurableSubscriberManipulatorTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.ArrayList; 6 | 7 | import javax.jms.JMSException; 8 | import javax.jms.TopicSubscriber; 9 | import javax.naming.InitialContext; 10 | 11 | import org.junit.After; 12 | import org.junit.Before; 13 | import org.junit.Test; 14 | 15 | /** 16 | * 17 | * @author Gursev Singh Kalra @ McAfee, Inc. 18 | * 19 | */ 20 | public class JmsDurableSubscriberManipulatorTest { 21 | private InitialContext ctx; 22 | private String durableSubscriberTopic = "durableSubscriberTopic"; 23 | private JmsDurableSubscriberManipulator manipulator = null; 24 | private String connFactName = "ConnectionFactory"; 25 | TopicSubscriber tsub; 26 | private String durableSubscriberName = "durableSubscriberName"; 27 | private String clientId = "gursev"; 28 | ArrayList tsAlist; 29 | 30 | 31 | @Before 32 | public void setUp() throws Exception { 33 | JmsInitialContextFactory contextFactory = new JmsInitialContextFactory("org.apache.activemq.jndi.ActiveMQInitialContextFactory", "tcp://localhost:61616"); 34 | contextFactory.addConnectionFactory(connFactName); 35 | contextFactory.addTopic(durableSubscriberTopic, "jms." + durableSubscriberTopic); 36 | ctx = contextFactory.getInitialContext(); 37 | manipulator = new JmsDurableSubscriberManipulator(ctx, durableSubscriberTopic, connFactName); 38 | manipulator.init(clientId); 39 | } 40 | 41 | @After 42 | public void tearDown() throws Exception { 43 | manipulator.close(); 44 | } 45 | 46 | @Test 47 | public void testCreateDurableSubscribers() throws JmsDiggerException { 48 | int count = 1; 49 | tsAlist = new ArrayList(); 50 | tsAlist = manipulator.createDurableSubscribers(count); 51 | assertEquals(count, tsAlist.size()); 52 | } 53 | 54 | @Test 55 | public void testCreateRandDurableSubscriber() throws JmsDiggerException, JMSException { 56 | tsub = null; 57 | tsub = manipulator.createRandDurableSubscriber(); 58 | assertNotNull(tsub); 59 | } 60 | 61 | @Test 62 | public void testCreateDurableSubscriberWithName() throws JmsDiggerException { 63 | tsub = null; 64 | tsub = manipulator.createDurableSubscriber(durableSubscriberName); 65 | assertNotNull(tsub); 66 | } 67 | 68 | @Test 69 | public void testCreateDurableSubscriberWithNameMessageSelectorAndNoLocal() throws JmsDiggerException { 70 | tsub = null; 71 | tsub = manipulator.createDurableSubscriber(durableSubscriberName, "test", true); 72 | assertNotNull(tsub); 73 | } 74 | 75 | @Test 76 | public void testEraseDurableSubscriber() throws JmsDiggerException { 77 | manipulator.createDurableSubscriber(durableSubscriberName+"Eraseme", "test", true); 78 | manipulator.close(); 79 | manipulator.init(clientId); 80 | manipulator.eraseDurableSubscriber(durableSubscriberName+"Eraseme"); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/JmsHelperTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import javax.jms.ConnectionFactory; 6 | import javax.jms.Destination; 7 | import javax.jms.JMSException; 8 | import javax.jms.Message; 9 | import javax.jms.Queue; 10 | import javax.jms.QueueConnectionFactory; 11 | import javax.jms.TextMessage; 12 | import javax.jms.Topic; 13 | import javax.naming.InitialContext; 14 | import javax.naming.NamingException; 15 | 16 | import org.junit.After; 17 | import org.junit.Before; 18 | import org.junit.Test; 19 | 20 | /** 21 | * 22 | * @author Gursev Singh Kalra @ McAfee, Inc. 23 | * 24 | */ 25 | public class JmsHelperTest { 26 | 27 | private JmsInitialContextFactory contextFactory; 28 | private InitialContext ctx; 29 | 30 | @Before 31 | public void setUp() throws Exception { 32 | contextFactory = new JmsInitialContextFactory("org.apache.activemq.jndi.ActiveMQInitialContextFactory", "tcp://localhost:61616"); 33 | contextFactory.addTopic("exploits", "jms.exploits"); 34 | contextFactory.addQueue("notInJndi", "jms.notInJndi"); 35 | ctx = contextFactory.getInitialContext(); 36 | } 37 | 38 | @After 39 | public void tearDown() throws Exception { 40 | } 41 | 42 | @Test 43 | public void testGetDestinationTrueInitCtxAndTrueJNDI() throws JmsDiggerException { 44 | Destination dest = JmsHelper.getDestination(ctx, "exploits"); 45 | assertNotNull(dest); 46 | } 47 | 48 | // @Test 49 | // public void randomTest() throws NamingException 50 | // { 51 | // InitialContext ctx = new InitialContext(); 52 | // //QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory)ctx.lookup("ConnectionFactory"); 53 | // Queue queue = (Queue)ctx.lookup("submissions"); 54 | // assertNull(queue); 55 | // 56 | // } 57 | 58 | 59 | /** 60 | * ActiveMQ auto creates new destinations during context looks up for a destination that is not present on the Broker 61 | */ 62 | @Test 63 | public void testGetDestinationTrueInitCtxAndFalseJNDI() throws JMSException{ 64 | Destination dest = JmsHelper.getDestination(ctx, "notInJndi"); 65 | if(dest instanceof Queue) 66 | { 67 | System.out.println(((Queue) dest).getQueueName()); 68 | } 69 | if(dest instanceof Topic) 70 | { 71 | System.out.println(((Topic) dest).getTopicName()); 72 | } 73 | 74 | assertNotNull(dest); 75 | } 76 | 77 | 78 | @Test (expected=JmsDiggerException.class) 79 | public void testGetDestinationFalseInitCtxAndTrueJNDI() throws JmsDiggerException { 80 | JmsHelper.getDestination(ctx, "results"); 81 | } 82 | 83 | 84 | @Test (expected=JmsDiggerException.class) 85 | public void testGetDestinationFalseInitCtxAndFalseJNDI() throws JmsDiggerException { 86 | JmsHelper.getDestination(ctx, "nowhere"); 87 | } 88 | 89 | 90 | @Test 91 | public void testGetConnectionFactory() { 92 | 93 | } 94 | 95 | @Test 96 | public void testGetDestinationIntrusive() 97 | { 98 | String cfName = "ConnectionFactory"; 99 | String destName = "exploits"; 100 | //Destination dest = JmsHelper.getDestinationIntrusiveConsumer(ctx, cfName, null, destName, result);//(ctx, cfName, destName, result); 101 | //Destination dest = JmsHelper.getDestinationIntrusiveCreateDestination(ctx, cfName, null, destName, result);//(ctx, cfName, destName, result); 102 | //assertNotNull(dest); 103 | //loginInfo = new JmsLoginInfo("gursev", "kalra"); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/JmsInitialContextFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import javax.naming.InitialContext; 6 | import javax.naming.NamingException; 7 | 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | /** 13 | * 14 | * @author Gursev Singh Kalra @ McAfee, Inc. 15 | * 16 | */ 17 | public class JmsInitialContextFactoryTest { 18 | private JmsInitialContextFactory contextFactory; 19 | 20 | @Before 21 | public void setUp() throws Exception { 22 | //TODO: right now this is hard tied to ActiveMQ. But will be modified to 23 | //run generic tests when the tool adds support for multiple providers 24 | contextFactory = new JmsInitialContextFactory("org.apache.activemq.jndi.ActiveMQInitialContextFactory", "tcp://localhost:61616"); 25 | } 26 | 27 | @After 28 | public void tearDown() throws Exception { 29 | } 30 | 31 | @Test 32 | public void testJmsInitialContextFactoryExists() throws JmsDiggerException { 33 | // make sure that ActiveMQ instance is running 34 | InitialContext ctx = contextFactory.getInitialContext(); 35 | assertNotNull(ctx); 36 | } 37 | 38 | @Test (expected=JmsDiggerException.class) 39 | public void testJmsInitialContextFactoryDoesNotExist() throws JmsDiggerException { 40 | contextFactory = new JmsInitialContextFactory("org.apache.activemq.jndi.ActiveMQInitialContextFactoryyyyy", "tcp://localhost:61616"); 41 | contextFactory.getInitialContext(); 42 | } 43 | 44 | @Test 45 | public void testAddQueueWhenEditableIsFalse() throws JmsDiggerException { 46 | InitialContext ctx = contextFactory.getInitialContext(); 47 | contextFactory.addQueue("bangbang", "bang"); 48 | try { 49 | assertFalse(ctx.getEnvironment().containsKey("bangbang")); 50 | } catch (NamingException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | @Test 56 | public void testAddRawPropertyToEnv() throws JmsDiggerException { 57 | contextFactory.addRawPropertyToEnv("bangbang", "bang"); 58 | InitialContext ctx = contextFactory.getInitialContext(); 59 | try { 60 | assertNotNull(ctx.getEnvironment().containsKey("bangbang")); 61 | } catch (NamingException e) { 62 | e.printStackTrace(); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/JmsLoginInfoTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | 10 | /** 11 | * 12 | * @author Gursev Singh Kalra @ McAfee, Inc. 13 | * 14 | */ 15 | public class JmsLoginInfoTest { 16 | 17 | private JmsLoginInfo loginInfo = null; 18 | @Before 19 | public void setUp() throws Exception { 20 | loginInfo = new JmsLoginInfo("gursev", "kalra"); 21 | } 22 | 23 | @After 24 | public void tearDown() throws Exception { 25 | } 26 | 27 | @Test 28 | public void testGetUsername() { 29 | assertEquals("gursev", loginInfo.getUsername()); 30 | } 31 | 32 | @Test 33 | public void testGetUsernameWrong() { 34 | assertNotEquals("_gursev", loginInfo.getUsername()); 35 | } 36 | 37 | @Test 38 | public void testGetPassword() { 39 | assertEquals("kalra", loginInfo.getPassword()); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/mcafee/JmsPasswordOpsTest.java: -------------------------------------------------------------------------------- 1 | package com.mcafee; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | /** 10 | * 11 | * @author Gursev Singh Kalra @ McAfee, Inc. 12 | * 13 | */ 14 | public class JmsPasswordOpsTest { 15 | private JmsPasswordOps passwdOps = new JmsPasswordOps(); 16 | 17 | @Before 18 | public void setUp() throws Exception { 19 | 20 | 21 | passwdOps.addPassword("new"); 22 | passwdOps.addPassword("new1"); 23 | passwdOps.addPassword("new2"); 24 | passwdOps.addPassword("new3"); 25 | passwdOps.addPassword("new4"); 26 | passwdOps.addPassword("new5"); 27 | passwdOps.addPassword("new6"); 28 | passwdOps.addPassword("new7"); 29 | passwdOps.addPassword("activemq"); 30 | passwdOps.addPassword("new8"); 31 | passwdOps.addPassword("new9"); 32 | passwdOps.addPassword(" "); 33 | } 34 | 35 | @After 36 | public void tearDown() throws Exception { 37 | 38 | } 39 | 40 | @Test 41 | public void testDecrypt() { 42 | String pass; 43 | pass = passwdOps.decrypt("Cf3Jf3tM+UrSOoaKU50od5CuBa8rxjoL"); 44 | assertEquals("password", pass); 45 | pass = passwdOps.decrypt("mYRkg+4Q4hua1kvpCCI2hg=="); 46 | assertEquals("manager", pass); 47 | 48 | } 49 | 50 | @Test 51 | public void testDecryptInvalidInput() { 52 | assertNull(passwdOps.decrypt("mYRkg+4Q4hua1kvpCCI2hg=")); 53 | 54 | } 55 | 56 | } 57 | --------------------------------------------------------------------------------