Статьи

Аутентификация SQL для ActiveMQ

Сегодня мы рассмотрим защиту брокера ActiveMQ с помощью Java и SQL, написав наш собственный плагин для ActiveMQ.

Вы также можете обратиться к официальной документации ActiveMQ, которая объясняет, как вы можете написать свои собственные плагины для ActiveMQ здесь  и здесь .

Мы создадим простое приложение на Java, которое будет перехватывать всех клиентов, которые пытаются подключиться к нашему брокеру, и на основе clientID мы будем искать имя пользователя и пароль для клиента, пытающегося подключиться к нашему брокеру. Если имя пользователя и пароль совпадают с предварительно настроенными именем пользователя и паролем и ClientID, мы разрешим клиенту подключиться к нашему брокеру, иначе мы выдадим исключение безопасности.

Основная концепция того, что мы разрабатываем, заключается в следующем:

  • Гибкость API плагинов ActiveMQ проистекает из  BrokerFilter класса
  • BrokerFilter Класс предоставляет возможность перехватывать многие из доступных операций брокера на уровне
  • Вы должны расширить  BrokerFilter класс и переопределить его методы в соответствии с вашими потребностями. (Мы собираемся переопределить   addConnection метод, который запускается, когда клиент пытается подключиться к брокеру).
  • Вы должны реализовать BrokerPlugin класс и переопределить его installPlugin метод, чтобы создать экземпляр плагина и вернуть нового перехваченного посредника.

Это означает, что мы должны создать два класса:

 1) Класс, отвечающий за установку плагина.
 2) Класс, который будет содержать логику аутентификации.

Давайте запачкаем руки частью кода.

Создайте новый проект Java (предпочтительно проект Maven) и добавьте зависимости для брокера active-mq и соединителя SQL:

<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
<version>5.15.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>

Мы создадим  класс как реализацию   класса , как показано ниже InstallerBrokerPlugin 

package com.authplugin.deviceauth;

import java.sql.Connection;
import java.sql.DriverManager;

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerPlugin;

public class MyAuthPlugin implements BrokerPlugin {

public String url;
public String username;
public String password;

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public Broker installPlugin(Broker broker) throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection(this.url, this.username, this.password);
return new MyAuthBroker(broker, con);
}

}

Здесь мы предоставили необходимые свойства для работы нашего плагина.

Поскольку плагин будет инициализирован аналогично Spring Bean в XML, мы можем указать значения для таких свойств, как URL источника данных, имя пользователя и пароль в файле XML, в который мы собираемся поместить наш плагин.

Затем мы должны создать класс фильтра путем расширения и, поскольку мы собираемся фильтровать соединения с нашим брокером, мы будем переопределять   метод, как показано ниже: BrokerFilter, addConnection

package com.authplugin.deviceauth;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.BrokerFilter;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ConnectionInfo;

public class MyAuthBroker extends BrokerFilter {

PreparedStatement pstmt;

public MyAuthBroker(Broker next,Connection con) {
super(next);
try {
pstmt = con.prepareStatement("select * from devices where clientID= ?");
} catch (SQLException e) {
e.printStackTrace();
}
}


public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
try {

pstmt.setString(1, info.getClientId());
ResultSet rs = pstmt.executeQuery();

if (rs.next()) {
String clientID = rs.getString("clientID");
String username = rs.getString("username");
String password = rs.getString("password");
if (username.equals(info.getUserName()) && password.equals(info.getPassword())) {
super.addConnection(context, info);
} else {
// username or password does not match
throw new SecurityException("invalid username or password from deviceID : " + clientID);
}
} else {
// device id not in DB, throw exception
throw new SecurityException("Client ID not in DB : " + info.getClientId());
}
} catch (SecurityException e) {
System.out.println(e.getMessage());
throw new Exception();
}
}

}

После этого нам нужно создать в базе данных таблицу устройств, в которой можно хранить имя пользователя и пароль для различных клиентов (в моем случае это устройства), по крайней мере, с тремя столбцами — clientID, username и password.

Скомпилируйте этот проект, чтобы создать jar, который мы поместили бы в брокер (deviceauth-0.0.1-SNAPSHOT.jar)

Теперь нам просто нужно разместить плагин в папке lib каталога установки брокера ActiveMQ вместе с jar-коннектором SQL. Не забудьте также поместить соединитель SQL в папку lib.

Поместив плагин и
jar-файлы коннектора в папку lib, перейдите в {activemq-installation-directory} /conf/activemq.xml и поместите следующие строки между тегом посредника с соответствующими свойствами соединения с базой данных. Кроме того, если вы назвали класс чем-то отличным от того, который указан в приведенном ниже теге bean, вы должны обновить его тоже:

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
.
.
.
<plugins>
<bean id="authPlugin" class="com.authplugin.deviceauth.MyAuthPlugin" xmlns="http://www.springframework.org/schema/beans">

<property name="url">
<value>{your-db-URL-here}</value>
</property>
<property name="username">
<value>{your-db-username-here}</value>
</property>
<property name="password">
<value>{your-db-password-here}</value>
</property>

</bean>
</plugins>
.
</broker>

Это оно! Запустите посредник, и теперь только клиенты с именем пользователя и паролем, назначенными им в базе данных, в соответствии с clientID, могут подключаться к посреднику.

Полный код для плагина доступен на моем GitHub здесь .

Я надеюсь, что этот пост был полезным и что вы узнали что-то новое сегодня. Спасибо за чтение и счастливого кодирования!