Skip to content

Commit 097fcf4

Browse files
committed
First round for the Approov demo with Java Spring.
Signed-off-by: Paulo Silva <paulos@criticalblue.com>
1 parent ae39383 commit 097fcf4

39 files changed

+2317
-0
lines changed

.env.example

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
############
2+
# APPROOV
3+
############
4+
5+
APPROOV_CLAIM_HEADER_NAME=Authorization
6+
7+
# Feel free to play with different secrets. For development only you can create them with:
8+
# $ openssl rand -base64 64 | tr -d '\n'; echo
9+
APPROOV_BASE64_SECRET=h+CX0tOzdAAR9l15bWAqvq7w9olk66daIH+Xk+IAHhVVHszjDzeGobzNnqyRze3lw/WVyWrc2gZfh3XXfBOmww==
10+
11+
APPROOV_ABORT_REQUEST_ON_INVALID_TOKEN=true
12+
APPROOV_ABORT_REQUEST_ON_INVALID_CUSTOM_PAYLOAD_CLAIM=true
13+
APPROOV_LOGGING_ENABLED=true

.gitignore

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
HELP.md
2+
.gradle
3+
/build/
4+
!gradle/wrapper/gradle-wrapper.jar
5+
6+
### STS ###
7+
.apt_generated
8+
.classpath
9+
.factorypath
10+
.project
11+
.settings
12+
.springBeans
13+
.sts4-cache
14+
15+
### IntelliJ IDEA ###
16+
.idea
17+
*.iws
18+
*.iml
19+
*.ipr
20+
/out/
21+
22+
### NetBeans ###
23+
/nbproject/private/
24+
/nbbuild/
25+
/dist/
26+
/nbdist/
27+
/.nb-gradle/
28+
29+
### VS Code ###
30+
.vscode/
31+
32+
.local/
33+
.env

bin/generate-token

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
GENERATE APPROOV TOKEN CLI
5+
6+
To be used only to generate Approov tokens for testing purposes during development.
7+
8+
Usage:
9+
generate-token
10+
generate-token [--expire EXPIRE] [--claim CLAIM] [--claim-example] [--secret SECRET]
11+
12+
Options:
13+
--expire EXPIRE The Approov token expire time in minutes [default: 5].
14+
--claim CLAIM The base64 encode sha256 hash of the custom payload claim for the Approov token.
15+
--claim-example Same as --claim but using an hard-coded claim example.
16+
--secret SECRET The base64 encoded secret to sign the Approov token for test purposes.
17+
-h --help Show this screen.
18+
-v --version Show version.
19+
20+
"""
21+
22+
# Standard Libraries
23+
from os import getenv
24+
from sys import exit
25+
from time import time
26+
from hashlib import sha256
27+
from base64 import b64decode, b64encode
28+
29+
# Third-Party Libraries
30+
from jwt import encode
31+
from docopt import docopt
32+
33+
# to base64 encode the custom payload claim hash: http://tomeko.net/online_tools/hex_to_base64.php
34+
REQUEST_CLAIM_RAW_VALUE_EXAMPLE = 'claim-value-to-be-sha256-hashed-and-base64-encoded'
35+
36+
def _generateSha256HashBase64Encoded(value):
37+
value_hash = sha256(value.encode('utf-8')).digest()
38+
return b64encode(value_hash).decode('utf-8')
39+
40+
def generateToken(approov_base64_secret, token_expire_in_minutes, request_claim_raw_value):
41+
"""Generates a token with a 5 minutes lifetime. Optionally we can set also a custom payload claim."""
42+
43+
approov_base64_secret = approov_base64_secret.strip()
44+
45+
if not approov_base64_secret:
46+
raise ValueError('Approov base64 encoded secret is missing.')
47+
48+
if not token_expire_in_minutes:
49+
token_expire_in_minutes = 5
50+
51+
payload = {
52+
'exp': time() + (60 * token_expire_in_minutes), # required - the timestamp for when the token expires.
53+
}
54+
55+
if request_claim_raw_value:
56+
payload['pay'] = _generateSha256HashBase64Encoded(request_claim_raw_value)
57+
58+
return encode(payload, b64decode(approov_base64_secret), algorithm='HS256').decode()
59+
60+
def main():
61+
62+
arguments = docopt(__doc__, version='GENERATE APPROOV TOKEN CLI - 1.0')
63+
64+
request_claim_raw_value = None
65+
token_expire_in_minutes = int(arguments['--expire'])
66+
approov_base64_secret = getenv("APPROOV_BASE64_SECRET")
67+
68+
if arguments['--claim']:
69+
request_claim_raw_value = arguments['--claim']
70+
71+
if not request_claim_raw_value and arguments['--claim-example'] is True:
72+
request_claim_raw_value = REQUEST_CLAIM_RAW_VALUE_EXAMPLE
73+
74+
if arguments['--secret']:
75+
approov_base64_secret = arguments['--secret']
76+
77+
if not approov_base64_secret:
78+
raise ValueError('--secret was provided as an empty string in the CLI or in the .env file.')
79+
80+
token = generateToken(approov_base64_secret, token_expire_in_minutes, request_claim_raw_value)
81+
82+
print('Token:\n', token)
83+
84+
return token
85+
86+
if __name__ == '__main__':
87+
try:
88+
main()
89+
exit(0)
90+
except Exception as error:
91+
print(error)
92+
exit(1)

build.gradle

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
plugins {
2+
id 'org.springframework.boot' version '2.1.3.RELEASE'
3+
id 'java'
4+
}
5+
6+
apply plugin: 'io.spring.dependency-management'
7+
8+
group = 'com.criticalblue'
9+
version = '0.0.1-SNAPSHOT'
10+
sourceCompatibility = '1.8'
11+
12+
repositories {
13+
mavenCentral()
14+
}
15+
16+
dependencies {
17+
implementation 'org.springframework.boot:spring-boot-starter-integration'
18+
implementation 'org.springframework.boot:spring-boot-starter-security'
19+
implementation 'org.springframework.boot:spring-boot-starter-web'
20+
implementation 'org.springframework.security:spring-security-core'
21+
implementation 'org.springframework.security:spring-security-web'
22+
implementation 'org.springframework.security:spring-security-config'
23+
24+
implementation 'io.jsonwebtoken:jjwt-api:0.10.5'
25+
runtime 'io.jsonwebtoken:jjwt-impl:0.10.5',
26+
'io.jsonwebtoken:jjwt-jackson:0.10.5'
27+
28+
compileOnly 'org.jetbrains:annotations:17.0.0'
29+
30+
compileOnly 'javax.servlet:servlet-api:2.5'
31+
32+
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
33+
testImplementation 'org.springframework.boot:spring-boot-starter-test'
34+
testImplementation 'org.springframework.security:spring-security-test'
35+
}

docker/Dockerfile

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
FROM openjdk:11.0.3-slim
2+
3+
ARG CONTAINER_USER="java"
4+
ARG CONTAINER_UID="1000"
5+
ARG ZSH_THEME="robbyrussell"
6+
ARG GRADLE_VERSION=5.2.1
7+
8+
9+
# Will not prompt for questions
10+
ENV DEBIAN_FRONTEND=noninteractive \
11+
CONTAINER_USER="${CONTAINER_USER}" \
12+
CONTAINER_UID="${CONTAINER_UID}" \
13+
ROOT_CA_DIR=/root-ca/ \
14+
ROOT_CA_KEY="self-signed-root-ca.key" \
15+
ROOT_CA_PEM="self-signed-root-ca.pem" \
16+
ROOT_CA_NAME="ApproovStackRootCA" \
17+
PROXY_CA_FILENAME="FirewallProxyCA.crt" \
18+
PROXY_CA_PEM="certificates/FirewallProxyCA.crt" \
19+
PROXY_CA_NAME="FirewallProxy" \
20+
NO_AT_BRIDGE=1 \
21+
DISPLAY=":0" \
22+
GRADLE_HOME=/opt/gradle/gradle-"${GRADLE_VERSION}" \
23+
PATH=/opt/gradle/gradle-"${GRADLE_VERSION}"/bin:${PATH}
24+
25+
COPY ./setup ${ROOT_CA_DIR}
26+
27+
RUN apt update && \
28+
apt -y upgrade && \
29+
30+
# Install Required Dependencies
31+
apt -y install \
32+
python3 \
33+
python3-pip \
34+
locales \
35+
tzdata \
36+
ca-certificates \
37+
inotify-tools \
38+
libnss3-tools \
39+
zip \
40+
zsh \
41+
curl \
42+
git \
43+
default-jdk \
44+
maven && \
45+
46+
47+
48+
# Force installation of missing dependencies
49+
apt -y -f install && \
50+
51+
#https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
52+
printf "fs.inotify.max_user_watches=524288\n" >> /etc/sysctl.conf && \
53+
54+
echo "en_GB.UTF-8 UTF-8" > /etc/locale.gen && \
55+
locale-gen en_GB.UTF-8 && \
56+
dpkg-reconfigure locales && \
57+
58+
useradd -m -u ${CONTAINER_UID} -s /usr/bin/zsh ${CONTAINER_USER} && \
59+
60+
cd ${ROOT_CA_DIR} && \
61+
./setup-root-certificate.sh "${ROOT_CA_KEY}" "${ROOT_CA_PEM}" "${ROOT_CA_NAME}" && \
62+
./add-proxy-certificate.sh "${PROXY_CA_PEM}" && \
63+
64+
curl -o gradle.zip -fsSL https://services.gradle.org/distributions/gradle-"${GRADLE_VERSION}"-bin.zip && \
65+
unzip -d /opt/gradle gradle.zip && \
66+
rm -f gradle.zip && \
67+
gradle --version && \
68+
69+
# Install Oh My Zsh for Root and Node user
70+
bash -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)" && \
71+
chsh -s /usr/bin/zsh && \
72+
cp -R /root/.oh-my-zsh /home/"${CONTAINER_USER}" && \
73+
cp /root/.zsh* /home/"${CONTAINER_USER}" && \
74+
sed -i "s/\/root/\/home\/${CONTAINER_USER}/g" /home/"${CONTAINER_USER}"/.zshrc && \
75+
chown -R "${CONTAINER_USER}":"${CONTAINER_USER}" /home/"${CONTAINER_USER}" && \
76+
77+
# cleaning
78+
rm -rvf /var/lib/apt/lists/*
79+
80+
ENV LANG=en_GB.UTF-8 \
81+
LANGUAGE=en_GB:en \
82+
LC_ALL=en_GB.UTF-8
83+
84+
USER ${CONTAINER_USER}
85+
86+
RUN pip3 install \
87+
pyjwt \
88+
docopt
89+
90+
# pip install will put the executables under ~/.local/bin
91+
ENV PATH=/home/"${CONTAINER_USER}"/.local/bin:$PATH
92+
93+
WORKDIR /home/${CONTAINER_USER}/workspace
94+
95+
CMD ["zsh"]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
# https://stackoverflow.com/a/48814971/6454622
4+
5+
set -eu
6+
7+
CA_PEM=${1?Missing certificate file name}
8+
9+
cert_name=$(openssl x509 -inform PEM -subject_hash_old -in ${CA_PEM} | head -1)
10+
cat ${CA_PEM} > $cert_name
11+
openssl x509 -inform PEM -text -in ${CA_PEM} -out nul >> $cert_name
12+
13+
adb shell mount -o rw,remount,rw /system
14+
adb push $cert_name /system/etc/security/cacerts/
15+
adb shell mount -o ro,remount,ro /system
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/bin/bash
2+
3+
set -eu
4+
5+
###
6+
# https://thomas-leister.de/en/how-to-import-ca-root-certificate/
7+
###
8+
9+
10+
### Script installs root.cert.pem to certificate trust store of applications using NSS
11+
### (e.g. Firefox, Thunderbird, Chromium)
12+
### Mozilla uses cert8, Chromium and Chrome use cert9
13+
14+
###
15+
### Requirement: apt install libnss3-tools
16+
###
17+
18+
CA_PEM="${1?Missing file path for the PEM certificate}"
19+
CA_NAME="${2?Missing Certificate Name}"
20+
BROWSER_CONFIG_DIR="${3:-/home/node}"
21+
22+
printf "\n>>> ADDING CERTIFICATE TO BROWSERS TRUSTED STORE <<<\n"
23+
24+
if [ -f "${CA_PEM}" ]
25+
then
26+
printf "\n--> CERTIFICATE FILE: ${CA_PEM}\n"
27+
printf "\n--> CERTIFICATE NAME: ${CA_NAME}\n"
28+
printf "\n--> BROWSER CONFIG DIR: ${BROWSER_CONFIG_DIR}\n"
29+
30+
###
31+
### For cert8 (legacy - DBM)
32+
###
33+
for certDB in $(find ${BROWSER_CONFIG_DIR} -name "cert8.db")
34+
do
35+
certdir=$(dirname ${certDB});
36+
certutil -A -n "${CA_NAME}" -t "TCu,Cu,Tu" -i ${CA_PEM} -d dbm:${certdir}
37+
done
38+
39+
###
40+
### For cert9 (SQL)
41+
###
42+
for certDB in $(find ${BROWSER_CONFIG_DIR} -name "cert9.db")
43+
do
44+
certdir=$(dirname ${certDB});
45+
certutil -A -n "${CA_NAME}" -t "TCu,Cu,Tu" -i ${CA_PEM} -d sql:${certdir}
46+
done
47+
else
48+
printf "\n>>> CERTIFICATE FILE NOT FOUND FOR: ${CA_PEM}\n"
49+
fi
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
3+
set -eu
4+
5+
CA_PEM_FILE="${1?Missing name for certificate file}"
6+
CA_EXTENSION="${CA_PEM_FILE##*.}"
7+
8+
if [ "${CA_EXTENSION}" != "pem" ]
9+
then
10+
printf "\nFATAL ERROR: Certificate must use .pem extension\n\n"
11+
exit 1
12+
fi
13+
14+
if [ -f "${CA_PEM_FILE}" ]
15+
then
16+
printf "\n>>> ADDING A CERTIFICATE TO NODE SERVER <<<\n"
17+
18+
# Add certificate to node, so that we can use npm install
19+
printf "cafile=${CA_PEM_FILE}" >> /root/.npmrc
20+
printf "cafile=${CA_PEM_FILE}" >> /home/${CONTAINER_USER}/.npmrc;
21+
22+
printf "\n >>> CERTICATE ADDED SUCCESEFULY<<<\n"
23+
24+
else
25+
printf "\n >>> NO CERTIFICATE TO ADD <<<\n"
26+
fi
27+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash
2+
3+
set -eu
4+
5+
PROXY_CA_PEM="${1?Missing name for Proxy CRT file}"
6+
7+
if [ -f "${PROXY_CA_PEM}" ]
8+
then
9+
printf "\n>>> ADDING A PROXY CERTIFICATE TO THE TRUSTED STORE <<<\n"
10+
11+
# add certificate tpo the trust store
12+
cp -v ${PROXY_CA_PEM} /usr/local/share/ca-certificates
13+
update-ca-certificates
14+
15+
# verifies the certificate
16+
openssl x509 -in ${PROXY_CA_PEM} -text -noout > "${PROXY_CA_PEM}.txt"
17+
18+
else
19+
printf "\n >>> FATAL ERROR: Certificate not found in path ${PROXY_CA_PEM} <<<\n"
20+
fi
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*
2+
!.gitignore

0 commit comments

Comments
 (0)