Fga tinkering
This commit is contained in:
parent
6abe8d9eb8
commit
278ec02a24
5 changed files with 120 additions and 58 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Ignore env file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Ignore pem files
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
|
32
Makefile
32
Makefile
|
@ -1,19 +1,37 @@
|
||||||
make: build
|
make: build-infra build
|
||||||
|
|
||||||
FGA_API_HOST="http://localhost:8080"
|
# Default environment variables
|
||||||
|
FGA_API=$${FGA_API:-"http://localhost:8080"}
|
||||||
|
PRIV_KEY_FILE=$${PRIV_KEY_FILE:-"jws-priv-key.pem"}
|
||||||
|
PRIV_KEY_FILE_SIZE=$${PRIV_KEY_FILE_SIZE:-2048}
|
||||||
|
DOCKER_FILE=$${DOCKER_FILE:-"docker-compose.yaml"}
|
||||||
|
|
||||||
.PHONY: infra-up
|
# Phony targets
|
||||||
|
.PHONY: infra-down infra-up check build clean
|
||||||
|
|
||||||
|
|
||||||
|
# Generate private key
|
||||||
|
gen-key:
|
||||||
|
echo ${PRIV_KEY_FILE} ${PRIV_KEY_FILE_SIZE}
|
||||||
|
@openssl genrsa -out ${PRIV_KEY_FILE} ${PRIV_KEY_FILE_SIZE}
|
||||||
|
|
||||||
infra-up:
|
infra-up:
|
||||||
@docker compose -f docker-compose.yaml up -d
|
@docker compose -f ${DOCKER_FILE} up -d
|
||||||
|
|
||||||
|
infra-down:
|
||||||
|
@docker compose -f ${DOCKER_FILE} down
|
||||||
|
|
||||||
|
|
||||||
.PHONY: check
|
|
||||||
check:
|
check:
|
||||||
@curl -X GET "${FGA_API_HOST}/healthz"
|
@curl -X GET "${FGA_API}/healthz"
|
||||||
|
|
||||||
.PHONY: build
|
|
||||||
build:
|
build:
|
||||||
@go build
|
@go build
|
||||||
|
|
||||||
|
run:
|
||||||
|
@env $(cat .env | grep -v "#" | xargs) ./fga-demo
|
||||||
|
|
||||||
|
# Clean binary data and priv key
|
||||||
clean:
|
clean:
|
||||||
@go clean
|
@go clean
|
||||||
|
@rm ${PRIV_KEY_FILE}
|
||||||
|
|
BIN
fga-demo
BIN
fga-demo
Binary file not shown.
36
gen_jwt.sh
Executable file
36
gen_jwt.sh
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
# From https://stackoverflow.com/questions/59002949/how-to-create-a-json-web-token-jwt-using-openssl-shell-commands
|
||||||
|
key=jws-priv-key.pem
|
||||||
|
|
||||||
|
# Construct the header
|
||||||
|
jwt_header=$(echo -n '{"alg":"HS256","typ":"JWT"}' | base64 | sed s/\+/-/g | sed 's/\//_/g' | sed -E s/=+$//)
|
||||||
|
|
||||||
|
# ans: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
|
||||||
|
|
||||||
|
# Construct the payload
|
||||||
|
payload=$(echo -n '{"email":"jordan@example.com"}' | base64 | sed s/\+/-/g |sed 's/\//_/g' | sed -E s/=+$//)
|
||||||
|
|
||||||
|
# ans: eyJlbWFpbCI6ImpvcmRhbkBleGFtcGxlLmNvbSJ9
|
||||||
|
|
||||||
|
# Store the raw user secret (with example of newline at end)
|
||||||
|
secret=$'bigsecretisveryhardtoguessbysneakypeopleright\n'
|
||||||
|
|
||||||
|
# Note, because the secret may have newline, need to reference using form $""
|
||||||
|
echo -n "$secret"
|
||||||
|
|
||||||
|
# Convert secret to hex (not base64)
|
||||||
|
hexsecret=$(echo -n "$secret" | xxd -p | paste -sd "")
|
||||||
|
|
||||||
|
# ans: 62696773656372657469737665727968617264746f67756573736279736e65616b7970656f706c6572696768740a
|
||||||
|
|
||||||
|
# For debug, also display secret in base64 (for input into https://jwt.io/)
|
||||||
|
echo -n "$secret" | base64
|
||||||
|
|
||||||
|
# ans: Ymlnc2VjcmV0aXN2ZXJ5aGFyZHRvZ3Vlc3NieXNuZWFreXBlb3BsZXJpZ2h0Cg==
|
||||||
|
|
||||||
|
# Calculate hmac signature -- note option to pass in the key as hex bytes
|
||||||
|
hmac_signature=$(echo -n "${jwt_header}.${payload}" | openssl dgst -sha256 -mac HMAC -macopt hexkey:$hexsecret -binary | base64 | sed s/\+/-/g | sed 's/\//_/g' | sed -E s/=+$//)
|
||||||
|
|
||||||
|
# Create the full token
|
||||||
|
jwt="${jwt_header}.${payload}.${hmac_signature}"
|
||||||
|
|
||||||
|
# ans: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImpvcmRhbkBleGFtcGxlLmNvbSJ9.C3MVjfmnul8dLNIgiv6Dt3jSefD07Y0QtDrOZ5oYSXo
|
103
main.go
103
main.go
|
@ -2,11 +2,13 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
jwt_fiber "github.com/gofiber/jwt/v3"
|
jwt_fiber "github.com/gofiber/jwt/v3"
|
||||||
|
@ -14,38 +16,12 @@ import (
|
||||||
fga "github.com/openfga/go-sdk"
|
fga "github.com/openfga/go-sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
const privKeyPEM = `
|
const PRIV_KEY_PATH_ENV = "PRIV_KEY_PATH"
|
||||||
-----BEGIN RSA PRIVATE KEY-----
|
const PRIV_KEY_SIZE_ENV = "PRIV_KEY_SIZE"
|
||||||
MIIEogIBAAKCAQEAtezzFs7wK1WqA7lFUOqbCNXkcnHKGs/eIlHHN1MfXN6QjzBU
|
|
||||||
1yz+d+QeRM986PYttFB041RF+9QoNJcfow26TUhwgY8UEyeh+93hYGWT/grWJn3r
|
|
||||||
lKhZcjOBQ3M9DDsg2oEoRZI7pOwUcoj0OpJHz0dcoj4zrkfY1JPCWLFJbr1QszsX
|
|
||||||
Yy/soga2M5jHyVNtYz/c4JAGjQMZpnA7tGbdsGFvnZDdH1t5naKX+ybAQYItwWjo
|
|
||||||
9kBwhf1QGoaEVm0gvu9e+VaqKT+qnqMsGqYW29iKWOSerIg1lushZL8TulAPMwFs
|
|
||||||
wzttRvEPqcQzCKYtbNfenmvZJIajA6HYq/lc7QIDAQABAoIBAE201Sxj3dAUuhb3
|
|
||||||
FvV2EByZCAgeNH55VV+BYL9v4NCRPFv8//AdBuB87rTjj24OYP1I9HR5dZ8YQsgb
|
|
||||||
2OaToYULMQsV6zQ3VIg5gN/k4266gDhWxr5rnjEacNc3rNbBlsneKy50RMewExfN
|
|
||||||
CczO2J9f0uB2AyspAyPhrTynFT+YIvE8YflbLhUVVNhsSY/yoNTmd/ybNn5tTDQY
|
|
||||||
uT1v4wVw/6QGW1FTAmbR27MN1D+ALfFKyG8xJ5ElfoVWciiy/rneo+Ty1EZF/Z32
|
|
||||||
DFCt5/pNr9g0hPIlBnCtMOHRUmTbfnHuWiJ0ibaMr6UC+AVgiIUKxpjbQT3hDAkW
|
|
||||||
MX9VTB0CgYEA5Az5/hGYBWkjgsk0atwK5hTyKmnxq/fIvXVReh6PT+dIeEbBkWud
|
|
||||||
kTat4eMZMJA/gGwkxwyBNXodFWYIhWxjiGdIpS2SXiyfQRTZPi1o3VOuw4OiYGBf
|
|
||||||
pb6kwD+dT39QcoOAU+PsQJesONbc4EETrVnPSE3+QW3YBsb2+my2KSsCgYEAzDjP
|
|
||||||
tyqR06rgwCcHF4EDIMizCRXhIXmMKrQyueI2QbtFFzpeTei1HzE5zqia/PlPpmWQ
|
|
||||||
t2ZadBBIhgj+XJF70GTq4v1Mphx8YaMkZlfjRree0vOLTXHmlV8IL/i2SnYTvzRg
|
|
||||||
PPFIUGxN9ICqNMC+syBdTUsnF4GxRbartEQe1kcCgYA3skukF5vvRlxb5tQcfR1U
|
|
||||||
UC1M2o8hluS6ENsTXj9WHoB+j5la8NOM0bPqBVLzn2dC8CaTTqSH8QkFXuQZ4fz1
|
|
||||||
JXSCkvy6b199v5/HJcQEuhlmutF/hEoX6tXF9kNvVQLK1P8UfggHRoPTZfaP9pTd
|
|
||||||
s5+CYzoDtNYb4aAUTVS3/QKBgF/uG9x9maylKxf3/UPULWT8AeW1qmAwGWCB7wYU
|
|
||||||
Ncpgro6/s0bDljkFxZLG7q8AaaLPONB9uuWkNH0Jwno3OMLmdNOViqjI3sB6gwG0
|
|
||||||
LSWt4WRUVM5XP6pQzqbCHNcTaik58C8QZBirF19QBSPsmmfIPyusrrtDB8OokDWI
|
|
||||||
fjfHAoGAJEwPDCzGi/4UXd221GaYidif2GW8Dpo2kqZQAC42IQwxuEw3LgWMj0v4
|
|
||||||
IQEfT6OOYgeMmM5/qJ0RSkox6uvwlUzNpcaFzXAfmu+JNxo2LFvV/dkS+BbZyZ/Z
|
|
||||||
HfmMlyl+W5OXOHodg+R7J/UWupYnPp0TwlWKWYUCfM88KbIl2jk=
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
`
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
privateKey *rsa.PrivateKey
|
privateKey *rsa.PrivateKey
|
||||||
|
privateKeySize int
|
||||||
)
|
)
|
||||||
|
|
||||||
func createStore() {
|
func createStore() {
|
||||||
|
@ -82,40 +58,65 @@ func createStore() {
|
||||||
|
|
||||||
fmt.Println(store_resp)
|
fmt.Println(store_resp)
|
||||||
fmt.Println(http_resp)
|
fmt.Println(http_resp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PRIV_KEY_SIZE = 2048
|
func readRSAPrivKey(path string) (*rsa.PrivateKey, error) {
|
||||||
|
file, errOpen := os.Open(os.Getenv(PRIV_KEY_PATH_ENV))
|
||||||
|
|
||||||
func readController(c *fiber.Ctx) error {
|
if errOpen != nil {
|
||||||
user := c.Locals("user").(*jwt.Token)
|
log.Fatalf("Error while loading %s private key", PRIV_KEY_PATH_ENV)
|
||||||
claims := user.Claims.(jwt.MapClaims)
|
return nil, errors.New("Error while opening private key")
|
||||||
name := claims["name"].(string)
|
|
||||||
return c.SendString(name + " read " + c.Params("document"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func runFiber() {
|
|
||||||
app := fiber.New()
|
|
||||||
rng := rand.Reader
|
|
||||||
var err error
|
|
||||||
privateKey, err = rsa.GenerateKey(rng, PRIV_KEY_SIZE)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("rsa.GenerateKey: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
keyData, errReading := ioutil.ReadAll(file)
|
||||||
|
|
||||||
|
if errReading != nil {
|
||||||
|
log.Fatalf("Error reading %s private key", PRIV_KEY_PATH_ENV)
|
||||||
|
return nil, errors.New("Error while reading private key")
|
||||||
|
}
|
||||||
|
|
||||||
|
return jwt.ParseRSAPrivateKeyFromPEM(keyData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDocument(c *fiber.Ctx) error {
|
||||||
|
log.Println(c)
|
||||||
|
// user := c.Locals("user").(*jwt.Token)
|
||||||
|
// claims := user.Claims.(jwt.MapClaims)
|
||||||
|
// name := claims["name"].(string)
|
||||||
|
// return c.SendString(name + " read " + c.Params("document"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runFiber(privateKey *rsa.PrivateKey) {
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
log.Println(privateKey.Public())
|
||||||
app.Use(jwt_fiber.New(jwt_fiber.Config{
|
app.Use(jwt_fiber.New(jwt_fiber.Config{
|
||||||
SigningMethod: "RS256",
|
SigningMethod: "RS256",
|
||||||
SigningKey: privateKey.Public(),
|
SigningKey: privateKey.Public(),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
app.Get("/read/:document", readController)
|
app.Get("/read/:document", readDocument)
|
||||||
|
|
||||||
app.Listen(":9999")
|
app.Listen(":9999")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
var err error = nil
|
||||||
|
privateKeySize, err = strconv.Atoi(os.Getenv(PRIV_KEY_SIZE_ENV))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error while geting private key size from %s environment variable", PRIV_KEY_SIZE_ENV)
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err = readRSAPrivKey(os.Getenv(PRIV_KEY_PATH_ENV))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error while geting private key from %s environment variable", PRIV_KEY_PATH_ENV)
|
||||||
|
}
|
||||||
|
|
||||||
createStore()
|
createStore()
|
||||||
runFiber()
|
runFiber(privateKey)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue