From acaf9d54ad962e02616a24a09ae7fd63b95f65aa Mon Sep 17 00:00:00 2001
From: cdanger <cdanger@users.noreply.github.com>
Date: Sun, 28 Feb 2021 21:33:59 +0100
Subject: [PATCH] Simplied JSON schema loading with new
 ClasspathAwareSchemaClient from org.everit.json.schema library

---
 .../xacml/json/model/XacmlJsonUtils.java      | 234 ++++++++----------
 .../xacml/json/model/Request.schema.json      |   2 +-
 2 files changed, 107 insertions(+), 129 deletions(-)

diff --git a/src/main/java/org/ow2/authzforce/xacml/json/model/XacmlJsonUtils.java b/src/main/java/org/ow2/authzforce/xacml/json/model/XacmlJsonUtils.java
index 90f4adf..35f826f 100644
--- a/src/main/java/org/ow2/authzforce/xacml/json/model/XacmlJsonUtils.java
+++ b/src/main/java/org/ow2/authzforce/xacml/json/model/XacmlJsonUtils.java
@@ -17,11 +17,6 @@
  */
 package org.ow2.authzforce.xacml.json.model;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
 import org.everit.json.schema.Schema;
 import org.everit.json.schema.loader.SchemaClient;
 import org.everit.json.schema.loader.SchemaLoader;
@@ -29,141 +24,124 @@ import org.json.JSONArray;
 import org.json.JSONObject;
 import org.json.JSONTokener;
 
+import java.io.IOException;
+import java.io.InputStream;
+
 /**
  * Instances of JSON schema as defined by JSON Profile of XACML 3.0
  *
  */
 public final class XacmlJsonUtils
 {
-	private XacmlJsonUtils()
-	{
-		// hide constructor
-	}
-
-	/**
-	 * JSON schema for validating Requests according to JSON Profile of XACML 3.0
-	 */
-	public static final Schema REQUEST_SCHEMA;
+    private static final SchemaClient CLASSPATH_AWARE_SCHEMA_CLIENT = SchemaClient.classPathAwareClient();
+    private static Schema loadSchema(String schemaFilenameRelativeToThisClass) {
+        try (InputStream inputStream = XacmlJsonUtils.class.getResourceAsStream(schemaFilenameRelativeToThisClass))
+        {
+            final JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream));
+            return SchemaLoader.builder().schemaJson(rawSchema).schemaClient(CLASSPATH_AWARE_SCHEMA_CLIENT).resolutionScope("classpath://org/ow2/authzforce/xacml/json/model/").build().load().build();
+        } catch (final IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
 
-	/**
-	 * JSON schema for validating Responses according to JSON Profile of XACML 3.0
-	 */
-	public static final Schema RESPONSE_SCHEMA;
+    /**
+     * JSON schema for validating Requests according to JSON Profile of XACML 3.0
+     */
+    public static final Schema REQUEST_SCHEMA;
 
-	/**
-	 * JSON schema for validating Policies according to AuthzForce/JSON policy format for XACML Policy(Set) (see Policy.schema.json)
-	 */
-	public static final Schema POLICY_SCHEMA;
+    /**
+     * JSON schema for validating Responses according to JSON Profile of XACML 3.0
+     */
+    public static final Schema RESPONSE_SCHEMA;
 
-	static
-	{
-		final Map<String, String> mutableCatalogMap = new HashMap<>();
-		mutableCatalogMap.put("https://raw.githubusercontent.com/authzforce/xacml-json-model/master/src/main/resources/org/ow2/authzforce/xacml/json/model/common-std.schema.json", "classpath:org/ow2/authzforce/xacml/json/model/common-std.schema.json");
-		mutableCatalogMap.put("https://raw.githubusercontent.com/authzforce/xacml-json-model/master/src/main/resources/org/ow2/authzforce/xacml/json/model/common-ng.schema.json", "classpath:org/ow2/authzforce/xacml/json/model/common-ng.schema.json");
-		final SchemaClient schemaClient = new SpringBasedJsonSchemaClient(mutableCatalogMap);
-		try (InputStream inputStream = SpringBasedJsonSchemaClient.class.getResourceAsStream("Request.schema.json"))
-		{
-			final JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream));
-			// final SchemaLoader schemaLoader = schemaLoaderBuilder.schemaJson(rawSchema).build();
-			REQUEST_SCHEMA = SchemaLoader.load(rawSchema, schemaClient); // schemaLoader.load().build();
-		}
-		catch (final IOException e)
-		{
-			throw new RuntimeException(e);
-		}
+    /**
+     * JSON schema for validating Policies according to AuthzForce/JSON policy format for XACML Policy(Set) (see Policy.schema.json)
+     */
+    public static final Schema POLICY_SCHEMA;
 
-		try (InputStream inputStream = SpringBasedJsonSchemaClient.class.getResourceAsStream("Response.schema.json"))
-		{
-			final JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream));
-			RESPONSE_SCHEMA = SchemaLoader.load(rawSchema/*, schemaClient*/);
-		}
-		catch (final IOException e)
-		{
-			throw new RuntimeException(e);
-		}
+    static
+    {
+        REQUEST_SCHEMA = loadSchema("Request.schema.json");
+        RESPONSE_SCHEMA = loadSchema("Response.schema.json");
+        POLICY_SCHEMA = loadSchema("Policy.schema.json");
+    }
 
-		try (InputStream inputStream = SpringBasedJsonSchemaClient.class.getResourceAsStream("Policy.schema.json"))
-		{
-			final JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream));
-			POLICY_SCHEMA = SchemaLoader.load(rawSchema/*, schemaClient*/);
-		}
-		catch (final IOException e)
-		{
-			throw new RuntimeException(e);
-		}
-	}
+    /**
+     * Canonicalize a XACML/JSON response, typically for comparison with another one. In particular, it removes every Result's status as we choose to ignore the Status. Indeed, a PDP implementation
+     * might return a perfectly XACML-compliant response but with extra StatusCode/Message/Detail that we would not expect.
+     *
+     * WARNING: this method modifies the content of {@code xacmlJsonResponse} directly
+     *
+     * @param xacmlJsonResponse
+     *            input XACML Response
+     * @return canonicalized response
+     */
+    public static JSONObject canonicalizeResponse(final JSONObject xacmlJsonResponse)
+    {
+        /*
+         * We iterate over all results, because for each results, we don't compare everything. In particular, we choose to ignore the StatusMessage, StatusDetail and any nested StatusCode. Indeed, a
+         * PDP implementation might return a perfectly XACML-compliant response but with extra StatusCode/Message/Detail that we would not expect.
+         */
+        for (final Object resultObj : xacmlJsonResponse.getJSONArray("Response"))
+        {
+            final JSONObject resultJsonObj = (JSONObject) resultObj;
+            // Status
+            final JSONObject statusJsonObj = resultJsonObj.optJSONObject("Status");
+            if (statusJsonObj != null)
+            {
+                // remove Status if StatusCode OK (optional, default implicit therefore useless)
+                final JSONObject statusCodeJsonObj = statusJsonObj.getJSONObject("StatusCode");
+                final String statusCodeVal = statusCodeJsonObj.getString("Value");
+                if (statusCodeVal.equals("urn:oasis:names:tc:xacml:1.0:status:ok"))
+                {
+                    // Status OK is useless, simplify
+                    resultJsonObj.remove("Status");
+                } else
+                {
+                    // remove any nested status code, StatusMessage and StatusDetail
+                    statusCodeJsonObj.remove("StatusCode");
+                    statusJsonObj.remove("StatusMessage");
+                    statusJsonObj.remove("StatusDetail");
+                }
+            }
 
-	/**
-	 * Canonicalize a XACML/JSON response, typically for comparison with another one. In particular, it removes every Result's status as we choose to ignore the Status. Indeed, a PDP implementation
-	 * might return a perfectly XACML-compliant response but with extra StatusCode/Message/Detail that we would not expect.
-	 * 
-	 * WARNING: this method modifies the content of {@code xacmlJsonResponse} directly
-	 * 
-	 * @param xacmlJsonResponse
-	 *            input XACML Response
-	 * @return canonicalized response
-	 */
-	public static JSONObject canonicalizeResponse(final JSONObject xacmlJsonResponse)
-	{
-		/*
-		 * We iterate over all results, because for each results, we don't compare everything. In particular, we choose to ignore the StatusMessage, StatusDetail and any nested StatusCode. Indeed, a
-		 * PDP implementation might return a perfectly XACML-compliant response but with extra StatusCode/Message/Detail that we would not expect.
-		 */
-		for (final Object resultObj : xacmlJsonResponse.getJSONArray("Response"))
-		{
-			final JSONObject resultJsonObj = (JSONObject) resultObj;
-			// Status
-			final JSONObject statusJsonObj = resultJsonObj.optJSONObject("Status");
-			if (statusJsonObj != null)
-			{
-				// remove Status if StatusCode OK (optional, default implicit therefore useless)
-				final JSONObject statusCodeJsonObj = statusJsonObj.getJSONObject("StatusCode");
-				final String statusCodeVal = statusCodeJsonObj.getString("Value");
-				if (statusCodeVal.equals("urn:oasis:names:tc:xacml:1.0:status:ok"))
-				{
-					// Status OK is useless, simplify
-					resultJsonObj.remove("Status");
-				}
-				else
-				{
-					// remove any nested status code, StatusMessage and StatusDetail
-					statusCodeJsonObj.remove("StatusCode");
-					statusJsonObj.remove("StatusMessage");
-					statusJsonObj.remove("StatusDetail");
-				}
-			}
+            // remove empty Category array if any
+            final JSONArray jsonArrayOfAttCats = resultJsonObj.optJSONArray("Category");
+            if (jsonArrayOfAttCats != null)
+            {
+                if (jsonArrayOfAttCats.length() == 0)
+                {
+                    resultJsonObj.remove("Category");
+                } else
+                {
+                    /*
+                     * Remove any IncludeInResult property which is useless and optional in XACML/JSON. (NB.: IncludeInResult is mandatory in XACML/XML schema but optional in JSON Profile).
+                     */
+                    for (final Object attCatJson : jsonArrayOfAttCats)
+                    {
+                        assert attCatJson instanceof JSONObject;
+                        final JSONObject attCatJsonObj = (JSONObject) attCatJson;
+                        final JSONArray jsonArrayOfAtts = attCatJsonObj.optJSONArray("Attribute");
+                        if (jsonArrayOfAtts != null)
+                        {
+                            jsonArrayOfAtts.forEach(attJson ->
+                            {
+                                assert attJson instanceof JSONObject;
+                                final JSONObject attJsonObj = (JSONObject) attJson;
+                                attJsonObj.remove("IncludeInResult");
+                            });
+                        }
+                    }
+                }
+            }
+        }
 
-			// remove empty Category array if any
-			final JSONArray jsonArrayOfAttCats = resultJsonObj.optJSONArray("Category");
-			if (jsonArrayOfAttCats != null)
-			{
-				if (jsonArrayOfAttCats.length() == 0)
-				{
-					resultJsonObj.remove("Category");
-				}
-				else
-				{
-					/*
-					 * Remove any IncludeInResult property which is useless and optional in XACML/JSON. (NB.: IncludeInResult is mandatory in XACML/XML schema but optional in JSON Profile).
-					 */
-					for (final Object attCatJson : jsonArrayOfAttCats)
-					{
-						assert attCatJson instanceof JSONObject;
-						final JSONObject attCatJsonObj = (JSONObject) attCatJson;
-						final JSONArray jsonArrayOfAtts = attCatJsonObj.optJSONArray("Attribute");
-						if (jsonArrayOfAtts != null)
-						{
-							jsonArrayOfAtts.forEach(attJson -> {
-								assert attJson instanceof JSONObject;
-								final JSONObject attJsonObj = (JSONObject) attJson;
-								attJsonObj.remove("IncludeInResult");
-							});
-						}
-					}
-				}
-			}
-		}
+        return xacmlJsonResponse;
+    }
 
-		return xacmlJsonResponse;
-	}
+    private XacmlJsonUtils()
+    {
+        // hide constructor
+    }
 }
diff --git a/src/main/resources/org/ow2/authzforce/xacml/json/model/Request.schema.json b/src/main/resources/org/ow2/authzforce/xacml/json/model/Request.schema.json
index 1183536..c101a43 100644
--- a/src/main/resources/org/ow2/authzforce/xacml/json/model/Request.schema.json
+++ b/src/main/resources/org/ow2/authzforce/xacml/json/model/Request.schema.json
@@ -80,7 +80,7 @@
 					"type": "array",
 					"items": 
 					{
-						"$ref": "common-std_.schema.json#/definitions/AttributeCategoryType"
+						"$ref": "common-std.schema.json#/definitions/AttributeCategoryType"
 					},
 
 					"minItems": 1
-- 
GitLab