From a9433bc48eeb57a5e8a2b987c8433b07a9d121a1 Mon Sep 17 00:00:00 2001 From: wangruidong <940853815@qq.com> Date: Sat, 8 Feb 2025 18:25:41 +0800 Subject: [PATCH] perf: Go and Python demo code --- apps/accounts/demos/go/README.zh-hans.md | 226 +++++++++---------- apps/accounts/demos/python/README.zh-hans.md | 125 +++------- 2 files changed, 144 insertions(+), 207 deletions(-) diff --git a/apps/accounts/demos/go/README.zh-hans.md b/apps/accounts/demos/go/README.zh-hans.md index 5eaef3574..3b4e49a43 100644 --- a/apps/accounts/demos/go/README.zh-hans.md +++ b/apps/accounts/demos/go/README.zh-hans.md @@ -1,133 +1,121 @@ -# JumpServer PAM 客户端 - -该包提供了一个 Go 客户端,用于与 JumpServer PAM API 交互,以检索各种资产的密码。它简化了发送请求和处理响应的过程。 - -## 功能 - -- 在发送请求之前验证参数。 -- 支持基于资产和账户的密码检索。 -- 使用 HMAC-SHA256 签名进行身份验证,方便与 JumpServer PAM API 集成。 - -## 使用说明 - -1. **下载 Go 代码文件**: - 将代码文件下载到您的项目目录中。 - -2. **导入包**: - 在您的 Go 文件中导入该包,您即可直接使用其功能。 - -## 需求 - -- `Go 1.16+` -- `github.com/google/uuid` -- `gopkg.in/twindagger/httpsig.v1` - -## 使用方法 - -### 初始化 - -要使用 JumpServer PAM 客户端,通过提供所需的 `endpoint`、`keyID` 和 `keySecret` 创建一个实例。 - ```go package main import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "encoding/json" "fmt" - - "your_module_path/jms_pam" + "log" + "net/http" + "net/url" + "os" + "strings" + "time" ) -func main() { - client := jms_pam.NewJumpServerPAM( - "http://127.0.0.1", // 替换为您的 JumpServer 端点 - "your-key-id", // 替换为您的实际 Key ID - "your-key-secret", // 替换为您的实际 Key Secret - "", // 留空以使用默认的组织 ID +type APIClient struct { + Client *http.Client + APIURL string + KeyID string + KeySecret string + OrgID string +} + +func NewAPIClient() *APIClient { + return &APIClient{ + Client: &http.Client{}, + APIURL: getEnv("API_URL", "http://127.0.0.1:8080"), + KeyID: getEnv("API_KEY_ID", "72b0b0aa-ad82-4182-a631-ae4865e8ae0e"), + KeySecret: getEnv("API_KEY_SECRET", "6fuSO7P1m4cj8SSlgaYdblOjNAmnxDVD7tr8"), + OrgID: getEnv("ORG_ID", "00000000-0000-0000-0000-000000000002"), + } +} + +func getEnv(key, defaultValue string) string { + value := os.Getenv(key) + if value == "" { + return defaultValue + } + return value +} + +func (c *APIClient) GetAccountSecret(asset, account string) (map[string]interface{}, error) { + u, err := url.Parse(c.APIURL) + if err != nil { + return nil, fmt.Errorf("failed to parse API URL: %v", err) + } + u.Path = "/api/v1/accounts/integration-applications/account-secret/" + + q := u.Query() + q.Add("asset", asset) + q.Add("account", account) + u.RawQuery = q.Encode() + + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %v", err) + } + + date := time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05 GMT") + req.Header.Set("Accept", "application/json") + req.Header.Set("X-JMS-ORG", c.OrgID) + req.Header.Set("Date", date) + req.Header.Set("X-Source", "jms-pam") + + headersList := []string{"(request-target)", "accept", "date", "x-jms-org"} + var signatureParts []string + + for _, h := range headersList { + var value string + if h == "(request-target)" { + value = strings.ToLower(req.Method) + " " + req.URL.RequestURI() + } else { + canonicalKey := http.CanonicalHeaderKey(h) + value = req.Header.Get(canonicalKey) + } + signatureParts = append(signatureParts, fmt.Sprintf("%s: %s", h, value)) + } + + signatureString := strings.Join(signatureParts, "\n") + mac := hmac.New(sha256.New, []byte(c.KeySecret)) + mac.Write([]byte(signatureString)) + signatureB64 := base64.StdEncoding.EncodeToString(mac.Sum(nil)) + + headersJoined := strings.Join(headersList, " ") + authHeader := fmt.Sprintf( + `Signature keyId="%s",algorithm="hmac-sha256",headers="%s",signature="%s"`, + c.KeyID, + headersJoined, + signatureB64, ) + req.Header.Set("Authorization", authHeader) + + resp, err := c.Client.Do(req) + if err != nil { + return nil, fmt.Errorf("request failed: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("API returned non-200 status: %d", resp.StatusCode) + } + + var result map[string]interface{} + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return nil, fmt.Errorf("failed to decode response: %v", err) + } + + return result, nil } -``` - -### 创建密码请求 - -您可以通过指定资产或账户信息来创建请求。 - -```go -request, err := jms_pam.NewSecretRequest("Linux", "", "root", "") -if err != nil { - fmt.Println("创建请求时出错:", err) - return -} -``` - -### 发送请求 - -使用客户端的 `Send` 方法发送请求。 - -```go -secretObj, err := client.Send(request) -if err != nil { - fmt.Println("发送请求时出错:", err) - return -} -``` - -### 处理响应 - -检查密码是否成功检索,并相应地处理响应。 - -```go -if secretObj.Valid { - fmt.Println("密码:", secretObj.Secret) -} else { - fmt.Println("获取密码失败:", string(secretObj.Desc)) -} -``` - -### 完整示例 - -以下是如何使用该客户端的完整示例: - -```go -package main - -import ( - "fmt" - - "your_module_path/jms_pam" -) func main() { - client := jms_pam.NewJumpServerPAM( - "http://127.0.0.1", - "your-key-id", - "your-key-secret", - "", - ) - - request, err := jms_pam.NewSecretRequest("Linux", "", "root", "") + client := NewAPIClient() + result, err := client.GetAccountSecret("ubuntu_docker", "root") if err != nil { - fmt.Println("创建请求时出错:", err) - return - } - - secretObj, err := client.Send(request) - if err != nil { - fmt.Println("发送请求时出错:", err) - return - } - - if secretObj.Valid { - fmt.Println("密码:", secretObj.Secret) - } else { - fmt.Println("获取密码失败:", string(secretObj.Desc)) + log.Fatalf("Error: %v", err) } + fmt.Printf("Result: %+v\n", result) } -``` - -## 错误处理 - -该库会在创建 `SecretRequest` 时返回无效参数的错误。这包括对有效 UUID 的检查以及确保提供了必需的参数。 - -## 贡献 - -欢迎贡献!如有任何增强或错误修复,请提出问题或提交拉取请求。 +``` \ No newline at end of file diff --git a/apps/accounts/demos/python/README.zh-hans.md b/apps/accounts/demos/python/README.zh-hans.md index b7dcc5121..f2ec3182d 100644 --- a/apps/accounts/demos/python/README.zh-hans.md +++ b/apps/accounts/demos/python/README.zh-hans.md @@ -1,96 +1,45 @@ -# JumpServer PAM 客户端 - -该包提供了一个 Python 客户端,用于与 JumpServer PAM API 交互,以检索各种资产的密码。它简化了发送请求和处理响应的过程。 - -## 特性 - -- 在发送请求之前验证参数。 -- 支持基于资产和账户的密码检索。 -- 通过 HTTP 签名轻松集成 JumpServer PAM API。 - -## 安装 - -您可以通过 pip 安装该包: - -```bash -pip install jms_pam-0.0.1-py3-none-any.whl -``` - -## 需求 - -- `Python 3.6+` -- `requests` -- `httpsig` - -## 使用方法 - -### 初始化 - -要使用 JumpServer PAM 客户端,通过提供所需的 `endpoint`、`key_id` 和 `key_secret` 创建一个实例。 - ```python -from jms_pam import JumpServerPAM, SecretRequest +import requests +import os +from datetime import datetime +from httpsig.requests_auth import HTTPSignatureAuth -client = JumpServerPAM( - endpoint='http://127.0.0.1', - key_id='your-key-id', - key_secret='your-key-secret' -) -``` +API_URL = os.getenv("API_URL", "http://127.0.0.1:8080") +KEY_ID = os.getenv("API_KEY_ID", "72b0b0aa-ad82-4182-a631-ae4865e8ae0e") +KEY_SECRET = os.getenv("API_KEY_SECRET", "6fuSO7P1m4cj8SSlgaYdblOjNAmnxDVD7tr8") +ORG_ID = os.getenv("ORG_ID", "00000000-0000-0000-0000-000000000002") -### 创建密码请求 -您可以通过指定资产或账户信息来创建一个密码请求。 +class APIClient: + def __init__(self): + self.session = requests.Session() + self.auth = HTTPSignatureAuth( + key_id=KEY_ID, secret=KEY_SECRET, + algorithm='hmac-sha256', headers=['(request-target)', 'accept', 'date', 'x-jms-org'] + ) -```python -request = SecretRequest(asset='Linux', account='root') -``` + def get_account_secret(self, asset, account): + url = f"{API_URL}/api/v1/accounts/integration-applications/account-secret/" + headers = { + 'Accept': 'application/json', + 'X-JMS-ORG': ORG_ID, + 'Date': datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT'), + 'X-Source': 'jms-pam' + } + params = {"asset": asset, "account": account} -### 发送请求 + try: + response = self.session.get(url, auth=self.auth, headers=headers, params=params, timeout=10) + response.raise_for_status() + return response.json() + except requests.RequestException as e: + print(f"API 请求失败: {e}") + return None -使用客户端的 `send` 方法发送请求。 -```python -secret_obj = client.send(request) -``` - -### 处理响应 - -检查密码是否成功检索,并相应地处理响应。 - -```python -if secret_obj.valid: - print('密码: %s' % secret_obj.secret) -else: - print('获取密码失败: %s' % secret_obj.desc) -``` - -### 完整示例 - -以下是如何使用该客户端的完整示例: - -```python -from jms_pam import JumpServerPAM, SecretRequest - -client = JumpServerPAM( - endpoint='http://127.0.0.1', - key_id='your-key-id', - key_secret='your-key-secret' -) - -request = SecretRequest(asset='Linux', account='root') -secret_obj = client.send(request) - -if secret_obj.valid: - print('密码: %s' % secret_obj.secret) -else: - print('获取密码失败: %s' % secret_obj.desc) -``` - -## 错误处理 - -如果提供的参数不符合验证要求,库会引发 `RequestParamsError`。这包括对有效 UUID 的检查和参数之间的相互依赖性检查。 - -## 贡献 - -欢迎贡献!请打开一个问题或提交拉取请求,以进行任何增强或修复错误。 +# 示例调用 +if __name__ == "__main__": + client = APIClient() + result = client.get_account_secret(asset="ubuntu_docker", account="root") + print(result) +``` \ No newline at end of file