6dccf494f8
cleanup permit policies and correct documentation * docs * policy cleanup * refactor * Merge remote-tracking branch 'origin/feature/permit-policy-cleanup' into feature/permit-policy-cleanup * docs and edits
219 lines
6.1 KiB
Go
219 lines
6.1 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/permitio/permit-golang/pkg/config"
|
|
"github.com/permitio/permit-golang/pkg/enforcement"
|
|
"github.com/permitio/permit-golang/pkg/permit"
|
|
)
|
|
|
|
const (
|
|
port = 4000
|
|
readTimeout = 10 * time.Second
|
|
writeTimeout = 30 * time.Second
|
|
idleTimeout = 120 * time.Second
|
|
|
|
// This is the subject value from our JWT once we have authenticated.
|
|
// Also found in the cognito user pool for the testuser.
|
|
testUserSubject = "e12bb510-30e1-7062-a69a-ca7f3f38d80e"
|
|
)
|
|
|
|
func main() {
|
|
// Get PDP URL from environment variable, default to local OPAL
|
|
pdpURL := os.Getenv("AUTH_PDP_URL")
|
|
if pdpURL == "" {
|
|
pdpURL = "http://localhost:7766"
|
|
}
|
|
|
|
// Get API key from environment variable (still needed for OPAL)
|
|
permitKey := os.Getenv("PERMIT_IO_KEY")
|
|
if permitKey == "" {
|
|
log.Fatal("PERMIT_IO_KEY environment variable is not set")
|
|
}
|
|
|
|
// Initialize the Permit.io SDK
|
|
permitClient := initPermitClient(permitKey, pdpURL)
|
|
|
|
// Set up routes
|
|
mux := setupRoutes(permitClient)
|
|
|
|
// Start server with timeout settings
|
|
startServer(port, mux)
|
|
}
|
|
|
|
// initPermitClient initializes and returns the Permit.io client
|
|
func initPermitClient(permitKey string, pdpURL string) *permit.Client {
|
|
return permit.NewPermit(
|
|
config.NewConfigBuilder(permitKey).
|
|
WithPdpUrl(pdpURL).
|
|
Build(),
|
|
)
|
|
}
|
|
|
|
// setupRoutes configures and returns the HTTP routes
|
|
func setupRoutes(permitClient *permit.Client) *http.ServeMux {
|
|
mux := http.NewServeMux()
|
|
|
|
// Register the endpoints
|
|
mux.HandleFunc("/query-endpoint", createPermissionHandler(permitClient, "query-endpoint"))
|
|
mux.HandleFunc("/admin-stuff", createPermissionHandler(permitClient, "admin-stuff"))
|
|
mux.HandleFunc("/", createHomeHandler())
|
|
|
|
return mux
|
|
}
|
|
|
|
// createHomeHandler returns the handler function for the root path
|
|
func createHomeHandler() http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "text/html")
|
|
_, err := w.Write([]byte(`
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Permit.io Test Harness</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
padding: 20px;
|
|
}
|
|
a {
|
|
display: block;
|
|
margin: 10px 0;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Permit.io Test Harness</h1>
|
|
<h2>Available endpoints:</h2>
|
|
<a href="/query-endpoint?action=read">Query Endpoint - Read Action</a>
|
|
<a href="/query-endpoint?action=write">Query Endpoint - Write Action</a>
|
|
<a href="/admin-stuff?action=read">Admin Stuff - Read Action</a>
|
|
<a href="/admin-stuff?action=write">Admin Stuff - Write Action</a>
|
|
</body>
|
|
</html>
|
|
`))
|
|
if err != nil {
|
|
log.Printf("Error writing response: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// createPermissionHandler creates a handler function for permission checks
|
|
func createPermissionHandler(permitClient *permit.Client, resourceType string) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
// Get and validate the action parameter
|
|
action, err := validateActionParam(r)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
_, writeErr := w.Write([]byte(err.Error()))
|
|
if writeErr != nil {
|
|
log.Printf("Error writing response: %v", writeErr)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Check permission
|
|
permitted, err := checkPermission(permitClient, testUserSubject, action, resourceType)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
_, writeErr := w.Write([]byte(fmt.Sprintf("Error checking permissions: %v", err)))
|
|
if writeErr != nil {
|
|
log.Printf("Error writing response: %v", writeErr)
|
|
}
|
|
return
|
|
}
|
|
|
|
// Determine response status and color
|
|
status, httpStatus, backgroundColor := getResponseStatus(permitted)
|
|
|
|
// Render the HTML response
|
|
renderHTMLResponse(w, resourceType, action, status, httpStatus, backgroundColor)
|
|
}
|
|
}
|
|
|
|
// validateActionParam extracts and validates the action parameter from the request
|
|
func validateActionParam(r *http.Request) (string, error) {
|
|
action := r.URL.Query().Get("action")
|
|
if action == "" {
|
|
return "", fmt.Errorf("Missing 'action' parameter")
|
|
}
|
|
return action, nil
|
|
}
|
|
|
|
// checkPermission performs the permission check using the Permit.io client
|
|
func checkPermission(permitClient *permit.Client, userID string, action string, resourceType string) (bool, error) {
|
|
// Create user for permission check
|
|
user := enforcement.UserBuilder(userID).Build()
|
|
|
|
// Create resource based on the endpoint
|
|
resource := enforcement.ResourceBuilder(resourceType).Build()
|
|
|
|
// Check permission
|
|
return permitClient.Check(user, enforcement.Action(action), resource)
|
|
}
|
|
|
|
// getResponseStatus determines the response status based on permission result
|
|
func getResponseStatus(permitted bool) (string, int, string) {
|
|
if permitted {
|
|
return "PERMITTED *********** OK ", http.StatusOK, "#d4ffcc" // Light green
|
|
}
|
|
return "NOT PERMITTED", http.StatusForbidden, "#ffcccc" // Light red
|
|
}
|
|
|
|
// renderHTMLResponse generates and sends the HTML response
|
|
func renderHTMLResponse(w http.ResponseWriter, resourceType, action, status string, httpStatus int, backgroundColor string) {
|
|
w.WriteHeader(httpStatus)
|
|
w.Header().Set("Content-Type", "text/html")
|
|
html := fmt.Sprintf(`
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Permit.io Test Result</title>
|
|
<style>
|
|
body {
|
|
background-color: %s;
|
|
font-family: Arial, sans-serif;
|
|
padding: 20px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Permission Check Result</h1>
|
|
<p>Action '%s' on endpoint '%s' was %s</p>
|
|
<p><a href="/">Back to home</a></p>
|
|
</body>
|
|
</html>
|
|
`, backgroundColor, action, resourceType, status)
|
|
_, err := w.Write([]byte(html))
|
|
if err != nil {
|
|
log.Printf("Error writing response: %v", err)
|
|
}
|
|
}
|
|
|
|
// startServer starts the HTTP server with proper timeout settings
|
|
func startServer(port int, handler http.Handler) {
|
|
// Create a server with timeout settings
|
|
server := &http.Server{
|
|
Addr: fmt.Sprintf(":%d", port),
|
|
Handler: handler,
|
|
ReadTimeout: readTimeout,
|
|
WriteTimeout: writeTimeout,
|
|
IdleTimeout: idleTimeout,
|
|
}
|
|
|
|
// Start the server
|
|
fmt.Printf("Listening on http://localhost:%d\n", port)
|
|
if err := server.ListenAndServe(); err != nil {
|
|
log.Fatalf("Server error: %v", err)
|
|
}
|
|
}
|