Templating creating new policy
This commit is contained in:
199
create-policy.go
Normal file
199
create-policy.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"libshared"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
// Custom claims struct
|
||||
type MyClaims struct {
|
||||
Sub string `json:"sub"`
|
||||
Purpose string `json:"purpose"`
|
||||
Account string `json:"account"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
type PolicyRequest struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
PolicyDocument Policy `json:"policydocument"`
|
||||
}
|
||||
|
||||
type PolicyResponse struct {
|
||||
// PolicyID string `json:"policy_id"`
|
||||
}
|
||||
|
||||
func CreatePolicy(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.Println("Create Policy Request")
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
// Only allow POST method
|
||||
if r.Method != http.MethodPost {
|
||||
log.Println("Invalid method:", r.Method)
|
||||
//w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Method not allowed", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
return
|
||||
}
|
||||
// Optional: enforce content type
|
||||
if r.Header.Get("Content-Type") != "application/json" {
|
||||
log.Println("Invalid Content-Type:", r.Header.Get("Content-Type"))
|
||||
//w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Content-Type must be application/json", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
//http.Error(w, "Content-Type must be application/json", http.StatusUnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
|
||||
// Get JWT from Authorization header
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
log.Println("Missing Authorization header")
|
||||
//w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Missing Authorization header", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
//http.Error(w, "Missing Authorization header", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
log.Println("Invalid Authorization header format")
|
||||
//w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Invalid Authorization format", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
//http.Error(w, "Invalid Authorization format", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
tokenString := parts[1]
|
||||
|
||||
// Replace with your actual secret or keyfunc
|
||||
secret := []byte("super-secret-key")
|
||||
|
||||
claims := &MyClaims{}
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
// Validate signing method if needed
|
||||
return secret, nil
|
||||
})
|
||||
|
||||
if err != nil || !token.Valid {
|
||||
log.Println("Invalid token:", err)
|
||||
//http.Error(w, "Invalid token", http.StatusUnauthorized)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Invalid token", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
return
|
||||
}
|
||||
|
||||
// Access parsed values
|
||||
log.Println("sub:", claims.Sub)
|
||||
log.Println("purpose:", claims.Purpose)
|
||||
log.Println("account:", claims.Account)
|
||||
// exp and iat come from RegisteredClaims
|
||||
log.Println("exp:", claims.ExpiresAt)
|
||||
log.Println("iat:", claims.IssuedAt)
|
||||
|
||||
// Read body with size limit (protect against huge requests)
|
||||
const maxBodyBytes = 1 << 20 // 1 MB
|
||||
r.Body = http.MaxBytesReader(w, r.Body, maxBodyBytes)
|
||||
|
||||
// Decode JSON into our struct
|
||||
var policydocumentrequest PolicyRequest
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
decoder.DisallowUnknownFields() // strict mode - reject unknown fields
|
||||
|
||||
if err := decoder.Decode(&policydocumentrequest); err != nil {
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
log.Println("Empty request body")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Empty request body", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
//http.Error(w, "Empty request body", http.StatusBadRequest)
|
||||
return
|
||||
case err.Error() == "http: request body too large":
|
||||
log.Println("Request body too large")
|
||||
w.WriteHeader(http.StatusRequestEntityTooLarge)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Request body too large (max 1MB)", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
//http.Error(w, "Request body too large (max 1MB)", http.StatusRequestEntityTooLarge)
|
||||
return
|
||||
default:
|
||||
log.Println("Invalid JSON:", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", fmt.Sprintf("Invalid JSON: %v", err), PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
//http.Error(w, fmt.Sprintf("Invalid JSON: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
checkExisting := libshared.Pool.QueryRow(
|
||||
context.Background(),
|
||||
`SELECT FROM policies WHERE name=$1 AND accountid=$2`,
|
||||
policydocumentrequest.Name,
|
||||
claims.Account,
|
||||
)
|
||||
err = checkExisting.Scan()
|
||||
if err == nil {
|
||||
log.Println("Policy with this name already exists for this account")
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Policy with this name already exists", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = libshared.Pool.Exec(
|
||||
context.Background(),
|
||||
`INSERT INTO policies (name, accountid, description, document) VALUES ($1, $2, $3, $4)`,
|
||||
policydocumentrequest.Name,
|
||||
claims.Account,
|
||||
policydocumentrequest.Description,
|
||||
policydocumentrequest.PolicyDocument,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Database error:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("fail", "Internal server error", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
return
|
||||
}
|
||||
|
||||
// Success response
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
|
||||
apiresponse := libshared.NewAPIResponse[PolicyResponse]("success", "Policy created", PolicyResponse{})
|
||||
json.NewEncoder(w).Encode(apiresponse)
|
||||
|
||||
// arnservice:region:account-id:resource-type:resource-id
|
||||
//pri := "pri:iam::" + accountid + ":policy/" + policydocumentrequest.PolicyName
|
||||
|
||||
// response := map[string]interface{}{
|
||||
// "status": "success",
|
||||
// //"pri": pri,
|
||||
// "message": "Policy created",
|
||||
// "timestamp": fmt.Sprintf("%d", time.Now().Unix()),
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user