6.2 activeMQ 授权 Authorization

6.2 Authorization

To build upon authentication, consider a use case requiring more fine-grained controlover clients to authorize certain tasks. In most stock trading applications, only specificapplications can write to a given destination. After all, you wouldn’t want any oldapplication publishing stock prices to the STOCKS.* destinations. Only an authenticatedand authorized application should have this ability.

For this reason, ActiveMQ provides two levels of authorization: operation-level authorization and message-level authorization. These two types of authorization provide a more detailed level of control than simple authentication. This section discusses these two types of authorization and walks through some examples to demonstrate each.

6.2 activeMQ 授权

6.2.1 Destination-level authorization

There are three types of user-level operations with JMS destinations:
 Write—The ability to send messages to the destination

6.2.1 目的地级别的授权

Through these well-known operations, you can control the ability to perform theoperations. Using the ActiveMQ XML configuration file, such authorization can beeasily defined. Take a look at the following listing to add some operation-specificauthorization to some destinations.  你可以控制上述三种常用的操作.使用ActiveMQ的XML配置文件可以很容易的配置上面的授权方式.下面的实例代码为一些消息目的地添加了几种特殊的操作授权:
Listing 6.2 Configuring destination-level authorization

...
<plugins>
<jaasAuthenticationPlugin configuration="activemq-domain" />
<authorizationPlugin>
<map>
<authorizationMap>
<authorizationEntries>
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
...
In the listing, the JAAS authorization plug-in has been defined and pointed at theactivemq-domain configuration in the login.config file. It has also been provided witha map of authorization entries. When configuring the map of authorization entries,the first task is to define the destination to be secured. This is achieved through theuse of either a topic or a queue attribute on the entry. The next task is to declarewhich users and/or groups have privileges for operations on that destination.  在上面的代码清单配置了JAAS授权插件并指向login.config文件中名称为activemq-domain的配置.并且,该配置还提供了一个包含一系列的授权实体的授权映射.在配置授权实体映射时,首要的工作是定义受安全保护的消息目的地.可以使用authorizationEntry的topic或者queue来定义受安全保护的消息目的地名称,接下来是要配置哪个用户和/或群组具有操作这个消息目的地的权限.
A handy feature is the ability to define the destination value using wildcards. Forexample, STOCKS.> means the entry applies to all destinations in the STOCKS pathrecursively. You can find more information on wildcards in chapter 11. Also, theauthorization operations will accept either a single group or a comma-separated list ofgroups as a value.

Considering this explanation, the configuration used in the previous example can be translated as follows:

Users from the admins group have full access to all topicsConsumers can consume and publishers can publish to the destinations in the STOCKS path

Guests can only consume from the STOCKS.ORCL topic

在配置消息目的地时,可以使用通配符来简化配置.例如,”STOCKS.>” 表示该授权实体可以递归地应用到路径以STOCKS开头的目的地中.更多有关于通配符的内容请参阅第11章内容.同时,配置中操作属性值可以是单一的群组名称或者一个以逗号分割的群组名称集合.

guests群组中的用户只能消费STOCKS.ORCL主题中的消息.

The previous example uses an additive model, where all operations on a topic have been restricted to administrators only. Beyond this, specific operations on specific destinations are added as needed.

In order to start the broker to test out both the JAAS authentication plug-in as well as the authorization entries, use the following command to start the broker:

前面例子中的配置采用了一种特殊的模式使得所有的主题操作都受到管理员的约束.除此之外,还给特定的消息目的地配置了具体的操作权限.

${ACTIVEMQ_HOME}/bin/activemq console -Djava.security.auth.login.config=src/main/resources/org/apache/activemq/book/ch6/login.config xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-authorization.xml (window启动命令:%ACTIVEMQ_HOME%/bin/activemq -Djava.security.auth.login.config=src/main/resources/org/apache/activemq/book/ch6/login.config xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-authorization.xml) ... xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-authorization.xml INFO | PListStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/tmp_storage started INFO | Using Persistence Adapter: KahaDBPersistenceAdapter[/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/KahaDB] INFO | JMX consoles can connect to service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi INFO | ActiveMQ 5.4.1 JMS Message Broker (localhost) is starting INFO | For help or more information please see:http://activemq.apache.org/ INFO | Scheduler using directory:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/scheduler INFO | JobSchedulerStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/schedulerstarted INFO | Listening for connections at: tcp://localhost:61616 INFO | Connector openwire Started INFO | ActiveMQ JMS Message Broker (localhost, ID:mongoose.local-62861-1289968271876-0:0) started Note the use of the java.security.auth.login.config system property to point tothe login.config file. This ensures that ActiveMQ can locate the file for its use.Now let’s see how introduction of authorization affects JMS clients. We’ll demonstrateour authorization setup by trying to consume from the stock topics. As we weredoing for the publisher example in the previous section, we’ll modify our originalstock portfolio consumer and make it pass an appropriate connection username andpassword. For example, in order to try consuming from the STOCKS.ORCL topic asguest, we should add the following to the consumer (marked as bold): 注意,使用java.security.auth.login.config系统属性是为了指到login.config文件,保证ActiveMQ能够定位并使用login.config文件.下面让我们看看引入的授权是如何影响客户端的.我们将通过消费股票消息来说明授权操作步骤.如前面章节中修改publisher一样,我们将修改原先的stock portfolio实例中consumer的代码以便能够传入适当的用户名和密码然后建立连接.比如,为了使得guest用户可以消费来自STOCKS.ORCL主题的消息,我们需要添加下面的代码到consumer(添加的代码以粗体显示) ... private String username = "guest"; private String password = "password"; public Consumer() throws JMSException { factory = new ActiveMQConnectionFactory(brokerURL); connection = factory.createConnection(username, password); connection.start(); session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE); } ... Credentials have been added so that the consumer can create a connection to the brokerusing an appropriate username and password. The modified consumer can befound in the org.apache.activemq.book.ch6.Consumer class. Now we can run ourexample and see how authorization configuration at the broker affects the client. Firststart the publisher using the following command: 授权凭证被加入到consumer的代码中,这样consumer可以使用适当的用户名了密码来建立到代理的连接.修改后的consumer参阅org.apache.activemq.book.ch6.Consumer类文件.现在,我们可以运行修改后的例子,以便观察代理中采用的授权配置如何影响客户端.首先,使用下面的命令启动publisher: $ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch6.Publisher -Dexec.args="CSCO ORCL"

...
Sending: {price=24.07337784180, stock=ORCL, offer=24.0974512196,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=73.49647952723, stock=CSCO, offer=73.5699760067,up=false} on destination: topic://STOCKS.CSCO
Sending: {price=24.282731805343, stock=ORCL, offer=24.307014537149,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=74.1916498091, stock=CSCO, offer=74.265841458,up=true} on destination: topic://STOCKS.CSCO
Sending: {price=24.350683304888, stock=ORCL, offer=24.375033988192,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=24.46113711010, stock=ORCL, offer=24.485598247216,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=24.219079287873, stock=ORCL, offer=24.243298367160,up=false} on destination: topic://STOCKS.ORCL
Sending: {price=24.282977831328, stock=ORCL, offer=24.307260809160,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=24.33344653108, stock=ORCL, offer=24.35777997761,up=true} on destination: topic://STOCKS.ORCL
Sending: {price=73.86498266780, stock=CSCO, offer=73.93884765047,up=false} on destination: topic://STOCKS.CSCO
Published '10' of '10' price messages
...
Now let’s see what happens when we try to access different destinations with guest usercredentials. For example, if you instruct it to consume messages from STOCKS.CSCOtopic, you’ll see the following exception:  接下来,让我们看看使用guest用来访问不同的消息目的地时会发生什么情况.比如,假如使用下面的命令,使用guest用户消费来自STOCKS.CSCO主题的消息,你将看到后面的异常:

$mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch6.Consumer -Dexec.args="STOCKS.CSCO" ... Exception in thread "main" javax.jms.JMSException: User guest is not authorized to read from: topic://STOCKS.CSCO ... This is exactly what we expected to happen. Consuming from the STOCKS.CSCO topicis restricted due to the authorization settings in listing 6.2. But the authorization configurationdoes allow guests to consume from the STOCKS.ORCL topic as shown in thefollowing example: 这个与我们期望的相符合,因为在代码列表6.2中对消费STOCKS.CSCO主题中的消息消费者做了限制.但是,授权配置中运行guests群组中的用户消费来自STOCKS.ORCL主题中的消息,如下所示: $ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch6.Consumer -Dexec.args="STOCKS.ORCL"
(译注: 貌似-Dexec.args参数值应该为 -Dexec.args="ORCL" 否则出错,因为配置有权限的topic为STOCKS.ORCL,

...
ORCL 9.66 9.67 down
ORCL 9.70 9.71 up
ORCL 9.80 9.81 up
ORCL 9.83 9.84 up
ORCL 9.80 9.81 down
ORCL 9.75 9.76 down
ORCL 9.81 9.82 up
ORCL 9.88 9.89 up
ORCL 9.80 9.81 down
ORCL 9.84 9.85 up
ORCL 9.84 9.85 up
ORCL 9.86 9.87 up
ORCL 9.95 9.96 up
ORCL 10.03 10.04 up
ORCL 10.03 10.04 down
...

As you can see, the authorization settings allowed only read access to the STOCKS.ORCL topic for users that belong to the guests group.

These simple examples demonstrate how easy it is to secure ActiveMQ destinationsand assign different security levels to various users and groups. But what if definingthe access levels per destination isn’t enough for your application’s needs? Luckily,ActiveMQ allows you to do a message-based authorization as well.

正如你看到的那样,授权设置只允许来自guests群组的用户读取来自STOCKS.ORCL主题的消息.

6.2.2 Message-level authorization

So far in this chapter, we’ve covered broker-level authentication and authorization.But as you can see, authorization was granted or denied in the process of creating aconnection to the broker. In some situations you might want to authorize access toonly particular messages in a destination. In this section, we’ll examine such messagelevel authorization.

We’ll implement a simple authorization plug-in that allows only applications runningon the same host as the broker (the localhost) to consume messages. The firstthing we need to do is to create an implementation of the org.apache.activemq.security.MessageAuthorizationPolicy interface, as shown in the following listing.

Listing 6.3 Implementation of MessageAuthorizationPolicy interface

6.2.2 消息级别的授权

public class AuthorizationPolicy implements MessageAuthorizationPolicy
{
private static final Log LOG = LogFactory.getLog(AuthorizationPolicy.class);

public boolean isAllowedToConsume(ConnectionContext context,Message message)
{
{
LOG.info("Permission to consume granted");
return true;
}
else
{
LOG.info("Permission to consume denied");
return false;
}
}
}

As you can see, the MessageAuthorizationPolicy interface is simple and defines onlyone method named isAllowedToConsume(). This method has access to the messagein question and the context of the connection in which the message will be consumed.

In this example, the remote address property for a connection is used (via thecall to the Connection.getRemoteAddress() method) to distinguish a remote consumerfrom a local consumer. The isAllowedToConsume() method then determineswhether the read operation is allowed for the given consumer. Of course, this implementationis arbitrary. You can use any message property or even some message contentto make the determination. The implementation of this method is meant to be asimple example.

如上述代码所示,MessageAuthorizationPolicy接口很简单只有一个方法isAllowedToConsume().这个方法可以访问需要权限控制的消息以及消息上下文中的连接(通过该连接,消息将会被消费).

Now this policy must be installed and configured in the ActiveMQ broker. The firstand most obvious step is to compile this class and package it in an appropriate JAR.Place this JAR into the lib/ directory of the ActiveMQ distribution and the policy isready to be used. You can do that by building and copying the book examples JAR:  接下来,这个消息访问控制策略必须要安装并配置到ActiveMQ的代理中.首先,显而易见的步骤是编译这个类并打包为适当的Jar文件.然后将改Jar文件放到ActiveMQ得到lib目录下面.你可以使用下面的命令编译并拷贝实例Jar包到ActiveMQ得到lib目录下面:
$mvn clean install ...$ cp target/activemq-in-action-examples.jar ${ACTIVEMQ_HOME}/lib/ Second, the policy must be configured to create an instance of the Authorization-Policy class in the ActiveMQ XML configuration file. Using the Spring beans–styleXML inside the <messageAuthorizationPolicy> element, the AuthorizationPolicyclass is instantiated when the broker starts up. Here’s an example of this configuration: 接着,必须在ActiveMQ的XML配置文件中配置策略并创建一个AuthorizationPolicy类的引用.使用Spring的bean风格的配置在<messageAuthorizationPolicy>元素中配置一个bean,是的AuthorizationPolicy类在代理启动时能够被实例化.下面是配置的实例代码: ... <messageAuthorizationPolicy> <bean class="org.apache.activemq.book.ch6.AuthorizationPolicy" xmlns="http://www.springframework.org/schema/beans" /> </messageAuthorizationPolicy> ... The only step left is to start up ActiveMQ and test out the new policy. Here’s the command to start up the broker using the appropriate configuration file: 接着需要启动ActiveMQ以便测试新的授权策略.下面是以相应的配置文件启动代理的命令: ${ACTIVEMQ_HOME}/bin/activemq console xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-policy.xml
(window下命令:%ACTIVEMQ_HOME%/bin/activemq  xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-policy.xml)
...
xbean:src/main/resources/org/apache/activemq/book/ch6/activemq-policy.xml
...
22:19:23,532 | INFO | PListStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/tmp_storage started
22:19:23,692 | INFO | JMX consoles can connect to service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
22:19:23,847 | INFO | ActiveMQ 5.4.1 JMS Message Broker (localhost) is starting
22:19:23,990 | INFO | Scheduler using directory:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/scheduler
22:19:24,041 | INFO | JobSchedulerStore:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/scheduler started
22:19:24,081 | INFO | Listening for connections at: tcp://localhost:61616
22:19:24,081 | INFO | Connector openwire Started
22:19:24,083 | INFO | ActiveMQ JMS Message Broker(localhost, ID:mongoose.local-64256-1289971163870-0:0) started
...
If you run the examples from chapter 3 now on the host on which your broker is running,you’ll see that everything works in the same manner as it did with the originalconfiguration. The producer produces messages:  如果你在运行代理的机器上运行第3章中的例子,你会发现所有程序工作正常,就像使用前面的配置一样.
producer发布消息的命如下:

$mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch3.portfolio.Publisher -Dexec.args="CSCO ORCL" ... Sending: {price=94.51516220513759, stock=ORCL, offer=94.60967736734271,up=true} on destination: topic://STOCKS.ORCL Sending: {price=94.12582896629408, stock=ORCL, offer=94.21995479526036,up=false} on destination: topic://STOCKS.ORCL Sending: {price=52.82279394171494, stock=CSCO, offer=52.87561673565665,up=false} on destination: topic://STOCKS.CSCO Sending: {price=93.30370880341836, stock=ORCL, offer=93.39701251222176,up=false} on destination: topic://STOCKS.ORCL Sending: {price=94.0890269658999, stock=ORCL, offer=94.1831159928658,up=true} on destination: topic://STOCKS.ORCL Sending: {price=52.50790406130471, stock=CSCO, offer=52.56041196536601,up=false} on destination: topic://STOCKS.CSCO Sending: {price=94.11072880595002, stock=ORCL, offer=94.20483953475596,up=true} on destination: topic://STOCKS.ORCL Sending: {price=52.947263764976896, stock=CSCO, offer=53.000211028741866,up=true} on destination: topic://STOCKS.CSCO Sending: {price=94.40912590172766, stock=ORCL, offer=94.50353502762938,up=true} on destination: topic://STOCKS.ORCL Sending: {price=95.0802935408136, stock=ORCL, offer=95.1753738343544,up=true} on destination: topic://STOCKS.ORCL Published '10' of '10' price messages And the consumer receives these stock messages: consumer接收消息命令如下: $ mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch3.portfolio.Consumer -Dexec.args="CSCO ORCL"
...
ORCL 94.52 94.61 up
ORCL 94.13 94.22 down
CSCO 52.82 52.88 down
ORCL 93.30 93.40 down
ORCL 94.09 94.18 up
CSCO 52.51 52.56 down
ORCL 94.11 94.20 up
CSCO 52.95 53.00 up
ORCL 94.41 94.50 up
ORCL 95.08 95.18 up
CSCO 52.90 52.96 down
ORCL 95.62 95.71 up
CSCO 53.32 53.37 up
ORCL 95.45 95.55 down
CSCO 53.59 53.64 up
...
You can also notice log messages from the policy in the broker’s console:  你可以看到运行代理的控制台窗口会打印以下信息:

INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
INFO | /127.0.0.1:50930
INFO | Permission to consume granted
But, when run from another host (for example, 192.168.10.10), the consumer won’t be able to consume messages, as our policy will deny the access. And you’ll notice log messages similar to these in the broker’s console:  但是,假如在其他机器上(比如在192.168.10.10)运行consumer,consumer将不能消费消息,因为前面的策略拒绝了consumer访问消息.你将在运行consumer的控制台上看到类型下面的日志信息:

INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied
INFO | /192.168.10.10:50930
INFO | Permission to consume denied

In this way, we verified that our message-based policy works and enables message consumption only from the local host.

通过这种方式,我们验证了基于消息的安全策略能够正常工作并且保证只有来自本地机器的消息消费者能消费消息.

Message-level authorization provides some powerful functionality with endless possibilities.Although a simple example was used here, you can adapt it to any securitymechanism used in your project. Just bear in mind that a message authorization policyis executed for every message that flows through the broker. So be careful not toadd functionality that could possibly slow down the flow of messages.

In addition to authorization, ActiveMQ provides a special class for tighter controlover broker-level operations that’s even more powerful. The next section examinesand demonstrates just such an example.

微信赞赏  支付宝赞赏