Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-pimenta-DME committed Oct 10, 2023
1 parent 9b66aad commit 943ece6
Show file tree
Hide file tree
Showing 17 changed files with 517 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
KEYCLOAK_LOGLEVEL=DEBUG
WILDFLY_LOGLEVEL=DEBUG
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=admin
KC_DB_URL_HOST=postgres
KC_DB=postgres
KC_DB_USERNAME=keycloak
KC_DB_PASSWORD=123456
KC_DB_URL_PORT=5432
KC_HEALTH_ENABLED=true
KC_FEATURES=account3,admin-fine-grained-authz,declarative-user-profile,recovery-codes,scripts
32 changes: 32 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "auth mode",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"args": [ "-auth", "-port", "8080" ]
},
{
"name": "resource mode",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"args": [ "-resource", "-port", "9090" ]
},
{
"name": "full mode",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${fileDirname}",
"args": [ "-auth", "-resource", "-port", "8080" ]
}
]
}
10 changes: 10 additions & 0 deletions app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM golang:alpine as builder
WORKDIR /appbuild
COPY src .
RUN go build

FROM alpine
WORKDIR /app
COPY --from=builder /appbuild/peptest .
ENTRYPOINT [ "/app/peptest" ]
CMD []
8 changes: 8 additions & 0 deletions app/src/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/rconway/peptest

go 1.16

require (
github.com/gorilla/mux v1.8.0
github.com/rconway/goutils v0.0.0-20210618151717-8d9e4a39ba6c
)
7 changes: 7 additions & 0 deletions app/src/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rconway/goutils v0.0.0-20210618151717-8d9e4a39ba6c h1:vNIgDcVdWK3U3DU8ktBTGQwcUCzRo4UJpbFJDpJiP5k=
github.com/rconway/goutils v0.0.0-20210618151717-8d9e4a39ba6c/go.mod h1:NT+m+AJMyUyPkQaIFExZeougOHEWmu+ShP8uI5GXPVo=
105 changes: 105 additions & 0 deletions app/src/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package main

import (
"flag"
"fmt"
"log"
"net/http"
"os"
"strconv"
"strings"

"github.com/gorilla/mux"
"github.com/rconway/goutils/httputils"
)

func main() {
// Flags
var authMode bool
var resourceMode bool
var port int
flag.BoolVar(&authMode, "auth", false, "use auth mode")
flag.BoolVar(&resourceMode, "resource", false, "use resource mode")
flag.IntVar(&port, "port", 80, "port to listen on")
flag.Parse()

router := mux.NewRouter()

// select handler based upon the indicated mode
var handler http.HandlerFunc
if authMode {
fmt.Println("auth mode enabled")
handler = authHandler
} else if resourceMode {
fmt.Println("resource mode enabled")
handler = resourceHandler
} else {
log.Fatal(fmt.Errorf("must specify one of -auth or -resource"))
}

// root
router.PathPrefix("/").HandlerFunc(handler)

// Start server
addr := fmt.Sprintf(":%v", port)
fmt.Printf("Starting to listen at %v\n", addr)
log.Fatal(http.ListenAndServe(addr, router))
}

// Handler to provide the 'auth' response
func authHandler(w http.ResponseWriter, r *http.Request) {
var statusCode int

// Response - deferred to end of function
defer func() {
w.Header().Set("WWW-Authenticate", "use this ticket: 123ABC")
w.WriteHeader(statusCode)
fmt.Fprintf(w, "Endpoint = Auth Handler\n")
httputils.DumpRequest(w, r)
httputils.DumpRequest(os.Stdout, r)
}()

// Get the Authorization header
authorizationStr := r.Header.Get("Authorization")

// UNAUTHORIZED - if there is no Authorization header then treat as UNAUTHORIZED
if len(authorizationStr) == 0 {
fmt.Println("UNAUTHORIZED: no Authorization header")
statusCode = http.StatusUnauthorized
return
}

// Get the Bearer token from the Authorization header
authParts := strings.Split(authorizationStr, " ")

// UNAUTHORIZED - if there is no Bearer token
if len(authParts) != 2 || authParts[0] != "Bearer" {
fmt.Println("UNAUTHORIZED: no Bearer token")
statusCode = http.StatusUnauthorized
return
}

// Get the value of the token as an int
requestedCode, err := strconv.Atoi(authParts[1])

// UNAUTHORIZED - if the Bearer token value is not an int
if err != nil {
fmt.Println("UNAUTHORIZED: non-integer Bearer token")
statusCode = http.StatusUnauthorized
return
}

// All checks pass - use the provided status code
w.Header().Set("X-Pep-Special-Header", "If needed, extra header(s) set by PEP")
statusCode = requestedCode
}

// Handler for the 'protected' resource
func resourceHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Endpoint = Resource Server\n")
httputils.DumpRequest(w, r)
// Output to stdout - but suppress output for k8s liveness probes
if !strings.HasPrefix(r.Header.Get("User-Agent"), "kube-probe/") {
httputils.DumpRequest(os.Stdout, r)
}
}
92 changes: 92 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
version: "3"

services:
# PROXY running in nginx
nginx:
image: nginx
container_name: nginx
networks:
- peptest
ports:
- 80:80
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
# PEP: running app `peptest -auth`
pep:
build: ./app
container_name: pep
command: ["-auth"]
networks:
- peptest
# ADES: running app `peptest -resource`
ades:
build: ./app
container_name: ades
depends_on:
- pep
command: ["-resource"]
networks:
- peptest
gatekeeper:
image: quay.io/gogatekeeper/gatekeeper:2.8.0
container_name: gatekeeper
ports:
- '3000:3000'
restart: on-failure
volumes:
- ./gatekeeper.yml:/gatekeeper/config.yml/:ro
environment:
- PROXY_CONFIG_FILE=/gatekeeper/config.yml
networks:
- peptest
keycloak:
image: quay.io/keycloak/keycloak:22.0.3
container_name: keycloak
restart: on-failure
ports:
- '8080:8080'
environment:
- KEYCLOAK_LOGLEVEL=${KEYCLOAK_LOGLEVEL}
- WILDFLY_LOGLEVEL=${WILDFLY_LOGLEVEL}
- KEYCLOAK_ADMIN=${KEYCLOAK_ADMIN}
- KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_ADMIN_PASSWORD}
- KC_DB_URL_HOST=${KC_DB_URL_HOST}
- KC_DB=${KC_DB}
- KC_DB_USERNAME=${KC_DB_USERNAME}
- KC_DB_PASSWORD=${KC_DB_PASSWORD}
- KC_DB_URL_PORT=${KC_DB_URL_PORT}
- KC_HEALTH_ENABLED=${KC_HEALTH_ENABLED}
- KC_FEATURES=${KC_FEATURES}
entrypoint: /opt/keycloak/bin/kc.sh start-dev
depends_on:
postgres:
condition: service_healthy
networks:
- peptest
postgres:
image: postgres:16.0
container_name: postgres
ports:
- '5432:5432'
volumes:
- ./postgres/data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=keycloak
- POSTGRES_USER=keycloak
- PGUSER=keycloak
- POSTGRES_PASSWORD=123456
- PGPASSWORD=123
- PGDATA=/var/lib/postgresql/data/keycloak
healthcheck:
test: ["CMD-SHELL", "pg_isready -d keycloak -U keycloak"]
interval: 10s
timeout: 5s
retries: 5
networks:
- peptest
networks:
peptest:
driver: bridge
ipam:
config:
- subnet: 192.168.234.0/24
14 changes: 14 additions & 0 deletions gatekeeper.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
discovery-url: http://keycloak:8080/realms/demo
client-id: dummy-service
client-secret: 52Bn2RNG6cERxGSB7EYwx9gOQILvkTNg
encryption-key: AgXa7xRcoClDEU0ZDSH4X0XhL5Qy2Z2j
upstream-url: http://ades
secure-cookie: false
enable-request-id: true
enable-refresh-tokens: true
enable-login-handler: true
enable-uma: true
enable-logout-redirect: true
enable-metrics: true
enable-logging: true
listen: :3000
58 changes: 58 additions & 0 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

events {}

http {
server {
listen 80;
proxy_buffers 4 512k;
proxy_buffer_size 256k;
# Need to specify a DNS resolver because we are using variables to
# specify the proxy_pass hostnames. This approach is useful because it
# allows nginx to start if the referenced endpoints are unobtainable
# - instead they are checked at runtime, hence the resolver requirement.
#
# This is the internal Docker DNS, cache only for 30s
# IMPORTANT: If using docker-compose with reliance upon internal DNS lookups
# between services, then use this...
resolver 127.0.0.11 valid=30s;
#
# Or google...
# resolver 8.8.8.8;

# the protected resource we are trying to reach
location /ades {
auth_request /authcheck;
set $protected_address ades;
proxy_pass http://$protected_address/;
auth_request_set $pep_special_header $upstream_http_x_pep_special_header;
proxy_set_header "X-Pep-Special-Header" $pep_special_header;
}

# the endpoint for performing auth checks
location /authcheck {
internal;
set $pep_address pep;
proxy_pass http://$pep_address/;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Method $request_method;
}

location / {
proxy_pass http://gatekeeper:3000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Host $host:80;
proxy_set_header X-Forwarded-Port 80;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 1;
proxy_read_timeout 30;
proxy_send_timeout 30;
proxy_http_version 1.1;
}
}
}
10 changes: 10 additions & 0 deletions requests/authorized.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

ORIG_DIR="$(pwd)"
cd "$(dirname "$0")"
BIN_DIR="$(pwd)"

trap "cd '${ORIG_DIR}'" EXIT

curl -v --location --request GET 'localhost/ades' \
--header 'Authorization: Bearer 200'
10 changes: 10 additions & 0 deletions requests/forbidden.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

ORIG_DIR="$(pwd)"
cd "$(dirname "$0")"
BIN_DIR="$(pwd)"

trap "cd '${ORIG_DIR}'" EXIT

curl -v --location --request GET 'localhost/ades' \
--header 'Authorization: Bearer 403'
Loading

0 comments on commit 943ece6

Please sign in to comment.