Skip to content

Commit

Permalink
Merge pull request #59 from Mateusz512/feature/#58-add-security-example
Browse files Browse the repository at this point in the history
#58 add security example
  • Loading branch information
Skejven authored Jan 24, 2020
2 parents 58167cf + 3a2952c commit 0ff272d
Show file tree
Hide file tree
Showing 27 changed files with 855 additions and 0 deletions.
52 changes: 52 additions & 0 deletions api-gateway/security/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@

# API Gateway security example
This project is a result of completing either [Getting Started with Knot.x Stack](http://knotx.io/tutorials/getting-started-with-knotx-stack/2_0/) or [Getting started with Docker](http://knotx.io/tutorials/getting-started-with-docker/2_0/) tutorials.

This example is built using the [Starter Kit](https://github.com/Knotx/knotx-starter-kit) template project.

## How to build & run

#### Prerequisites
- JDK 8
- Docker

#### Run
```
$ ./gradlew build-docker
```

The [build-docker](https://github.com/Knotx/knotx-starter-kit#build--validate-docker-image) builds and validates the custom project Docker image.

Then, start Docker container:
```
$ docker run -p8092:8092 knotx/secure-api-gateway
```

## Endpoints:

- [`localhost:8092/api/secure/basic`](http://localhost:8092/api/security/basic) endpoint protected with [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
- Available credentials: user `john` password `s3cr3t`
- Sample call:
```shell script
curl -X GET http://localhost:8092/api/secure/basic -H 'Authorization: Basic am9objpzM2NyM3Q='
```
- [`localhost:8092/api/secure/jwt`](http://localhost:8092/api/security/jwt) endpoint protected with [JWT](https://jwt.io/)
- Symmetric key using `HS256`: `M0NTY3ODkwIiwibmFtZSI6`
- Sample call:
```shell script
curl -X GET http://localhost:8092/api/secure/jwt -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.vPWK59pl5GWimz8UVbL3CmrceSfmNvvCgyzwLVV9jT8'
```
- [`localhost:8092/api/secure/login`](http://localhost:8092/api/security/jwt) endpoint implementing *Authorization Code* flow of [OAuth2](https://oauth.net/2/)
- It redirects to Google Account consent page
- [`localhost:8092/api/secure/oauth2`](http://localhost:8092/api/security/oauth2) endpoint expecting a redirect from Google Account consent page as part of [OAuth2](https://oauth.net/2/)
- It uses received Authorization Code to obtain Access Token and uses the received token to fetch user data


## What is the delta between [Starter Kit](https://github.com/Knotx/knotx-starter-kit)?

- `security-module` that includes implementation of security handlers
- `hello-module` module that includes a handler that prints a configured message to response
- `health-check` module is modified to rely on `/api/public`
- `functional` tests also rely on `/api/public`
- new tests in `functional` module that verify security endpoints
- this code was cleaned from unnecessary example modules and configurations (**not covered in tutorials**)
62 changes: 62 additions & 0 deletions api-gateway/security/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import com.bmuschko.gradle.docker.tasks.container.DockerStopContainer

/*
* Copyright (C) 2019 Knot.x Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id("io.knotx.distribution")
id("com.bmuschko.docker-remote-api")
id("java")
}

dependencies {
subprojects.forEach { "dist"(project(":${it.name}")) }
}

sourceSets.named("test") {
java.srcDir("functional/src/test/java")
}

allprojects {
group = "com.project"

repositories {
jcenter()
mavenLocal()
maven { url = uri("https://plugins.gradle.org/m2/") }
maven { url = uri("https://oss.sonatype.org/content/groups/staging/") }
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
}
}

tasks.named("build") {
dependsOn("build-stack")
}

tasks.register("build-docker") {
group = "docker"
dependsOn("runFunctionalTest")
}

tasks.register("build-stack") {
group = "stack"
// https://github.com/Knotx/knotx-gradle-plugins/blob/master/src/main/kotlin/io/knotx/distribution.gradle.kts
dependsOn("assembleCustomDistribution")
mustRunAfter("build-docker")
}

apply(from = "https://raw.githubusercontent.com/Knotx/knotx-starter-kit/master/gradle/docker.gradle.kts")
apply(from = "https://raw.githubusercontent.com/Knotx/knotx-starter-kit/master/gradle/javaAndUnitTests.gradle.kts")

9 changes: 9 additions & 0 deletions api-gateway/security/buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
repositories {
mavenLocal()
mavenCentral()
gradlePluginPortal()
}
dependencies {
implementation("com.bmuschko:gradle-docker-plugin:4.10.0")
implementation("io.knotx:knotx-gradle-plugins:0.1.2")
}
11 changes: 11 additions & 0 deletions api-gateway/security/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM knotx/knotx:$knotx_version
LABEL maintainer="Knot.x Project"

COPY ./out/knotx /usr/local/knotx

ENV JAVA_OPTS "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=18092"

HEALTHCHECK --interval=5s --timeout=2s --retries=12 \
CMD curl --silent --fail localhost:8092/healthcheck || exit 1

CMD [ "knotx", "run-knotx" ]
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.project.test.functional;

import static io.restassured.RestAssured.given;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class BasicAuthITCase {

@Test
@DisplayName("GIVEN no authorization WHEN call basicAuth API EXPECT Unauthorized")
void givenNoAuthorizationWhenCallBasicAuthApiExpectUnauthorized() {
// @formatter:off
given()
.port(8092)
.when()
.get("/api/secure/basic")
.then()
.assertThat()
.statusCode(401);
// @formatter:on
}

@Test
@DisplayName("GIVEN authorization WHEN call basicAuth API EXPECT Ok")
void givenAuthorizationWhenCallBasicAuthApiExpectOk() {
// @formatter:off
given()
.port(8092)
.header("Authorization", "Basic am9objpzM2NyM3Q=")
.when()
.get("/api/secure/basic")
.then()
.assertThat()
.statusCode(200);
// @formatter:on
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.project.test.functional;

import static io.restassured.RestAssured.given;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class JWTAuthITCase {

@Test
@DisplayName("GIVEN no authorization WHEN call JWT secured API EXPECT Unauthorized")
void givenNoAuthorizationWhenCallBasicAuthApiExpectUnauthorized() {
// @formatter:off
given()
.port(8092)
.when()
.get("/api/secure/jwt")
.then()
.assertThat()
.statusCode(401);
// @formatter:on
}

@Test
@DisplayName("GIVEN authorization WHEN call JWT secured API EXPECT Ok")
void givenAuthorizationWhenCallBasicAuthApiExpectOk() {
// @formatter:off
given()
.port(8092)
.header("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.vPWK59pl5GWimz8UVbL3CmrceSfmNvvCgyzwLVV9jT8")
.when()
.get("/api/secure/jwt")
.then()
.assertThat()
.statusCode(200);
// @formatter:on
}
}
4 changes: 4 additions & 0 deletions api-gateway/security/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
version=2.0.0-SNAPSHOT
knotx.version=2.0.0
knotx.conf=knotx
docker.image.name=knotx-example/secure-api-gateway
Binary file not shown.
5 changes: 5 additions & 0 deletions api-gateway/security/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading

0 comments on commit 0ff272d

Please sign in to comment.