[ 
https://issues.apache.org/jira/browse/AMQ-4249?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Timothy Bish resolved AMQ-4249.
-------------------------------

       Resolution: Fixed
    Fix Version/s: 5.8.0

Nice investigation, patch applied to trunk.
                
> Race condition in PropertiesLoginModule
> ---------------------------------------
>
>                 Key: AMQ-4249
>                 URL: https://issues.apache.org/jira/browse/AMQ-4249
>             Project: ActiveMQ
>          Issue Type: Bug
>          Components: Broker
>    Affects Versions: 5.5.1, 5.6.0, 5.7.0, 5.8.0
>         Environment: ActiveMQ 5.5.1 with JAAS authentication via 
> PropertiesLoginModule configured, Spring JMS 3.0.5, 64-bit, Intel quad core 
> CPU (i7 950), Windows 7
>            Reporter: Tarjei Skorgenes
>            Priority: Minor
>              Labels: Authentication, JAAS, Security
>             Fix For: 5.8.0
>
>         Attachments: AMQ-4249-proposed-fix.diff, AMQ-4249-testcase.diff
>
>
> h1. Problem
> While setting up a connection pool towards ActiveMq 5.5.1 using Bitronix 
> 2.1.3 I've been having some issues related to authentication and 
> authorization of the JMS connections.
> When doing a clean restart of the JMS-clients JVM the connection pool has 
> been unable to connect successfully with one or more of the 14 connections 
> it's been set up to use.
> The error messages I've been getting has usually been one of the following 
> two:
> # User system is not authorized to read from: 
> ActiveMQ.Advisory.TempQueue,ActiveMQ.Advisory.TempTopic
> # User name or password is invalid.
> The broker has been set up using a very simplistic configuration:
> {code:xml}
> <?xml version="1.0" encoding="UTF-8"?>
> <beans xmlns="http://www.springframework.org/schema/beans";
>       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
> xmlns:context="http://www.springframework.org/schema/context";
>       xsi:schemaLocation="http://activemq.apache.org/schema/core 
> http://activemq.apache.org/schema/core/activemq-core-5.5.0.xsd
>               http://www.springframework.org/schema/beans 
> http://www.springframework.org/schema/beans/spring-beans.xsd
>               http://www.springframework.org/schema/context 
> http://www.springframework.org/schema/context/spring-context.xsd";>
>       <context:property-placeholder />
>       <broker brokerId="localhost" 
> xmlns="http://activemq.apache.org/schema/core";
>               dataDirectory="${datadir}" start="false">
>               <managementContext>
>                       <managementContext connectorHost="0.0.0.0"
>                               connectorPort="14522" createConnector="true" />
>               </managementContext>
>               <plugins>
>                       <jaasAuthenticationPlugin 
> configuration="activemq-domain"
>                               discoverLoginConfig="true" />
>                       <authorizationPlugin>
>                               <map>
>                                       <authorizationMap>
>                                               <authorizationEntries>
>                                                       <authorizationEntry 
> queue=">" read="admins"
>                                                               write="admins" 
> admin="admins" />
>                                                       <authorizationEntry 
> topic=">" read="admins"
>                                                               write="admins" 
> admin="admins" />
>                                                       <authorizationEntry 
> topic="ActiveMQ.Advisory.>"
>                                                               
> read="guests,users" write="guests,users" admin="guests,users" />
>                                               </authorizationEntries>
>                                       </authorizationMap>
>                               </map>
>                       </authorizationPlugin>
>               </plugins>
>               <transportConnectors>
>                       <transportConnector id="openwire" 
> uri="tcp://0.0.0.0:61616?trace=true" />
>               </transportConnectors>
>       </broker>
> </beans>
> {code}
> The JAAS-configuration has been verified to match username and password used 
> by the client when connecting (username = system):
> h4. login.config
> {code}
> activemq-domain {
>     org.apache.activemq.jaas.PropertiesLoginModule required
>         debug=false
>         org.apache.activemq.jaas.properties.user="users.properties"
>         org.apache.activemq.jaas.properties.group="groups.properties";
> };
> {code}
> h4.users.properties
> {code}
> system=manager
> user=password
> guest=password
> {code}
> h4. groups.properties
> {code}
> admins=system
> users=user
> guests=guest
> {code}
> h1. Cause
> After debugging the problem it seems as if the problem is caused by a race 
> condition introduced in PropertiesLoginModule in revision 
> [1086219|https://fisheye6.atlassian.com/changelog/activemq?showid=1086219] 
> (AMQ-3244). When the reload-support was added the users- and groups-fields 
> were changed into static fields. But no additional synchronization was 
> introduced, thereby introducing a race condition when several threads are 
> entering the initialize- and commit-methods are the same time.
> The following section of the initialize-method in PropertiesLoginModule 
> contains the first part of the race condition. Please note the unsynchronized 
> modification of both the users- and groups static fields:
> {code:java}
>         if (reload || users == null || uf.lastModified() > usersReloadTime) {
>             if (debug) {
>                 LOG.debug("Reloading users from " + uf.getAbsolutePath());
>             }
>             try {
>                 users = new Properties(); // XXX Here be dragons
>                 java.io.FileInputStream in = new java.io.FileInputStream(uf);
>                 users.load(in);
>                 in.close();
>                 usersReloadTime = System.currentTimeMillis();
>             } catch (IOException ioe) {
>                 LOG.warn("Unable to load user properties file " + uf);
>             }
>         }
>         groupsFile = (String) options.get(GROUP_FILE) + "";
>         File gf = baseDir != null ? new File(baseDir, groupsFile) : new 
> File(groupsFile);
>         if (reload || groups == null || gf.lastModified() > groupsReloadTime) 
> {
>             if (debug) {
>                 LOG.debug("Reloading groups from " + gf.getAbsolutePath());
>             }
>             try {
>                 groups = new Properties(); // XXX Here be dragons
>                 java.io.FileInputStream in = new java.io.FileInputStream(gf);
>                 groups.load(in);
>                 in.close();
>                 groupsReloadTime = System.currentTimeMillis();
>             } catch (IOException ioe) {
>                 LOG.warn("Unable to load group properties file " + gf);
>             }
>         }
> {code}
> The next part comes in the login-method when the users password is retrieved:
> {code:java}
>         String password = users.getProperty(user); 
> {code}
> The final part of the puzzle occurs in the commit-method:
> {code:java}
>             for (Enumeration<?> enumeration = groups.keys(); 
> enumeration.hasMoreElements();) {
>                 String name = (String)enumeration.nextElement();
>                 String[] userList = ((String)groups.getProperty(name) + 
> "").split(",");
>                 for (int i = 0; i < userList.length; i++) {
>                     if (user.equals(userList[i])) {
>                         principals.add(new GroupPrincipal(name));
>                         break;
>                     }
>                 }
>             }
> {code}
> The retrieval of the user password will fail if invoked by a thread 
> immediately after a different thread has assigned an empty Properties-object 
> to the users field in the initialize-method.
> Similarly population of the GroupPrincipals into the Subject in the 
> commit-method will silently fail if executed by a thread immediately after a 
> different thread has assigned an empty Properties-object to the groups-field 
> in the initialize-method.
> h1. Proposed solution
> I've created a testcase that reproduces the problem and an additional patch 
> that introduces a wrapper around the Properties-objects for the users- and 
> groups-fields.
> The testcase and the proposed solution is available via 
> https://github.com/lothor/activemq.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to