From 9acf3c2e8aca9016daf76785747d838cdc5b0330 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Mon, 9 Jul 2018 10:11:25 +0200 Subject: add SL20 connecter-backend in a first beta version (getCertificate looks good, create signature is untested) --- .../gv/egiz/sl20/utils/SL20JSONExtractorUtils.java | 422 +++++++++++++++++++++ 1 file changed, 422 insertions(+) create mode 100644 pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java (limited to 'pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java') diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java b/pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java new file mode 100644 index 00000000..5a438e16 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java @@ -0,0 +1,422 @@ +package at.gv.egiz.sl20.utils; + +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.utils.URIBuilder; +import org.jose4j.base64url.Base64Url; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import at.gv.egiz.sl20.data.VerificationResult; +import at.gv.egiz.sl20.exceptions.SL20Exception; +import at.gv.egiz.sl20.exceptions.SLCommandoParserException; + +public class SL20JSONExtractorUtils { + private static final Logger log = LoggerFactory.getLogger(SL20JSONExtractorUtils.class); + + /** + * Extract String value from JSON + * + * @param input + * @param keyID + * @param isRequired + * @return + * @throws SLCommandoParserException + */ + public static String getStringValue(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException { + try { + JsonElement internal = getAndCheck(input, keyID, isRequired); + + if (internal != null) + return internal.getAsString(); + else + return null; + + } catch (SLCommandoParserException e) { + throw e; + + } catch (Exception e) { + log.warn("Can not extract String value with keyId: " + keyID); + throw new SLCommandoParserException(e); + + } + } + + /** + * Extract Boolean value from JSON + * + * @param input + * @param keyID + * @param isRequired + * @return + * @throws SLCommandoParserException + */ + public static boolean getBooleanValue(JsonObject input, String keyID, boolean isRequired, boolean defaultValue) throws SLCommandoParserException { + try { + JsonElement internal = getAndCheck(input, keyID, isRequired); + + if (internal != null) + return internal.getAsBoolean(); + else + return defaultValue; + + } catch (SLCommandoParserException e) { + throw e; + + } catch (Exception e) { + log.warn("Can not extract Boolean value with keyId: " + keyID); + throw new SLCommandoParserException(e); + + } + } + + /** + * Extract JSONObject value from JSON + * + * @param input + * @param keyID + * @param isRequired + * @return + * @throws SLCommandoParserException + */ + public static JsonObject getJSONObjectValue(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException { + try { + JsonElement internal = getAndCheck(input, keyID, isRequired); + + if (internal != null) + return internal.getAsJsonObject(); + else + return null; + + } catch (SLCommandoParserException e) { + throw e; + + } catch (Exception e) { + log.warn("Can not extract Boolean value with keyId: \" + keyID"); + throw new SLCommandoParserException(e); + + } + } + + /** + * Extract Map of Key/Value pairs from a JSON Element + * + * @param input parent JSON object + * @param keyID KeyId of the child that should be parsed + * @param isRequired + * @return + * @throws SLCommandoParserException + */ + public static Map getMapOfStringElements(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException { + JsonElement internal = getAndCheck(input, keyID, isRequired); + return getMapOfStringElements(internal); + + } + + /** + * Extract a List of String elements from a JSON element + * + * @param input + * @param isRequired + * @param keyID + * @return + * @throws SLCommandoParserException + */ + public static List getListOfStringElements(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException { + JsonElement internal = getAndCheck(input, keyID, isRequired); + + List result = new ArrayList(); + if (internal != null) { + if (internal.isJsonArray()) { + Iterator arrayIterator = internal.getAsJsonArray().iterator(); + while(arrayIterator.hasNext()) { + JsonElement next = arrayIterator.next(); + if (next.isJsonPrimitive()) + result.add(next.getAsString()); + } + + } else if (internal.isJsonPrimitive()) { + result.add(internal.getAsString()); + + } else { + log.warn("JSON Element IS NOT a JSON array or a JSON Primitive"); + throw new SLCommandoParserException(); + } + } + + return result; + } + + + /** + * Extract Map of Key/Value pairs from a JSON Element + * + * @param input + * @return + * @throws SLCommandoParserException + */ + public static Map getMapOfStringElements(JsonElement input) throws SLCommandoParserException { + Map result = new HashMap(); + + if (input != null) { + if (input.isJsonArray()) { + Iterator arrayIterator = input.getAsJsonArray().iterator(); + while(arrayIterator.hasNext()) { + JsonElement next = arrayIterator.next(); + Iterator> entry = next.getAsJsonObject().entrySet().iterator(); + entitySetToMap(result, entry); + + } + + } else if (input.isJsonObject()) { + Iterator> objectKeys = input.getAsJsonObject().entrySet().iterator(); + entitySetToMap(result, objectKeys); + + } else { + log.warn("JSON Element IS NOT a JSON array or a JSON object"); + throw new SLCommandoParserException(); + } + + } + + return result; + } + + private static void entitySetToMap(Map result, Iterator> entry) { + while (entry.hasNext()) { + Entry el = entry.next(); + if (result.containsKey(el.getKey())) + log.info("Attr. Map already contains Element with Key: " + el.getKey() + ". Overwrite element ... "); + + result.put(el.getKey(), el.getValue().getAsString()); + + } + + } + + + public static JsonElement extractSL20Result(JsonObject command, IJOSETools decrypter, boolean mustBeEncrypted) throws SL20Exception { + JsonElement result = command.get(SL20Constants.SL20_COMMAND_CONTAINER_RESULT); + JsonElement encryptedResult = command.get(SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT); + + if (result == null && encryptedResult == null) { + log.warn("NO result OR encryptedResult FOUND."); + throw new SLCommandoParserException(); + + } else if (encryptedResult == null && mustBeEncrypted) { + log.warn("result MUST be signed."); + throw new SLCommandoParserException(); + + } else if (encryptedResult != null && encryptedResult.isJsonPrimitive()) { + try { + return decrypter.decryptPayload(encryptedResult.getAsString()); + + } catch (Exception e) { + log.info("Can NOT decrypt SL20 result. Reason:" + e.getMessage()); + if (!mustBeEncrypted) { + log.warn("Decrypted results are disabled by configuration. Parse result in plain if it is possible"); + + //dummy code + try { + String[] signedPayload = encryptedResult.toString().split("\\."); + JsonElement payLoad = new JsonParser().parse(new String(Base64Url.decodeToUtf8String(signedPayload[1]))); + return payLoad; + + } catch (Exception e1) { + log.debug("DummyCode FAILED, Reason: " + e1.getMessage() + " Ignore it ..."); + throw new SL20Exception(e.getMessage(), e); + + } + + } else + throw e; + + } + + } else if (result != null) { + return result; + + } else { + log.error("Internal build error"); + throw new SLCommandoParserException(); + + } + + + } + + /** + * Extract payLoad from generic transport container + * + * @param container + * @param joseTools + * @return + * @throws SLCommandoParserException + */ + public static VerificationResult extractSL20PayLoad(JsonObject container, IJOSETools joseTools, boolean mustBeSigned) throws SL20Exception { + + JsonElement sl20Payload = container.get(SL20Constants.SL20_PAYLOAD); + JsonElement sl20SignedPayload = container.get(SL20Constants.SL20_SIGNEDPAYLOAD); + + if (mustBeSigned && joseTools == null) { + log.warn("'joseTools' MUST be set if 'mustBeSigned' is 'true'"); + throw new SLCommandoParserException(); + + } + + if (sl20Payload == null && sl20SignedPayload == null) { + log.warn("NO payLoad OR signedPayload FOUND."); + throw new SLCommandoParserException(); + + } else if (sl20SignedPayload == null && mustBeSigned) { + log.warn("payLoad MUST be signed."); + throw new SLCommandoParserException(); + + } else if (joseTools != null && sl20SignedPayload != null && sl20SignedPayload.isJsonPrimitive()) { + try { + return joseTools.validateSignature(sl20SignedPayload.getAsString()); + + } catch (SL20Exception e) { + if (!mustBeSigned && sl20Payload == null) { + log.debug("Signature verification FAILED with reason: " + e.getMessage() + + " but response MUST NOT be signed by configuration" + + " Starting backup process ... "); + String[] split = sl20SignedPayload.getAsString().split("\\."); + if (split.length == 3) { + JsonElement payLoad = new JsonParser().parse(new String(Base64Url.decodeToUtf8String(split[1]))); + log.info("Signature verification FAILED with reason: " + e.getMessage() + " Use plain result as it is"); + return new VerificationResult(payLoad.getAsJsonObject()); + + } + } + + throw e; + + } + + } else if (sl20Payload != null) + return new VerificationResult(sl20Payload.getAsJsonObject()); + + else if (joseTools == null && !mustBeSigned && sl20SignedPayload != null && sl20SignedPayload.isJsonPrimitive()) { + log.info("Received signed SL20 response, but verification IS NOT required and NOT CONFIGURATED. Skip signature verification ... "); + String[] split = sl20SignedPayload.getAsString().split("\\."); + if (split.length == 3) { + JsonElement payLoad = new JsonParser().parse(new String(Base64Url.decodeToUtf8String(split[1]))); + return new VerificationResult(payLoad.getAsJsonObject()); + + } else { + log.warn("Can NOT skip signature verification, because signed result has an unsupported format!"); + throw new SLCommandoParserException(); + + } + + } else { + log.warn("Internal build error"); + throw new SLCommandoParserException(); + + } + + + } + + + /** + * Extract generic transport container from httpResponse + * + * @param httpResp + * @return + * @throws SLCommandoParserException + */ + public static JsonObject getSL20ContainerFromResponse(HttpResponse httpResp) throws SLCommandoParserException { + try { + JsonObject sl20Resp = null; + if (httpResp.getStatusLine().getStatusCode() == 307) { + Header[] locationHeader = httpResp.getHeaders("Location"); + if (locationHeader == null) { + log.warn("Find Redirect statuscode but not Location header"); + throw new SLCommandoParserException(); + + } + String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue(); + sl20Resp = new JsonParser().parse(Base64Url.encode((sl20RespString.getBytes()))).getAsJsonObject(); + + } else if (httpResp.getStatusLine().getStatusCode() == 200) { + if (!httpResp.getEntity().getContentType().getValue().startsWith("application/json")) { + log.warn("SL20 response with a wrong ContentType: " + httpResp.getEntity().getContentType().getValue()); + throw new SLCommandoParserException(); + + } + sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); + + } else if ( (httpResp.getStatusLine().getStatusCode() == 500) || + (httpResp.getStatusLine().getStatusCode() == 401) || + (httpResp.getStatusLine().getStatusCode() == 400) ) { + log.info("SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode() + + ". Search for error message"); + sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); + + + } else { + log.warn("SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode()); + throw new SLCommandoParserException(); + + } + + log.info("Find JSON object in http response"); + return sl20Resp; + + } catch (Exception e) { + log.warn("SL20 response parsing FAILED! Reason: " + e.getMessage(), e); + throw new SLCommandoParserException(e); + + } + } + + private static JsonObject parseSL20ResultFromResponse(HttpEntity resp) throws Exception { + if (resp != null && resp.getContent() != null) { + JsonElement sl20Resp = new JsonParser().parse(new InputStreamReader(resp.getContent())); + if (sl20Resp != null && sl20Resp.isJsonObject()) { + return sl20Resp.getAsJsonObject(); + + } else { + log.warn("SL2.0 can NOT parse to a JSON object"); + throw new SLCommandoParserException(); + + } + + + } else { + log.warn("Can NOT find content in http response"); + throw new SLCommandoParserException(); + + } + + } + + + private static JsonElement getAndCheck(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException { + JsonElement internal = input.get(keyID); + + if (internal == null && isRequired) { + log.warn("REQUIRED Element with keyId: " + keyID + " does not exist"); + throw new SLCommandoParserException(); + + } + + return internal; + + } +} -- cgit v1.2.3 From 236cd00a49b04523a325e06fdc8839be9049f892 Mon Sep 17 00:00:00 2001 From: emusic Date: Fri, 27 Jul 2018 12:28:01 +0200 Subject: adding additional data transfer type --- .../java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java') diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java b/pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java index 5a438e16..5fbce83b 100644 --- a/pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java +++ b/pdf-as-lib/src/main/java/at/gv/egiz/sl20/utils/SL20JSONExtractorUtils.java @@ -206,8 +206,7 @@ public class SL20JSONExtractorUtils { } } - - + public static JsonElement extractSL20Result(JsonObject command, IJOSETools decrypter, boolean mustBeEncrypted) throws SL20Exception { JsonElement result = command.get(SL20Constants.SL20_COMMAND_CONTAINER_RESULT); JsonElement encryptedResult = command.get(SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT); @@ -242,20 +241,15 @@ public class SL20JSONExtractorUtils { } } else - throw e; - + throw e; } - } else if (result != null) { return result; } else { log.error("Internal build error"); throw new SLCommandoParserException(); - } - - } /** -- cgit v1.2.3