6.2Authorization

为了在authentication上建立,考虑这样一个use case,若需要对客户端有更多细致入微的控制来批准某些task。在大多数的股票交易应用中,只有特殊的应用能够write to一个给定的destination。毕竟,你不想任何老

的应用发布股票价格到STOCKS.* destinations.应该只有一个authenticated 并且 authorized 的应用有这个能力。
正因如此,ActiveMQ提供了两级authorization:operation-lever 和 message-level authorization。这两种authorization提供了比简单authentication更详细层级的控制。该节讨论这两类authorization并通过示例来

验证它们。
6.2.1Destination-level authorization
这里有三类JSM destination的user-level operations:
■Read--从destination接收消息的能力
■Write--向destination发送消息的能力
■Admin--管理destination的能力
通过这个众所周知的操作,你能控制这些能力来执行操作。使用ActiveMQ XML配置文件,这样的authorization能被简单地定义。看看下面列举的添加一个操作特殊的authorization给一些destination。
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>
...
在这个列表中,JAAS authorization插件已经被定义并且被指向在login.config文件中的activemq-domain配置。它也被提供了一个authorization entry的映射。当配置这个authorization entry的map,第一个任务是定

义要被安全化的destination。这是通过使用一个在entry上的topic或者queue属性来实现的。下一个任务是声明哪些用户和/或组有特权在destination上操作。
一个便利的特性是使用wildcards定义destination值的能力。例如,STOCKS.>意味着这个entry应用到所有STOCKS递归路径上的destination中。你能在第11章中找到更过关于wildcards的信息。同时,authorization操作

将接受要么单一组要么以逗号分隔的组列表为一个值。
考虑这个说明:在前面的示例中使用的配置文件能被如下翻译:
■在admin组中的用户有所有tops的完全权限
■Consumers能消费并且publishers能发布到在STOCKS路径中的destination
■Guest只能consumer从STOCKS.ORCL topic来的消息。
之前的示例使用了一个additive model,在那里所有关于一个topic的操作被restricted到管理员。除此之外,在特殊testinations上的特殊操作如需添加了。
为了启动一个代理来测试JAAS authentication 插件和authorization entries,使用如下的命令:
${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
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/scheduler
started
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


注意使用java.security.auth.login.config系统属性指向login.config文件。这个确认了ActiveMQ能定位它使用的文件。
现在让我们看看authorization的引用是如何影响JMS客户端的。我们将通过从stock topic消费消息演示我们的authorization的建立。正如我们在前面章节中所做的我们将修改我们原始的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 已经被添加所以consumer能使用一个合适的用户名和密码建立到代理的连接。修改过的consumer能在org.apache.activemq.book.ch6.Consumer类中找到。现在我们能运行我们的示例并看到在代理中

authorization配置是如何影响客户端的。首先使用如下命令启动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
...

现在让我们看看当我们使用guest用户的credentials尝试进入不同的destination时发生了什么。例如,如果你通知它从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 ...

正如我们所料。由于在列表6.2中authorization设置,从STOCKS.CSCO主题上消费消息被限制了。但是authorization配置确实允许guests用户消费从STOCKS.ORCL主题消费,如下所示:
$ mvn exec:java \
-Dexec.mainClass=org.apache.activemq.book.ch6.Consumer \
-Dexec.args="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
...
如你所见,对于属于guests用户组的用户,authorization设置仅允许对STOCKS.ORCL topic的读取权限。
这些简单的示例展示了安全化ActiveMQ destinations和分配给多个用户和组不同的的安全权限是多么容易。但是如果为每个destination定义访问等级不足以应付你的应用需求会这样?幸运的是,ActiveMQ也允许你做一

个基于消息的authorization设置。

6.2.2Message-level authorization
讨论到这里,我们已经论述了代理级别的authentication和authorization。但是如你所见,authorization在建立到代理的新连接的时候被granted或者denied。在一些情况下你可能想要在一个destination中仅为某些特

定的消息设置访问权限。在该节我们将讨论这样的message-level authorization。
我们将实现一个简单的authorization插件来仅允许和代理运行在同一个主机(the localhost)的应用消费消息。需要我们做的第一件事是去创建一个org.apache.activemq.security.MessageAuthorizationPolicy接口的

实现,如下列表显示:
Listing 6.3 Implementation of MessageAuthorizationPolicy interface
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;
    }
  }
}

如你所见的,MessageAuthorizationPolicy接口很简单并且仅定义了一个名为isAllowedToConsume()的方法。这个方法有一个讨论中的消息的入口和一个连接环境,在这个环境中消息将被消费。在这个示例中,连接的远

程地址属性被使用(通过调用Connection.getRemoteAddress()方法)来识别远程consumer和本地consumer。然后这个isAllowedToConsume()方法决定对于给定的consumer读操作是否被允许。当然,这个实现是arbitrary

。你能使用任何消息属性或甚至一些消息内容来做决定。给方法的实现是一个简单的示例。
现在这个policy必须被安装盒配置与ActiveMQ代理内。第一个和最显然的步骤是编译这个类并把它打包为合适的JAR包。将这个JAR包放置在ActiveMQ部署的lib/ 目录下然后policy就准备好被使用了。你能通过建立和拷贝

本书的示例JAR:
$ mvn clean install
...
$ cp target/activemq-in-action-examples.jar ${ACTIVEMQ_HOME}/lib/

第二步,这个policy必须在ActiveMQ的XML配置文件中被配置来新建一个AuthorizationPolicy类的实例。在<messageAuthorizationPolicy>元素内部使用Spring beans-style XML, AuthorizationPolicy类在代理启动的

时候被实例化。下面有一个配置的例子:
...
<messageAuthorizationPolicy>
  <bean
    class="org.apache.activemq.book.ch6.AuthorizationPolicy"
    xmlns="http://www.springframework.org/schema/beans" />
</messageAuthorizationPolicy>
...
剩下的唯一步骤是启动ActiveMQ并测试新的policy。这里有一个使用合适配置文件的启动代理的命令:
${ACTIVEMQ_HOME}/bin/activemq console\
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
...

如果你在代理运行的主机上运行第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
...

并且consumer接收这个stock消息:
$ 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
...

你也能看一下从代理控制台上的policy来的日志消息:
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

但是,当从另一台主机(例如192.168.10.10)运行,那么consumer将不能消费消息,因为我们的policy将拒绝访问。并且你将注意到日志文件和代理控制台上的类似:
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

以这种方法,我们已经verified我们的message-base policy能工作并使所有的消息consumption来自本地主机。
Message-level authorization 以无尽的可能性提供了一些强有效的functionality。虽然在这里使用了一个简单的示例,你能在你的项目中将它应用到任何安全机制中。就请记住一个消息authorization policy被实行与每一个流过该代理的消息。所以请消息不要添加任何可能会减慢消息流的方法。
除了authorization,为了对代理有更tighter的控制ActiveMQ提供了一个特殊的类,它甚至更强大。在下一节我们将讨论并进行示例演示。

猜你喜欢

转载自flxchy4.iteye.com/blog/1709162