ConfigurationFilePrincipalDatabaseManager.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.server.security.auth.database;
022 
023 import java.io.FileNotFoundException;
024 import java.io.IOException;
025 import java.lang.reflect.Method;
026 import java.util.HashMap;
027 import java.util.List;
028 import java.util.Map;
029 
030 import org.apache.commons.configuration.Configuration;
031 import org.apache.commons.configuration.ConfigurationException;
032 
033 import org.apache.log4j.Logger;
034 
035 import org.apache.qpid.configuration.PropertyUtils;
036 import org.apache.qpid.configuration.PropertyException;
037 import org.apache.qpid.server.configuration.ServerConfiguration;
038 import org.apache.qpid.server.registry.ApplicationRegistry;
039 import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
040 import org.apache.qpid.server.security.auth.database.PrincipalDatabaseManager;
041 import org.apache.qpid.server.security.access.management.AMQUserManagementMBean;
042 import org.apache.qpid.AMQException;
043 
044 import javax.management.JMException;
045 
046 public class ConfigurationFilePrincipalDatabaseManager implements PrincipalDatabaseManager
047 {
048     private static final Logger _logger = Logger.getLogger(ConfigurationFilePrincipalDatabaseManager.class);
049 
050     Map<String, PrincipalDatabase> _databases;
051 
052     public ConfigurationFilePrincipalDatabaseManager(ServerConfiguration _configurationthrows Exception
053     {
054         _logger.info("Initialising PrincipleDatabase authentication manager");
055         _databases = initialisePrincipalDatabases(_configuration);
056     }
057 
058     private Map<String, PrincipalDatabase> initialisePrincipalDatabases(ServerConfiguration _configurationthrows Exception
059     {
060         List<String> databaseNames = _configuration.getPrincipalDatabaseNames();
061         List<String> databaseClasses = _configuration.getPrincipalDatabaseClass();
062         Map<String, PrincipalDatabase> databases = new HashMap<String, PrincipalDatabase>();
063 
064         if (databaseNames.size() == 0)
065         {
066             _logger.warn("No Principal databases specified. Broker running with NO AUTHENTICATION");
067         }
068 
069         for (int i = 0; i < databaseNames.size(); i++)
070         {
071             Object o;
072             try
073             {
074                 o = Class.forName(databaseClasses.get(i)).newInstance();
075             }
076             catch (Exception e)
077             {
078                 throw new Exception("Error initialising principal database: " + e, e);
079             }
080 
081             if (!(instanceof PrincipalDatabase))
082             {
083                 throw new Exception("Principal databases must implement the PrincipalDatabase interface");
084             }
085 
086             initialisePrincipalDatabase((PrincipalDatabaseo, _configuration, i);
087 
088             String name = databaseNames.get(i);
089             if ((name == null|| (name.length() == 0))
090             {
091                 throw new Exception("Principal database names must have length greater than or equal to one character");
092             }
093 
094             PrincipalDatabase pd = databases.get(name);
095             if (pd != null)
096             {
097                 throw new Exception("Duplicate principal database name not permitted");
098             }
099 
100             _logger.info("Initialised principal database '" + name + "' successfully");
101             databases.put(name, (PrincipalDatabaseo);
102         }
103 
104         return databases;
105     }
106 
107     private void initialisePrincipalDatabase(PrincipalDatabase principalDatabase, ServerConfiguration _configuration, int index)
108             throws FileNotFoundException, ConfigurationException
109     {
110         List<String> argumentNames = _configuration.getPrincipalDatabaseAttributeNames(index);
111         List<String> argumentValues = _configuration.getPrincipalDatabaseAttributeValues(index);
112         for (int i = 0; i < argumentNames.size(); i++)
113         {
114             String argName = argumentNames.get(i);
115             if ((argName == null|| (argName.length() == 0))
116             {
117                 throw new ConfigurationException("Argument names must have length >= 1 character");
118             }
119 
120             if (Character.isLowerCase(argName.charAt(0)))
121             {
122                 argName = Character.toUpperCase(argName.charAt(0)) + argName.substring(1);
123             }
124 
125             String methodName = "set" + argName;
126             Method method = null;
127             try
128             {
129                 method = principalDatabase.getClass().getMethod(methodName, String.class);
130             }
131             catch (Exception e)
132             {
133                 // do nothing.. as on error method will be null
134             }
135 
136             if (method == null)
137             {
138                 throw new ConfigurationException("No method " + methodName + " found in class "
139                                                  + principalDatabase.getClass()
140                                                  " hence unable to configure principal database. The method must be public and "
141                                                  "have a single String argument with a void return type");
142             }
143 
144             try
145             {
146                 method.invoke(principalDatabase, PropertyUtils.replaceProperties(argumentValues.get(i)));
147             }
148             catch (Exception ite)
149             {
150                 if (ite instanceof ConfigurationException)
151                 {
152                     throw(ConfigurationExceptionite;
153                 }
154                 else
155                 {
156                     throw new ConfigurationException(ite.getMessage(), ite);
157                 }
158             }
159         }
160     }
161 
162     public Map<String, PrincipalDatabase> getDatabases()
163     {
164         return _databases;
165     }
166 
167     public void initialiseManagement(ServerConfiguration configthrows ConfigurationException
168     {
169         try
170         {
171             AMQUserManagementMBean _mbean = new AMQUserManagementMBean();
172 
173             List<String> principalDBs = config.getManagementPrincipalDBs();
174 
175             if (principalDBs.size() == 0)
176             {
177                 throw new ConfigurationException("No principal-database specified for jmx security");
178             }
179 
180             String databaseName = principalDBs.get(0);
181 
182             PrincipalDatabase database = getDatabases().get(databaseName);
183 
184             if (database == null)
185             {
186                 throw new ConfigurationException("Principal-database '" + databaseName + "' not found");
187             }
188 
189             _mbean.setPrincipalDatabase(database);
190 
191             List<String> jmxaccesslist = config.getManagementAccessList();
192 
193             if (jmxaccesslist.size() == 0)
194             {
195                 throw new ConfigurationException("No access control files specified for jmx security");
196             }
197 
198             String jmxaccesssFile = null;
199 
200             try
201             {
202                 jmxaccesssFile = PropertyUtils.replaceProperties(jmxaccesslist.get(0));
203             }
204             catch (PropertyException e)
205             {
206                 throw new ConfigurationException("Unable to parse access control filename '" + jmxaccesssFile + "'");
207             }
208 
209             try
210             {
211                 _mbean.setAccessFile(jmxaccesssFile);
212             }
213             catch (IOException e)
214             {
215                 _logger.warn("Unable to load access file:" + jmxaccesssFile);
216             }
217 
218             try
219             {
220                 _mbean.register();
221             }
222             catch (AMQException e)
223             {
224                 _logger.warn("Unable to register user management MBean");
225             }
226         }
227         catch (JMException e)
228         {
229             _logger.warn("User management disabled as unable to create MBean:" + e);
230         }
231     }
232 }