/*
   * (non-Javadoc)
   *
   * @see org.apache.solr.security.SolrAuthorizationPlugin#init(java.util.Map)
   */
  @Override
  public void init(Map<String, Object> initInfo) {
    logger.info("init()");

    try {
      solrPlugin.init();

      useProxyIP = RangerConfiguration.getInstance().getBoolean(PROP_USE_PROXY_IP, useProxyIP);
      proxyIPHeader = RangerConfiguration.getInstance().get(PROP_PROXY_IP_HEADER, proxyIPHeader);

    } catch (Throwable t) {
      logger.fatal("Error init", t);
    }
  }
  RangerPolicyRepository(ServicePolicies servicePolicies, RangerPolicyEngineOptions options) {
    super();

    serviceName = servicePolicies.getServiceName();
    serviceDef = servicePolicies.getServiceDef();
    policies = Collections.unmodifiableList(servicePolicies.getPolicies());
    policyVersion =
        servicePolicies.getPolicyVersion() != null
            ? servicePolicies.getPolicyVersion().longValue()
            : -1;

    List<RangerContextEnricher> contextEnrichers = new ArrayList<RangerContextEnricher>();
    if (!options.disableContextEnrichers
        && !CollectionUtils.isEmpty(serviceDef.getContextEnrichers())) {
      for (RangerServiceDef.RangerContextEnricherDef enricherDef :
          serviceDef.getContextEnrichers()) {
        if (enricherDef == null) {
          continue;
        }

        RangerContextEnricher contextEnricher = buildContextEnricher(enricherDef);

        if (contextEnricher != null) {
          contextEnrichers.add(contextEnricher);
        }
      }
    }
    this.contextEnrichers = Collections.unmodifiableList(contextEnrichers);

    List<RangerPolicyEvaluator> policyEvaluators = new ArrayList<RangerPolicyEvaluator>();
    for (RangerPolicy policy : servicePolicies.getPolicies()) {
      if (!policy.getIsEnabled()) {
        continue;
      }

      RangerPolicyEvaluator evaluator = buildPolicyEvaluator(policy, serviceDef, options);

      if (evaluator != null) {
        policyEvaluators.add(evaluator);
      }
    }
    Collections.sort(policyEvaluators);
    this.policyEvaluators = Collections.unmodifiableList(policyEvaluators);

    String propertyName = "ranger.plugin." + serviceName + ".policyengine.auditcachesize";

    if (options.cacheAuditResults) {
      int auditResultCacheSize =
          RangerConfiguration.getInstance()
              .getInt(propertyName, RANGER_POLICYENGINE_AUDITRESULT_CACHE_SIZE);

      accessAuditCache =
          Collections.synchronizedMap(new CacheMap<String, Boolean>(auditResultCacheSize));
    } else {
      accessAuditCache = null;
    }
  }
  @Override
  public void init(String serviceName, String appId, String configPropertyPrefix) {
    if (LOG.isDebugEnabled()) {
      LOG.debug("==> RangerAdminJersey2RESTClient.init(" + configPropertyPrefix + ")");
    }

    _serviceName = serviceName;
    _pluginId = _utils.getPluginId(serviceName, appId);
    _baseUrl = _utils.getPolicyRestUrl(configPropertyPrefix);
    _sslConfigFileName = _utils.getSsslConfigFileName(configPropertyPrefix);
    _isSSL = _utils.isSsl(_baseUrl);
    _restClientConnTimeOutMs =
        RangerConfiguration.getInstance()
            .getInt(configPropertyPrefix + ".policy.rest.client.connection.timeoutMs", 120 * 1000);
    _restClientReadTimeOutMs =
        RangerConfiguration.getInstance()
            .getInt(configPropertyPrefix + ".policy.rest.client.read.timeoutMs", 30 * 1000);

    LOG.info(
        "Init params: "
            + String.format(
                "Base URL[%s], SSL Congig filename[%s], ServiceName=[%s]",
                _baseUrl, _sslConfigFileName, _serviceName));

    _client = getClient();
    _client.property(ClientProperties.CONNECT_TIMEOUT, _restClientConnTimeOutMs);
    _client.property(ClientProperties.READ_TIMEOUT, _restClientReadTimeOutMs);

    if (LOG.isDebugEnabled()) {
      LOG.debug(
          "<== RangerAdminJersey2RESTClient.init("
              + configPropertyPrefix
              + "): "
              + _client.toString());
    }
  }
  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
    gsonBuilder =
        new GsonBuilder()
            .setDateFormat("yyyyMMdd-HH:mm:ss.SSS-Z")
            .setPrettyPrinting()
            .registerTypeAdapter(RangerAccessRequest.class, new RangerAccessRequestDeserializer())
            .registerTypeAdapter(RangerAccessResource.class, new RangerResourceDeserializer())
            .create();

    // For setting up auditProvider
    Properties auditProperties = new Properties();

    String AUDIT_PROPERTIES_FILE = "xasecure-audit.properties";

    File propFile = new File(AUDIT_PROPERTIES_FILE);

    if (propFile.exists()) {
      System.out.println("Loading Audit properties file" + AUDIT_PROPERTIES_FILE);

      auditProperties.load(new FileInputStream(propFile));
    } else {
      System.out.println("Audit properties file missing: " + AUDIT_PROPERTIES_FILE);

      auditProperties.setProperty(
          "xasecure.audit.jpa.javax.persistence.jdbc.url",
          "jdbc:mysql://node-1:3306/xasecure_audit");
      auditProperties.setProperty("xasecure.audit.jpa.javax.persistence.jdbc.user", "xalogger");
      auditProperties.setProperty("xasecure.audit.jpa.javax.persistence.jdbc.password", "xalogger");
      auditProperties.setProperty(
          "xasecure.audit.jpa.javax.persistence.jdbc.driver", "com.mysql.jdbc.Driver");

      auditProperties.setProperty(
          "xasecure.audit.is.enabled", "false"); // Set this to true to enable audit logging
      auditProperties.setProperty("xasecure.audit.log4j.is.enabled", "false");
      auditProperties.setProperty("xasecure.audit.log4j.is.async", "false");
      auditProperties.setProperty("xasecure.audit.log4j.async.max.queue.size", "100000");
      auditProperties.setProperty("xasecure.audit.log4j.async.max.flush.interval.ms", "30000");
      auditProperties.setProperty("xasecure.audit.db.is.enabled", "false");
      auditProperties.setProperty("xasecure.audit.db.is.async", "false");
      auditProperties.setProperty("xasecure.audit.db.async.max.queue.size", "100000");
      auditProperties.setProperty("xasecure.audit.db.async.max.flush.interval.ms", "30000");
      auditProperties.setProperty("xasecure.audit.db.batch.size", "100");
    }

    AuditProviderFactory.getInstance()
        .init(auditProperties, "hdfs"); // second parameter does not matter for v2

    AuditHandler provider = AuditProviderFactory.getAuditProvider();

    System.out.println("provider=" + provider.toString());

    File file = File.createTempFile("ranger-admin-test-site", ".xml");
    file.deleteOnExit();

    FileOutputStream outStream = new FileOutputStream(file);
    OutputStreamWriter writer = new OutputStreamWriter(outStream);

    /*
    // For setting up TestTagProvider

    writer.write("<configuration>\n" +
    		"        <property>\n" +
    		"                <name>ranger.plugin.tag.policy.rest.url</name>\n" +
    		"                <value>http://os-def:6080</value>\n" +
    		"        </property>\n" +
    		"        <property>\n" +
    		"                <name>ranger.externalurl</name>\n" +
    		"                <value>http://os-def:6080</value>\n" +
    		"        </property>\n" +
    		"</configuration>\n");
    		*/

    writer.write(
        "<configuration>\n"
            +
            /*
            // For setting up TestTagProvider
            "        <property>\n" +
            "                <name>ranger.plugin.tag.policy.rest.url</name>\n" +
            "                <value>http://os-def:6080</value>\n" +
            "        </property>\n" +
            "        <property>\n" +
            "                <name>ranger.externalurl</name>\n" +
            "                <value>http://os-def:6080</value>\n" +
            "        </property>\n" +
            */
            // For setting up x-forwarded-for for Hive
            "        <property>\n"
            + "                <name>ranger.plugin.hive.use.x-forwarded-for.ipaddress</name>\n"
            + "                <value>true</value>\n"
            + "        </property>\n"
            + "        <property>\n"
            + "                <name>ranger.plugin.hive.trusted.proxy.ipaddresses</name>\n"
            + "                <value>255.255.255.255; 128.101.101.101;128.101.101.99</value>\n"
            + "        </property>\n"
            + "</configuration>\n");
    writer.close();

    RangerConfiguration config = RangerConfiguration.getInstance();
    config.addResource(new org.apache.hadoop.fs.Path(file.toURI()));
  }
  private void runTests(InputStreamReader reader, String testName) {
    PolicyEngineTestCase testCase = gsonBuilder.fromJson(reader, PolicyEngineTestCase.class);

    assertTrue(
        "invalid input: " + testName,
        testCase != null
            && testCase.serviceDef != null
            && testCase.policies != null
            && testCase.tests != null);

    ServicePolicies servicePolicies = new ServicePolicies();
    servicePolicies.setServiceName(testCase.serviceName);
    servicePolicies.setServiceDef(testCase.serviceDef);
    servicePolicies.setPolicies(testCase.policies);

    if (null != testCase.tagPolicyInfo) {
      ServicePolicies.TagPolicies tagPolicies = new ServicePolicies.TagPolicies();
      tagPolicies.setServiceName(testCase.tagPolicyInfo.serviceName);
      tagPolicies.setServiceDef(testCase.tagPolicyInfo.serviceDef);
      tagPolicies.setPolicies(testCase.tagPolicyInfo.tagPolicies);

      servicePolicies.setTagPolicies(tagPolicies);
    }

    RangerPolicyEngineOptions policyEngineOptions = new RangerPolicyEngineOptions();

    policyEngineOptions.disableTagPolicyEvaluation = false;

    boolean useForwardedIPAddress =
        RangerConfiguration.getInstance()
            .getBoolean("ranger.plugin.hive.use.x-forwarded-for.ipaddress", false);
    String trustedProxyAddressString =
        RangerConfiguration.getInstance().get("ranger.plugin.hive.trusted.proxy.ipaddresses");
    String[] trustedProxyAddresses = StringUtils.split(trustedProxyAddressString, ';');
    if (trustedProxyAddresses != null) {
      for (int i = 0; i < trustedProxyAddresses.length; i++) {
        trustedProxyAddresses[i] = trustedProxyAddresses[i].trim();
      }
    }
    policyEngine = new RangerPolicyEngineImpl(testName, servicePolicies, policyEngineOptions);
    policyEngine.setUseForwardedIPAddress(useForwardedIPAddress);
    policyEngine.setTrustedProxyAddresses(trustedProxyAddresses);

    RangerAccessRequest request = null;

    for (TestData test : testCase.tests) {
      request = test.request;
      if (request.getContext().containsKey(RangerAccessRequestUtil.KEY_CONTEXT_TAGS)
          || request
              .getContext()
              .containsKey(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES)) {
        // Create a new AccessRequest
        RangerAccessRequestImpl newRequest =
            new RangerAccessRequestImpl(
                request.getResource(),
                request.getAccessType(),
                request.getUser(),
                request.getUserGroups());

        newRequest.setClientType(request.getClientType());
        newRequest.setAccessTime(request.getAccessTime());
        newRequest.setAction(request.getAction());
        newRequest.setRemoteIPAddress(request.getRemoteIPAddress());
        newRequest.setForwardedAddresses(request.getForwardedAddresses());
        newRequest.setRequestData(request.getRequestData());
        newRequest.setSessionId(request.getSessionId());

        Map<String, Object> context = request.getContext();
        String tagsJsonString = (String) context.get(RangerAccessRequestUtil.KEY_CONTEXT_TAGS);
        context.remove(RangerAccessRequestUtil.KEY_CONTEXT_TAGS);

        if (!StringUtils.isEmpty(tagsJsonString)) {
          try {
            Type listType = new TypeToken<List<RangerTag>>() {}.getType();
            List<RangerTag> tagList = gsonBuilder.fromJson(tagsJsonString, listType);

            context.put(RangerAccessRequestUtil.KEY_CONTEXT_TAGS, tagList);
          } catch (Exception e) {
            System.err.println(
                "TestPolicyEngine.runTests(): error parsing TAGS JSON string in file "
                    + testName
                    + ", tagsJsonString="
                    + tagsJsonString
                    + ", exception="
                    + e);
          }
        } else if (request
            .getContext()
            .containsKey(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES)) {
          String resourcesJsonString =
              (String) context.get(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES);
          context.remove(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES);
          if (!StringUtils.isEmpty(resourcesJsonString)) {
            try {
              /*
              Reader stringReader = new StringReader(resourcesJsonString);
              RangerRequestedResources resources = gsonBuilder.fromJson(stringReader, RangerRequestedResources.class);
              */

              Type myType = new TypeToken<RangerRequestedResources>() {}.getType();
              RangerRequestedResources resources =
                  gsonBuilder.fromJson(resourcesJsonString, myType);

              context.put(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES, resources);
            } catch (Exception e) {
              System.err.println(
                  "TestPolicyEngine.runTests(): error parsing REQUESTED_RESOURCES string in file "
                      + testName
                      + ", resourcesJsonString="
                      + resourcesJsonString
                      + ", exception="
                      + e);
            }
          }
        }
        newRequest.setContext(context);

        // accessResource.ServiceDef is set here, so that we can skip call to
        // policyEngine.preProcess() which
        // sets the serviceDef in the resource AND calls enrichers. We dont want enrichers to be
        // called when
        // context already contains tags -- This may change when we want enrichers to enrich request
        // in the
        // presence of tags!!!

        // Safe cast
        RangerAccessResourceImpl accessResource = (RangerAccessResourceImpl) request.getResource();
        accessResource.setServiceDef(testCase.serviceDef);

        request = newRequest;

      } else if (!request
          .getContext()
          .containsKey(RangerAccessRequestUtil.KEY_CONTEXT_REQUESTED_RESOURCES)) {
        policyEngine.preProcess(request);
      }

      RangerAccessResultProcessor auditHandler = new RangerDefaultAuditHandler();

      if (test.result != null) {
        RangerAccessResult expected = test.result;
        RangerAccessResult result = policyEngine.isAccessAllowed(request, auditHandler);

        assertNotNull("result was null! - " + test.name, result);
        assertEquals(
            "isAllowed mismatched! - " + test.name, expected.getIsAllowed(), result.getIsAllowed());
        assertEquals(
            "isAudited mismatched! - " + test.name, expected.getIsAudited(), result.getIsAudited());
        assertEquals(
            "policyId mismatched! - " + test.name, expected.getPolicyId(), result.getPolicyId());
      }

      if (test.dataMaskResult != null) {
        RangerDataMaskResult expected = test.dataMaskResult;
        RangerDataMaskResult result = policyEngine.evalDataMaskPolicies(request, auditHandler);

        assertNotNull("result was null! - " + test.name, result);
        assertEquals(
            "maskType mismatched! - " + test.name, expected.getMaskType(), result.getMaskType());
        assertEquals(
            "maskCondition mismatched! - " + test.name,
            expected.getMaskCondition(),
            result.getMaskCondition());
        assertEquals(
            "maskedValue mismatched! - " + test.name,
            expected.getMaskedValue(),
            result.getMaskedValue());
        assertEquals(
            "policyId mismatched! - " + test.name, expected.getPolicyId(), result.getPolicyId());
      }

      if (test.rowFilterResult != null) {
        RangerRowFilterResult expected = test.rowFilterResult;
        RangerRowFilterResult result = policyEngine.evalRowFilterPolicies(request, auditHandler);

        assertNotNull("result was null! - " + test.name, result);
        assertEquals(
            "filterExpr mismatched! - " + test.name,
            expected.getFilterExpr(),
            result.getFilterExpr());
        assertEquals(
            "policyId mismatched! - " + test.name, expected.getPolicyId(), result.getPolicyId());
      }

      if (test.resourceAccessInfo != null) {
        RangerResourceAccessInfo expected = new RangerResourceAccessInfo(test.resourceAccessInfo);
        RangerResourceAccessInfo result = policyEngine.getResourceAccessInfo(test.request);

        assertNotNull("result was null! - " + test.name, result);
        assertEquals(
            "allowedUsers mismatched! - " + test.name,
            expected.getAllowedUsers(),
            result.getAllowedUsers());
        assertEquals(
            "allowedGroups mismatched! - " + test.name,
            expected.getAllowedGroups(),
            result.getAllowedGroups());
        assertEquals(
            "deniedUsers mismatched! - " + test.name,
            expected.getDeniedUsers(),
            result.getDeniedUsers());
        assertEquals(
            "deniedGroups mismatched! - " + test.name,
            expected.getDeniedGroups(),
            result.getDeniedGroups());
      }
    }
  }