mirror of https://github.com/jumpserver/jumpserver
perf: Go and Python demo code
parent
217818f2b7
commit
a9433bc48e
|
@ -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
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"your_module_path/jms_pam"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
type APIClient struct {
|
||||||
client := jms_pam.NewJumpServerPAM(
|
Client *http.Client
|
||||||
"http://127.0.0.1", // 替换为您的 JumpServer 端点
|
APIURL string
|
||||||
"your-key-id", // 替换为您的实际 Key ID
|
KeyID string
|
||||||
"your-key-secret", // 替换为您的实际 Key Secret
|
KeySecret string
|
||||||
"", // 留空以使用默认的组织 ID
|
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() {
|
func main() {
|
||||||
client := jms_pam.NewJumpServerPAM(
|
client := NewAPIClient()
|
||||||
"http://127.0.0.1",
|
result, err := client.GetAccountSecret("ubuntu_docker", "root")
|
||||||
"your-key-id",
|
|
||||||
"your-key-secret",
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
|
|
||||||
request, err := jms_pam.NewSecretRequest("Linux", "", "root", "")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("创建请求时出错:", err)
|
log.Fatalf("Error: %v", 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))
|
|
||||||
}
|
}
|
||||||
|
fmt.Printf("Result: %+v\n", result)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 错误处理
|
|
||||||
|
|
||||||
该库会在创建 `SecretRequest` 时返回无效参数的错误。这包括对有效 UUID 的检查以及确保提供了必需的参数。
|
|
||||||
|
|
||||||
## 贡献
|
|
||||||
|
|
||||||
欢迎贡献!如有任何增强或错误修复,请提出问题或提交拉取请求。
|
|
|
@ -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
|
```python
|
||||||
from jms_pam import JumpServerPAM, SecretRequest
|
import requests
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from httpsig.requests_auth import HTTPSignatureAuth
|
||||||
|
|
||||||
client = JumpServerPAM(
|
API_URL = os.getenv("API_URL", "http://127.0.0.1:8080")
|
||||||
endpoint='http://127.0.0.1',
|
KEY_ID = os.getenv("API_KEY_ID", "72b0b0aa-ad82-4182-a631-ae4865e8ae0e")
|
||||||
key_id='your-key-id',
|
KEY_SECRET = os.getenv("API_KEY_SECRET", "6fuSO7P1m4cj8SSlgaYdblOjNAmnxDVD7tr8")
|
||||||
key_secret='your-key-secret'
|
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
|
def get_account_secret(self, asset, account):
|
||||||
request = SecretRequest(asset='Linux', account='root')
|
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)
|
if __name__ == "__main__":
|
||||||
```
|
client = APIClient()
|
||||||
|
result = client.get_account_secret(asset="ubuntu_docker", account="root")
|
||||||
### 处理响应
|
print(result)
|
||||||
|
```
|
||||||
检查密码是否成功检索,并相应地处理响应。
|
|
||||||
|
|
||||||
```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 的检查和参数之间的相互依赖性检查。
|
|
||||||
|
|
||||||
## 贡献
|
|
||||||
|
|
||||||
欢迎贡献!请打开一个问题或提交拉取请求,以进行任何增强或修复错误。
|
|
Loading…
Reference in New Issue