Skip to content

Commit 4e6f2f5

Browse files
committed
Quickstart with IMS included
1 parent 819b867 commit 4e6f2f5

11 files changed

Lines changed: 112 additions & 203 deletions

File tree

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The following app permissions need to be available in the manifest to use Approo
2626
<uses-permission android:name="android.permission.INTERNET" />
2727
```
2828

29-
Note that the minimum SDK version you can use with the Approov package is 21 (Android 5.0).
29+
Note that the minimum SDK version you can use with the Approov package is 23 (Android 6.0).
3030

3131
Please [read this](https://approov.io/docs/latest/approov-usage-documentation/#targeting-android-11-and-above) section of the reference documentation if targeting Android 11 (API level 30) or above.
3232

@@ -51,9 +51,11 @@ The `<enter-your-config-string-here>` is a custom string that configures your Ap
5151
You can then make Approov enabled `HttpsUrlConnection` API calls using the following call on any `HttpsUrlConnection` connection, just before the connection is made:
5252

5353
```Java
54-
ApproovService.addApproov(connection);
54+
connection = ApproovService.addApproov(connection);
5555
```
5656

57+
Always continue to use the returned `connection` instance afterwards, because the service layer may wrap the original connection when it needs to apply additional request mutations such as URL rewriting.
58+
5759
> **NOTE:** It is important that this call is made just prior to the connection being made and thus within any retry loop, to ensure that an updated Approov token is always made available on the connection request.
5860
5961
For API domains that are configured to be protected with an Approov token, this adds the `Approov-Token` header and pins the connection. This may also substitute header values when using secrets protection.

REFERENCE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ It is possible to pass an empty `config` string to indicate that no initializati
2626
Adds Approov to the given `connection`. The Approov token is added in a header and this also overrides the HostnameVerifier with something that pins the connections. If a binding header has been specified then its hash will be set if it is present. This function may also substitute header values to hold secure string secrets. If it is not possible to fetch an Approov token due to networking issues, or header substitution fails due to attestation rejection, then `ApproovException` is thrown.
2727

2828
```Java
29-
void addApproov(HttpsURLConnection connection) throws ApproovException
29+
HttpsURLConnection addApproov(HttpsURLConnection connection) throws ApproovException
3030
```
3131

32+
The returned `HttpsURLConnection` should always be used for subsequent calls such as `connect()`, reading the response body, and `disconnect()`. In many cases this will be the same instance that was passed in, but a wrapped connection may be returned when additional request mutation is required.
33+
3234
## SetProceedOnNetworkFail
3335
If the provided `proceed` value is `true` then this indicates that the networking should proceed anyway if it is not possible to obtain an Approov token due to a networking failure. If this is called then the backend API can receive calls without the expected Approov token header being added, or without header/query parameter substitutions being made. This should only ever be used if there is some particular reason, perhaps due to local network conditions, that you believe that traffic to the Approov cloud service will be particularly problematic.
3436

SECRETS-PROTECTION.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ In some cases it might not be possible to automatically substitute a secret in a
5454
In this case it is possible to make an explicit call at runtime to obtain the secret value, for apps passing attestation. Here is an example for using the required method in `ApproovService`:
5555

5656
```Java
57-
import io.approov.service.okhttp.ApproovException;
58-
import io.approov.service.okhttp.ApproovNetworkException;
59-
import io.approov.service.okhttp.ApproovRejectionException;
57+
import io.approov.service.httpsurlconn.ApproovException;
58+
import io.approov.service.httpsurlconn.ApproovNetworkException;
59+
import io.approov.service.httpsurlconn.ApproovRejectionException;
6060

6161
...
6262

SHAPES-EXAMPLE.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Tokens for this domain will be automatically signed with the specific secret for
6262

6363
## MODIFY THE APP TO USE APPROOV
6464

65-
Uncomment the three lines of Approov initialization code in `io/approov/shapes/ShapesApp.java`:
65+
Uncomment the Approov initialization code in `io/approov/shapes/ShapesApp.java`:
6666

6767
![Approov Initialization](readme-images/approov-init-code.png)
6868

@@ -74,9 +74,11 @@ Next we need to use Approov when we make request for the shapes. Change the mark
7474

7575
Note you will also need to uncomment the `ApproovService` import near the start of the file.
7676

77-
We pass the `HttpsUrlConnection` to the `ApproovService.addApproov` method and this automatically fetches an Approov token and adds it as a header to the request. It also pins the connection to the endpoint to ensure that no Man-in-the-Middle can eavesdrop on any communication being made.
77+
We pass the `HttpsUrlConnection` to the `ApproovService.addApproov` method and continue with the returned `HttpsURLConnection`. This automatically fetches an Approov token and adds it as a header to the request. It also pins the connection to the endpoint to ensure that no Man-in-the-Middle can eavesdrop on any communication being made.
7878

79-
Note that this method may throw an `ApproovException` (derived from `IOException`) if it is unable to fetch an Approov token due to no or poor Internet connectivity then `ApproovNetworkException` is thrown. In this case the user should be able to initiate a retry. Therefore the call should be in a`try-catch` block, possibly the same one as [`connect`](https://developer.android.com/reference/java/net/URLConnection.html#connect()) or reads of the body for a `GET`.
79+
Note that this method may return a wrapped connection when it needs to apply additional request mutations, such as URL rewriting. For that reason you should always keep using the returned `connection` reference afterwards.
80+
81+
Note that this method may throw an `ApproovException` (derived from `IOException`) if it is unable to fetch an Approov token due to no or poor Internet connectivity then `ApproovNetworkException` is thrown. In this case the user should be able to initiate a retry. Therefore the call should be in a `try-catch` block, possibly the same one as [`connect`](https://developer.android.com/reference/java/net/URLConnection.html#connect()) or reads of the body for a `GET`.
8082

8183
You should also edit the `res/values/strings.xml` file to change to using the shapes `https://shapes.approov.io/v3/shapes/` endpoint that checks Approov tokens (as well as the API key built into the app):
8284

@@ -115,6 +117,29 @@ If you still don't get a valid shape then there are some things you can try. Rem
115117
* Use `approov metrics` to see [Live Metrics](https://approov.io/docs/latest/approov-usage-documentation/#metrics-graphs) of the cause of failure.
116118
* You can use a debugger or emulator and get valid Approov tokens on a specific device by ensuring you are [forcing a device ID to pass](https://approov.io/docs/latest/approov-usage-documentation/#forcing-a-device-id-to-pass). As a shortcut, you can use the `latest` as discussed so that the `device ID` doesn't need to be extracted from the logs or an Approov token.
117119
* Also, you can use a debugger or Android emulator and get valid Approov tokens on any device if you [mark the signing certificate as being for development](https://approov.io/docs/latest/approov-usage-documentation/#development-app-signing-certificates).
120+
121+
## SHAPES APP WITH INSTALLATION MESSAGE SIGNING
122+
123+
This section shows how to add message signing as an additional layer of protection in addition to an Approov token.
124+
125+
1. Edit the `res/values/strings.xml` file to use the shapes `https://shapes.approov.io/v5/shapes/` endpoint. The v5 endpoint performs a message signature check in addition to the Approov token check.
126+
127+
2. Uncomment the message signing setup code in `io/approov/shapes/ShapesApp.java`. This installs an `ApproovService` mutator that adds the message signature to the request automatically.
128+
129+
3. Configure Approov to add the public message signing key to the Approov token. This key is used by the v5 endpoint to perform its message signature check.
130+
131+
```
132+
approov policy -setInstallPubKey on
133+
```
134+
135+
4. Build and run the app again and press the `Get Shape` button. You should see this (or another shape):
136+
137+
<p>
138+
<img src="readme-images/shapes-good.png" width="256" title="Shapes Good">
139+
</p>
140+
141+
This indicates that in addition to the app obtaining a validly signed Approov token, the message also has a valid signature.
142+
118143
## SHAPES APP WITH SECRETS PROTECTION
119144

120145
This section provides an illustration of an alternative option for Approov protection if you are not able to modify the backend to add an Approov Token check. Firstly, revert any previous change to `res/values/strings.xml` to using `https://shapes.approov.io/v1/shapes/` that simply checks for an API key. The `shapes_api_key` should also be changed to `shapes_api_key_placeholder`, removing the actual API key out of the code:

shapes-app/.project

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
</natures>
1717
<filteredResources>
1818
<filter>
19-
<id>1645701082319</id>
19+
<id>1776687200928</id>
2020
<name></name>
2121
<type>30</type>
2222
<matcher>
2323
<id>org.eclipse.core.resources.regexFilterMatcher</id>
24-
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
24+
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
2525
</matcher>
2626
</filter>
2727
</filteredResources>

shapes-app/.settings/org.eclipse.buildship.core.prefs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
arguments=--init-script /home/richardt/.config/Code/User/globalStorage/redhat.java/1.13.0/config_linux/org.eclipse.osgi/51/0/.cp/gradle/init/init.gradle --init-script /home/richardt/.config/Code/User/globalStorage/redhat.java/1.13.0/config_linux/org.eclipse.osgi/51/0/.cp/gradle/protobuf/init.gradle
1+
arguments=--init-script /var/folders/d1/7dc4qrgd51v_5zzdcgsm3k0m0000gn/T/db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle --init-script /var/folders/d1/7dc4qrgd51v_5zzdcgsm3k0m0000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle --init-script /var/folders/d1/7dc4qrgd51v_5zzdcgsm3k0m0000gn/T/861a75667e10803d304a058d833cb7404195ca44013d0d61d3b653eb084379b8.gradle --init-script /var/folders/d1/7dc4qrgd51v_5zzdcgsm3k0m0000gn/T/68eb1b6516fe21c6fbba58e63c99c3207ccfc918360613709367eecde56fa77f.gradle --init-script /var/folders/d1/7dc4qrgd51v_5zzdcgsm3k0m0000gn/T/da64152279c70a8b4f3de4ca9ea66fd3b3405b7aca4e1f20f2d08e5593aa1ce1.gradle
22
auto.sync=false
33
build.scans.enabled=false
44
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
55
connection.project.dir=
66
eclipse.preferences.version=1
77
gradle.user.home=
8-
java.home=/usr/lib/jvm/java-11-openjdk-amd64
8+
java.home=/Users/charlesoj/Library/Java/JavaVirtualMachines/jbr-17.0.14/Contents/Home
99
jvm.arguments=
1010
offline.mode=false
1111
override.workspace.settings=true

shapes-app/app/.classpath

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<classpath>
3-
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
3+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17/"/>
44
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
55
<classpathentry kind="output" path="bin/default"/>
66
</classpath>

shapes-app/app/.project

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222
</natures>
2323
<filteredResources>
2424
<filter>
25-
<id>1645701082300</id>
25+
<id>1776687200918</id>
2626
<name></name>
2727
<type>30</type>
2828
<matcher>
2929
<id>org.eclipse.core.resources.regexFilterMatcher</id>
30-
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
30+
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
3131
</matcher>
3232
</filter>
3333
</filteredResources>

0 commit comments

Comments
 (0)