GeoMesa授权

本教程演示了将数据级安全性应用于GeoMesa的方法。这是一个更高级的教程;您应该已经熟悉了GeoMesa和Geoserver的基础知识。本教程的目标是Acumulo-GeoMesa也通过相同的机制支持HBase可见性,但这里不介绍所需的HBase配置。看见 HBase可见性 有关HBase的更多信息。

在本教程中,您将学习如何:

  1. 设置数据在接收到GeoMesa期间的可见性

  2. 通过GeoMesa对您的查询应用授权

  3. 通过GeoMesa Geoserver插件实施用户授权,使用PKI证书通过Geoserver进行身份验证,并使用LDAP存储授权

背景

可见性和授权

Acumulo最强大的功能之一是实现单元级安全,使用 visibilitiesauthorizations 。受可见性保护的数据只能由拥有相应授权的用户查看。这允许基于任意标签对数据进行细粒度保护。

备注

授权不同于表级权限,其操作粒度要精细得多。

公钥基础设施(PKI)

公钥基础设施可用于对终端用户进行安全身份验证。在公钥基础设施中, certificate authority (CA)将颁发数字证书,以验证特定公钥属于特定个人。然后,其他用户可以信任该证书,因为它已由CA数字签名。

在本教程中,使用的密钥不是由受信任的CA提供的。因此,有必要将CA的证书导入Java密钥库,这允许Java(以及扩展Tomcat)信任由CA验证的任何密钥。

公钥基础设施解决了 authentication ( who 用户是)但不是 authorization ( what 用户可以这样做)。在本教程中,授权是由一个LDAP服务器提供的。

先决条件

在开始之前,您必须具备以下条件:

  • Java JDK 1.8

  • Apache Maven 3.6 or later

  • GitHub客户端

  • 一场积雨 2.0 or 2.1 实例

  • 同时具有CREATE-TABLE和WRITE权限的Acumulo用户

  • 为您的实例安装的GeoMesa分布式运行时

如果您不熟悉Acumulo授权,您应该查看相关的Acumulo documentation

关于本教程

本教程通过插入数千个要素,然后查询这些要素来进行操作。这些功能插入了可见性标签,然后向两个不同的用户查询,以显示授权是如何工作的。

GeoMesa中的可见性

GeoMesa支持为编写的每个功能设置可见性。这可以通过简单功能中的用户数据进行设置:

SimpleFeature sf = ...;
// set user data directly
sf.getUserData().put(SecurityUtils.FEATURE_VISIBILITY, "user&admin");
// alternatively, use static utility methods
org.locationtech.geomesa.security.SecurityUtils.setFeatureVisibilities(sf, "user", "admin");

有关要素级别可见性的详细信息,请参阅 功能级可见性和安全性

GeoMesa中的授权

执行查询时,GeoMesa将检索授权委托给 service providers 它们实现了以下接口:

package org.locationtech.geomesa.security;

public interface AuthorizationsProvider {

    /**
     * Gets the authorizations for the current context. This may change over time
     * (e.g. in a multi-user environment), so the result should not be cached.
     *
     * @return
     */
    List<String> getAuthorizations();

    /**
     * Configures this instance with parameters passed into the DataStoreFinder
     *
     * @param params
     */
    void configure(Map<String, Serializable> params);
}

当一个地理台地 DataStore is instantiated, it will scan for available service providers. Third-party implementations can be enabled by placing them on the classpath and including a special service descriptor file. See the Oracle Javadoc 有关实施服务提供商的详细信息,请参阅。

地理台地 DataStore 会打来电话 configure()AuthorizationsProvider 实现,将参数映射从调用传递到 DataStoreFinder.getDataStore(Map params) 。这允许 AuthorizationsProvider 根据环境进行自我配置。

以确保正确的 AuthorizationsProvider 如果在类路径上发现多个第三方服务提供商,则GeoMesa将抛出异常。在此方案中,要使用的特定服务提供程序类可由以下系统属性指定:

AuthorizationsProvider.AUTH_PROVIDER_SYS_PROPERTY = "geomesa.auth.provider.impl";

对于简单的场景,可在创建GeoMesa时指定应用于所有查询的授权集 DataStore 通过使用 geomesa.security.auths 配置参数。这将使用 DefaultAuthorizationsProvider 由GeoMesa提供的实现。

// create a map containing initialization data for the GeoMesa data store
Map<String, String> configuration = new HashMap<>();
configuration.put("geomesa.security.auths", "user,admin");
DataStore dataStore = DataStoreFinder.getDataStore(configuration);

如果没有 AuthorizationsProvider 类路径上发现的S,以及 geomesa.security.auths 参数,则GeoMesa将默认使用与基础Acumulo连接相关联的授权(即 accumulo.user 配置值)。

警告

对于生产系统,这不是推荐的方法。

另外,请注意,任何场景中使用的授权都不能超过底层Acumulo连接的授权。

在Acumulo中创建可见性

本教程要求您指定可见性字符串和关联的授权字符串。可见性可以是对您的Acumulo实例有效的任何内容。在本练习的其余部分中,我们将假定可见性字符串为 user 。您可以通过AcumuloShell查看当前为您的用户启用的可见性:

$ accumulo shell -u <username> -p <password>

一旦进入Shell:

> getauths
user,admin

如果您的用户还没有授权,您可以通过AcumuloShell使用 addauths 命令:

> getauths
user
> addauths -s admin -u myuser
> getauths
user,admin

备注

除非用户具有System.ALTER_USER权限,否则该用户无法设置授权。

运行完教程代码后,当您通过AcumuloShell扫描索引表时,您应该会看到方括号中的可见性标签:

> scan -t mytable_id
\x0100700230-fdfe-422e-b4d1-8072db6f3dda SFT: [user]    \x02\x00\x00\x01b00700230...

下载并构建教程

在您的计算机上选择一个合理的目录,然后运行:

$ git clone https://github.com/geomesa/geomesa-tutorials.git
$ cd geomesa-tutorials

警告

确保下载或检出与您的GeoMesa版本对应的教程项目版本。看见 关于教程版本 了解更多详细信息。

若要确保快速入门适用于您的环境,请修改 pom.xml 为Acumulo、Hadoop等设置适当的版本。

为了便于使用,该项目构建了一个捆绑的构件,该构件在单个JAR中包含所有必需的依赖项。要构建,请运行:

$ mvn clean install -pl geomesa-tutorials-accumulo/geomesa-tutorials-accumulo-authorizations -am

运行教程

在命令行上,运行:

$ java -cp geomesa-tutorials-accumulo/geomesa-tutorials-accumulo-authorizations/target/geomesa-tutorials-accumulo-authorizations-${geomesa.version}.jar \
    org.geomesa.example.accumulo.auths.AuthorizationsTutorial \
    --accumulo.instance.name <instance>                       \
    --accumulo.zookeepers <zookeepers>                        \
    --accumulo.user <user>                                    \
    --accumulo.password <password>                            \
    --accumulo.catalog <table>                                \
    --geomesa.security.auths <authorizations>                 \
    --visibilities <visibilities>

其中,您可以提供以下参数:

  • <instance> 您的Acumulo实例的名称

  • <zookeepers> 您的ZooKeeper节点,用逗号分隔

  • <user> 有权创建、读取和写入表的Acumulo用户的名称

  • <password> 前面提到的Acumulo用户的密码

  • <table> 将接受这些测试记录的目标表的名称。此表不应存在或应为空

  • <visibilities> the visibilities label to apply to the data, e.g. user

  • <authorizations> 与您选择的可见性关联的授权,例如 user 。确保您的Acumulo用户拥有您使用的授权

警告

如果已将GeoMesa Acumulo分布式运行时设置为在命名空间内隔离(请参见 命名空间安装 )的价值 <table> 应包括命名空间(例如 myNamespace.geomesa )。

您还可以指定教程应在完成后删除其数据。使用 --cleanup 标志,当您运行以启用此行为时。

运行后,您应该会看到以下输出:

Loading datastore

Loading datastore

Creating schema: GLOBALEVENTID:String,Actor1Name:String,Actor1CountryCode:String,Actor2Name:String,Actor2CountryCode:String,EventCode:String,NumMentions:Integer,NumSources:Integer,NumArticles:Integer,ActionGeo_Type:Integer,ActionGeo_FullName:String,ActionGeo_CountryCode:String,dtg:Date,geom:Point

Generating test data

Writing test data
Wrote 2356 features

Executing query with AUTHORIZED data store: auths are 'user'
Running query dtg BETWEEN 2017-12-31T00:00:00+00:00 AND 2018-01-02T00:00:00+00:00 AND BBOX(geom, -83.0,33.0,-80.0,35.0)
01 719024887=719024887|DEPUTY||||010|4|1|4|3|Abbeville County, South Carolina, United States|US|2017-12-31T00:00:00.000Z|POINT (-82.4665 34.2334)
02 719024893=719024893|UNITED STATES|USA|DEPUTY||010|6|1|6|3|Abbeville County, South Carolina, United States|US|2017-12-31T00:00:00.000Z|POINT (-82.4665 34.2334)
03 719024895=719024895|UNITED STATES|USA|EMPLOYEE||010|2|1|2|3|Ninety Six, South Carolina, United States|US|2017-12-31T00:00:00.000Z|POINT (-82.024 34.1751)
04 719025110=719025110|||UNITED STATES|USA|051|6|1|6|3|Edgefield, South Carolina, United States|US|2018-01-01T00:00:00.000Z|POINT (-81.9296 33.7896)
05 719025605=719025605|SCHOOL||ADMINISTRATION||043|16|1|16|3|Greenwood County, South Carolina, United States|US|2018-01-01T00:00:00.000Z|POINT (-82.1165 34.1668)
06 719025410=719025410|POLICE||||193|1|1|1|3|Ninety Six National Historic Site, South Carolina, United States|US|2018-01-01T00:00:00.000Z|POINT (-82.0193 34.146)
07 719027188=719027188|UNITED STATES|USA|UNITED STATES|USA|193|1|1|1|3|Ware Shoals, South Carolina, United States|US|2018-01-01T00:00:00.000Z|POINT (-82.2468 34.3985)
08 719024941=719024941|||DEPUTIES||090|8|1|8|3|Edgewood, South Carolina, United States|US|2018-01-01T00:00:00.000Z|POINT (-80.6137 34.2874)
09 719024950=719024950|||DEPUTIES||190|8|1|8|3|Edgewood, South Carolina, United States|US|2018-01-01T00:00:00.000Z|POINT (-80.6137 34.2874)
10 719024894=719024894|UNITED STATES|USA|DEPUTY||010|2|1|2|3|Abbeville County, South Carolina, United States|US|2017-12-31T00:00:00.000Z|POINT (-82.4665 34.2334)

Returned 39 total features

Executing query with UNAUTHORIZED data store: auths are ''
Running query dtg BETWEEN 2017-12-31T00:00:00+00:00 AND 2018-01-02T00:00:00+00:00 AND BBOX(geom, -83.0,33.0,-80.0,35.0)

Returned 0 total features

Done

第一个查询应返回1个或多个结果。第二个查询应该返回0个结果,因为它们被可见性隐藏。

看《守则》

源代码对于本教程来说是可以访问的。主要逻辑包含在 org.geomesa.example.accumulo.auths.AuthorizationsTutorialgeomesa-tutorials-accumulo/geomesa-tutorials-accumulo-authorizations 模块。一些相关的方法包括:

  • createDataStore 使用系统属性控制每个数据存储使用的可见性提供程序

  • queryFeatures 对每个数据存储运行相同的查询

// get an instance of the data store that uses our authorizations provider,
// that always returns empty auths
System.setProperty(AuthorizationsProvider.AUTH_PROVIDER_SYS_PROPERTY,
                   EmptyAuthorizationsProvider.class.getName());
unauthorizedDatastore = super.createDataStore(params);

// get an instance of the data store that uses the default authorizations provider,
// which will use whatever auths the connector has available
System.setProperty(AuthorizationsProvider.AUTH_PROVIDER_SYS_PROPERTY,
                   DefaultAuthorizationsProvider.class.getName());
return super.createDataStore(params);

此代码片断显示如何指定 AuthorizationProvider 与系统属性一起使用。这个 DefaultAuthorizationsProvider 类由GeoMesa提供,并在找不到其他实现时使用。

这个 EmptyAuthorizationsProvider 类包含在本教程中。这个 EmptyAuthorizationsProvider 将始终返回空的 Authorizations 对象,这意味着不会返回以可见性存储的任何数据。

有一种更有用的实现 AuthorizationsProvider 这将在下一节中更详细地讨论 LdapAuthorizationsProvider

使用PKIS和LDAP将授权和可见性应用于Geoserver

本节将向您展示如何配置Geoserver以使用PKI对用户进行身份验证、使用LDAP存储授权以及基于每个用户/每个查询应用授权。

基本用户身份验证将通过用户证书进行。每个用户都将拥有自己的公钥/私钥对来唯一地标识他们。

用户授权将来自ldap。一旦通过PKI验证了用户的身份,我们将在LDAP中查找该用户的详细信息。

获得用户的身份验证和授权后,我们将使用自定义 AuthorizationsProvider 实施。

在Tomcat中运行Geoserver

备注

如果您已经在Tomcat中运行Geoserver,则可以跳过此步骤。

Geoserver默认附带嵌入式Jetty Servlet。为了使用PKI登录,我们需要将其安装在Tomcat中。

  1. 下载并安装 Tomcat 9

  2. 创建一个指向Tomcat安装的环境变量(您可能希望将其添加到bash init脚本中):

    $ export CATALINA_HOME=/path/to/tomcat
    
  3. 如果要重复使用现有的Geoserver配置,请创建一个指向Geoserver数据目录的环境变量(您可能希望将其添加到您的Shell初始化脚本中):

    $ export GEOSERVER_DATA_DIR=/path/to/geoserver/data_dir
    
  4. 将Geoserver Web应用程序从Geoserver分发版复制到Tomcat Servlet中:

    $ cp -r /path/to/geoserver/webapps/geoserver/ $CATALINA_HOME/webapps/
    
  5. 增加分配给Tomcat的内存,以便在Geoserver中运行复杂查询(此处的值可能不适用于所有安装):

    $ cd $CATALINA_HOME/bin
    $ echo 'CATALINA_OPTS="-Xmx2g -XX:MaxPermSize=128m"' >> setenv.sh
    
  6. 启动Tomcat,作为服务或通过启动脚本,并确保Geoserver在http://localhost:8080/geoserver/web/.上可用

在Geoserver中创建Acumulo数据存储和图层

使用您的用户和密码凭据登录到Geoserver。点击“商店”和“添加新商店”。选择 Accumulo (GeoMesa) 矢量数据源,并填写所需参数。

基本店铺信息:

  • workspace 这取决于您的Geoserver安装

  • data source name pick a sensible name, such as geomesa_authorizations

  • description this is strictly decorative; GeoMesa authorizations tutorial

连接参数:

  • 这些参数值与您在运行本教程时在命令行上提供的参数值相同;它们描述了如何连接到数据所在的Acumulo实例

  • geomesa.security.auths 将此字段留空

点击“保存”,Geoserver将在您的累积表中搜索任何GeoMesa管理的要素类型。

发布该层

Geoserver应该识别 gdelt-secure 要素类型,并应将其显示为可发布的图层。点击“发布”链接。

您将被带到“编辑层”屏幕。您需要为数据边框输入值。在这种情况下,您可以单击链接以根据数据计算这些值。

完成后,请单击“保存”按钮。

配置Geoserver以进行PKI登录

按照Geoserver中的说明操作 documentation 以启用PKI登录到Geoserver。

在将‘cert’过滤器添加到‘Filter Chains’的步骤中,还要将其添加到‘Rest’、‘GWC’和‘Default’链(除Web之外)。

我们将使用‘rod’和‘Scott’用户,因此请确保将它们安装到您的浏览器中。

警告

确保您点击了所有Geoserver屏幕上的“保存”按钮。否则,您的更改可能会丢失。

通过重新启动Tomcat并检查‘web’筛选器链是否选择了‘cert’筛选器来验证更改是否已应用:

Web筛选器面板

Web筛选器面板

安装用于存储授权的LDAP服务器

备注

如果您已经设置了一个LDAP服务器,则可以跳过此步骤。

  1. 下载并安装 ApacheDS

  2. 作为服务运行,或通过启动脚本运行:

$ cd apacheds-2.0.0-M20/bin
$ chmod 755 *.sh
$ ./apacheds.sh

配置用于存储授权的LDAP

我们希望使用与我们正在测试的Spring Security PKI相匹配的用户来配置LDAP。我们希望的最终结果是创建以下用户:

DN: cn=rod,ou=Spring Security,o=Spring Framework

为此,我们将使用ApacheDirectoryStudio。

  1. 下载并运行 Apache Directory Studio

  2. 按照说明连接到您的LDAP实例(ApacheDS here (注:除非您愿意,否则不需要更改密码)。

  3. 为我们的数据创建分区:

    1. 右键单击“Connection”选项卡下的“ApacheDS(Localhost)”条目,然后选择“Open Configuration”。

    2. 点击‘高级分区配置...’。

    3. 点击‘添加’。

    4. 将ID字段设置为‘Spring框架’。

    5. 将Suffix字段设置为‘o=Spring框架’。

    6. 取消选中“从后缀dn自动生成上下文项”。

    7. 在上下文条目中设置以下属性:

      • 对象类:ExtensibleObject

      • 对象类:顶部

      • 对象类:域

      • DC:弹簧框架2

      • O:弹簧框架2

    8. 命中 Ctrl-s 以保存分区。ApacheDS Partition

  4. Restart ApacheDS. 否则,分区将不可用,LDIF导入将失败。

  5. 加载以下LDIF文件,该文件将创建Spring Security OU和‘rod’用户:

    • spring-security-rod.ldif

    • 在ldap浏览器中右键点击‘Root DSE’节点,然后选择‘导入->LDIF导入...’

使用教程代码测试LDAP连接

该教程代码包括一个 AuthorizationsProvider 将连接到LDAP以检索授权的实现,在类中 com.example.geomesa.auths.LdapAuthorizationsProvider

提供程序将根据 geomesa-ldap.properties 类路径上的文件(在 src/main/resources ):

# ldap connection properties
java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
java.naming.provider.url=ldap://localhost:10389
java.naming.security.authentication=simple
java.naming.security.principal=uid=admin,ou=system
java.naming.security.credentials=secret

# the ldap node to start the query from
geomesa.ldap.search.root=o=Spring Framework
# the query that will be applied to find the user's record
# the '{}' will be replaced with the common name from the certificate the user has logged in with
geomesa.ldap.search.filter=(&(objectClass=person)(cn={}))
# the ldap attribute that holds the comma-delimited authorizations for the user
geomesa.ldap.auths.attribute=employeeType

本教程中包含的默认文件将连接到我们在前面的步骤中设置的LDAP实例。如果您使用的是不同的LDAP配置,则需要适当修改该文件。

这个 LdapAuthorizationsProvider 将在逗号分隔的列表中查找存储用户授权的特定LDAP属性。为简单起见,在本教程中,我们重新调整了现有属性的用途, employeeType 。可以通过属性文件修改要使用的属性。

当我们将‘rod’记录插入到ldap时,我们设置了他的 employeeType 设置为‘USER,ADMIN’,对应于我们的Acumulo授权。如果使用不同的授权,则需要更新属性以进行匹配。

教程代码在类中包含了一个测试用例,用于连接到LDAP LdapAuthorizationsProviderTest

一旦您修改了 geomesa-ldap.properties 要连接到您的LDAP,您可以通过运行以下测试类来测试连接:

$ java -cp geomesa-tutorials-accumulo/geomesa-tutorials-accumulo-authorizations/target/geomesa-tutorials-accumulo-authorizations-${geomesa.version}.jar \
    org.geomesa.example.accumulo.auths.LdapAuthorizationsProviderTest rod

程序(‘rod’)的参数是要检索其授权的用户。您应该会得到以下输出:

Checking auths from LDAP for user 'rod'
Retrieved auths: user,admin

在Geoserver中安装LDAP AuthorizationProvider

为了使用 LdapAuthorizationsProvider ,我们需要将其作为服务提供商安装到Geoserver中,在那里它将被GeoMesa自动拾取。

教程代码包括服务提供者注册表 META-INF/services 文件夹。默认情况下,提供程序类被指定为 EmptyAuthorizationsProvider

  1. 通过运行以下命令确保您的LDAP配置正确 LdapAuthorizationsProviderTest ,如上所述。

  2. 更改单行文件中的提供程序类 src/main/resources/META-INF/services/org.locationtech.geomesa.security.AuthorizationsProvider 成为 org.geomesa.example.accumulo.auths.LdapAuthorizationsProvider

  3. 重新构建教程JAR并安装 unshaded original Geoserver中的JAR:

    $ mvn clean install -pl geomesa-tutorials-accumulo/geomesa-tutorials-accumulo-authorizations
    $ cp geomesa-tutorials-accumulo/geomesa-tutorials-accumulo-authorizations/target/geomesa-tutorials-accumulo-authorizations-${geomesa.version}.jar \
        /path/to/tomcat/webapps/geoserver/WEB-INF/lib/
    

备注

我们希望使用未着色的JAR,因为所有必需的依赖项都已安装在Geoserver中。

  1. 重新启动Geoserver(如果Geoserver未运行,则将其启动)。

在这一点上,您应该已经完成了所有配置并就位。

验证Geoserver中的LDAP授权

为了验证授权是否正常工作,请在您的浏览器中通过HTTPS调用WMS提供商来对GeoMesa执行查询:

https://localhost:8443/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=geomesa:gdelt_auths&styles=&bbox=31.6,44,37.4,47.75&width=1200&height=600&srs=EPSG:4326&format=application/openlayers

出现提示时,选择“rod”证书。

您应该会看到正常数据返回,许多红点表示数据:

授权结果

授权结果

现在尝试相同的查询,但使用‘Scott’证书。这一次,应该不会返回任何数据,因为‘Scott’用户没有在LDAP中设置任何授权。

备注

一种同时使用不同证书的简单方法是打开多个“隐姓埋名”或“私人”的浏览器窗口。