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
|
||||
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 的检查以及确保提供了必需的参数。
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎贡献!如有任何增强或错误修复,请提出问题或提交拉取请求。
|
||||
```
|
|
@ -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)
|
||||
```
|
Loading…
Reference in New Issue