You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by ni...@apache.org on 2019/03/20 13:52:35 UTC

[metron] branch master updated: METRON-2035 Allow User to Configure Role Names for Access Control (nickwallen) closes apache/metron#1355

This is an automated email from the ASF dual-hosted git repository.

nickallen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/metron.git


The following commit(s) were added to refs/heads/master by this push:
     new ef1ce3c  METRON-2035 Allow User to Configure Role Names for Access Control (nickwallen) closes apache/metron#1355
ef1ce3c is described below

commit ef1ce3c3d82758452fb63ca9d5cee31d266031ee
Author: nickwallen <ni...@nickallen.org>
AuthorDate: Wed Mar 20 09:52:16 2019 -0400

    METRON-2035 Allow User to Configure Role Names for Access Control (nickwallen) closes apache/metron#1355
---
 .../CURRENT/configuration/metron-security-env.xml  |  15 +-
 .../CURRENT/package/scripts/params/params_linux.py |   4 +
 .../METRON/CURRENT/package/templates/metron.j2     |   4 +
 .../METRON/CURRENT/themes/metron_theme.json        |  47 +++-
 metron-interface/metron-rest/README.md             | 272 ++++++++++++---------
 .../src/main/config/rest_application.yml           |   4 +
 .../rest/config/MetronAuthoritiesMapper.java       | 125 ++++++++++
 .../metron/rest/config/WebSecurityConfig.java      |  41 +---
 .../rest/config/MetronAuthoritiesMapperTest.java   | 101 ++++++++
 9 files changed, 461 insertions(+), 152 deletions(-)

diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-security-env.xml b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-security-env.xml
index ab3e532..06c14ca 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-security-env.xml
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/configuration/metron-security-env.xml
@@ -225,5 +225,18 @@
       <overridable>false</overridable>
     </value-attributes>
   </property>
-
+  <property>
+    <name>metron_user_role</name>
+    <display-name>User Role Name</display-name>
+    <value>USER</value>
+    <description>Name of the role at the authentication provider that provides user access to Metron.</description>
+    <on-ambari-upgrade add="true"/>
+  </property>
+  <property>
+    <name>metron_admin_role</name>
+    <display-name>Admin Role Name</display-name>
+    <value>ADMIN</value>
+    <description>Name of the role at the authentication provider that provides administrative access to Metron.</description>
+    <on-ambari-upgrade add="true"/>
+  </property>
 </configuration>
\ No newline at end of file
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
index e97c0e8..095acda 100755
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/scripts/params/params_linux.py
@@ -294,6 +294,10 @@ metron_ldap_group_role = config['configurations']['metron-security-env']['metron
 metron_ldap_ssl_truststore = config['configurations']['metron-security-env']['metron.ldap.ssl.truststore']
 metron_ldap_ssl_truststore_password = config['configurations']['metron-security-env']['metron.ldap.ssl.truststore.password']
 
+# Roles
+metron_user_role = config['configurations']['metron-security-env']['metron_user_role']
+metron_admin_role = config['configurations']['metron-security-env']['metron_admin_role']
+
 # REST
 metron_rest_pid_dir = config['configurations']['metron-rest-env']['metron_rest_pid_dir']
 metron_rest_pid = 'metron-rest.pid'
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/templates/metron.j2 b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/templates/metron.j2
index 08d4281..936118c 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/templates/metron.j2
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/package/templates/metron.j2
@@ -44,6 +44,10 @@ METRON_LDAP_GROUP_SEARCHFILTER="{{metron_ldap_group_searchfilter}}"
 METRON_LDAP_GROUP_ROLE="{{metron_ldap_group_role}}"
 METRON_LDAP_SSL_TRUSTSTORE="{{metron_ldap_ssl_truststore}}"
 
+#Roles
+METRON_USER_ROLE="{{metron_user_role}}"
+METRON_ADMIN_ROLE="{{metron_admin_role}}"
+
 ZOOKEEPER="{{zookeeper_quorum}}"
 BROKERLIST="{{kafka_brokers}}"
 HADOOP_CONF_DIR="/etc/hadoop/conf/"
diff --git a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json
index 65b2767..69084e3 100644
--- a/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json
+++ b/metron-deployment/packaging/ambari/metron-mpack/src/main/resources/common-services/METRON/CURRENT/themes/metron_theme.json
@@ -425,11 +425,11 @@
             "name": "security",
             "display-name": "Security",
             "layout": {
-              "tab-columns": "2",
-              "tab-rows": "2",
+              "tab-columns": "1",
+              "tab-rows": "3",
               "sections": [
                 {
-                  "name": "section-security-ldap",
+                  "name": "section-security-roles",
                   "row-index": "0",
                   "column-index": "0",
                   "row-span": "1",
@@ -438,6 +438,25 @@
                   "section-rows": "1",
                   "subsections": [
                     {
+                      "name": "subsection-security-roles",
+                      "display-name": "Roles",
+                      "row-index": "0",
+                      "column-index": "0",
+                      "row-span": "1",
+                      "column-span": "1"
+                    }
+                  ]
+                },
+                {
+                  "name": "section-security-ldap",
+                  "row-index": "1",
+                  "column-index": "0",
+                  "row-span": "1",
+                  "column-span": "1",
+                  "section-columns": "1",
+                  "section-rows": "1",
+                  "subsections": [
+                    {
                       "name": "subsection-security-ldap",
                       "display-name": "LDAP",
                       "row-index": "0",
@@ -449,7 +468,7 @@
                 },
                 {
                   "name": "section-security-knox",
-                  "row-index": "1",
+                  "row-index": "2",
                   "column-index": "0",
                   "row-span": "1",
                   "column-span": "1",
@@ -904,6 +923,14 @@
           "subsection-name": "subsection-alerts-ui"
         },
         {
+          "config": "metron-security-env/metron_user_role",
+          "subsection-name": "subsection-security-roles"
+        },
+        {
+          "config": "metron-security-env/metron_admin_role",
+          "subsection-name": "subsection-security-roles"
+        },
+        {
           "config": "metron-security-env/metron.ldap.enabled",
           "subsection-name": "subsection-security-ldap"
         },
@@ -1651,6 +1678,18 @@
         }
       },
       {
+        "config": "metron-security-env/metron_admin_role",
+        "widget": {
+          "type": "text-field"
+        }
+      },
+      {
+        "config": "metron-security-env/metron_user_role",
+        "widget": {
+          "type": "text-field"
+        }
+      },
+      {
         "config": "metron-security-env/metron.ldap.enabled",
         "widget": {
           "type": "toggle"
diff --git a/metron-interface/metron-rest/README.md b/metron-interface/metron-rest/README.md
index 8d7d99f..3201f21 100644
--- a/metron-interface/metron-rest/README.md
+++ b/metron-interface/metron-rest/README.md
@@ -19,6 +19,14 @@ limitations under the License.
 
 This module provides a RESTful API for interacting with Metron.
 
+* [Prerequisites](#prerequisites)
+* [Installation](#installation)
+* [Configuration](#configuration)
+* [Usage](#usage)
+* [Security](#security)
+* [API](#api)
+* [Testing](#testing)
+
 ## Prerequisites
 
 * A running Metron cluster
@@ -71,15 +79,17 @@ No optional parameter has a default.
 | HDFS_URL                              | HDFS url or `fs.defaultFS` Hadoop setting (ex. hdfs://node1:8020)
 
 ### Optional - With Defaults
-| Environment Variable                  | Description                                                       | Required | Default
-| ------------------------------------- | ----------------------------------------------------------------- | -------- | -------
-| METRON_LOG_DIR                        | Directory where the log file is written                           | Optional | /var/log/metron/
-| METRON_PID_FILE                       | File where the pid is written                                     | Optional | /var/run/metron/
-| METRON_REST_PORT                      | REST application port                                             | Optional | 8082
-| METRON_JDBC_CLIENT_PATH               | Path to JDBC client jar                                           | Optional | H2 is bundled
-| METRON_TEMP_GROK_PATH                 | Temporary directory used to test grok statements                  | Optional | ./patterns/temp
-| METRON_DEFAULT_GROK_PATH              | Defaults HDFS directory used to store grok statements             | Optional | /apps/metron/patterns
-| SECURITY_ENABLED                      | Enables Kerberos support                                          | Optional | false
+| Environment Variable                  | Description                                                                          | Required | Default
+| ------------------------------------- | ------------------------------------------------------------------------------------ | -------- | -------
+| METRON_LOG_DIR                        | Directory where the log file is written                                              | Optional | /var/log/metron/
+| METRON_PID_FILE                       | File where the pid is written                                                        | Optional | /var/run/metron/
+| METRON_REST_PORT                      | REST application port                                                                | Optional | 8082
+| METRON_JDBC_CLIENT_PATH               | Path to JDBC client jar                                                              | Optional | H2 is bundled
+| METRON_TEMP_GROK_PATH                 | Temporary directory used to test grok statements                                     | Optional | ./patterns/temp
+| METRON_DEFAULT_GROK_PATH              | Defaults HDFS directory used to store grok statements                                | Optional | /apps/metron/patterns
+| SECURITY_ENABLED                      | Enables Kerberos support                                                             | Optional | false
+| METRON_USER_ROLE                      | Name of the role at the authentication provider that provides user access to Metron. | Optional | USER
+| METRON_ADMIN_ROLE                     | Name of the role at the authentication provider that provides administrative access to Metron.| Optional | ADMIN
 
 ### Optional - Blank Defaults
 | Environment Variable                  | Description                                                       | Required
@@ -96,11 +106,129 @@ No optional parameter has a default.
 
 These are set in the `/etc/default/metron` file.
 
-## Database setup
+## Usage
+
+The REST application can be accessed with the Swagger UI at http://host:port/swagger-ui.html#/.  The default port is 8082.
+
+### Logging
+
+Logging for the REST application can be configured in Ambari.  Log levels can be changed at the root, package and class level:
+
+1. Navigate to Services > Metron > Configs > REST and locate the `Metron Spring options` setting.
+
+1. Logging configuration is exposed through Spring properties as explained [here](https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html#howto-logging).
+
+1. The root logging level defaults to ERROR but can be changed to INFO by adding `--logging.level.root=INFO` to the `Metron Spring options` setting.
+
+1. The Metron REST logging level can be changed to INFO by adding `--logging.level.org.apache.metron.rest=INFO`.
+
+1. HTTP request and response logging can be enabled by adding `--logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG --logging.level.org.apache.metron.rest.web.filter.ResponseLoggingFilter=DEBUG`.
+
+### Spring Profiles
+
+The REST application comes with a few [Spring Profiles](http://docs.spring.io/autorepo/docs/spring-boot/current/reference/html/boot-features-profiles.html) to aid in testing and development.
+
+| Profile                  | Description                                   |
+| ------------------------ | --------------------------------------------- |
+| test                     | adds test users `[user, user1, user2, admin]` to the database with password "`password`". sets variables to in-memory services, only used for integration testing |
+| dev                      | adds test users `[user, user1, user2, admin]` to the database with password "`password`" |
+| vagrant                  | sets configuration variables to match the Metron vagrant environment |
+| docker                   | sets configuration variables to match the Metron docker environment |
+
+Setting active profiles is done with the METRON_SPRING_PROFILES_ACTIVE variable.  For example, set this variable in `/etc/default/metron` to configure the REST application for the Vagrant environment and add a test user:
+```
+METRON_SPRING_PROFILES_ACTIVE="vagrant,dev"
+```
+
+## Security
+
+* [Kerberos](#kerberos)
+* [LDAP Authentication](#ldap-authentication)
+* [JDBC Authentication](#jdbc-authentication)
+
+### Kerberos
+
+Metron REST can be configured for a cluster with Kerberos enabled.  A client JAAS file is required for Kafka and Zookeeper and a Kerberos keytab for the metron user principal is required for all other services.  Configure these settings in the `/etc/default/metron` file:
+```
+SECURITY_ENABLED=true
+METRON_JVMFLAGS="-Djava.security.auth.login.config=$METRON_HOME/client_jaas.conf"
+METRON_PRINCIPAL_NAME="metron@EXAMPLE.COM"
+METRON_SERVICE_KEYTAB="/etc/security/keytabs/metron.keytab"
+```
+
+### LDAP Authentication
+
+Metron REST can be configured to use LDAP for authentication and roles. Use the following steps to enable LDAP.
+
+1. In Ambari, go to Metron > Config > Security > Roles
+
+    * Set "User Role Name" to the name of the role at the authentication provider that provides user level access to Metron.
+
+    * Set "Admin Role Name" to the name of the role at the authentication provider that provides administrative access to Metron.
+
+1. In Ambari, go to Metron > Config > Security > LDAP
+
+    * Turn on LDAP using the toggle.
+
+    * Set "LDAP URL" to your LDAP instance. For example, `ldap://<host>:<port>`.
+
+    * Set "Bind User" to the name of the bind user.  For example, `cn=admin,dc=apache,dc=org`.
+
+    * Set the "Bind User Password"
+
+    * Other fields may be required depending on your LDAP configuration.
+
+1. Save the changes and restart the required services.
+
+By default, configuration will default to matching Knox's Demo LDAP for convenience. This should only be used for development purposes. Manual instructions for setting up demo LDAP and finalizing configuration (e.g. setting up the user LDIF file) can be found in the [Development README](../../metron-deployment/development/README.md#knox-demo-ldap).
+
+#### LDAPS
+
+There is configuration to provide a path to a truststore with SSL certificates and provide a password. Users should import certificates as needed to appropriate truststores.  An example of doing this is:
+```
+keytool -import -alias <alias> -file <certificate> -keystore <keystore_file> -storepass <password>
+```
+
+#### Roles
+
+Roles used by Metron are `ROLE_ADMIN` and `ROLE_USER`. Metron will use a property in a group containing the appropriate role to construct this.
+
+Metron can be configured to map the roles defined in your authorization provider to the authorities used internally for access control.  This can be configured under Security > Roles in Ambari.
+
+For example, our ldif file could create this group:
+```
+dn: cn=admin,ou=groups,dc=hadoop,dc=apache,dc=org
+objectclass:top
+objectclass: groupofnames
+cn: admin
+description:admin group
+member: uid=admin,ou=people,dc=hadoop,dc=apache,dc=org
+```
+
+If we are using "cn" as our role attribute, Metron will give the "admin" user the role "ROLE_ADMIN".
+
+Similarly, we could give a user "sam" ROLE_USER with the following group:
+```
+dn: cn=user,ou=groups,dc=hadoop,dc=apache,dc=org
+objectclass:top
+objectclass: groupofnames
+cn: user
+description: user group
+member: uid=sam,ou=people,dc=hadoop,dc=apache,dc=org
+```
+
+### JDBC Authentication
 
 The REST application persists data in a relational database and requires a dedicated database user and database (see https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html for more detail).  
 Spring uses Hibernate as the default ORM framework but another framework is needed becaused Hibernate is not compatible with the Apache 2 license.  For this reason Metron uses [EclipseLink](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-embedded-database-support).  See the [Spring Data JPA - EclipseLink](https://github.com/spring-projects/spring-data-examples/tree/master/jpa/eclipselink) project for an example on how to configure Eclip [...]
 
+The metron-rest module uses [Spring Security](http://projects.spring.io/spring-security/) for authentication and stores user credentials in the relational database configured above.  The required tables are created automatically the first time the application is started so that should be done first.  For example (continuing the MySQL example above), users can be added by connecting to MySQL and running:
+```
+use metronrest;
+insert into users (username, password, enabled) values ('your_username','your_password',1);
+insert into authorities (username, authority) values ('your_username', 'ROLE_USER');
+```
+
 ### Development
 
 The REST application comes with [embedded database support](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-embedded-database-support) for development purposes.
@@ -169,98 +297,6 @@ The following configures the application for MySQL:
     unset METRON_JDBC_PASSWORD;
     ```
 
-## Usage
-
-The REST application can be accessed with the Swagger UI at http://host:port/swagger-ui.html#/.  The default port is 8082.
-
-## Security
-
-### Authentication
-
-The metron-rest module uses [Spring Security](http://projects.spring.io/spring-security/) for authentication and stores user credentials in the relational database configured above.  The required tables are created automatically the first time the application is started so that should be done first.  For example (continuing the MySQL example above), users can be added by connecting to MySQL and running:
-```
-use metronrest;
-insert into users (username, password, enabled) values ('your_username','your_password',1);
-insert into authorities (username, authority) values ('your_username', 'ROLE_USER');
-```
-
-### Kerberos
-
-Metron REST can be configured for a cluster with Kerberos enabled.  A client JAAS file is required for Kafka and Zookeeper and a Kerberos keytab for the metron user principal is required for all other services.  Configure these settings in the `/etc/default/metron` file:
-```
-SECURITY_ENABLED=true
-METRON_JVMFLAGS="-Djava.security.auth.login.config=$METRON_HOME/client_jaas.conf"
-METRON_PRINCIPAL_NAME="metron@EXAMPLE.COM"
-METRON_SERVICE_KEYTAB="/etc/security/keytabs/metron.keytab"
-```
-
-### LDAP
-
-Metron REST can be configured to use LDAP for authentication and roles. Configuration can be performed via Ambari in the "Security" tab.
-
-Configuration will default to matching Knox's Demo LDAP for convenience. This should only be used for development purposes. Manual instructions for setting up demo LDAP and finalizing configuration (e.g. setting up the user LDIF file) can be found in the [Development README](../../metron-deployment/development/README.md#knox-demo-ldap).
-
-#### LDAPS
-There is configuration to provide a path to a truststore with SSL certificates and provide a password. Users should import certificates as needed to appropriate truststores.  An example of doing this is:
-```
-keytool -import -alias <alias> -file <certificate> -keystore <keystore_file> -storepass <password>
-```
-
-
-#### Roles
-Roles used by Metron are ROLE_ADMIN and ROLE_USER. Metron will use a property in a group containing the appropriate role to construct this.
-
-For example, our ldif file could create this group:
-```
-dn: cn=admin,ou=groups,dc=hadoop,dc=apache,dc=org
-objectclass:top
-objectclass: groupofnames
-cn: admin
-description:admin group
-member: uid=admin,ou=people,dc=hadoop,dc=apache,dc=org
-```
-
-If we are using "cn" as our role attribute, Metron will give the "admin" user the role "ROLE_ADMIN".
-
-Similarly, we could give a user "sam" ROLE_USER with the following group:
-```
-dn: cn=user,ou=groups,dc=hadoop,dc=apache,dc=org
-objectclass:top
-objectclass: groupofnames
-cn: user
-description: user group
-member: uid=sam,ou=people,dc=hadoop,dc=apache,dc=org
-```
-
-## Spring Profiles
-
-The REST application comes with a few [Spring Profiles](http://docs.spring.io/autorepo/docs/spring-boot/current/reference/html/boot-features-profiles.html) to aid in testing and development.
-
-| Profile                  | Description                                   |
-| ------------------------ | --------------------------------------------- |
-| test                     | adds test users `[user, user1, user2, admin]` to the database with password "`password`". sets variables to in-memory services, only used for integration testing |
-| dev                      | adds test users `[user, user1, user2, admin]` to the database with password "`password`" |
-| vagrant                  | sets configuration variables to match the Metron vagrant environment |
-| docker                   | sets configuration variables to match the Metron docker environment |
-
-Setting active profiles is done with the METRON_SPRING_PROFILES_ACTIVE variable.  For example, set this variable in `/etc/default/metron` to configure the REST application for the Vagrant environment and add a test user:
-```
-METRON_SPRING_PROFILES_ACTIVE="vagrant,dev"
-```
-
-## Logging
-
-Logging for the REST application can be configured in Ambari.  Log levels can be changed at the root, package and class level:
-
-1. Navigate to Services > Metron > Configs > REST and locate the `Metron Spring options` setting.
-
-1. Logging configuration is exposed through Spring properties as explained [here](https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html#howto-logging).
-
-1. The root logging level defaults to ERROR but can be changed to INFO by adding `--logging.level.root=INFO` to the `Metron Spring options` setting.
-
-1. The Metron REST logging level can be changed to INFO by adding `--logging.level.org.apache.metron.rest=INFO`.
-
-1. HTTP request and response logging can be enabled by adding `--logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG --logging.level.org.apache.metron.rest.web.filter.ResponseLoggingFilter=DEBUG`.
 
 ## Pcap Query
 
@@ -276,12 +312,12 @@ REST will supply the script with raw pcap data through standard in and expects P
 Pcap query jobs can be configured for submission to a YARN queue.  This setting is exposed as the Spring property `pcap.yarn.queue` and can be set in the PCAP tab under Metron service -> Configs in Ambari.  If configured, the REST application will set the `mapreduce.job.queuename` Hadoop property to that value.
 It is highly recommended that a dedicated YARN queue be created and configured for Pcap queries to prevent a job from consuming too many cluster resources.  More information about setting up YARN queues can be found [here](https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/CapacityScheduler.html#Setting_up_queues).
 
-Pcap query results are stored in HDFS.  The location of query results when run through the REST app is determined by a couple factors.  The root of Pcap query results defaults to `/apps/metron/pcap/output` but can be changed with the 
+Pcap query results are stored in HDFS.  The location of query results when run through the REST app is determined by a couple factors.  The root of Pcap query results defaults to `/apps/metron/pcap/output` but can be changed with the
 Spring property `pcap.final.output.path`.  Assuming the default Pcap query output directory, the path to a result page will follow this pattern:
 ```
 /apps/metron/pcap/output/{username}/MAP_REDUCE/{job id}/page-{page number}.pcap
 ```
-Over time Pcap query results will accumulate in HDFS.  Currently these results are not cleaned up automatically so cluster administrators should be aware of this and monitor them.  It is highly recommended that a process be put in place to 
+Over time Pcap query results will accumulate in HDFS.  Currently these results are not cleaned up automatically so cluster administrators should be aware of this and monitor them.  It is highly recommended that a process be put in place to
 periodically delete files and directories under the Pcap query results root.
 
 Users should also be mindful of date ranges used in queries so they don't produce result sets that are too large.  Currently there are no limits enforced on date ranges.
@@ -401,7 +437,7 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
     * alerts - The alerts to be escalated
   * Returns:
     * 200 - Alerts were escalated
-    
+
 ### `GET /api/v1/alerts/ui/settings`
   * Description: Retrieves the current user's settings
   * Returns:
@@ -591,21 +627,21 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
     * fixedPcapRequest - A Fixed Pcap Request which includes fixed filter fields like ip source address and protocol
   * Returns:
     * 200 - Returns a job status with job ID.
-    
+
 ### `POST /api/v1/pcap/query`
   * Description: Executes a Query Filter Pcap Query.
   * Input:
     * queryPcapRequest - A Query Pcap Request which includes Stellar query field
   * Returns:
     * 200 - Returns a job status with job ID.
-    
+
 ### `GET /api/v1/pcap`
   * Description: Gets a list of job statuses for Pcap query jobs that match the requested state.
   * Input:
     * state - Job state
   * Returns:
     * 200 - Returns a list of job statuses for jobs that match the requested state.  
- 
+
 ### `GET /api/v1/pcap/{jobId}`
   * Description: Gets job status for Pcap query job.
   * Input:
@@ -613,7 +649,7 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
   * Returns:
     * 200 - Returns a job status for the Job ID.
     * 404 - Job is missing.
-    
+
 ### `GET /api/v1/pcap/{jobId}/pdml`
   * Description: Gets Pcap Results for a page in PDML format.
   * Input:
@@ -622,7 +658,7 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
   * Returns:
     * 200 - Returns PDML in json format.
     * 404 - Job or page is missing.
-    
+
 ### `GET /api/v1/pcap/{jobId}/raw`
   * Description: Download Pcap Results for a page.
   * Input:
@@ -631,14 +667,14 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
   * Returns:
     * 200 - Returns Pcap as a file download.
     * 404 - Job or page is missing.
-    
+
 ### `DELETE /api/v1/pcap/kill/{jobId}`
   * Description: Kills running job.
   * Input:
     * jobId - Job ID of submitted job
   * Returns:
     * 200 - Kills passed job.
-    
+
 ### `GET /api/v1/pcap/{jobId}/config`
   * Description: Gets job configuration for Pcap query job.
   * Input:
@@ -805,7 +841,7 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
   * Returns:
     * 200 - Returns SensorParserConfig
     * 404 - SensorParserConfig is missing
-    
+
 ### `POST /api/v1/sensor/parser/group`
   * Description: Updates or creates a SensorParserGroup in Zookeeper
   * Input:
@@ -813,7 +849,7 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
   * Returns:
     * 200 - SensorParserGroup updated. Returns saved SensorParserGroup
     * 201 - SensorParserGroup created. Returns saved SensorParserGroup
-    
+
 ### `GET /api/v1/sensor/parser/group/{name}`
   * Description: Retrieves a SensorParserGroup from Zookeeper
   * Input:
@@ -821,12 +857,12 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
   * Returns:
     * 200 - Returns SensorParserGroup
     * 404 - SensorParserGroup is missing
-    
+
 ### `GET /api/v1/sensor/parser/group`
   * Description: Retrieves all SensorParserGroups from Zookeeper
   * Returns:
     * 200 - Returns all SensorParserGroups
-    
+
 ### `DELETE /api/v1/sensor/parser/group/{name}`
   * Description: Deletes a SensorParserGroup from Zookeeper
   * Input:
@@ -1024,14 +1060,14 @@ Request and Response objects are JSON formatted.  The JSON schemas are available
   * Returns:
     * 200 - Nothing
     * 404 - Document not found
-    
+
 ### `POST /api/v1/update/add/comment`
   * Description: Add a comment to an alert
   * Input:
     * request - Comment add request
   * Returns:
     * 200 - Returns the complete alert document with comments added.
-    
+
 ### `POST /api/v1/update/remove/comment`
   * Description: Remove a comment from an alert
   * Input:
diff --git a/metron-interface/metron-rest/src/main/config/rest_application.yml b/metron-interface/metron-rest/src/main/config/rest_application.yml
index 7ab7b73..b6709a9 100644
--- a/metron-interface/metron-rest/src/main/config/rest_application.yml
+++ b/metron-interface/metron-rest/src/main/config/rest_application.yml
@@ -78,3 +78,7 @@ ldap:
     searchBase: ${METRON_LDAP_GROUP_SEARCHBASE}
     searchFilter: ${METRON_LDAP_GROUP_SEARCHFILTER}
     roleAttribute: ${METRON_LDAP_GROUP_ROLE}
+
+authorities:
+  user: ${METRON_USER_ROLE}
+  admin: ${METRON_ADMIN_ROLE}
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/MetronAuthoritiesMapper.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/MetronAuthoritiesMapper.java
new file mode 100644
index 0000000..dd983df
--- /dev/null
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/MetronAuthoritiesMapper.java
@@ -0,0 +1,125 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.metron.rest.config;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
+
+import java.lang.invoke.MethodHandles;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Optional;
+
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_ADMIN;
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_PREFIX;
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_USER;
+
+/**
+ * Maps the authorities used in Metron to the roles defined at the authentication provider.
+ */
+@Configuration
+public class MetronAuthoritiesMapper implements GrantedAuthoritiesMapper {
+  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  /**
+   * The name of the role at the authentication provider that maps to ROLE_USER.
+   */
+  @Value("${authorities.user:" + SECURITY_ROLE_USER + "}")
+  private String userRole;
+
+  /**
+   * The name of the role at the authentication provider that maps to ROLE_ADMIN.
+   */
+  @Value("${authorities.admin:" + SECURITY_ROLE_ADMIN + "}")
+  private String adminRole;
+
+  /**
+   * The prefix that is appended to each role after they are retrieved
+   * from the authorization provider.
+   *
+   * <p>This prefix needs to be considered when mapping roles to authorities.
+   */
+  @Value("${authorities.prefix:" + SECURITY_ROLE_PREFIX + "}")
+  private String prefix;
+
+  @Override
+  public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
+    LOG.debug("Mapping roles to authorities; '{}'->'{}', '{}'->'{}'",
+            prefix + userRole, SECURITY_ROLE_PREFIX + SECURITY_ROLE_USER,
+            prefix + adminRole, SECURITY_ROLE_PREFIX + SECURITY_ROLE_ADMIN);
+
+    HashSet<GrantedAuthority> mapped = new HashSet(authorities.size());
+    Iterator<? extends GrantedAuthority> iterator = authorities.iterator();
+    while(iterator.hasNext()) {
+      GrantedAuthority authority = iterator.next();
+      mapAuthority(authority.getAuthority()).ifPresent(auth -> mapped.add(auth));
+    }
+
+    return mapped;
+  }
+
+  public Optional<GrantedAuthority> mapAuthority(final String authority) {
+    Optional<GrantedAuthority> result;
+    if(StringUtils.equals(authority, prefix + userRole)) {
+      result = Optional.of(new SimpleGrantedAuthority(SECURITY_ROLE_PREFIX + SECURITY_ROLE_USER));
+      LOG.debug("Mapped '{}' to '{}'", authority, result.get().getAuthority());
+
+    } else if(StringUtils.equals(authority, prefix + adminRole)) {
+      result = Optional.of(new SimpleGrantedAuthority(SECURITY_ROLE_PREFIX + SECURITY_ROLE_ADMIN));
+      LOG.debug("Mapped '{}' to '{}'", authority, result.get().getAuthority());
+
+    } else {
+      // otherwise, we do not care about the role
+      LOG.debug("Ignoring unused role; role={}", authority);
+      result = Optional.empty();
+    }
+
+    return result;
+  }
+
+  public String getUserRole() {
+    return userRole;
+  }
+
+  public void setUserRole(String userRole) {
+    this.userRole = userRole;
+  }
+
+  public String getAdminRole() {
+    return adminRole;
+  }
+
+  public void setAdminRole(String adminRole) {
+    this.adminRole = adminRole;
+  }
+
+  public String getPrefix() {
+    return prefix;
+  }
+
+  public void setPrefix(String prefix) {
+    this.prefix = prefix;
+  }
+}
diff --git a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/WebSecurityConfig.java b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/WebSecurityConfig.java
index 835889c..3244e67 100644
--- a/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/WebSecurityConfig.java
+++ b/metron-interface/metron-rest/src/main/java/org/apache/metron/rest/config/WebSecurityConfig.java
@@ -17,20 +17,6 @@
  */
 package org.apache.metron.rest.config;
 
-import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_ADMIN;
-import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_USER;
-
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.interfaces.RSAPublicKey;
-import java.util.Arrays;
-import java.util.List;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.sql.DataSource;
 import org.apache.metron.rest.MetronRestConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,36 +25,30 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.env.Environment;
-import org.springframework.http.HttpMethod;
-import org.springframework.ldap.core.AttributesMapper;
-import org.springframework.ldap.core.DirContextOperations;
 import org.springframework.ldap.core.LdapTemplate;
-import org.springframework.ldap.core.support.LdapContextSource;
-import org.springframework.security.authentication.ProviderManager;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.core.Authentication;
 import org.springframework.security.crypto.password.LdapShaPasswordEncoder;
 import org.springframework.security.crypto.password.NoOpPasswordEncoder;
 import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
-import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
-import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
-import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
-import org.springframework.security.web.authentication.logout.LogoutHandler;
-import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
 import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
+import javax.sql.DataSource;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_ADMIN;
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_USER;
+
 @Configuration
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(securedEnabled = true)
@@ -85,6 +65,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     @Autowired(required = false)
     private LdapTemplate ldapTemplate;
 
+    @Autowired
+    private MetronAuthoritiesMapper authoritiesMapper;
+
     @Value("${ldap.provider.url}")
     private String providerUrl;
 
@@ -124,7 +107,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     @Value("${knox.sso.cookie:hadoop-jwt}")
     private String knoxCookie;
 
-
     @RequestMapping(value = {"/login", "/logout", "/sensors", "/sensors*/**"}, method = RequestMethod.GET)
     public String handleNGRequests() {
         return "forward:/index.html";
@@ -170,6 +152,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
         if (activeProfiles.contains(MetronRestConstants.LDAP_PROFILE)) {
             LOG.debug("Setting up LDAP authentication against {}.", providerUrl);
             auth.ldapAuthentication()
+                .authoritiesMapper(authoritiesMapper)
                 .userDnPatterns(userDnPatterns)
                 .userSearchBase(userSearchBase)
                 .userSearchFilter(userSearchFilter)
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/config/MetronAuthoritiesMapperTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/config/MetronAuthoritiesMapperTest.java
new file mode 100644
index 0000000..b3af370
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/config/MetronAuthoritiesMapperTest.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.metron.rest.config;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_ADMIN;
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_PREFIX;
+import static org.apache.metron.rest.MetronRestConstants.SECURITY_ROLE_USER;
+
+public class MetronAuthoritiesMapperTest {
+
+  private MetronAuthoritiesMapper mapper;
+
+  @Test
+  public void shouldMapUserRole() {
+    mapper = new MetronAuthoritiesMapper();
+    mapper.setUserRole("ACME_USER");
+    mapper.setAdminRole("ACME_ADMIN");
+    mapper.setPrefix("ROLE_");
+
+    // spring will prefix the roles retrieved from the authorization provider with "ROLE_" by default
+    List<GrantedAuthority> input = new ArrayList<>();
+    input.add(new SimpleGrantedAuthority("ROLE_" + "ACME_USER"));
+
+    // should map "ACME_METRON_USER" to "ROLE_USER"
+    Collection<? extends GrantedAuthority> actuals = mapper.mapAuthorities(input);
+    Assert.assertEquals(1, actuals.size());
+    Assert.assertEquals(SECURITY_ROLE_PREFIX + SECURITY_ROLE_USER, actuals.iterator().next().getAuthority());
+  }
+
+  @Test
+  public void shouldMapAdminRole() {
+    mapper = new MetronAuthoritiesMapper();
+    mapper.setUserRole("ACME_USER");
+    mapper.setAdminRole("ACME_ADMIN");
+    mapper.setPrefix("ROLE_");
+
+    List<GrantedAuthority> input = new ArrayList<>();
+    input.add(new SimpleGrantedAuthority("ROLE_" + "ACME_ADMIN"));
+
+    // should map "ACME_ADMIN" to "ROLE_ADMIN"
+    Collection<? extends GrantedAuthority> actuals = mapper.mapAuthorities(input);
+    Assert.assertEquals(1, actuals.size());
+    Assert.assertEquals(SECURITY_ROLE_PREFIX + SECURITY_ROLE_ADMIN, actuals.iterator().next().getAuthority());
+  }
+
+  @Test
+  public void shouldIgnoreOtherRoles() {
+    mapper = new MetronAuthoritiesMapper();
+    mapper.setUserRole("ACME_USER");
+    mapper.setAdminRole("ACME_ADMIN");
+    mapper.setPrefix("ROLE_");
+
+    List<GrantedAuthority> input = new ArrayList<>();
+    input.add(new SimpleGrantedAuthority("ROLE_" + "ANOTHER_ROLE"));
+    input.add(new SimpleGrantedAuthority("ROLE_" + "YET_ANOTHER_ROLE"));
+
+    Collection<? extends GrantedAuthority> actuals = mapper.mapAuthorities(input);
+    Assert.assertEquals(0, actuals.size());
+  }
+
+  @Test
+  public void shouldMapRolesWithNoPrefix() {
+    // change the prefix
+    mapper = new MetronAuthoritiesMapper();
+    mapper.setUserRole("ACME_USER");
+    mapper.setAdminRole("ACME_ADMIN");
+    mapper.setPrefix("");
+
+    List<GrantedAuthority> input = new ArrayList<>();
+    input.add(new SimpleGrantedAuthority("ACME_ADMIN"));
+
+    // should map "ACME_ADMIN" to "ROLE_ADMIN"
+    Collection<? extends GrantedAuthority> actuals = mapper.mapAuthorities(input);
+    Assert.assertEquals(1, actuals.size());
+    Assert.assertEquals(SECURITY_ROLE_PREFIX + SECURITY_ROLE_ADMIN, actuals.iterator().next().getAuthority());
+  }
+}