6.2 授权

6.2 Authorization

6.2 授权

To build upon authentication, consider a use case requiring more fine-grained control

over clients to authorize certain tasks. In most stock trading applications, only specific

applications can write to a given destination. After all, you wouldn’t want any old

application publishing stock prices to the STOCKS.* destinations. Only an authenticated

and authorized application should have this ability.

创建完验证后,考虑下面这种情况:需要对客户端进行更细粒度的控制以控制对特定任务的授权.

在大多数股票交易程序中,只有特定的应用程序可以往给定的目的地写入数据.毕竟,你不希望

任何老程序还能往STOCKS.*消息目的地发布股票价格信息,只有验证和授权过后的程序才可以

具有发布股票消息到目的地的功能.

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.

为此,ActiveMQ提供两种级别的授权:操作级别授权和消息级别授权.这两者授权方式提供了

比简单认证方式更细致的访问控制.本节将讨论这两种授权方式并通过实例加以说明.

6.2.1 Destination-level authorization

6.2.1 目的地级别的授权

There are three types of user-level operations with JMS destinations:

 Read—The ability to receive messages from the destination

 Write—The ability to send messages to the destination

 Admin—The ability to administer the destination

针对JMS消息目的地一共有三种用户操作权限:

    读     -- 具有从特定目的地接收消息的权限

    写     -- 具有发送消息到特定目的地的权限

    管理   -- 具有管理消息目的地的权限

Through these well-known operations, you can control the ability to perform the

operations. Using the ActiveMQ XML configuration file, such authorization can be

easily defined. Take a look at the following listing to add some operation-specific

authorization to some destinations.

你可以控制上述三种常用的操作.使用ActiveMQ的XML配置文件可以很容易的配置上面的授权方式.

下面的实例代码为一些消息目的地添加了几种特殊的操作授权:

Listing 6.2 Configuring destination-level authorization

...

<plugins>

  <jaasAuthenticationPlugin configuration="activemq-domain" />

  <authorizationPlugin>

    <map>

      <authorizationMap>

        <authorizationEntries>

          <authorizationEntry topic=">" read="admins" write="admins" admin="admins" />

          <authorizationEntry topic="STOCKS.>" read="consumers" write="publishers" admin="publishers" />

          <authorizationEntry topic="STOCKS.ORCL" read="guests" />

          <authorizationEntry topic="ActiveMQ.Advisory.>" 

                              read="admins,publishers,consumers,guests" 

                              write="admins,publishers,consumers,guests" 

                              admin="admins,publishers,consumers,guests" />

        </authorizationEntries>

      </authorizationMap>

    </map>

  </authorizationPlugin>

</plugins>

...

In the listing, the JAAS authorization plug-in has been defined and pointed at the

activemq-domain configuration in the login.config file. It has also been provided with

a 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 the

use of either a topic or a queue attribute on the entry. The next task is to declare

which 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. For

example, STOCKS.> means the entry applies to all destinations in the STOCKS path

recursively. You can find more information on wildcards in chapter 11. Also, the

authorization operations will accept either a single group or a comma-separated list of

groups as a value.

在配置消息目的地时,可以使用通配符来简化配置.例如,"STOCKS.>" 表示该授权实体可以递归地应用到

路径以STOCKS开头的目的地中.更多有关于通配符的内容请参阅第11章内容.同时,配置中操作属性值可以是

单一的群组名称或者一个以逗号分割的群组名称集合.

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 topics

   来自admins群组中的用户具有所有主题的操作权限.

 Consumers can consume and publishers can publish to the destinations in the STOCKS path

   消息消费者可以消费路径以STOCKS开头的主题中的消息,消息发布者可以发布消息到路径以STOCKS开头的主题中.

 Guests can only consume from the STOCKS.ORCL topic

   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:

为了测试配置了授权实体的JAAS插件,使用如下命令来启动代理:

${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 to

the 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 demonstrate

our authorization setup by trying to consume from the stock topics. As we were

doing for the publisher example in the previous section, we’ll modify our original

stock portfolio consumer and make it pass an appropriate connection username and

password. For example, in order to try consuming from the STOCKS.ORCL topic as

guest, 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 broker

using an appropriate username and password. The modified consumer can be

found in the org.apache.activemq.book.ch6.Consumer class. Now we can run our

example and see how authorization configuration at the broker affects the client. First

start 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 user

credentials. For example, if you instruct it to consume messages from STOCKS.CSCO

topic, 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 topic

is restricted due to the authorization settings in listing 6.2. But the authorization configuration

does allow guests to consume from the STOCKS.ORCL topic as shown in the

following 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,

代码中使用这个参数语句为:createTopic("STOCKS." + stock);

修改后的命令为: mvn exec:java -Dexec.mainClass=org.apache.activemq.book.ch6.Consumer -Dexec.args="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.

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

These simple examples demonstrate how easy it is to secure ActiveMQ destinations

and assign different security levels to various users and groups. But what if defining

the access levels per destination isn’t enough for your application’s needs? Luckily,

ActiveMQ allows you to do a message-based authorization as well.

这些简单的例子说明,对ActiveMQ进行安全控制并为不同的群组和用户设置不同的安全等级是相当容易的.

但是,假如在消息目的地级别进行访问控制已不能完全符合应用需求时,改如何操作? 很幸运的是,ActiveMQ

还允许你进行基于消息级别的授权.

6.2.2 Message-level authorization

6.2.2 消息级别的授权

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 a

connection to the broker. In some situations you might want to authorize access to

only particular messages in a destination. In this section, we’ll examine such message

level authorization.

到目前为止,我们已经介绍了代理界别的认证和授权.但是,正如你所看到的,授权被允许或拒绝的过程都是

发生在创建到代理的连接时.有些情况下,你可能需要授权仅仅针对某个消息目的地中的某个消息.本节中

我们将讨论这种消息级别的授权.

We’ll implement a simple authorization plug-in that allows only applications running

on the same host as the broker (the localhost) to consume messages. The first

thing we need to do is to create an implementation of the org.apache.activemq.

security.MessageAuthorizationPolicy interface, as shown in the following listing.

我们将实现一个简单授权插件,该插件仅允许与代理(localhost)在同一机器上的应用程序消费消息.

首先我们要做的就是实现org.apache.activemq.security.MessageAuthorizationPolicy的接口,

如下所示.

Listing 6.3 Implementation of MessageAuthorizationPolicy interface

代码清单6.3 实现MessageAuthorizationPolicy接口

public class AuthorizationPolicy implements MessageAuthorizationPolicy 

{

  private static final Log LOG = LogFactory.getLog(AuthorizationPolicy.class);

  

  public boolean isAllowedToConsume(ConnectionContext context,Message message) 

  {

    LOG.info(context.getConnection().getRemoteAddress());

    String remoteAddress = context.getConnection().getRemoteAddress();

    if (remoteAddress.startsWith("/127.0.0.1")) 

    {

      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 only

one method named isAllowedToConsume(). This method has access to the message

in question and the context of the connection in which the message will be consumed.

如上述代码所示,MessageAuthorizationPolicy接口很简单只有一个方法isAllowedToConsume().这个方法

可以访问需要权限控制的消息以及消息上下文中的连接(通过该连接,消息将会被消费).

In this example, the remote address property for a connection is used (via the

call to the Connection.getRemoteAddress() method) to distinguish a remote consumer

from a local consumer. The isAllowedToConsume() method then determines

whether the read operation is allowed for the given consumer. Of course, this implementation

is arbitrary. You can use any message property or even some message content

to make the determination. The implementation of this method is meant to be a

simple example.

在这个示例代码中,使用connection的远程地址属性值(通过Connection.getRemoteAddress()方法获取)来区分

远程的消息消费者是否是一个本地的消费者.接着,isAllowedToConsume()方法决定是否允许当前的消息消费者

进行读取消息的操作.当然,这个实现有些随意,你可以使用消息的任何属性甚至消息内容来决定当前消费者

能否消费该消息.这里的实现仅仅作为一个简单的示例.

Now this policy must be installed and configured in the ActiveMQ broker. The first

and 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 is

ready 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–style

XML inside the <messageAuthorizationPolicy> element, the AuthorizationPolicy

class 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)

...

Loading message broker from:

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,717 | INFO | Using Persistence Adapter: KahaDBPersistenceAdapter[/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/KahaDB]

22:19:23,815 | DEBUG | loading

22:19:23,847 | INFO | ActiveMQ 5.4.1 JMS Message Broker (localhost) is starting

22:19:23,848 | INFO | For help or more information please see: http://activemq.apache.org/

22:19:23,990 | INFO | Scheduler using directory:/Users/bsnyder/amq/apache-activemq-5.4.1/data/localhost/scheduler

22:19:24,037 | DEBUG | loading

22:19:24,039 | DEBUG | loading

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 original

configuration. 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 security

mechanism used in your project. Just bear in mind that a message authorization policy

is executed for every message that flows through the broker. So be careful not to

add functionality that could possibly slow down the flow of messages.

消息级的授权提供了一些强大的功能与无限的可能性。尽管这里使用的仅仅是一个简单的示例,但你可以

将消息级别的授权扩展使用任意安全机制的工程中.需要注意的是消息授权策略将影响该代理中的所有消息.

所以,需要注意不要因为增加消息验证的功能额拖慢了消息的传送.

In addition to authorization, ActiveMQ provides a special class for tighter control

over broker-level operations that’s even more powerful. The next section examines

and demonstrates just such an example.

除了授权机制外,ActiveMQ还提供一种特殊的类以便能够更紧密的控制代理级别的操作,进而提供

更加强大的功能.下面的章节中,我们将以一个实例来说明.

猜你喜欢

转载自jackyin5918.iteye.com/blog/1965664