package main import ( "context" "encoding/json" "fmt" "io" "libshared" "log" "net/http" "strings" "time" "github.com/golang-jwt/jwt/v5" ) /* * Returns a temporary token with the permissions of the specified role. */ type AssumeRoleRequest struct { Rolename string `json:"rolename"` } type AssumeRoleResponse struct { Token string `json:"token"` } func assumeRole(w http.ResponseWriter, r *http.Request) { log.Println("Assume Role Request") var response APIResponse[string] // Only allow POST if r.Method != http.MethodPost { response.Timestamp = time.Now().Unix() response.Status = "error" response.Message = "HTTP POST method not allowed" //response.Response: "Testing" w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusMethodNotAllowed) json.NewEncoder(w).Encode(response) return } // Get JWT from Authorization header authHeader := r.Header.Get("Authorization") if authHeader == "" { response.Timestamp = time.Now().Unix() response.Status = "error" response.Message = "HTTP POST method not allowed" //response.Response: "Testing" w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusUnauthorized) json.NewEncoder(w).Encode(response) return } parts := strings.SplitN(authHeader, " ", 2) if len(parts) != 2 || parts[0] != "Bearer" { fmt.Println("Invalid Authorization header format") 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 { fmt.Println("Invalid token:", err) http.Error(w, "Invalid token", http.StatusUnauthorized) 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) if claims.ExpiresAt == nil || time.Now().After(claims.ExpiresAt.Time) { log.Println("Token expired") http.Error(w, "Token expired", http.StatusUnauthorized) return } // Read the raw request body body, err := io.ReadAll(r.Body) if err != nil { log.Println("Failed to read body:", err) http.Error(w, "Failed to read body", http.StatusBadRequest) return } defer r.Body.Close() // Parse JSON into Role struct var role AssumeRoleRequest if err := json.Unmarshal(body, &role); err != nil { log.Println("Invalid JSON:", err) http.Error(w, "Invalid JSON", http.StatusBadRequest) return } if role.Rolename == "" { log.Println("Rolename is required") http.Error(w, "Rolename is required", http.StatusBadRequest) return } // Print the parsed values to terminal log.Println("Rolename:", role.Rolename) // Prevent duplication of roles with the same name for the same account checkExisting := pool.QueryRow(context.Background(), "SELECT id FROM roles WHERE accountid = $1 AND rolename = $2", claims.Account, role.Rolename) var existingRoleID int64 err = checkExisting.Scan(&existingRoleID) if err != nil { log.Println("Role does not exist", err) w.WriteHeader(http.StatusNotFound) return } fmt.Println("Role ID", existingRoleID) roleToken, err := createJWT(secret, claims.Account, role.Rolename) if err != nil { log.Println("Error creating JWT:", err) w.WriteHeader(http.StatusInternalServerError) return } fmt.Println(roleToken) apiresponse := libshared.APIResponse[AssumeRoleResponse]{} apiresponse.Timestamp = time.Now().Unix() apiresponse.Status = "success" apiresponse.Message = "Role assumed successfully" apiresponse.Content = AssumeRoleResponse{Token: roleToken} w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(apiresponse) // w.Write([]byte("JWT parsed successfully")) }