diff --git a/CordApp.md b/CSDE.md similarity index 95% rename from CordApp.md rename to CSDE.md index cfe11c1..b50ed03 100644 --- a/CordApp.md +++ b/CSDE.md @@ -1,5 +1,3 @@ -# CSDE - The CorDapp Standard Development Environment (CSDE) makes the process of prototyping CorDapps more straight-forward. The CSDE is obtained by cloning our `CSDE-cordapp-template-kotlin` or `CSDE-cordapp-template-java` repository to your local machine. The CSDE provides: - a prepared CorDapp project that you can use as a starting point to develop your own prototypes. @@ -11,13 +9,13 @@ The CorDapp Standard Development Environment (CSDE) makes the process of prototy - the ability to configure the members of the local Corda network. -## Installation +# Installation -### Prerequisites +## Prerequisites Be sure to [install](https://docs.r3.com/en/platform/corda/5.0/developing-applications/getting-started/prerequisites.html) required SW and CLI tools prior starting development with CSDE. -## Template project +# Template project Template Java or Kotlin projects are availvable as a git repo. @@ -31,7 +29,7 @@ git remote add origin In order for the `CSDE-cordapp-template` app to work on MacOS with VsCode, these steps must be made: -### Add `$rootDir` prefix in `build.gradle` +## Add `$rootDir` prefix in `build.gradle` For some reason, to run gradle tasks from VsCode, the default `build.gradle` must be updated with absolute paths. Unpatched file works just fine for commands from CLI. @@ -61,7 +59,7 @@ For some reason, to run gradle tasks from VsCode, the default `build.gradle` mus Note, that there must be no prefix for `r3RootCertFile` property. -### JDK +## JDK [Install](https://docs.azul.com/core/zulu-openjdk/install/macos) recommend JDK (Azul Zulu 11) and tell gradle to use it. @@ -94,13 +92,13 @@ Even if CordaCLI is actually installed! /usr/libexec/java_home -V ``` -## Execution +# Execution Gradle commands shall be accessible to you at this moment. Although, it is possible to run gradle tasks in VsCode, it is **suggested to execute them as a generic bash commands**, since most of the configuration files are tested and finetuned only for JetBrains IDEA. Type `./gradlew tasks` to get list of availvable tasks. The most basic of which are: -### Start local Corda application network +## Start local Corda application network ```sh ./gradlew startCord @@ -108,7 +106,7 @@ Type `./gradlew tasks` to get list of availvable tasks. The most basic of which > [!note] Be sure to have your Docker demon up and running -### Run virtual nodes +## Run virtual nodes ```sh ./gradlew 5-vNodesSetup diff --git a/Home.md b/Home.md index 5d08b7b..487baf5 100644 --- a/Home.md +++ b/Home.md @@ -1 +1,11 @@ -Welcome to the Wiki. \ No newline at end of file +# Major development milestones + +- [[ReactJs and SpringBoot]] + Classic WebApp with ReactJS frontend and SpringBoot backend. +- [[CSDE|Corda Standard Dev Environment]] + CSDE will be hosting and enforcing Checkers game logic. +- [[Secure REST Client]] + Communication channel between SpringBoot server and CordApp. + +# TODOs +- Use [jsonschema2pojo](https://github.com/joelittlejohn/jsonschema2pojo/tree/master/jsonschema2pojo-gradle-plugin) to generate POJO objects for SpringBoot server from REST API schemas provided by CSDE \ No newline at end of file diff --git a/Secure REST Client.md b/Secure REST Client.md new file mode 100644 index 0000000..37543f0 --- /dev/null +++ b/Secure REST Client.md @@ -0,0 +1,220 @@ +Since [[CSDE]] expose its services via REST API, our [[ReactJs and SpringBoot#Backend|SpringBoot backend]] server needs a way to call HTTPS endpoints. + +# Apache HttpClient 5.0 + +Although the `java.net` package provides basic functionality for accessing resources via HTTP, it doesn't provide the full flexibility or functionality needed by many applications. [HttpClient](https://hc.apache.org/httpcomponents-client-5.2.x/quickstart.html) seeks to fill this void by providing an efficient, up-to-date, and feature-rich package implementing the client side of the most recent HTTP standards and recommendations. + +*`build.gradle`* +```groovy +dependencies { + implementation 'org.apache.httpcomponents.client5:httpclient5:5.2.1' + //implementation 'org.apache.httpcomponents.client5:httpclient5-fluent:5.2.1' +} +``` + +*`quickStart.java`* +```java +try (CloseableHttpClient httpclient = HttpClients.createDefault()) { + ClassicHttpRequest httpGet = ClassicRequestBuilder + .get("http://httpbin.org/get") + .build(); + // The underlying HTTP connection is still held by the response object + // to allow the response content to be streamed directly from the network + // socket. + // In order to ensure correct deallocation of system resources + // the user MUST call CloseableHttpResponse#close() from a finally clause. + // Please note that if response content is not fully consumed the underlying + // connection cannot be safely re-used and will be shut down and discarded + // by the connection manager. + httpclient.execute(httpGet, response -> { + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + final HttpEntity entity1 = response.getEntity(); + // do something useful with the response body + // and ensure it is fully consumed + EntityUtils.consume(entity1); + return null; + }); + + ClassicHttpRequest httpPost = ClassicRequestBuilder + .post("http://httpbin.org/post") + .setEntity(new UrlEncodedFormEntity(Arrays.asList( + new BasicNameValuePair("username", "vip"), + new BasicNameValuePair("password", "secret")))) + .build(); + httpclient.execute(httpPost, response -> { + System.out.println(response.getCode() + " " + response.getReasonPhrase()); + final HttpEntity entity2 = response.getEntity(); + // do something useful with the response body + // and ensure it is fully consumed + EntityUtils.consume(entity2); + return null; + }); +} +``` + +# Secure HTTPS endpoints + +If we would to try to to GET some data from [[CSDE]] on `https://localhost:8888/api/v1/virtualnode` we would fail with `unable to find valid certification path to requested target` runtime exception. This is because we need to use SLL to implement HTPPS support. + +This sample client is suitable only for testing purposes, since it does not perform any form of serve cert validation, and establishes encrypted connection with any server. + +*`naiveSecureRestClient.java`* +```java +final TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; + +final SSLContext sslContext = SSLContexts.custom() + .loadTrustMaterial(null, acceptingTrustStrategy) + .build(); + +final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + +final Registry socketFactoryRegistry = RegistryBuilder. create() + .register("https", sslsf) + .register("http", new PlainConnectionSocketFactory()) + .build(); + +final BasicHttpClientConnectionManager connectionManager = + new BasicHttpClientConnectionManager(socketFactoryRegistry); + +try (CloseableHttpClient httpclient = HttpClients + .custom() + .setConnectionManager(connectionManager) + .build()) { + // Your HTTP handeling +} +``` + +## Certification Authority + +CA usage, is a common strategy for clients to ensure servers validity. In this project, CordApp uses self signed certificate, which our client shall use as its CA. + +1. Obtain servers certificate with + ```sh + openssl s_client -connect localhost:8888 2>&1 virtualNodes) { } +``` + +This simple Java record class is annotated with `@JsonIgnoreProperties` from the Jackson JSON processing library to indicate that any properties not bound in this type should be ignored, and represent a top level POJO representation of JSON document returned from the CSDE API for `https://localhost:8888/api/v1/virtualnode` endpoint. + +For direct binding of some data to some custom type, you need to specify the variable name to be exactly the same as the key in JSON. In case the variable name and the key do not match - use `@JsonProperty` annotation to specify the exact key of the JSON document. + +## Implementation example + +Create Bean for **RestTemplate** under the **@Configuration** annotated class. You can even write a separate class and annotate with @Configuration + +```java +@Configuration +public class RestTemplateConfig { + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + return builder.build(); + } +} +``` + +Then, define **RestTemplate** with **@Autowired** or **@Injected** under your Service / Controller + +```java +@Autowired +private RestTemplate restTemplate; +``` + +All is ready to perform actual REST API request with help of RestTemplate. For this we can use multiple methods like **exchange()**, **getForEntity()**, **getForObject()**. + +```java +// Request authorization header +HttpHeaders headers = new HttpHeaders(); +headers.setBasicAuth("admin", "admin"); + +// String authStr = "username:password"; +// String base64Creds = Base64.getEncoder().encodeToString(authStr.getBytes()); +// headers.add("Authorization", "Basic " + base64Creds); + +// Request +final HttpEntity request = new HttpEntity<>(headers); + +ResponseEntity response = new RestTemplate(requestFactory) + .exchange("https://localhost:8888/api/v1/virtualnode", + HttpMethod.GET, + request, + virtualnode.class ); + +if (response.getStatusCode() == HttpStatus.OK && + response.hasBody()) { + virtualnode vNode = response.getBody(); +} +``` + +## Configure RestTemplate to use HttpClient + +The final bit of a puzzle, is that we need a way to tell HttpClient to use RestTemplate + +```java +CloseableHttpClient httpClient = HttpClientBuilder + //.create() + //.disableCookieManagement() + .setConnectionManager(connectionManager) + .build(); + +HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + +factory.setReadTimeout(readTimeout); +factory.setConnectTimeout(connectTimeout); + +RestTemplate restTemplate = new RestTemplate(factory); +``` + +