001    /** 
002     * 
003     * Copyright 2004 Hiram Chirino
004     * 
005     * Licensed under the Apache License, Version 2.0 (the "License"); 
006     * you may not use this file except in compliance with the License. 
007     * You may obtain a copy of the License at 
008     * 
009     * http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS, 
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
014     * See the License for the specific language governing permissions and 
015     * limitations under the License. 
016     * 
017     **/
018    package org.activemq.security.jassjacc;
019    
020    import java.io.IOException;
021    import java.util.ArrayList;
022    import java.util.Arrays;
023    import java.util.Enumeration;
024    import java.util.HashMap;
025    import java.util.HashSet;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.Properties;
029    import java.util.regex.Matcher;
030    import java.util.regex.Pattern;
031    
032    import org.activemq.message.ActiveMQQueue;
033    import org.activemq.message.ActiveMQTopic;
034    
035    /**
036     * Parses a Properties object into a set of {@see org.activemq.security.jassjacc.BrokerSecurityConfig} and
037     * {@see org.activemq.security.jassjacc.DestinationSecurityConfig} objects that can be used to
038     * secure the ActiveMQ broker.
039     * 
040     * Sample properties configuration:
041     * <pre>
042     * 
043     * # Secure a connection the the 'localhost' broker
044     * connect.roles=admins,traders,brokers,guests
045     * 
046     * # Secure the TEST_TOPIC topic.
047     * topic.T1.names=TEST_TOPIC
048     * topic.T1.consume.roles=traders
049     * topic.T1.produce.roles=traders,brokers 
050     * topic.T1.send.roles=traders,brokers 
051     * 
052     * # You can also secure more than one destination in one go.
053     * queue.Q1.names=TEST_QUEUE,A_QUEUE,B_QUEUE
054     * queue.Q1.consume.roles=traders
055     * queue.Q1.produce.roles=traders,brokers 
056     * queue.Q1.send.roles=traders,brokers
057     *  
058     * </pre>
059     *  
060     * 
061     * @version $Revision: 1.1.1.1 $
062     */
063    public class PropertiesConfigLoader {
064            
065            HashMap destinationMap = new HashMap();
066            BrokerSecurityConfig brokerSecurityConfig = new BrokerSecurityConfig();
067            
068            public PropertiesConfigLoader(String brokerName, Properties props) throws IOException {
069            
070                    brokerSecurityConfig.setBrokerName(brokerName);
071                    Pattern brokerConnectRoles = Pattern.compile("^connect\\.roles$");              
072                    Pattern destNames = Pattern.compile("^(queue|topic)\\.([^\\.]+)\\.names$");             
073                    Pattern destConsumeRoles = Pattern.compile("^(queue|topic)\\.([^\\.]+)\\.consume\\.roles$");            
074                    Pattern destProduceRoles = Pattern.compile("^(queue|topic)\\.([^\\.]+)\\.produce\\.roles$");            
075                    Pattern destSendRoles = Pattern.compile("^(queue|topic)\\.([^\\.]+)\\.send\\.roles$");          
076                    
077                    Matcher matcher;
078                    Enumeration enumeration;
079                    
080                    enumeration = props.propertyNames();
081                    while (enumeration.hasMoreElements()) {
082                            String prop = (String) enumeration.nextElement();
083                            if ((matcher=brokerConnectRoles.matcher(prop)).matches()) {                             
084                                    String[] roles = trim(props.getProperty(prop).split("\\,"));
085                                    brokerSecurityConfig.setConnectRoles(new HashSet(Arrays.asList(roles)));
086                            } else if ((matcher=destNames.matcher(prop)).matches()) {                               
087                                    String type = matcher.group(1);                         
088                                    String dest = matcher.group(2);                         
089                                    setDestNames( type, dest, trim(props.getProperty(prop).split("\\,")) );
090                            }
091                    }
092                    
093                    enumeration = props.propertyNames();
094                    while (enumeration.hasMoreElements()) {
095                            String prop = (String) enumeration.nextElement();
096                            if ((matcher=destConsumeRoles.matcher(prop)).matches()) {                               
097                                    String type = matcher.group(1);                         
098                                    String dest = matcher.group(2);                         
099                                    setDestConsumeRoles( type, dest, trim(props.getProperty(prop).split("\\,")) );
100                            } else if ((matcher=destProduceRoles.matcher(prop)).matches()) {                                
101                                    String type = matcher.group(1);                         
102                                    String dest = matcher.group(2);                         
103                                    setDestProduceRoles( type, dest, trim(props.getProperty(prop).split("\\,")) );
104                            } else if ((matcher=destSendRoles.matcher(prop)).matches()) {                           
105                                    String type = matcher.group(1);                         
106                                    String dest = matcher.group(2);                         
107                                    setDestSendRoles( type, dest, trim(props.getProperty(prop).split("\\,")) );
108                            }                               
109                    }
110                    
111            }
112    
113            private void setDestSendRoles(String type, String dest, String[] roles) throws IOException {
114                    List configs = getDestConfig(type, dest);
115                    for (Iterator iter = configs.iterator(); iter.hasNext();) {
116                            DestinationSecurityConfig config = (DestinationSecurityConfig) iter.next();
117                            config.setProduceRoles(new HashSet(Arrays.asList(roles)));
118                    }
119            }
120    
121            private void setDestProduceRoles(String type, String dest, String[] roles) throws IOException {
122                    List configs = getDestConfig(type, dest);
123                    for (Iterator iter = configs.iterator(); iter.hasNext();) {
124                            DestinationSecurityConfig config = (DestinationSecurityConfig) iter.next();
125                            config.setProduceRoles(new HashSet(Arrays.asList(roles)));
126                    }
127            }
128    
129            private void setDestConsumeRoles(String type, String dest, String[] roles) throws IOException {
130                    List configs = getDestConfig(type, dest);
131                    for (Iterator iter = configs.iterator(); iter.hasNext();) {
132                            DestinationSecurityConfig config = (DestinationSecurityConfig) iter.next();
133                            config.setConsumeRoles(new HashSet(Arrays.asList(roles)));                      
134                    }
135            }
136    
137            private List getDestConfig(String type, String dest) throws IOException {
138                    List rc = (List) destinationMap.get(type+":"+dest);
139                    if( rc==null ) {
140                            throw new IOException("Expected property not found: "+type+"."+dest+".names");
141                    }
142                    return rc;
143            }
144    
145            private void setDestNames(String type, String dest, String[] names) throws IOException {
146                    ArrayList list = new ArrayList();
147                    for (int i = 0; i < names.length; i++) {
148                            DestinationSecurityConfig config = new DestinationSecurityConfig();
149                            config.setBrokerName( brokerSecurityConfig.getBrokerName() );
150                            if( "queue".equals(type) ) {
151                                    config.setDestination(new ActiveMQQueue(dest));
152                            } else {
153                                    config.setDestination(new ActiveMQTopic(dest));
154                            }
155                            list.add(config);                       
156                    }               
157                    destinationMap.put(type+":"+dest, list);                
158            }
159    
160            private static String[] trim(String[] brokers) {
161                    for (int i = 0; i < brokers.length; i++) {
162                            brokers[i] = brokers[i].trim();
163                    }
164                    return brokers;
165            }
166            
167            public DestinationSecurityConfig[] getDestinationSecurityConfigs() {
168                    ArrayList answer = new ArrayList();             
169                    for (Iterator iter = destinationMap.values().iterator(); iter.hasNext();) {
170                            List l = (List) iter.next();
171                            answer.addAll(l);
172                    }
173                    
174                    DestinationSecurityConfig rc[] = new DestinationSecurityConfig[answer.size()];
175                    answer.toArray(rc);
176                    return rc;              
177            }
178            
179            public BrokerSecurityConfig getBrokerSecurityConfig() {
180                    return brokerSecurityConfig;            
181            }
182    
183            public void installSecurity() {
184                    JassJaccSecurityAdapter.secure(brokerSecurityConfig);
185    
186                    DestinationSecurityConfig[] destinationSecurityConfigs = getDestinationSecurityConfigs();
187                    for (int i = 0; i < destinationSecurityConfigs.length; i++) {
188                            DestinationSecurityConfig config = destinationSecurityConfigs[i];
189                            JassJaccSecurityAdapter.secure(config);
190                    }
191    
192            }
193            
194    }