http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/pom.xml ---------------------------------------------------------------------- diff --git a/ranger-plugin/pom.xml b/ranger-plugin/pom.xml new file mode 100644 index 0000000..20d3112 --- /dev/null +++ b/ranger-plugin/pom.xml @@ -0,0 +1,248 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.hawq</groupId> + <artifactId>ranger-plugin</artifactId> + <version>2.1.0.0</version> + <packaging>pom</packaging> + <name>HAWQ Ranger Plugin</name> + <description>HAWQ Ranger Plugin</description> + + <modules> + <module>admin-plugin</module> + <module>service</module> + </modules> + + <properties> + <jackson.version>1.9</jackson.version> + <release.version>1</release.version> + <postgresql.version>9.1-901-1.jdbc4</postgresql.version> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <build> + <testResources> + <testResource> + <directory>src/test/resources</directory> + <includes> + <include>**/*</include> + </includes> + <filtering>true</filtering> + </testResource> + </testResources> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>rpm-maven-plugin</artifactId> + <version>2.0.1</version> + <inherited>false</inherited> + <executions> + <execution> + <inherited>false</inherited> + <phase>install</phase> + <goals> + <goal>rpm</goal> + </goals> + </execution> + </executions> + + <configuration> + <copyright>ASL 2.0</copyright> + <group>org.apache.hawq.ranger</group> + <defaultUsername>gpadmin</defaultUsername> + <defaultGroupname>gpadmin</defaultGroupname> + <description> + HAWQ Ranger plugin. + </description> + <release>${release.version}</release> + <requires> + <require>bigtop-tomcat</require> + <require>hawq_${hawq.name.version} >= ${project.version}</require> + </requires> + <mappings> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/bin</directory> + <filemode>755</filemode> + <sources> + <source> + <location>scripts</location> + </source> + </sources> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/lib</directory> + <sources> + <source> + <location>admin-plugin/target/ranger-plugin-admin-${project.version}.jar</location> + </source> + <source> + <location>admin-plugin/target/lib/postgresql-${postgresql.version}.jar</location> + </source> + </sources> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/etc</directory> + <sources> + <source> + <location>conf/ranger-servicedef-hawq.json</location> + </source> + </sources> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/plugin-service</directory> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/plugin-service/bin</directory> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/plugin-service/logs</directory> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/plugin-service/temp</directory> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/plugin-service/work</directory> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/plugin-service/webapps</directory> + <sources> + <source> + <location>service/target/ranger-plugin-service-${project.version}.war</location> + <destination>rps.war</destination> + </source> + </sources> + </mapping> + <mapping> + <directory>/usr/local/hawq_${hawq.name.version}/ranger/plugin-service/conf</directory> + <sources> + <source> + <location>conf/tomcat-server.xml</location> + </source> + </sources> + </mapping> + </mappings> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>build-helper-maven-plugin</artifactId> + <version>1.7</version> + <executions> + <execution> + <id>regex-property</id> + <goals> + <goal>regex-property</goal> + </goals> + <configuration> + <name>hawq.name.version</name> + <value>${project.version}</value> + <regex>^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)?$</regex> + <replacement>$1_$2_$3_$4</replacement> + <failIfNoMatch>true</failIfNoMatch> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + </plugins> + </build> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.ranger</groupId> + <artifactId>ranger-plugins-common</artifactId> + <version>0.6.0</version> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>1.2.17</version> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>postgresql</groupId> + <artifactId>postgresql</artifactId> + <version>${postgresql.version}</version> + </dependency> + <dependency> + <groupId>org.codehaus.jackson</groupId> + <artifactId>jackson-xc</artifactId> + <version>1.9.13</version> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>11.0.2</version> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>2.5</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>javax.servlet.jsp</groupId> + <artifactId>jsp-api</artifactId> + <version>2.1</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.10.19</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>1.6.5</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + <version>1.6.5</version> + <scope>test</scope> + </dependency> + </dependencies> + </dependencyManagement> + +</project> \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/scripts/register_hawq.sh ---------------------------------------------------------------------- diff --git a/ranger-plugin/scripts/register_hawq.sh b/ranger-plugin/scripts/register_hawq.sh new file mode 100755 index 0000000..11e2df8 --- /dev/null +++ b/ranger-plugin/scripts/register_hawq.sh @@ -0,0 +1,217 @@ +#!/usr/bin/env bash + +# +# 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. +# + +function usage() { + echo "USAGE: register_hawq.sh -r ranger_host:ranger_port -u ranger_user -p ranger_password -h hawq_host:hawq_port -w hawq_user -q hawq_password" + exit 1 +} + +function fail() { + echo "ERROR: $1" + exit 1 +} + +function mask() { + printf -v stars '%*s' ${#1} '' + echo "[${stars// /*}]" +} + +function read_value() { + local input + read -p "Enter value for $1 : " input + echo $input +} + +function read_password() { + local input + read -s -p "Enter value for $1 : " input + echo $input +} + +function get_ranger_url() { + while [[ -z "$RANGER_URL" ]] + do + RANGER_URL=$(read_value "Ranger Admin host and port (e.g. abc.com:6080)") + done + local prefix="http://" + RANGER_URL=${RANGER_URL#$prefix} +} + +function get_ranger_user() { + while [[ -z "$RANGER_USER" ]] + do + RANGER_USER=$(read_value "Ranger Admin user name") + done +} + +function get_ranger_password() { + while [[ -z "$RANGER_PASSWORD" ]] + do + RANGER_PASSWORD=$(read_password "Ranger Admin password") + echo + done +} + +function get_hawq_url() { + #todo read hawq-site.xml ? + local default=`hostname -f` + default="${default}:5432" + while [[ -z "$HAWQ_URL" ]] + do + HAWQ_URL=$(read_value "HAWQ Master host and port [${default}]") + done + local prefix="http://" + HAWQ_URL=${HAWQ_URL#$prefix} + local parts=(${HAWQ_URL//:/ }) + if [ ${#parts[@]} != 2 ]; then + fail "Incorrect value for HAWQ Master host and port." + fi + HAWQ_HOST=${parts[0]} + HAWQ_PORT=${parts[1]} +} + +function get_hawq_user() { + local default="gpadmin" + while [[ -z "$HAWQ_USER" ]] + do + HAWQ_USER=$(read_value "HAWQ user name [${default}]") + done +} + +function get_hawq_password() { + while [[ -z "$HAWQ_PASSWORD" ]] + do + HAWQ_PASSWORD=$(read_password "HAWQ password") + echo + done +} + +function parse_params() { + while [[ $# -gt 0 ]] + do + key="$1" + case $key in + -r) + RANGER_URL="$2" + shift + ;; + -u) + RANGER_USER="$2" + shift + ;; + -p) + RANGER_PASSWORD="$2" + shift + ;; + -h) + HAWQ_URL="$2" + shift + ;; + -w) + HAWQ_USER="$2" + shift + ;; + -q) + HAWQ_PASSWORD="$2" + shift + ;; + *) + usage + ;; + esac + shift + done +} + +function validate_params() { + get_ranger_url + get_ranger_user + get_ranger_password + get_hawq_url + get_hawq_user + get_hawq_password + echo "RANGER URL = ${RANGER_URL}" + echo "RANGER User = ${RANGER_USER}" + echo "RANGER Password = $(mask ${RANGER_PASSWORD})" + echo "HAWQ HOST = ${HAWQ_HOST}" + echo "HAWQ PORT = ${HAWQ_PORT}" + echo "HAWQ User = ${HAWQ_USER}" + echo "HAWQ Password = $(mask ${HAWQ_PASSWORD})" +} + +function check_hawq_service_definition() { + echo $(curl -sS -u ${RANGER_USER}:${RANGER_PASSWORD} http://${RANGER_URL}/service/public/v2/api/servicedef/name/hawq | grep hawq | wc -l) +} + +function create_hawq_service_definition() { + if [ $(check_hawq_service_definition) == 0 ]; then + local json_file="$(dirname ${SCRIPT_DIR})/etc/ranger-servicedef-hawq.json" + if [ ! -f ${json_file} ]; then + fail "File ${json_file} not found." + fi + echo "HAWQ service definition was not found in Ranger Admin, creating it by uploading ${json_file}" + local output=$(curl -sS -u ${RANGER_USER}:${RANGER_PASSWORD} -H "Content-Type: application/json" -X POST http://${RANGER_URL}/service/plugins/definitions -d @${json_file}) + local created=$(echo ${output} | grep created | wc -l) + if [ ${created} == 0 ] || [ $(check_hawq_service_definition) == 0 ]; then + fail "Creation of HAWQ service definition from ${json_file} in Ranger Admin at ${RANGER_URL} failed. ${output}" + fi + else + echo "HAWQ service definition already exists in Ranger Admin, nothing to do." + fi +} + +function check_hawq_service_instance() { + echo $(curl -sS -u ${RANGER_USER}:${RANGER_PASSWORD} http://${RANGER_URL}/service/public/v2/api/service/name/hawq | grep hawq | wc -l) +} + +function create_hawq_service_instance() { + if [ $(check_hawq_service_instance) == 0 ]; then + local payload="{\"name\":\"hawq\", + \"type\":\"hawq\", + \"description\":\"HAWQ Master\", + \"isEnabled\":true, + \"configs\":{\"username\":\"${HAWQ_USER}\", + \"password\":\"${HAWQ_PASSWORD}\", + \"hostname\":\"${HAWQ_HOST}\", + \"port\":\"${HAWQ_PORT}\"}}" + + echo "HAWQ service instance was not found in Ranger Admin, creating it." + local output=$(curl -sS -u ${RANGER_USER}:${RANGER_PASSWORD} -H "Content-Type: application/json" -X POST http://${RANGER_URL}/service/public/v2/api/service -d "${payload}") + local created=$(echo ${output} | grep created | wc -l) + if [ ${created} == 0 ] || [ $(check_hawq_service_instance) == 0 ]; then + fail "Creation of HAWQ service instance in Ranger Admin at ${RANGER_URL} failed. ${output}" + fi + else + echo "HAWQ service instance already exists in Ranger Admin, nothing to do." + fi +} + +main() { + if [[ $# -lt 1 ]]; then + usage + fi + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + parse_params "$@" + validate_params + create_hawq_service_definition + create_hawq_service_instance +} +main "$@" http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/scripts/rps.sh ---------------------------------------------------------------------- diff --git a/ranger-plugin/scripts/rps.sh b/ranger-plugin/scripts/rps.sh new file mode 100755 index 0000000..e8ccf3a --- /dev/null +++ b/ranger-plugin/scripts/rps.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +# +# 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. +# + +if [ $# -le 0 ]; then + echo "Usage: rps (start|stop|init) [<catalina-args...>]" + exit 1 +fi + +actionCmd=$1 +shift + +CWDIR=$( cd $( dirname ${BASH_SOURCE[0]} ) && pwd ) +source $CWDIR/rps_env.sh + +setup_rps() { + echo "Initializing Hawq Ranger Plugin Service..." + cp $CATALINA_HOME/conf.template/* $CATALINA_BASE/conf + cp $CATALINA_BASE/conf/tomcat-server.xml $CATALINA_BASE/conf/server.xml + pushd $CATALINA_BASE/webapps >/dev/null + unzip -d rps rps.war >/dev/null + find . -name ranger-hawq-security.xml | xargs sed -i \ + "s/localhost:6080/$RANGER_ADMIN_HOST:$RANGER_ADMIN_PORT/g" + popd >/dev/null + echo "Hawq Ranger Plugin Service installed on http://$RPS_HOST:$RPS_PORT/rps" + echo "Please use 'rps.sh start' to start the service" +} + +case $actionCmd in + (init) + setup_rps + ;; + (start) + $CATALINA_HOME/bin/catalina.sh start "$@" + echo "Waiting for RPS service to start..." + sleep 15 + ;; + (stop) + $CATALINA_HOME/bin/catalina.sh stop "$@" + echo "Waiting for RPS service to stop..." + sleep 10 + ;; +esac http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/scripts/rps_env.sh ---------------------------------------------------------------------- diff --git a/ranger-plugin/scripts/rps_env.sh b/ranger-plugin/scripts/rps_env.sh new file mode 100755 index 0000000..ae36e8f --- /dev/null +++ b/ranger-plugin/scripts/rps_env.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# +# 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. +# + +export CATALINA_HOME=/usr/lib/bigtop-tomcat +export CATALINA_BASE=/usr/local/hawq/ranger/plugin-service + +export RANGER_ADMIN_HOST=${RANGER_ADMIN_HOST:-localhost} +export RANGER_ADMIN_PORT=${RANGER_ADMIN_PORT:-6080} + +export RPS_HOST=${RPS_HOST:-localhost} +export RPS_PORT=${RPS_PORT:-8432} +export CATALINA_OPTS="-Dhttp.host=$RPS_HOST -Dhttp.port=$RPS_PORT" http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/pom.xml ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/pom.xml b/ranger-plugin/service/pom.xml new file mode 100644 index 0000000..3f2f9f8 --- /dev/null +++ b/ranger-plugin/service/pom.xml @@ -0,0 +1,88 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.hawq</groupId> + <artifactId>ranger-plugin-service</artifactId> + <packaging>war</packaging> + <name>HAWQ Ranger Service</name> + <description>HAWQ Ranger Service</description> + <parent> + <groupId>org.apache.hawq</groupId> + <artifactId>ranger-plugin</artifactId> + <version>2.1.0.0</version> + <relativePath>..</relativePath> + </parent> + <build> + <resources> + <resource> + <directory>src/main/resources</directory> + <filtering>true</filtering> + </resource> + </resources> + <plugins> + <plugin> + <!-- use mvn tomcat6:run-war to run the appserver with the app deployed --> + <groupId>org.apache.tomcat.maven</groupId> + <artifactId>tomcat6-maven-plugin</artifactId> + <version>2.2</version> + <configuration> + <path>/rps</path> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.codehaus.jackson</groupId> + <artifactId>jackson-xc</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.ranger</groupId> + <artifactId>ranger-plugins-common</artifactId> + </dependency> + + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + </dependency> + </dependencies> + + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/HawqAuthorizer.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/HawqAuthorizer.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/HawqAuthorizer.java new file mode 100644 index 0000000..625ce50 --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/HawqAuthorizer.java @@ -0,0 +1,36 @@ +/* + * 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.hawq.ranger.authorization; + +import org.apache.hawq.ranger.authorization.model.AuthorizationRequest; +import org.apache.hawq.ranger.authorization.model.AuthorizationResponse; + +/** + * Interface for making authorization decisions. + */ +public interface HawqAuthorizer { + + /** + * Determines whether access should be allowed for the given authorization request. + * @param request authorization request + * @return authorization response + */ + AuthorizationResponse isAccessAllowed(AuthorizationRequest request); +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/RangerHawqAuthorizer.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/RangerHawqAuthorizer.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/RangerHawqAuthorizer.java new file mode 100644 index 0000000..04d6f99 --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/RangerHawqAuthorizer.java @@ -0,0 +1,263 @@ +/* + * 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.hawq.ranger.authorization; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hawq.ranger.authorization.model.AuthorizationRequest; +import org.apache.hawq.ranger.authorization.model.AuthorizationResponse; +import org.apache.hawq.ranger.authorization.model.HawqPrivilege; +import org.apache.hawq.ranger.authorization.model.HawqResource; +import org.apache.hawq.ranger.authorization.model.ResourceAccess; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.service.RangerBasePlugin; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static org.apache.hawq.ranger.authorization.Utils.HAWQ; + +/** + * Authorizer implementation that uses Ranger to make access decision. Implemented as a singleton. + */ +public class RangerHawqAuthorizer implements HawqAuthorizer { + + private static final Log LOG = LogFactory.getLog(RangerHawqAuthorizer.class); + + private static final RangerHawqAuthorizer INSTANCE = new RangerHawqAuthorizer(); + + private RangerBasePlugin rangerPlugin; + + /** + * Returns the instance of the RangerHawqAuthorizer. + * @return the singleton instance + */ + public static RangerHawqAuthorizer getInstance() { + return INSTANCE; + } + + /** + * Constructor. Initializes Ranger Base Plugin to fetch policies from Ranger. + */ + private RangerHawqAuthorizer() { + + LOG.info("Initializing RangerHawqAuthorizer"); + + String appId = Utils.getAppId(); + + LOG.info(String.format("Initializing RangerBasePlugin for service %s:%s", HAWQ, appId)); + rangerPlugin = new RangerBasePlugin(HAWQ, appId); + rangerPlugin.init(); + LOG.info(String.format("Initialized RangerBasePlugin for service %s:%s", HAWQ, appId)); + } + + @Override + public AuthorizationResponse isAccessAllowed(AuthorizationRequest request) { + + // validate request to make sure no data is missing + validateRequest(request); + + // prepare response object + AuthorizationResponse response = new AuthorizationResponse(); + response.setRequestId(request.getRequestId()); + Set<ResourceAccess> access = new HashSet<>(); + response.setAccess(access); + + // iterate over resource requests, augment processed ones with the decision and add to the response + for (ResourceAccess resourceAccess : request.getAccess()) { + boolean accessAllowed = authorizeResource(resourceAccess, request.getUser()); + resourceAccess.setAllowed(accessAllowed); + access.add(resourceAccess); + } + + return response; + } + + /** + * Authorizes access to a single resource for a given user. + * + * @param resourceAccess resource to authorize access to + * @param user user requesting authorization + * @return true if access is authorized, false otherwise + */ + private boolean authorizeResource(ResourceAccess resourceAccess, String user) { + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Request: access for user=%s to resource=%s with privileges=%s", + user, resourceAccess.getResource(), resourceAccess.getPrivileges())); + } + + RangerAccessResourceImpl rangerResource = new RangerAccessResourceImpl(); + //resource.setOwnerUser(); + for (Map.Entry<HawqResource, String> resourceEntry : resourceAccess.getResource().entrySet()) { + rangerResource.setValue(resourceEntry.getKey().name(), resourceEntry.getValue()); + } + + boolean accessAllowed = true; + // iterate over all privileges requested + for (HawqPrivilege privilege : resourceAccess.getPrivileges()) { + // TODO not clear how we will get user groups -- Kerberos case ? + Set<String> userGroups = Collections.emptySet(); + boolean privilegeAuthorized = authorizeResourcePrivilege(rangerResource, privilege.name(), user, userGroups); + // ALL model of evaluation -- all privileges must be authorized for access to be allowed + if (!privilegeAuthorized) { + accessAllowed = false; + break; // terminate early if even a single privilege is not authorized + } + } + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Decision: accessAllowed=%s for user=%s to resource=%s with privileges=%s", + accessAllowed, user, resourceAccess.getResource(), resourceAccess.getPrivileges())); + } + + return accessAllowed; + } + + /** + * Authorizes access of a given type (privilege) to a single resource for a given user. + * + * @param rangerResource resource to authorize access to + * @param accessType privilege requested for a given resource + * @param user user requesting authorization + * @param userGroups groups a user belongs to + * @return true if access is authorized, false otherwise + */ + private boolean authorizeResourcePrivilege(RangerAccessResource rangerResource, String accessType, String user, Set<String> userGroups) { + + Map<String, String> resourceMap = rangerResource.getAsMap(); + String database = resourceMap.get(HawqResource.database.name()); + String schema = resourceMap.get(HawqResource.schema.name()); + int resourceSize = resourceMap.size(); + + // special handling for non-leaf policies + if (accessType.equals(HawqPrivilege.create.name()) && database != null && schema == null && resourceSize == 1) { + accessType = HawqPrivilege.create_schema.toValue(); + LOG.debug("accessType mapped to: create-schema"); + } else if (accessType.equals(HawqPrivilege.usage.name()) && database != null && schema != null && resourceSize == 2) { + accessType = HawqPrivilege.usage_schema.toValue(); + LOG.debug("accessType mapped to: usage-schema"); + } + + RangerAccessRequest rangerRequest = new RangerAccessRequestImpl(rangerResource, accessType, user, userGroups); + RangerAccessResult result = rangerPlugin.isAccessAllowed(rangerRequest); + boolean accessAllowed = result != null && result.getIsAllowed(); + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("--- RangerDecision: accessAllowed=%s for user=%s to resource=%s with privileges=%s, result present=%s", + accessAllowed, user, rangerResource.getAsString(), accessType, result!=null)); + } + + return accessAllowed; + } + + /** + * Validates that authorization requests do not have any missing data. + * + * @param request authorization request + * @throws IllegalArgumentException if any data is missing + */ + private void validateRequest(AuthorizationRequest request) { + LOG.debug("Validating authorization request"); + + if (request == null) { + throw new IllegalArgumentException("request is null"); + } + + if (request.getRequestId() == null) { + throw new IllegalArgumentException("requestId field is missing or null in the request"); + } + + if (StringUtils.isEmpty(request.getUser())) { + throw new IllegalArgumentException("user field is missing or empty in the request"); + } + + if (StringUtils.isEmpty(request.getClientIp())) { + throw new IllegalArgumentException("clientIp field is missing or empty in the request"); + } + + if (StringUtils.isEmpty(request.getContext())) { + throw new IllegalArgumentException("context field is missing or empty in the request"); + } + + Set<ResourceAccess> accessSet = request.getAccess(); + if (CollectionUtils.isEmpty(accessSet)) { + throw new IllegalArgumentException("access field is missing or empty in the request"); + } + + for (ResourceAccess access : accessSet) { + validateResourceAccess(access); + } + + LOG.debug("Successfully validated authorization request"); + } + + /** + * Validates that resource access does not have any missing data. + * + * @param access resource access data + * @throws IllegalArgumentException if any data is missing + */ + private void validateResourceAccess(ResourceAccess access) { + Map<HawqResource, String> resourceMap = access.getResource(); + if (MapUtils.isEmpty(resourceMap)) { + throw new IllegalArgumentException("resource field is missing or empty in the request"); + } + for (Map.Entry<HawqResource, String> resourceEntry : resourceMap.entrySet()) { + if (StringUtils.isEmpty(resourceEntry.getValue())) { + throw new IllegalArgumentException( + String.format("resource value is missing for key=%s in the request", resourceEntry.getKey()) + ); + } + } + if (CollectionUtils.isEmpty(access.getPrivileges())) { + throw new IllegalArgumentException("set of privileges is missing empty in the request"); + } + } + + + + /** + * Sets an instance of the Ranger Plugin for testing. + * + * @param plugin plugin instance to use while testing + */ + void setRangerPlugin(RangerBasePlugin plugin) { + rangerPlugin = plugin; + } + + /** + * Returns the instance of the Ranger Plugin for testing. + * + * @return BaseRangerPlugin instance + */ + RangerBasePlugin getRangerPlugin() { + return rangerPlugin; + } +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/RangerHawqPluginResource.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/RangerHawqPluginResource.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/RangerHawqPluginResource.java new file mode 100644 index 0000000..26a7660 --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/RangerHawqPluginResource.java @@ -0,0 +1,86 @@ +/* + * 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.hawq.ranger.authorization; + +import com.sun.jersey.spi.resource.Singleton; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hawq.ranger.authorization.model.AuthorizationRequest; +import org.apache.hawq.ranger.authorization.model.AuthorizationResponse; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.Date; + +/** + * JAX-RS resource for the authorization endpoint. + */ +@Path("/") +@Singleton +public class RangerHawqPluginResource { + + private static final Log LOG = LogFactory.getLog(RangerHawqPluginResource.class); + + private HawqAuthorizer authorizer; + private String version; + + /** + * Constructor. Creates a new instance of the resource that uses <code>RangerHawqAuthorizer</code>. + */ + public RangerHawqPluginResource() { + this.authorizer = RangerHawqAuthorizer.getInstance(); + } + + + @Path("/version") + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response version() + { + String output = "{\"version\":\"" + Utils.getVersion() + "\"}"; + return Response.status(200).entity(output).build(); + } + + /** + * Authorizes a request to access protected resources with requested privileges. + * @param request authorization request + * @return authorization response + */ + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public AuthorizationResponse authorize(AuthorizationRequest request) + { + if (LOG.isDebugEnabled()) { + LOG.debug("Received authorization request: " + request); + } + + // exceptions are handled by ServiceExceptionMapper + AuthorizationResponse response = authorizer.isAccessAllowed(request); + + if (LOG.isDebugEnabled()) { + LOG.debug("Returning authorization response: " + response); + } + return response; + } +} + + http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/ServiceExceptionMapper.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/ServiceExceptionMapper.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/ServiceExceptionMapper.java new file mode 100644 index 0000000..b983d72 --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/ServiceExceptionMapper.java @@ -0,0 +1,97 @@ +/* + * 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.hawq.ranger.authorization; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +/** + * Maps service exceptions to HTTP response. + */ +@Provider +public class ServiceExceptionMapper implements ExceptionMapper<Throwable> { + + private static final Log LOG = LogFactory.getLog(ServiceExceptionMapper.class); + + @Override + public Response toResponse(Throwable e) { + + LOG.error("Service threw an exception: ", e); + + // default to internal server error (HTTP 500) + Response.Status status = Response.Status.INTERNAL_SERVER_ERROR; + + if (e instanceof IllegalArgumentException) { + status = Response.Status.BAD_REQUEST; + } + + ErrorPayload error = new ErrorPayload(status.getStatusCode(), e.getMessage()); + + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Returning error response: status=%s message=%s", + error.getStatus(), error.getMessage())); + } + + return Response.status(status) + .entity(error) + .type(MediaType.APPLICATION_JSON) + .build(); + } + + /** + * Represents payload to be serialized as JSON into response. + */ + public static class ErrorPayload { + private int status; + private String message; + + /** + * Constructor. + * @param status HTTP error status + * @param message error message + */ + public ErrorPayload(int status, String message) { + this.status = status; + this.message = message; + } + + /** + * Returns status code + * @return status code + */ + public int getStatus() { + return status; + } + + /** + * Returns error message + * @return error message + */ + public String getMessage() { + return message; + } + + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/Utils.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/Utils.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/Utils.java new file mode 100644 index 0000000..86f7fc4 --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/Utils.java @@ -0,0 +1,80 @@ +/* + * 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.hawq.ranger.authorization; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * Utility class for reading values from the property file. + */ +public abstract class Utils { + + public static final String HAWQ = "hawq"; + public static final String UNKNOWN = "unknown"; + public static final String APP_ID_PROPERTY = "ranger.hawq.instance"; + public static final String VERSION_PROPERTY = "version"; + public static final String RANGER_SERVICE_PROPERTY_FILE = "rps.properties"; + + private static final Log LOG = LogFactory.getLog(Utils.class); + private static final Properties properties = readPropertiesFromFile(); + + /** + * Retrieves the app id from the environment variable with the key ranger.hawq.instance + * or from the rps.properties file with the key ranger.hawq.instance + * + * If none exist, hawq is used as the default + * + * @return String id of the app + */ + public static String getAppId() { + return System.getProperty(APP_ID_PROPERTY, properties.getProperty(APP_ID_PROPERTY, HAWQ)); + } + + /** + * Retrieves the version read from the property file. + * + * If none exist, unknown is used as the default + * + * @return version of the service + */ + public static String getVersion() { + return properties.getProperty(VERSION_PROPERTY, UNKNOWN); + } + + /** + * Reads properties from the property file. + * @return properties read from the file + */ + private static Properties readPropertiesFromFile() { + Properties prop = new Properties(); + InputStream inputStream = Utils.class.getClassLoader().getResourceAsStream(RANGER_SERVICE_PROPERTY_FILE); + try { + prop.load(inputStream); + } catch (IOException e) { + LOG.error("Failed to read from: " + RANGER_SERVICE_PROPERTY_FILE); + } + return prop; + } +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/AuthorizationRequest.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/AuthorizationRequest.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/AuthorizationRequest.java new file mode 100644 index 0000000..6e8ab4f --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/AuthorizationRequest.java @@ -0,0 +1,115 @@ +/* + * 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.hawq.ranger.authorization.model; + +import java.util.Set; + +/** + * Model for submitting an authorization request for multiple resources. + */ +public class AuthorizationRequest { + + private Integer requestId; + private String user; + private String clientIp; + private String context; + private Set<ResourceAccess> access; + + /** + * Returns request id. + * @return id of the request + */ + public Integer getRequestId() { + return requestId; + } + + /** + * Sets request id. + * @param requestId id of the request + */ + public void setRequestId(Integer requestId) { + this.requestId = requestId; + } + + /** + * Returns user name for the user submitting the access request. + * @return name of the user + */ + public String getUser() { + return user; + } + + /** + * Sets user name for the user submitting the access request. + * @param user name of the user + */ + public void setUser(String user) { + this.user = user; + } + + /** + * Returns IP address of the client where the user request is made from. + * @return IP address of the user's client + */ + public String getClientIp() { + return clientIp; + } + + /** + * Sets IP address of the client where the user request is made from. + * @param clientIp IP address of the user's client + */ + public void setClientIp(String clientIp) { + this.clientIp = clientIp; + } + + /** + * Returns context of the request, usually a SQL query that the user ran + * @return context of the request + */ + public String getContext() { + return context; + } + + /** + * Sets the context of the request, usually a SQL query that the user ran + * @param context context of the request + */ + public void setContext(String context) { + this.context = context; + } + + /** + * Returns a set of <code>ResourceAccess</code> objects. + * @return s set of <code>ResourceAccess</code> objects + */ + public Set<ResourceAccess> getAccess() { + return access; + } + + /** + * Sets <code>ResourceAccess</code> objects + * @param access a set of <code>ResourceAccess</code> objects + */ + public void setAccess(Set<ResourceAccess> access) { + this.access = access; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/AuthorizationResponse.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/AuthorizationResponse.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/AuthorizationResponse.java new file mode 100644 index 0000000..f989b8d --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/AuthorizationResponse.java @@ -0,0 +1,63 @@ +/* + * 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.hawq.ranger.authorization.model; + +import java.util.Set; + +/** + * Model for response containing authorization decisions for access to multiple resources. + */ +public class AuthorizationResponse { + + private Integer requestId; + private Set<ResourceAccess> access; + + /** + * Returns request id. + * @return id of the request + */ + public Integer getRequestId() { + return requestId; + } + + /** + * Sets request id. + * @param requestId id of the request + */ + public void setRequestId(Integer requestId) { + this.requestId = requestId; + } + + /** + * Returns a set of <code>ResourceAccess</code> objects. + * @return a set of <code>ResourceAccess</code> objects + */ + public Set<ResourceAccess> getAccess() { + return access; + } + + /** + * Sets <code>ResourceAccess</code> objects + * @param access a set of <code>ResourceAccess</code> objects + */ + public void setAccess(Set<ResourceAccess> access) { + this.access = access; + } +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/HawqPrivilege.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/HawqPrivilege.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/HawqPrivilege.java new file mode 100644 index 0000000..ffce67a --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/HawqPrivilege.java @@ -0,0 +1,61 @@ +/* + * 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.hawq.ranger.authorization.model; + +import org.codehaus.jackson.annotate.JsonCreator; +import org.codehaus.jackson.annotate.JsonValue; + +/** + * Model enumeration of types of HAWQ privileges. + */ +public enum HawqPrivilege { + select, + insert, + update, + delete, + references, + usage, + create, + connect, + execute, + temp, + create_schema, + usage_schema, + all; + + /** + * Returns HawqPrivilege type by case-insensitive lookup of the value. + * @param key case insensitive string representation of the privilege + * @return instance of HawqPrivilege + */ + @JsonCreator + public static HawqPrivilege fromString(String key) { + return key == null ? null : HawqPrivilege.valueOf(key.replace('-', '_').toLowerCase()); + } + + /** + * Returns string representation of the enum, replaces underscores with dashes. + * @return string representation of the enum + */ + @JsonValue + public String toValue() { + return name().replace('_', '-'); + } +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/HawqResource.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/HawqResource.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/HawqResource.java new file mode 100644 index 0000000..c9de4e7 --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/HawqResource.java @@ -0,0 +1,46 @@ +/* + * 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.hawq.ranger.authorization.model; + +import org.codehaus.jackson.annotate.JsonCreator; + +/** + * Model enumeration of types of HAWQ resources. + */ +public enum HawqResource { + database, + schema, + table, + sequence, + function, + language, + tablespace, + protocol; + + /** + * Returns HawqResource type by case-insensitive lookup of the value. + * @param key case insensitive string representation of the resource + * @return instance of HawqResource + */ + @JsonCreator + public static HawqResource fromString(String key) { + return key == null ? null : HawqResource.valueOf(key.toLowerCase()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/ResourceAccess.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/ResourceAccess.java b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/ResourceAccess.java new file mode 100644 index 0000000..df1631a --- /dev/null +++ b/ranger-plugin/service/src/main/java/org/apache/hawq/ranger/authorization/model/ResourceAccess.java @@ -0,0 +1,85 @@ +/* + * 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.hawq.ranger.authorization.model; + +import org.apache.commons.lang.builder.ToStringBuilder; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Model object for requesting access to a single resource. + */ +public class ResourceAccess { + + private Map<HawqResource, String> resource; + private Set<HawqPrivilege> privileges; + private boolean allowed = false; + + public Set<HawqPrivilege> getPrivileges() { + return privileges; + } + + public void setPrivileges(Set<HawqPrivilege> privileges) { + this.privileges = privileges; + } + + public boolean isAllowed() { + return allowed; + } + + public void setAllowed(boolean allowed) { + this.allowed = allowed; + } + + public Map<HawqResource, String> getResource() { + return resource; + } + + public void setResource(Map<HawqResource, String> resource) { + this.resource = resource; + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("resource", resource) + .append("privileges", privileges) + .append("allowed", allowed) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ResourceAccess that = (ResourceAccess) o; + return allowed == that.allowed && + Objects.equals(resource, that.resource) && + Objects.equals(privileges, that.privileges); + } + + @Override + public int hashCode() { + return Objects.hash(resource, privileges, allowed); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/resources/log4j.properties b/ranger-plugin/service/src/main/resources/log4j.properties new file mode 100644 index 0000000..6bbdaed --- /dev/null +++ b/ranger-plugin/service/src/main/resources/log4j.properties @@ -0,0 +1,42 @@ +# 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. + +# see debug messages during unit tests +project.root.logger=DEBUG,console + +# suppress all logging output during unit tests +#project.root.logger=FATAL,devnull + +# +# Loggers +# +log4j.rootLogger=${project.root.logger} + +# ignore most errors from the Apache Ranger and Hadoop for unit tests +log4j.logger.org.apache.ranger=FATAL +log4j.logger.org.apache.hadoop=FATAL + +# +# Appenders +# + +# nothing +log4j.appender.devnull=org.apache.log4j.varia.NullAppender + +# console +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.target=System.err +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2}: %m%n \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/resources/ranger-hawq-security.xml ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/resources/ranger-hawq-security.xml b/ranger-plugin/service/src/main/resources/ranger-hawq-security.xml new file mode 100644 index 0000000..46dd75d --- /dev/null +++ b/ranger-plugin/service/src/main/resources/ranger-hawq-security.xml @@ -0,0 +1,92 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/xsl" href="configuration.xsl"?> + +<!-- + 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. +--> + +<configuration xmlns:xi="http://www.w3.org/2001/XInclude"> + <property> + <name>ranger.plugin.hawq.service.name</name> + <value>hawq</value> + <description> + Name of the Ranger service containing policies for this HAWQ instance + </description> + </property> + + <property> + <name>ranger.plugin.hawq.policy.source.impl</name> + <value>org.apache.ranger.admin.client.RangerAdminRESTClient</value> + <description> + Class to retrieve policies from the source + </description> + </property> + + <property> + <name>ranger.plugin.hawq.policy.rest.url</name> + <value>http://localhost:6080</value> + <description> + URL to Ranger Admin + </description> + </property> + + <property> + <name>ranger.plugin.hawq.policy.rest.ssl.config.file</name> + <value>/usr/local/hawq/ranger/etc/ranger-policymgr-ssl.xml</value> + <description> + Path to the file containing SSL details to contact Ranger Admin + </description> + </property> + + <property> + <name>ranger.plugin.hawq.policy.pollIntervalMs</name> + <value>30000</value> + <description> + How often to poll for changes in policies? + </description> + </property> + + <property> + <name>ranger.plugin.hawq.policy.cache.dir</name> + <value>/usr/local/hawq/ranger/policycache</value> + <description> + Directory where Ranger policies are cached after successful retrieval from the source + </description> + </property> + + <!-- + <property> + <name>xasecure.hive.update.xapolicies.on.grant.revoke</name> + <value>true</value> + <description>Should Hive plugin update Ranger policies for updates to permissions done using GRANT/REVOKE?</description> + </property> + --> + <property> + <name>ranger.plugin.hawq.policy.rest.client.connection.timeoutMs</name> + <value>120000</value> + <description> + RangerRESTClient Connection Timeout in Milliseconds + </description> + </property> + + <property> + <name>ranger.plugin.hawq.policy.rest.client.read.timeoutMs</name> + <value>30000</value> + <description> + RangerRESTClient read Timeout in Milliseconds + </description> + </property> +</configuration> http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/resources/rps.properties ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/resources/rps.properties b/ranger-plugin/service/src/main/resources/rps.properties new file mode 100644 index 0000000..9e2b1f4 --- /dev/null +++ b/ranger-plugin/service/src/main/resources/rps.properties @@ -0,0 +1,17 @@ +# 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. + +ranger.hawq.instance=hawq +version=${project.version} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/main/webapp/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/main/webapp/WEB-INF/web.xml b/ranger-plugin/service/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..36c976f --- /dev/null +++ b/ranger-plugin/service/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,72 @@ +<?xml version="1.0"?> + +<!-- +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. +--> + +<web-app version="3.0" + xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> + + <!-- + This is the HAWQ Ranger Plugin Service webapp xml descriptor + + servlet-class Jersey entrypoint class + init-param com.sun.jersey.config.property.packages + Tells Jersey where are the REST components of this webapp + jersey.config.server.provider.scanning.recursive + Tells Jersey to recusively scan package for REST resources + load-on-startup Initialize the webapp on app server startup + servlet-mapping Maps the path of the servlet (ranger-plugin/*) + listener A class called after the webapp was initialized and before it's about to go down + --> + + <servlet> + <servlet-name>HAWQ_Ranger_Plugin_Service</servlet-name> + <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> + <init-param> + <param-name>com.sun.jersey.config.property.packages</param-name> + <param-value>org.apache.hawq.ranger.authorization</param-value> + </init-param> + <init-param> + <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> + <param-value>true</param-value> + </init-param> + <load-on-startup>1</load-on-startup> + </servlet> + <servlet-mapping> + <servlet-name>HAWQ_Ranger_Plugin_Service</servlet-name> + <url-pattern>/*</url-pattern> + </servlet-mapping> + + <!-- + <listener> + <listener-class>org.apache.hawq.pxf.service.rest.ServletLifecycleListener</listener-class> + </listener> + --> + <!-- log4j configuration + Log4jConfigListener looks for a file under log4jConfigLocation. + When not using absolute path, the path starts from the webapp root directory. + If this file cannot be read, log4j will revert to using the default + pxf-log4j.properties inside the webapp. --> + <context-param> + <param-name>log4jConfigLocation</param-name> + <param-value>/etc/pxf/conf/pxf-log4j.properties</param-value> + </context-param> +</web-app> http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7f36b35b/ranger-plugin/service/src/test/java/org/apache/hawq/ranger/authorization/RangerHawqAuthorizerAppIdTest.java ---------------------------------------------------------------------- diff --git a/ranger-plugin/service/src/test/java/org/apache/hawq/ranger/authorization/RangerHawqAuthorizerAppIdTest.java b/ranger-plugin/service/src/test/java/org/apache/hawq/ranger/authorization/RangerHawqAuthorizerAppIdTest.java new file mode 100644 index 0000000..461864e --- /dev/null +++ b/ranger-plugin/service/src/test/java/org/apache/hawq/ranger/authorization/RangerHawqAuthorizerAppIdTest.java @@ -0,0 +1,39 @@ +/* + * 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.hawq.ranger.authorization; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(Utils.class) +public class RangerHawqAuthorizerAppIdTest { + + @Test + public void testAppIdIsSet() { + PowerMockito.mockStatic(Utils.class); + when(Utils.getAppId()).thenReturn("foo"); + assertEquals("foo", RangerHawqAuthorizer.getInstance().getRangerPlugin().getAppId()); + } +}
