From f009be1359bbb534546d3182273dfdfd929b5f5b Mon Sep 17 00:00:00 2001 From: duanliguo Date: Fri, 21 Oct 2022 17:48:45 +0800 Subject: [PATCH] Update features in bos and iam --- README.md | 2 + auth/signer.go | 4 +- bce/config.go | 2 +- doc/IAM.md | 897 ++++++++++++++++++++++++++++++ http/constants.go | 1 + init.go | 1 + services/bbc/model.go | 2 + services/bos/api/bucket.go | 3 + services/bos/api/model.go | 5 + services/bos/api/multipart.go | 15 + services/bos/api/object.go | 29 + services/bos/api/util.go | 3 + services/bos/client.go | 32 ++ services/cdn/api/domain_config.go | 67 ++- services/iam/api/accesskey.go | 130 +++++ services/iam/api/constants.go | 13 +- services/iam/api/group.go | 9 + services/iam/api/model.go | 75 ++- services/iam/api/policy.go | 68 +++ services/iam/api/role.go | 125 +++++ services/iam/api/user.go | 8 + services/iam/client.go | 60 ++ services/iam/client_test.go | 194 ++++++- services/sts/client.go | 6 +- services/vpn/model.go | 4 +- services/vpn/vpn.go | 4 +- 26 files changed, 1711 insertions(+), 48 deletions(-) create mode 100644 doc/IAM.md create mode 100644 services/iam/api/accesskey.go create mode 100644 services/iam/api/role.go diff --git a/README.md b/README.md index c36f2730..b20f49b3 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ bce-sdk-go | |--eni //ENIC弹性网卡 | |--esg //企业安全组 | |--etGateway //专线网关 +| |--iam //身份管理 | |--rds //云数据库 | |--scs //SCS服务目录 | |--sms //SMS服务目录 @@ -257,6 +258,7 @@ SSL证书服务 | CERT | github.com/baidubce/bce-sdk-go/services/cert ENIC弹性网卡 | ENIC | github.com/baidubce/bce-sdk-go/services/eni | [ENIC.md](./doc/ENIC.md) 企业安全组 | ESG | github.com/baidubce/bce-sdk-go/services/esg | [ESG.md](./doc/ESG.md) 专线网关 | EtGateway | github.com/baidubce/bce-sdk-go/services/etGateway | [ETGateway.md](./doc/ETGateway.md) +身份管理 | IAM | github.com/baidubce/bce-sdk-go/services/iam | [IAM.md](./doc/IAM.md) 内网DNS | LOCALDNS | github.com/baidubce/bce-sdk-go/services/localDns | [LOCALDNS.md](./doc/LOCALDNS.md) 云数据库 | RDS | github.com/baidubce/bce-sdk-go/services/rds | [RDS.md](./doc/RDS.md) 分布式缓存服务 | SCS | github.com/baidubce/bce-sdk-go/services/scs | [SCS.md](./doc/SCS.md) diff --git a/auth/signer.go b/auth/signer.go index 57347980..c5c01d1a 100644 --- a/auth/signer.go +++ b/auth/signer.go @@ -88,8 +88,8 @@ func (b *BceV1Signer) Sign(req *http.Request, cred *BceCredentials, opt *SignOpt signDate = util.FormatISO8601Date(opt.Timestamp) } - // Set security token if using session credentials - if len(cred.SessionToken) != 0 { + // Set security token if using session credentials and session token not in param + if len(cred.SessionToken) != 0 && req.Param(http.BCE_SECURITY_TOKEN) == "" { req.SetHeader(http.BCE_SECURITY_TOKEN, cred.SessionToken) } diff --git a/bce/config.go b/bce/config.go index 0ff6f34d..b39f3b79 100644 --- a/bce/config.go +++ b/bce/config.go @@ -26,7 +26,7 @@ import ( // Constants and default values for the package bce const ( - SDK_VERSION = "0.9.136" + SDK_VERSION = "0.9.137" URI_PREFIX = "/" // now support uri without prefix "v1" so just set root path DEFAULT_DOMAIN = "baidubce.com" DEFAULT_PROTOCOL = "http" diff --git a/doc/IAM.md b/doc/IAM.md new file mode 100644 index 00000000..769fab9c --- /dev/null +++ b/doc/IAM.md @@ -0,0 +1,897 @@ +# IAM服务 + +# 概述 + +本文档主要介绍普通型IAM GO SDK的使用。在使用本文档前,您需要先了解IAM的一些基本知识。若您还不了解IAM,可以参考[产品描述](https://cloud.baidu.com/doc/IAM/s/xjwvybxhv)和[应用场景](https://cloud.baidu.com/doc/IAM/s/Djwvybxus)。 + +# 初始化 + +## 确认Endpoint + +在确认您使用SDK时配置的Endpoint时,可先阅读开发人员指南中关于[IAM访问域名](https://cloud.baidu.com/doc/IAM/s/cjwvxnzix)的部分,理解Endpoint相关的概念。百度云目前开放了多区域支持,请参考[区域选择说明](https://cloud.baidu.com/doc/Reference/s/2jwvz23xx/)。 + +## 获取密钥 + +要使用百度云IAM,您需要拥有一个有效的AK(Access Key ID)和SK(Secret Access Key)用来进行签名认证。AK/SK是由系统分配给用户的,均为字符串,用于标识用户,为访问IAM做签名验证。 + +可以通过如下步骤获得并了解您的AK/SK信息: + +[注册百度云账号](https://login.bce.baidu.com/reg.html?tpl=bceplat&from=portal) + +[创建AK/SK](https://console.bce.baidu.com/iam/#/iam/accesslist) + +## 新建IAM Client + +普通型IAM Client是IAM服务的客户端,为开发者与IAM服务进行交互提供了一系列的方法。 + +### 使用AK/SK新建IAM Client + +通过AK/SK方式访问IAM,用户可以参考如下代码新建一个IAM Client: + +```go +import ( + "github.com/baidubce/bce-sdk-go/services/iam" +) + +func main() { + // 用户的Access Key ID和Secret Access Key + ACCESS_KEY_ID, SECRET_ACCESS_KEY := , + + // 初始化一个IAMClient + iamClient, err := iam.NewClient(AK, SK) +} +``` + +在上面代码中,`ACCESS_KEY_ID`对应控制台中的“Access Key ID”,`SECRET_ACCESS_KEY`对应控制台中的“Access Key Secret”,获取方式请参考《操作指南 [管理ACCESSKEY](https://cloud.baidu.com/doc/IAM/s/ojwvynrqn)》。 + +### 使用STS创建IAM Client + +**申请STS token** + +IAM可以通过STS机制实现第三方的临时授权访问。STS(Security Token Service)是百度云提供的临时授权服务。通过STS,您可以为第三方用户颁发一个自定义时效和权限的访问凭证。第三方用户可以使用该访问凭证直接调用百度云的API或SDK访问百度云资源。 + +通过STS方式访问IAM,用户需要先通过STS的client申请一个认证字符串,申请方式可参见[百度云STS使用介绍](https://cloud.baidu.com/doc/IAM/s/gjwvyc7n7)。 + +**用STS token新建IAM Client** + +申请好STS后,可将STS Token配置到IAM Client中,从而实现通过STS Token创建IAM Client。 + +**代码示例** + +GO SDK实现了STS服务的接口,用户可以参考如下完整代码,实现申请STS Token和创建IAM Client对象: + +```go +import ( + "fmt" + + "github.com/baidubce/bce-sdk-go/auth" //导入认证模块 + "github.com/baidubce/bce-sdk-go/services/iam" //导入IAM服务模块 + "github.com/baidubce/bce-sdk-go/services/sts" //导入STS服务模块 +) + +func main() { + // 创建STS服务的Client对象,Endpoint使用默认值 + AK, SK := , + stsClient, err := sts.NewClient(AK, SK) + if err != nil { + fmt.Println("create sts client object :", err) + return + } + + // 获取临时认证token,有效期为60秒,ACL为空 + stsObj, err := stsClient.GetSessionToken(60, "") + if err != nil { + fmt.Println("get session token failed:", err) + return + } + fmt.Println("GetSessionToken result:") + fmt.Println(" accessKeyId:", stsObj.AccessKeyId) + fmt.Println(" secretAccessKey:", stsObj.SecretAccessKey) + fmt.Println(" sessionToken:", stsObj.SessionToken) + fmt.Println(" createTime:", stsObj.CreateTime) + fmt.Println(" expiration:", stsObj.Expiration) + fmt.Println(" userId:", stsObj.UserId) + + // 使用申请的临时STS创建IAM服务的Client对象,Endpoint使用默认值 + iamClient, err := iam.NewClient(stsObj.AccessKeyId, stsObj.SecretAccessKey, "") + if err != nil { + fmt.Println("create iam client failed:", err) + return + } + stsCredential, err := auth.NewSessionBceCredentials( + stsObj.AccessKeyId, + stsObj.SecretAccessKey, + stsObj.SessionToken) + if err != nil { + fmt.Println("create sts credential object failed:", err) + return + } + iamClient.Config.Credentials = stsCredential +} +``` + +> 注意: +> 目前使用STS配置IAM Client时,无论对应IAM服务的Endpoint在哪里,STS的Endpoint都需配置为http://sts.bj.baidubce.com。上述代码中创建STS对象时使用此默认值。 + +## 配置HTTPS协议访问IAM + +IAM支持HTTPS传输协议,您可以通过在创建IAM Client对象时指定的Endpoint中指明HTTPS的方式,在IAM GO SDK中使用HTTPS访问IAM服务: + +```go +// import "github.com/baidubce/bce-sdk-go/services/iam" + +ENDPOINT := "https://iam.bj.baidubce.com" //指明使用HTTPS协议 +AK, SK := , +iamClient, _ := iam.NewClientWithEndpoint(AK, SK, ENDPOINT) +``` + +## 配置IAM Client + +如果用户需要配置IAM Client的一些细节的参数,可以在创建IAM Client对象之后,使用该对象的导出字段`Config`进行自定义配置,可以为客户端配置代理,最大连接数等参数。 + +### 使用代理 + +下面一段代码可以让客户端使用代理访问IAM服务: + +```go +// import "github.com/baidubce/bce-sdk-go/services/iam" + +//创建IAM Client对象 +AK, SK := , +ENDPOINT := "iam.bj.baidubce.com +client, _ := iam.NewClient(AK, SK, ENDPOINT) + +//代理使用本地的8080端口 +client.Config.ProxyUrl = "127.0.0.1:8080" +``` + +### 设置网络参数 + +用户可以通过如下的示例代码进行网络参数的设置: + +```go +// import "github.com/baidubce/bce-sdk-go/services/iam" + +AK, SK := , +client, _ := iam.NewClient(AK, SK) + +// 配置不进行重试,默认为Back Off重试 +client.Config.Retry = bce.NewNoRetryPolicy() + +// 配置连接超时时间为30秒 +client.Config.ConnectionTimeoutInMillis = 30 * 1000 +``` + +### 配置生成签名字符串选项 + +```go +// import "github.com/baidubce/bce-sdk-go/services/iam" + +AK, SK := , +client, _ := iam.NewClient(AK, SK) + +// 配置签名使用的HTTP请求头为`Host` +headersToSign := map[string]struct{}{"Host": struct{}{}} +client.Config.SignOption.HeadersToSign = HeadersToSign + +// 配置签名的有效期为30秒 +client.Config.SignOption.ExpireSeconds = 30 +``` + +**参数说明** + +用户使用GO SDK访问IAM时,创建的IAM Client对象的`Config`字段支持的所有参数如下表所示: + +配置项名称 | 类型 | 含义 +-----------|---------|-------- +Endpoint | string | 请求服务的域名 +ProxyUrl | string | 客户端请求的代理地址 +Region | string | 请求资源的区域 +UserAgent | string | 用户名称,HTTP请求的User-Agent头 +Credentials| \*auth.BceCredentials | 请求的鉴权对象,分为普通AK/SK与STS两种 +SignOption | \*auth.SignOptions | 认证字符串签名选项 +Retry | RetryPolicy | 连接重试策略 +ConnectionTimeoutInMillis| int | 连接超时时间,单位毫秒,默认20分钟 + +说明: + +1. `Credentials`字段使用`auth.NewBceCredentials`与`auth.NewSessionBceCredentials`函数创建,默认使用前者,后者为使用STS鉴权时使用,详见“使用STS创建IAM Client”小节。 +2. `SignOption`字段为生成签名字符串时的选项,详见下表说明: + +名称 | 类型 | 含义 +--------------|-------|----------- +HeadersToSign |map[string]struct{} | 生成签名字符串时使用的HTTP头 +Timestamp | int64 | 生成的签名字符串中使用的时间戳,默认使用请求发送时的值 +ExpireSeconds | int | 签名字符串的有效期 + + 其中,HeadersToSign默认为`Host`,`Content-Type`,`Content-Length`,`Content-MD5`;TimeStamp一般为零值,表示使用调用生成认证字符串时的时间戳,用户一般不应该明确指定该字段的值;ExpireSeconds默认为1800秒即30分钟。 +3. `Retry`字段指定重试策略,目前支持两种:`NoRetryPolicy`和`BackOffRetryPolicy`。默认使用后者,该重试策略是指定最大重试次数、最长重试时间和重试基数,按照重试基数乘以2的指数级增长的方式进行重试,直到达到最大重试测试或者最长重试时间为止。 + +# 主要接口 + +## 用户管理 + +### 创建用户 +通过以下代码可以创建子用户 + +```go + + name := "test-user-sdk-go" + args := &api.CreateUserArgs{ + Name: name, + Description: "description", + } + + result, err := client.CreateUser(args) + if err != nil { + fmt.Println("Create iam user failed", err) + } else { + fmt.Println("Create iam user success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[CreateUser创建用户](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7) + +### 查询用户 +通过以下代码可以查询单个子用户 +```go + name := "test-user-sdk-go" + result, err := client.GetUser(name) + if err != nil { + fmt.Println("Get iam user failed", err) + } else { + fmt.Println("Get iam user success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[GetUser查询用户](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E6%9F%A5%E8%AF%A2%E7%94%A8%E6%88%B7) + +### 更新用户 +通过以下代码可以更新子用户 + +```go + name := "test-user-sdk-go" + args := &api.UpdateUserArgs{ + Description: "newDescription", + } + + result, err := client.UpdateUser(name, args) + if err != nil { + fmt.Println("Update iam user failed", err) + } else { + fmt.Println("Update iam user success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[UpdateUser更新用户](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7) + +### 列举用户 +通过以下代码可以列举子用户 +```go + result, err := client.ListUser() + if err != nil { + fmt.Println("List iam user failed", err) + } else { + fmt.Println("List iam user success", result) + } +``` + +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[ListUser创建用户](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%88%97%E4%B8%BE%E7%94%A8%E6%88%B7) + +### 删除用户 +通过以下代码可以更新子用户 + +```go + name := "test-user-sdk-go" + err = client.DeleteUser(name) + if err != nil { + fmt.Println("Delete iam user failed", err) + } else { + fmt.Println("Delete iam user success", name) + } +``` + +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[DeleteUser删除用户](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%88%A0%E9%99%A4%E7%94%A8%E6%88%B7) + + +### 配置用户控制台登录 +通过以下代码可以配置用户的控制台登录,为其配置登录密码、开启登录MFA、配置第三方账号绑定等 + +```go + name := "test-user-sdk-go-login-profile" + args := &api.UpdateUserLoginProfileArgs{ + Password: "1@3Qwe4f", + EnabledLoginMfa: false, + LoginMfaType: "PHONE", + } + + result, err := client.UpdateUserLoginProfile(name, args) + if err != nil { + fmt.Println("Update iam user login profile failed", err) + } else { + fmt.Println("Update iam user login profile success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[UpdateUserLoginProfile配置用户控制台登录](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E9%85%8D%E7%BD%AE%E7%94%A8%E6%88%B7%E7%9A%84%E6%8E%A7%E5%88%B6%E5%8F%B0%E7%99%BB%E5%BD%95) + +### 查询控制台登录配置 +通过以下代码可以查询用户的控制台登录配置 +```go + name := "test-user-sdk-go-login-profile" + result, err := client.GetUserLoginProfile(name) + if err != nil { + fmt.Println("Get iam user login profile failed", err) + } else { + fmt.Println("Get iam user login profile success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[GetUserLoginProfile查询用户控制台登录](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E6%9F%A5%E8%AF%A2%E6%8E%A7%E5%88%B6%E5%8F%B0%E7%99%BB%E5%BD%95%E9%85%8D%E7%BD%AE) + +### 关闭控制台登录配置 +关闭用户的控制台登录配置,即关闭用户的控制台登录 +```go + name := "test-user-sdk-go-login-profile" + err = client.DeleteUserLoginProfile(name) + if err != nil { + fmt.Println("Delete iam user login profile failed", err) + } else { + fmt.Println("Delete iam user login profile success", name) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[DeleteUserLoginProfile关闭用户控制台登录](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%85%B3%E9%97%AD%E6%8E%A7%E5%88%B6%E5%8F%B0%E7%99%BB%E5%BD%95%E9%85%8D%E7%BD%AE) + +### 创建用户的AccessKey +通过以下代码为用户创建一组AccessKey访问密钥 + +```go + name := "test-user-sdk-go-accessKey" + result, err := client.CreateAccessKey(name) + if err != nil { + fmt.Println("Create accessKey failed", err) + } else { + fmt.Println("Create accessKey success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[创建用户的AccessKey](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7%E7%9A%84accesskey) + +### 禁用用户的AccessKey +通过以下代码为禁用用户的AccessKey +```go + name := "test-user-sdk-go-accessKey" + accessKeyId := "" + result, err := client.DisableAccessKey(name, accessKeyId) + if err != nil { + fmt.Println("Disable accessKey failed", err) + } else { + fmt.Println("Disable accessKey success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[禁用用户的AccessKey](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7%E7%9A%84accesskey) + +### 启用用户的AccessKey +通过以下代码为启用用户的AccessKey +```go + name := "test-user-sdk-go-accessKey" + accessKeyId := "" + result, err := client.EnableAccessKey(name, accessKeyId) + if err != nil { + fmt.Println("Enable accessKey failed", err) + } else { + fmt.Println("Enable accessKey success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[启用用户的AccessKey](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%90%AF%E7%94%A8%E7%94%A8%E6%88%B7%E7%9A%84accesskey) + +### 删除用户的AccessKey +删除用户的指定一组AccessKey访问密钥 +```go + name := "test-user-sdk-go-accessKey" + accessKeyId := "" + err = client.DeleteAccessKey(name, accessKeyId) + if err != nil { + fmt.Println("Delete accessKey failed", err) + } else { + fmt.Println("Delete accessKey success", accessKeyId) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[删除用户的AccessKey](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%88%A0%E9%99%A4%E7%94%A8%E6%88%B7%E7%9A%84accesskey) + +### 列举用户的AccessKey +列举用户的全部AccessKey访问密钥 +```go + name := "test-user-sdk-go-accessKey" + result, err := client.ListAccessKey(name) + if err != nil { + fmt.Println("List accessKey failed", err) + } else { + fmt.Println("List accessKey success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举用户的AccessKey](https://cloud.baidu.com/doc/IAM/s/mjx35fixq#%E5%88%97%E4%B8%BE%E7%94%A8%E6%88%B7%E7%9A%84accesskey) + + +### 创建组 +通过以下代码创建组 +```go + name := "test_group_sdk_go" + args := &api.CreateGroupArgs{ + Name: name, + Description: name, + } + + result, err := client.CreateGroup(args) + if err != nil { + fmt.Println("Create group failed", err) + } else { + fmt.Println("Create group success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[创建组](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E5%88%9B%E5%BB%BA%E7%BB%84) + + +### 查询组 +通过以下代码查询组 +```go + name := "test_group_sdk_go" + result, err := client.GetGroup(name) + if err != nil { + fmt.Println("Get group failed", err) + } else { + fmt.Println("Get group success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[查询组](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E6%9F%A5%E8%AF%A2%E7%BB%84) + + +### 更新组 +通过以下代码更新组 +```go + name := "test_group_sdk_go" + args := &api.UpdateGroupArgs{ + Description: "newDes", + } + result, err := client.UpdateGroup(name, args) + if err != nil { + fmt.Println("Update group failed", err) + } else { + fmt.Println("Update group success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[更新组](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E6%9B%B4%E6%96%B0%E7%BB%84) + +### 删除组 +通过以下代码删除组 +```go + name := "test_group_sdk_go" + err = client.DeleteGroup(name) + if err != nil { + fmt.Println("Delete group failed", err) + } else { + fmt.Println("Delete group success", name) + } + +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[删除组](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E5%88%A0%E9%99%A4%E7%BB%84) + +### 列举组 +通过以下代码删除组 +```go + result, err := client.ListGroup() + if err != nil { + fmt.Println("Delete group failed", err) + } else { + fmt.Println("Delete group success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举组](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E5%88%97%E4%B8%BE%E7%BB%84) + +### 添加用户到组 +通过以下代码添加用户到组 +```go + userName := "test_user_sdk_go" + groupName := "test_user_sdk_go" + err = client.AddUserToGroup(userName, groupName) + if err != nil { + fmt.Println("Add user to group failed", err) + } else { + fmt.Println("Add user to group success", userName) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[添加用户到组](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E6%B7%BB%E5%8A%A0%E7%94%A8%E6%88%B7%E5%88%B0%E7%BB%84) + + +### 从组内移除用户 +通过以下代码从组内移除用户 +```go + userName := "test_user_sdk_go" + groupName := "test_user_sdk_go" + err = client.DeleteUserFromGroup(userName, groupName) + if err != nil { + fmt.Println("Add user to group failed", err) + } else { + fmt.Println("Add user to group success", userName) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[从组内移除用户](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E4%BB%8E%E7%BB%84%E5%86%85%E7%A7%BB%E9%99%A4%E7%94%A8%E6%88%B7) + +### 列举用户的组 +通过以下代码列举用户的组 +```go + userName := "test_user_sdk_go" + result, err := client.ListGroupsForUser(userName) + if err != nil { + fmt.Println("List groups for user failed", err) + } else { + fmt.Println("List groups for user success", result) + } + +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举用户的组](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E5%88%97%E4%B8%BE%E7%94%A8%E6%88%B7%E7%9A%84%E7%BB%84) + +### 列举组内用户 +通过以下代码列举组内用户 +```go + groupName := "test_user_sdk_go" + result, err := client.ListUsersInGroup(groupName) + if err != nil { + fmt.Println("List user in group failed", err) + } else { + fmt.Println("List user in group success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举组内用户](https://cloud.baidu.com/doc/IAM/s/ljx35h8lx#%E5%88%97%E4%B8%BE%E7%BB%84%E5%86%85%E7%94%A8%E6%88%B7) + +### 创建角色 +通过以下代码创建角色 +```go + roleName := "test_role_sdk_go" + args := &api.CreateRoleArgs{ + Name: roleName, + Description: "description", + AssumeRolePolicyDocument: "{\"version\":\"v1\",\"accessControlList\":[{\"service\":\"bce:iam\",\"permission\"" + + ":[\"AssumeRole\"],\"region\":\"*\",\"grantee\":[{\"id\":\"grantee-id\"}],\"effect\":\"Allow\"}]}", + } + + result, err := client.CreateRole(args) + if err != nil { + fmt.Println("Create role failed", err) + } else { + fmt.Println("Create role success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[创建角色](https://cloud.baidu.com/doc/IAM/s/ek5eq1zp1) + +### 查询角色 +通过以下代码查询角色 +```go + roleName := "test_role_sdk_go" + result, err := client.GetRole(roleName) + if err != nil { + fmt.Println("Get role failed", err) + } else { + fmt.Println("Get role success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[查询角色](https://cloud.baidu.com/doc/IAM/s/ek5eq1zp1#%E6%9F%A5%E8%AF%A2%E8%A7%92%E8%89%B2) + +### 更新角色 +通过以下代码查询角色 +```go + args := &api.UpdateRoleArgs{ + Description: "newDescription", + AssumeRolePolicyDocument: "{\"version\":\"v1\",\"accessControlList\":[{\"service\":\"bce:iam\",\"permission\"" + + ":[\"AssumeRole\"],\"region\":\"*\",\"grantee\":[{\"id\":\"grantee-id\"}],\"effect\":\"Allow\"}]}", + } + + roleName := "test_role_sdk_go" + result, err := client.UpdateRole(roleName, args) + if err != nil { + fmt.Println("Update role failed", err) + } else { + fmt.Println("Update role success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[更新角色](https://cloud.baidu.com/doc/IAM/s/ek5eq1zp1#%E6%9B%B4%E6%96%B0%E8%A7%92%E8%89%B2) + +### 删除角色 +通过以下代码查询角色 +```go + roleName := "test_role_sdk_go" + err = client.DeleteRole(roleName) + if err != nil { + fmt.Println("Delete role failed", err) + } else { + fmt.Println("Delete role success", roleName) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[删除角色](https://cloud.baidu.com/doc/IAM/s/ek5eq1zp1#%E5%88%A0%E9%99%A4%E8%A7%92%E8%89%B2) + +### 列举角色 +通过以下代码列举角色 +```go + result, err := client.ListRole() + if err != nil { + fmt.Println("List role failed", err) + } else { + fmt.Println("List role success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举角色](https://cloud.baidu.com/doc/IAM/s/ek5eq1zp1#%E5%88%97%E4%B8%BE%E8%A7%92%E8%89%B2) + +### 创建策略 +通过以下代码创建策略 +```go + +name := "test_sdk_go_policy" +args := &api.CreatePolicyArgs{ + Name: name, + Description: "description", + Document: "{\"accessControlList\": [{\"region\":\"bj\",\"service\":\"bcc\"," + +"\"resource\":[\"*\"],\"permission\":[\"*\"],\"effect\":\"Allow\"}]}", +} + +result, err := client.CreatePolicy(args) +if err != nil { + fmt.Println("Update policy failed", err) +} else { + fmt.Println("Update policy success", result) +} +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[创建策略](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%88%9B%E5%BB%BA%E7%AD%96%E7%95%A5) + +### 查询策略 +通过以下代码查询策略 +```go + name := "test_sdk_go_policy" + policyType := "Custom" + result, err := client.GetPolicy(name, policyType) + if err != nil { + fmt.Println("Update policy failed", err) + } else { + fmt.Println("Update policy success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[创建策略](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%88%9B%E5%BB%BA%E7%AD%96%E7%95%A5) + +### 删除策略 +通过以下代码删除策略 +```go + name := "test_sdk_go_policy" + err = client.DeletePolicy(name) + if err != nil { + fmt.Println("List policy failed", err) + } else { + fmt.Println("List policy success", name) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[删除策略](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5) + + +### 列举策略 +通过以下代码列举策略 +```go + name := "test_sdk_go_policy" + policyType := "Custom" + result, err := client.ListPolicy(name, policyType) + if err != nil { + fmt.Println("List policy failed", err) + } else { + fmt.Println("List policy success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举策略](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%88%97%E4%B8%BE%E7%AD%96%E7%95%A5) + +### 关联用户权限 +通过以下代码关联用户权限 +```go + userName := "test_sdk_go_user" + policyName := "test_sdk_go_policy" + args := &api.AttachPolicyToUserArgs{ + UserName: userName, + PolicyName: policyName, + } + err = client.AttachPolicyToUser(args) + if err != nil { + fmt.Println("Attach policy to user failed", err) + } else { + fmt.Println("Attach policy to user success", args) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[关联用户权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%85%B3%E8%81%94%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90) + +### 解除用户权限 +通过以下代码解除用户权限 +```go + userName := "test_sdk_go_user" + policyName := "test_sdk_go_policy" + args := &api.DetachPolicyFromUserArgs{ + UserName: userName, + PolicyName: policyName, + } + err = client.DetachPolicyFromUser(args) + if err != nil { + fmt.Println("Detach policy to user failed", err) + } else { + fmt.Println("Detach policy to user success", args) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[解除用户权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E8%A7%A3%E9%99%A4%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90) + +### 列举用户的权限 +通过以下代码列举用户的权限 +```go + userName := "test_sdk_go_user" + result, err := client.ListUserAttachedPolicies(userName) + if err != nil { + fmt.Println("List user attached policy failed", err) + } else { + fmt.Println("List user attached policy success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举用户的权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%88%97%E4%B8%BE%E7%94%A8%E6%88%B7%E7%9A%84%E6%9D%83%E9%99%90) + +### 关联组权限 +通过以下代码关联组权限 +```go + groupName := "test_sdk_go_group" + policyName := "test_sdk_go_policy" + args := &api.AttachPolicyToGroupArgs{ + GroupName: groupName, + PolicyName: policyName, + } + err = client.AttachPolicyToGroup(args) + if err != nil { + fmt.Println("Attach policy to group failed", err) + } else { + fmt.Println("Attach policy to group success", args) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[关联组权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%85%B3%E8%81%94%E7%BB%84%E6%9D%83%E9%99%90) + +### 解除组权限 +通过以下代码解除组权限 +```go + groupName := "test_sdk_go_group" + policyName := "test_sdk_go_policy" + args := &api.DetachPolicyFromGroupArgs{ + GroupName: groupName, + PolicyName: policyName, + } + err = client.DetachPolicyFromGroup(args) + if err != nil { + fmt.Println("Detach policy to group failed", err) + } else { + fmt.Println("Detach policy to group success", args) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[解除组权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E8%A7%A3%E9%99%A4%E7%BB%84%E6%9D%83%E9%99%90) + +### 列举组权限 +通过以下代码列举组权限 +```go + groupName := "test_sdk_go_group" + result, err := client.ListGroupAttachedPolicies(groupName) + if err != nil { + fmt.Println("List group attached policy failed", err) + } else { + fmt.Println("List group attached policy success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举组权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%88%97%E4%B8%BE%E7%BB%84%E7%9A%84%E6%9D%83%E9%99%90) + +### 关联角色权限 +通过以下代码关联角色权限 +```go + roleName := "test_sdk_go_group" + policyName := "test_sdk_go_policy" + args := &api.AttachPolicyToRoleArgs{ + RoleName: roleName, + PolicyName: policyName, + } + err = client.AttachPolicyToRole(args) + if err != nil { + fmt.Println("Attach policy to role failed", err) + } else { + fmt.Println("Attach policy to role success", args) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[关联角色权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%85%B3%E8%81%94%E8%A7%92%E8%89%B2%E6%9D%83%E9%99%90) + +### 解除角色权限 +通过以下代码关联角色权限 +```go + roleName := "test_sdk_go_group" + policyName := "test_sdk_go_policy" + args := &api.DetachPolicyToRoleArgs{ + RoleName: roleName, + PolicyName: policyName, + } + err = client.DetachPolicyFromRole(args) + if err != nil { + fmt.Println("Detach policy to role failed", err) + } else { + fmt.Println("Detach policy to role success", args) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[解除角色权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E8%A7%A3%E9%99%A4%E8%A7%92%E8%89%B2%E6%9D%83%E9%99%90) + +### 列举角色的权限 +通过以下代码列举角色权限 +```go + roleName := "test_sdk_go_group" + result, err := client.ListRoleAttachedPolicies(roleName) + if err != nil { + fmt.Println("List role attached policy failed", err) + } else { + fmt.Println("List role attached policy success", result) + } +``` +> **提示:** +> - 详细的参数配置及限制条件,可以参考IAM API 文档[列举角色的权限](https://cloud.baidu.com/doc/IAM/s/Wjx35jxes#%E5%88%97%E4%B8%BE%E8%A7%92%E8%89%B2%E7%9A%84%E6%9D%83%E9%99%90) + + +# 错误处理 + +GO语言以error类型标识错误,IAM支持两种错误见下表: + +错误类型 | 说明 +----------------|------------------- +BceClientError | 用户操作产生的错误 +BceServiceError | IAM服务返回的错误 + +## 客户端异常 + +客户端异常表示客户端尝试向IAM发送请求以及数据传输时遇到的异常。例如,当发送请求时网络连接不可用时,则会返回BceClientError;当上传文件时发生IO异常时,也会抛出BceClientError。 + +## 服务端异常 + +当IAM服务端出现异常时,IAM服务端会返回给用户相应的错误信息,以便定位问题。常见服务端异常可参见[IAM错误返回](https://cloud.baidu.com/doc/IAM/s/Rjx4d0rxo) + +# 版本变更记录 + +## v0.9.11 [2022-10-13] + +首次发布: + +- 创建、查看、列表、更新、删除IAM用户 +- 配置、查询、关闭用户控制台配置 +- 创建、查看、列表、删除、启用、禁用AccessKey +- 创建、查看、列表、更新、删除IAM用户组 +- 创建、列表、列表、更新、删除角色 +- 创建、查看、列表、更新、删除、关联用户权限、解除用户权限、列举用户权限、关联组权限、解除组权限、列举组权限、关联角色权限、解除角色权限、列举角色的权限 diff --git a/http/constants.go b/http/constants.go index 69c5e426..2f9a1e18 100644 --- a/http/constants.go +++ b/http/constants.go @@ -80,4 +80,5 @@ const ( BCE_RESTORE = "x-bce-restore" BCE_FORBID_OVERWRITE = "x-bce-forbid-overwrite" BCE_SYMLINK_TARGET = "x-bce-symlink-target" + BCE_TRAFFIC_LIMIT = "x-bce-traffic-limit" ) diff --git a/init.go b/init.go index ea0e61bc..97cb7aa8 100644 --- a/init.go +++ b/init.go @@ -38,6 +38,7 @@ import ( _ "github.com/baidubce/bce-sdk-go/services/ddc/v2" _ "github.com/baidubce/bce-sdk-go/services/eip" _ "github.com/baidubce/bce-sdk-go/services/etGateway" + _ "github.com/baidubce/bce-sdk-go/services/iam" _ "github.com/baidubce/bce-sdk-go/services/mms" _ "github.com/baidubce/bce-sdk-go/services/rds" _ "github.com/baidubce/bce-sdk-go/services/scs" diff --git a/services/bbc/model.go b/services/bbc/model.go index 0f1b71d8..d4c9effe 100644 --- a/services/bbc/model.go +++ b/services/bbc/model.go @@ -123,6 +123,7 @@ type CreateInstanceArgs struct { InternalIps []string `json:"internalIps,omitempty"` RequestToken string `json:"requestToken"` EnableNuma bool `json:"enableNuma"` + EnableHt bool `json:"enableHt"` RootPartitionType string `json:"rootPartitionType,omitempty"` DataPartitionType string `json:"dataPartitionType,omitempty"` } @@ -164,6 +165,7 @@ type CreateSpecialInstanceArgs struct { InternalIps []string `json:"internalIps,omitempty"` RequestToken string `json:"requestToken"` EnableNuma bool `json:"enableNuma"` + EnableHt bool `json:"enableHt"` RootPartitionType string `json:"rootPartitionType,omitempty"` DataPartitionType string `json:"dataPartitionType,omitempty"` // CreateInstanceArgs 的基础上增加的参数 diff --git a/services/bos/api/bucket.go b/services/bos/api/bucket.go index 177467d8..9046364c 100644 --- a/services/bos/api/bucket.go +++ b/services/bos/api/bucket.go @@ -95,6 +95,7 @@ func ListObjects(cli bce.Client, bucket string, if err := resp.ParseJsonBody(result); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return result, nil } @@ -189,6 +190,7 @@ func GetBucketLocation(cli bce.Client, bucket string) (string, error) { if err := resp.ParseJsonBody(result); err != nil { return "", err } + defer func() { resp.Body().Close() }() return result.LocationConstraint, nil } @@ -255,6 +257,7 @@ func GetBucketAcl(cli bce.Client, bucket string) (*GetBucketAclResult, error) { if err := resp.ParseJsonBody(result); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return result, nil } diff --git a/services/bos/api/model.go b/services/bos/api/model.go index 47d3efd3..30fd7f73 100644 --- a/services/bos/api/model.go +++ b/services/bos/api/model.go @@ -259,6 +259,7 @@ type PutObjectArgs struct { ContentCrc32 string StorageClass string Process string + TrafficLimit int64 } // CopyObjectArgs defines the optional args structure for the copy object api. @@ -269,6 +270,7 @@ type CopyObjectArgs struct { IfNoneMatch string IfModifiedSince string IfUnmodifiedSince string + TrafficLimit int64 } type MultiCopyObjectArgs struct { @@ -397,6 +399,7 @@ type AppendObjectArgs struct { ContentSha256 string ContentCrc32 string StorageClass string + TrafficLimit int64 } // AppendObjectResult defines the result data structure for appending object. @@ -449,6 +452,7 @@ type UploadPartArgs struct { ContentMD5 string ContentSha256 string ContentCrc32 string + TrafficLimit int64 } // UploadPartCopyArgs defines the optional arguments of UploadPartCopy. @@ -458,6 +462,7 @@ type UploadPartCopyArgs struct { IfNoneMatch string IfModifiedSince string IfUnmodifiedSince string + TrafficLimit int64 } type PutSymlinkArgs struct { diff --git a/services/bos/api/multipart.go b/services/bos/api/multipart.go index ada259e5..806017b3 100644 --- a/services/bos/api/multipart.go +++ b/services/bos/api/multipart.go @@ -118,6 +118,14 @@ func UploadPart(cli bce.Client, bucket, object, uploadId string, partNumber int, http.BCE_CONTENT_SHA256: args.ContentSha256, http.BCE_CONTENT_CRC32: args.ContentCrc32, }) + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return "", bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + } // Send request and get the result @@ -227,6 +235,13 @@ func UploadPartCopy(cli bce.Client, bucket, object, source, uploadId string, par http.BCE_COPY_SOURCE_IF_MODIFIED_SINCE: args.IfModifiedSince, http.BCE_COPY_SOURCE_IF_UNMODIFIED_SINCE: args.IfUnmodifiedSince, }) + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } } // Send request and get the result diff --git a/services/bos/api/object.go b/services/bos/api/object.go index 4301757a..fc8bf40e 100644 --- a/services/bos/api/object.go +++ b/services/bos/api/object.go @@ -78,6 +78,14 @@ func PutObject(cli bce.Client, bucket, object string, body *bce.Body, req.SetBody(body) // re-assign body } + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return "", bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + // Reset the contentMD5 if set by user if len(args.ContentMD5) != 0 { req.SetHeader(http.CONTENT_MD5, args.ContentMD5) @@ -173,6 +181,15 @@ func CopyObject(cli bce.Client, bucket, object, source string, args.StorageClass) } } + + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } + if err := setUserMetadata(req, args.UserMeta); err != nil { return nil, err } @@ -549,6 +566,13 @@ func AppendObject(cli bce.Client, bucket, object string, content *bce.Body, if err := setUserMetadata(req, args.UserMeta); err != nil { return nil, err } + //set traffic-limit + if args.TrafficLimit > 0 { + if args.TrafficLimit > TRAFFIC_LIMIT_MAX || args.TrafficLimit < TRAFFIC_LIMIT_MIN { + return nil, bce.NewBceClientError(fmt.Sprintf("TrafficLimit must between %d ~ %d, current value:%d", TRAFFIC_LIMIT_MIN, TRAFFIC_LIMIT_MAX, args.TrafficLimit)) + } + req.SetHeader(http.BCE_TRAFFIC_LIMIT, fmt.Sprintf("%d", args.TrafficLimit)) + } } // Send request and get the result @@ -719,6 +743,11 @@ func GeneratePresignedUrlInternal(conf *bce.BceClientConfiguration, signer auth. if expire != 0 { option.ExpireSeconds = expire } + + if conf.Credentials.SessionToken != "" { + req.SetParam(http.BCE_SECURITY_TOKEN, conf.Credentials.SessionToken) + } + // Generate the authorization string and return the signed url. signer.Sign(&req.Request, conf.Credentials, &option) req.SetParam("authorization", req.Header(http.AUTHORIZATION)) diff --git a/services/bos/api/util.go b/services/bos/api/util.go index 9be25733..85aa4b99 100644 --- a/services/bos/api/util.go +++ b/services/bos/api/util.go @@ -45,6 +45,9 @@ const ( THRESHOLD_100_CONTINUE = 1 << 20 // add 100 continue header if body size bigger than 1MB + TRAFFIC_LIMIT_MAX = 8 * (100 << 20) // 100M bit = 838860800 + TRAFFIC_LIMIT_MIN = 8 * (100 << 10) // 100K bit = 819200 + STATUS_ENABLED = "enabled" STATUS_DISABLED = "disabled" diff --git a/services/bos/client.go b/services/bos/client.go index fb0591f5..b449a869 100644 --- a/services/bos/client.go +++ b/services/bos/client.go @@ -29,6 +29,7 @@ import ( "github.com/baidubce/bce-sdk-go/auth" "github.com/baidubce/bce-sdk-go/bce" "github.com/baidubce/bce-sdk-go/services/bos/api" + "github.com/baidubce/bce-sdk-go/services/sts" "github.com/baidubce/bce-sdk-go/util/log" ) @@ -71,6 +72,37 @@ func NewClient(ak, sk, endpoint string) (*Client, error) { RedirectDisabled: false, }) } + +// NewStsClient make the BOS service client with STS configuration, it will first apply stsAK,stsSK, sessionToken, then return bosClient using temporary sts Credential +func NewStsClient(ak, sk, endpoint string, expiration int) (*Client, error) { + stsClient, err := sts.NewClient(ak, sk) + if err != nil { + fmt.Println("create sts client object :", err) + return nil, err + } + sts, err := stsClient.GetSessionToken(expiration, "") + if err != nil { + fmt.Println("get session token failed:", err) + return nil, err + } + + bosClient, err := NewClient(sts.AccessKeyId, sts.SecretAccessKey, endpoint) + if err != nil { + fmt.Println("create bos client failed:", err) + return nil, err + } + stsCredential, err := auth.NewSessionBceCredentials( + sts.AccessKeyId, + sts.SecretAccessKey, + sts.SessionToken) + if err != nil { + fmt.Println("create sts credential object failed:", err) + return nil, err + } + bosClient.Config.Credentials = stsCredential + return bosClient, nil +} + func NewClientWithConfig(config *BosClientConfiguration) (*Client, error) { var credentials *auth.BceCredentials var err error diff --git a/services/cdn/api/domain_config.go b/services/cdn/api/domain_config.go index 0bce8c97..63d93c43 100644 --- a/services/cdn/api/domain_config.go +++ b/services/cdn/api/domain_config.go @@ -11,21 +11,36 @@ import ( // DomainConfig defined a struct for a specified domain's configuration type DomainConfig struct { - Domain string `json:"domain"` - Cname string `json:"cname"` - Status string `json:"status"` - CreateTime string `json:"createTime"` - LastModifyTime string `json:"lastModifyTime"` - IsBan string `json:"isBan"` - Origin []OriginPeer `json:"origin"` - DefaultHost string `json:"defaultHost,omitempty"` - CacheTTL []CacheTTL `json:"cacheTTL"` - LimitRate int `json:"limitRate"` - RequestAuth *RequestAuth `json:"requestAuth,omitempty"` - Https *HTTPSConfig `json:"https,omitempty"` - FollowProtocol bool `json:"followProtocol"` - SeoSwitch *SeoSwitch `json:"seoSwitch"` - Form string `json:"form"` + Domain string `json:"domain"` + Cname string `json:"cname"` + Status string `json:"status"` + CreateTime string `json:"createTime"` + LastModifyTime string `json:"lastModifyTime"` + IsBan string `json:"isBan"` + Origin []OriginPeer `json:"origin"` + DefaultHost string `json:"defaultHost,omitempty"` + CacheTTL []CacheTTL `json:"cacheTTL"` + LimitRate int `json:"limitRate"` + RequestAuth *RequestAuth `json:"requestAuth,omitempty"` + Https *HTTPSConfig `json:"https,omitempty"` + FollowProtocol bool `json:"followProtocol"` + SeoSwitch *SeoSwitch `json:"seoSwitch"` + Form string `json:"form"` + RangeSwitch string `json:"rangeSwitch"` + OfflineMode bool `json:"offlineMode"` + ClientIp *ClientIp `json:"clientIp"` + OCSP bool `json:"ocsp"` + HttpHeader []HttpHeader `json:"httpHeader"` + MediaDragConf *MediaDragConf `json:"mediaDragConf"` + FileTrim bool `json:"fileTrim"` + QUIC bool `json:"quic"` + RefererACL *RefererACL `json:"refererACL"` + IpACL *IpACL `json:"ipACL"` + UaAcl *UaACL `json:"uaAcl"` + AccessLimit *AccessLimit `json:"accessLimit"` + TrafficLimit *TrafficLimit `json:"trafficLimit"` + ErrorPage []ErrorPage `json:"errorPage"` + CacheShare *CacheShared `json:"cacheShare"` } // CacheTTL defined a struct for cached rules setting @@ -56,14 +71,16 @@ type RequestAuth struct { // HTTPSConfig defined a struct for configuration about HTTPS type HTTPSConfig struct { - Enabled bool `json:"enabled"` - CertId string `json:"certId,omitempty"` - HttpRedirect bool `json:"httpRedirect"` - HttpRedirectCode int `json:"httpRedirectCode,omitempty"` - HttpsRedirect bool `json:"httpsRedirect"` - HttpsRedirectCode int `json:"httpsRedirectCode"` - Http2Enabled bool `json:"http2Enabled"` - SslVersion string `json:"sslVersion,omitempty"` + Enabled bool `json:"enabled"` + CertId string `json:"certId,omitempty"` + HttpRedirect bool `json:"httpRedirect"` + HttpRedirectCode int `json:"httpRedirectCode,omitempty"` + HttpsRedirect bool `json:"httpsRedirect"` + HttpsRedirectCode int `json:"httpsRedirectCode"` + Http2Enabled bool `json:"http2Enabled"` + SslVersion string `json:"sslVersion,omitempty"` + VerifyClient bool `json:"verifyClient"` + SslProtocols []string `json:"sslProtocols,omitempty"` // Deprecated: You can no longer use this field, // The better choice is use SetOriginProtocol/GetOriginProtocol. @@ -1763,9 +1780,9 @@ func GetRangeSwitch(cli bce.Client, domain string) (bool, error) { // RETURNS: // - error: nil if success otherwise the specific error func SetContentEncoding(cli bce.Client, domain string, enabled bool, encodingType string) error { - if enabled && encodingType != "gzip" && encodingType != "br" { + if enabled && encodingType != "gzip" && encodingType != "br" && encodingType != "all" { errMsg := fmt.Sprintf("invalid encoding type \"%s\" for setting Content-Encoding,"+ - " it must in \"gzip\" and \"br\"", encodingType) + " it must in \"gzip\", \"br\" and \"all\"", encodingType) return errors.New(errMsg) } diff --git a/services/iam/api/accesskey.go b/services/iam/api/accesskey.go new file mode 100644 index 00000000..0dd6134e --- /dev/null +++ b/services/iam/api/accesskey.go @@ -0,0 +1,130 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package api + +import ( + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +func CreateAccessKey(cli bce.Client, userName string) (*CreateAccessKeyResult, error) { + req := &bce.BceRequest{} + req.SetUri(getAccessKeyUri(userName)) + req.SetMethod(http.POST) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + + jsonBody := &CreateAccessKeyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func DisableAccessKey(cli bce.Client, userName, accessKeyId string) (*UpdateAccessKeyResult, error) { + req := &bce.BceRequest{} + req.SetUri(getAccessKeyWithIdUri(userName, accessKeyId)) + req.SetParam(ACCESSKEY_STATUS_DISABLE, "") + req.SetMethod(http.PUT) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + + jsonBody := &UpdateAccessKeyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func EnableAccessKey(cli bce.Client, userName, accessKeyId string) (*UpdateAccessKeyResult, error) { + req := &bce.BceRequest{} + req.SetUri(getAccessKeyWithIdUri(userName, accessKeyId)) + req.SetParam(ACCESSKEY_STATUS_ENABLE, "") + req.SetMethod(http.PUT) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + + jsonBody := &UpdateAccessKeyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func DeleteAccessKey(cli bce.Client, userName, accessKeyId string) error { + req := &bce.BceRequest{} + req.SetUri(getAccessKeyWithIdUri(userName, accessKeyId)) + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func ListAccessKey(cli bce.Client, userName string) (*ListAccessKeyResult, error) { + req := &bce.BceRequest{} + req.SetUri(getAccessKeyUri(userName)) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListAccessKeyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func getAccessKeyUri(userName string) string { + return URI_PREFIX + URI_USER + "/" + userName + URI_ACCESSKEY +} + +func getAccessKeyWithIdUri(userName, accessKeyId string) string { + return getAccessKeyUri(userName) + "/" + accessKeyId +} diff --git a/services/iam/api/constants.go b/services/iam/api/constants.go index ea3b718b..93521e79 100644 --- a/services/iam/api/constants.go +++ b/services/iam/api/constants.go @@ -15,11 +15,16 @@ package api const ( - URI_PREFIX = "/v1" - URI_USER = "/user" - URI_GROUP = "/group" - URI_POLICY = "/policy" + URI_PREFIX = "/v1" + URI_USER = "/user" + URI_GROUP = "/group" + URI_POLICY = "/policy" + URI_ACCESSKEY = "/accesskey" + URI_ROLE = "/role" POLICY_TYPE_SYSTEM = "System" POLICY_TYPE_CUSTOM = "Custom" + + ACCESSKEY_STATUS_ENABLE = "enable" + ACCESSKEY_STATUS_DISABLE = "disable" ) diff --git a/services/iam/api/group.go b/services/iam/api/group.go index d238a827..d55061e0 100644 --- a/services/iam/api/group.go +++ b/services/iam/api/group.go @@ -37,6 +37,7 @@ func CreateGroup(cli bce.Client, body *bce.Body) (*CreateGroupResult, error) { if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -56,6 +57,7 @@ func GetGroup(cli bce.Client, name string) (*GetGroupResult, error) { if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -77,6 +79,7 @@ func UpdateGroup(cli bce.Client, name string, body *bce.Body) (*UpdateGroupResul if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -92,6 +95,7 @@ func DeleteGroup(cli bce.Client, name string) error { if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -111,6 +115,7 @@ func ListGroup(cli bce.Client) (*ListGroupResult, error) { if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -126,6 +131,7 @@ func AddUserToGroup(cli bce.Client, userName string, groupName string) error { if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -141,6 +147,7 @@ func DeleteUserFromGroup(cli bce.Client, userName string, groupName string) erro if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -160,6 +167,7 @@ func ListUsersInGroup(cli bce.Client, name string) (*ListUsersInGroupResult, err if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -179,6 +187,7 @@ func ListGroupsForUser(cli bce.Client, name string) (*ListGroupsForUserResult, e if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } diff --git a/services/iam/api/model.go b/services/iam/api/model.go index 05760bd9..0e90c124 100644 --- a/services/iam/api/model.go +++ b/services/iam/api/model.go @@ -44,6 +44,23 @@ type ListUserResult struct { Users []UserModel `json:"users"` } +type AccessKeyModel struct { + Id string `json:"id"` + Secret string `json:"secret"` + CreateTime time.Time `json:"createTime"` + LastUsedTime time.Time `json:"lastUsedTime"` + Enabled bool `json:"enabled"` + Description string `json:"description"` +} + +type CreateAccessKeyResult AccessKeyModel + +type UpdateAccessKeyResult AccessKeyModel + +type ListAccessKeyResult struct { + AccessKeys []AccessKeyModel `json:"accessKeys"` +} + type LoginProfileModel struct { Password string `json:"password,omitempty"` NeedResetPassword bool `json:"needResetPassword"` @@ -91,12 +108,17 @@ type ListUsersInGroupResult ListUserResult type ListGroupsForUserResult ListGroupResult type AclEntry struct { - Eid string `json:"eid,omitempty"` - Service string `json:"service"` - Region string `json:"region"` - Permission []string `json:"permission"` - Resource []string `json:"resource"` - Effect string `json:"effect"` + Eid string `json:"eid,omitempty"` + Service string `json:"service"` + Region string `json:"region"` + Permission []string `json:"permission"` + Resource []string `json:"resource,omitempty"` + Grantee []Grantee `json:"grantee,omitempty"` + Effect string `json:"effect"` +} + +type Grantee struct { + ID string `json:"id"` } type Acl struct { @@ -150,3 +172,44 @@ type DetachPolicyFromGroupArgs struct { PolicyName string `json:"policyName"` PolicyType string `json:"policyType,omitempty"` } + +type AttachPolicyToRoleArgs struct { + RoleName string `json:"roleName"` + PolicyName string `json:"policyName"` + PolicyType string `json:"policyType,omitempty"` +} + +type DetachPolicyToRoleArgs struct { + RoleName string `json:"roleName"` + PolicyName string `json:"policyName"` + PolicyType string `json:"policyType,omitempty"` +} + +type RoleModel struct { + Id string `json:"id"` + Name string `json:"name"` + CreateTime time.Time `json:"createTime"` + Description string `json:"description"` + AssumeRolePolicyDocument string `json:"assumeRolePolicyDocument"` +} + +type CreateRoleArgs struct { + Name string `json:"name"` + Description string `json:"description,omitempty"` + AssumeRolePolicyDocument string `json:"assumeRolePolicyDocument"` +} + +type UpdateRoleArgs struct { + Description string `json:"description"` + AssumeRolePolicyDocument string `json:"assumeRolePolicyDocument,omitempty"` +} + +type CreateRoleResult RoleModel + +type GetRoleResult RoleModel + +type UpdateRoleResult RoleModel + +type ListRoleResult struct { + Roles []RoleModel `json:"roles"` +} diff --git a/services/iam/api/policy.go b/services/iam/api/policy.go index 67f3cdd2..8a7f4ec0 100644 --- a/services/iam/api/policy.go +++ b/services/iam/api/policy.go @@ -37,6 +37,7 @@ func CreatePolicy(cli bce.Client, body *bce.Body) (*CreatePolicyResult, error) { if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -59,6 +60,7 @@ func GetPolicy(cli bce.Client, name, policyType string) (*GetPolicyResult, error if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -74,6 +76,7 @@ func DeletePolicy(cli bce.Client, name string) error { if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -99,6 +102,7 @@ func ListPolicy(cli bce.Client, nameFilter, policyType string) (*ListPolicyResul if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -117,6 +121,7 @@ func AttachPolicyToUser(cli bce.Client, args *AttachPolicyToUserArgs) error { if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -135,6 +140,7 @@ func DetachPolicyFromUser(cli bce.Client, args *DetachPolicyFromUserArgs) error if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -154,6 +160,7 @@ func ListUserAttachedPolicies(cli bce.Client, name string) (*ListPolicyResult, e if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -172,6 +179,7 @@ func AttachPolicyToGroup(cli bce.Client, args *AttachPolicyToGroupArgs) error { if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -190,6 +198,7 @@ func DetachPolicyFromGroup(cli bce.Client, args *DetachPolicyFromGroupArgs) erro if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -209,6 +218,65 @@ func ListGroupAttachedPolicies(cli bce.Client, name string) (*ListPolicyResult, if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func AttachPolicyToRole(cli bce.Client, args *AttachPolicyToRoleArgs) error { + req := &bce.BceRequest{} + req.SetUri(getRoleUri(args.RoleName) + URI_POLICY + "/" + args.PolicyName) + req.SetMethod(http.PUT) + if args.PolicyType != "" { + req.SetParam("policyType", args.PolicyType) + } + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func DetachPolicyFromRole(cli bce.Client, args *DetachPolicyToRoleArgs) error { + req := &bce.BceRequest{} + req.SetUri(getRoleUri(args.RoleName) + URI_POLICY + "/" + args.PolicyName) + req.SetMethod(http.DELETE) + if args.PolicyType != "" { + req.SetParam("policyType", args.PolicyType) + } + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func ListRoleAttachedPolicies(cli bce.Client, roleName string) (*ListPolicyResult, error) { + req := &bce.BceRequest{} + req.SetUri(getRoleUri(roleName) + URI_POLICY) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListPolicyResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() return jsonBody, nil } diff --git a/services/iam/api/role.go b/services/iam/api/role.go new file mode 100644 index 00000000..db4372c0 --- /dev/null +++ b/services/iam/api/role.go @@ -0,0 +1,125 @@ +/* + * Copyright 2021 Baidu, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + +package api + +import ( + "github.com/baidubce/bce-sdk-go/bce" + "github.com/baidubce/bce-sdk-go/http" +) + +func CreateRole(cli bce.Client, body *bce.Body) (*CreateRoleResult, error) { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_ROLE) + req.SetMethod(http.POST) + req.SetBody(body) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + + jsonBody := &CreateRoleResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func GetRole(cli bce.Client, roleName string) (*GetRoleResult, error) { + req := &bce.BceRequest{} + req.SetUri(getRoleUri(roleName)) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &GetRoleResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func UpdateRole(cli bce.Client, roleName string, body *bce.Body) (*UpdateRoleResult, error) { + req := &bce.BceRequest{} + req.SetUri(getRoleUri(roleName)) + req.SetMethod(http.PUT) + req.SetBody(body) + req.SetHeader(http.CONTENT_TYPE, bce.DEFAULT_CONTENT_TYPE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &UpdateRoleResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func DeleteRole(cli bce.Client, roleName string) error { + req := &bce.BceRequest{} + req.SetUri(getRoleUri(roleName)) + req.SetMethod(http.DELETE) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return err + } + if resp.IsFail() { + return resp.ServiceError() + } + defer func() { resp.Body().Close() }() + return nil +} + +func ListRole(cli bce.Client) (*ListRoleResult, error) { + req := &bce.BceRequest{} + req.SetUri(URI_PREFIX + URI_ROLE) + req.SetMethod(http.GET) + + resp := &bce.BceResponse{} + if err := cli.SendRequest(req, resp); err != nil { + return nil, err + } + if resp.IsFail() { + return nil, resp.ServiceError() + } + jsonBody := &ListRoleResult{} + if err := resp.ParseJsonBody(jsonBody); err != nil { + return nil, err + } + defer func() { resp.Body().Close() }() + return jsonBody, nil +} + +func getRoleUri(roleName string) string { + return URI_PREFIX + URI_ROLE + "/" + roleName +} diff --git a/services/iam/api/user.go b/services/iam/api/user.go index dc454287..7b5b194a 100644 --- a/services/iam/api/user.go +++ b/services/iam/api/user.go @@ -37,6 +37,7 @@ func CreateUser(cli bce.Client, body *bce.Body) (*CreateUserResult, error) { if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -56,6 +57,7 @@ func GetUser(cli bce.Client, name string) (*GetUserResult, error) { if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -71,6 +73,7 @@ func DeleteUser(cli bce.Client, name string) error { if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } @@ -92,6 +95,7 @@ func UpdateUser(cli bce.Client, name string, body *bce.Body) (*UpdateUserResult, if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -111,6 +115,7 @@ func ListUser(cli bce.Client) (*ListUserResult, error) { if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -132,6 +137,7 @@ func UpdateUserLoginProfile(cli bce.Client, name string, body *bce.Body) (*Updat if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -151,6 +157,7 @@ func GetUserLoginProfile(cli bce.Client, name string) (*GetUserLoginProfileResul if err := resp.ParseJsonBody(jsonBody); err != nil { return nil, err } + defer func() { resp.Body().Close() }() return jsonBody, nil } @@ -166,6 +173,7 @@ func DeleteUserLoginProfile(cli bce.Client, name string) error { if resp.IsFail() { return resp.ServiceError() } + defer func() { resp.Body().Close() }() return nil } diff --git a/services/iam/client.go b/services/iam/client.go index db548655..8296461a 100644 --- a/services/iam/client.go +++ b/services/iam/client.go @@ -194,6 +194,66 @@ func (c *Client) ListGroupAttachedPolicies(name string) (*api.ListPolicyResult, return api.ListGroupAttachedPolicies(c, name) } +func (c *Client) CreateAccessKey(userName string) (*api.CreateAccessKeyResult, error) { + return api.CreateAccessKey(c, userName) +} + +func (c *Client) DisableAccessKey(userName, accessKeyId string) (*api.UpdateAccessKeyResult, error) { + return api.DisableAccessKey(c, userName, accessKeyId) +} + +func (c *Client) EnableAccessKey(userName, accessKeyId string) (*api.UpdateAccessKeyResult, error) { + return api.EnableAccessKey(c, userName, accessKeyId) +} + +func (c *Client) DeleteAccessKey(userName, accessKeyId string) error { + return api.DeleteAccessKey(c, userName, accessKeyId) +} + +func (c *Client) ListAccessKey(userName string) (*api.ListAccessKeyResult, error) { + return api.ListAccessKey(c, userName) +} + +func (c *Client) CreateRole(args *api.CreateRoleArgs) (*api.CreateRoleResult, error) { + body, err := NewBodyFromStruct(args) + if err != nil { + return nil, err + } + return api.CreateRole(c, body) +} + +func (c *Client) GetRole(roleName string) (*api.GetRoleResult, error) { + return api.GetRole(c, roleName) +} + +func (c *Client) UpdateRole(roleName string, args *api.UpdateRoleArgs) (*api.UpdateRoleResult, error) { + body, err := NewBodyFromStruct(args) + if err != nil { + return nil, err + } + return api.UpdateRole(c, roleName, body) +} + +func (c *Client) DeleteRole(roleName string) error { + return api.DeleteRole(c, roleName) +} + +func (c *Client) ListRole() (*api.ListRoleResult, error) { + return api.ListRole(c) +} + +func (c *Client) AttachPolicyToRole(args *api.AttachPolicyToRoleArgs) error { + return api.AttachPolicyToRole(c, args) +} + +func (c *Client) DetachPolicyFromRole(args *api.DetachPolicyToRoleArgs) error { + return api.DetachPolicyFromRole(c, args) +} + +func (c *Client) ListRoleAttachedPolicies(name string) (*api.ListPolicyResult, error) { + return api.ListRoleAttachedPolicies(c, name) +} + func NewBodyFromStruct(args interface{}) (*bce.Body, error) { jsonBytes, err := json.Marshal(args) if err != nil { diff --git a/services/iam/client_test.go b/services/iam/client_test.go index 252cb183..fb52b251 100644 --- a/services/iam/client_test.go +++ b/services/iam/client_test.go @@ -28,8 +28,9 @@ import ( // For security reason, ak/sk should not hard write here. type Conf struct { - AK string - SK string + AK string + SK string + Endpoint string } var IAM_CLIENT *Client @@ -48,7 +49,7 @@ func init() { decoder := json.NewDecoder(fp) confObj := &Conf{} decoder.Decode(confObj) - IAM_CLIENT, _ = NewClient(confObj.AK, confObj.SK) + IAM_CLIENT, _ = NewClientWithEndpoint(confObj.AK, confObj.SK, confObj.Endpoint) log.SetLogLevel(log.DEBUG) } @@ -256,6 +257,26 @@ func getPolicyDocument() string { return string(document) } +func getAssumeRolePolicyDocument() string { + + grantee := api.Grantee{ + ID: "test-account-id", + } + + aclEntry := api.AclEntry{ + Service: "bce:iam", + Region: "*", + Permission: []string{"AssumeRole"}, + Grantee: []api.Grantee{grantee}, + Effect: "Allow", + } + acl := &api.Acl{ + AccessControlList: []api.AclEntry{aclEntry}, + } + document, _ := json.Marshal(acl) + return string(document) +} + func TestCreateGetListDeletePolicy(t *testing.T) { name := "test_sdk_go_policy" args := &api.CreatePolicyArgs{ @@ -375,3 +396,170 @@ func TestGroupAttachDetachPolicy(t *testing.T) { err = IAM_CLIENT.DeleteGroup(groupName) ExpectEqual(t.Errorf, err, nil) } + +func TestAccessKeyCreateAndDelete(t *testing.T) { + name := "test-user-sdk-go-ak" + args := &api.CreateUserArgs{ + Name: name, + Description: "description", + } + res, err := IAM_CLIENT.CreateUser(args) + ExpectEqual(t.Errorf, err, nil) + jsonRes, _ := json.Marshal(res) + t.Logf(string(jsonRes)) + ExpectEqual(t.Errorf, res.Name, args.Name) + ExpectEqual(t.Errorf, res.Description, args.Description) + + akRes, err := IAM_CLIENT.CreateAccessKey(name) + jsonAkRes, _ := json.Marshal(akRes) + t.Logf(string(jsonAkRes)) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, akRes.Enabled, true) + + accessKeys, err := IAM_CLIENT.ListAccessKey(name) + ExpectEqual(t.Errorf, err, nil) + if accessKeys == nil || len(accessKeys.AccessKeys) == 0 { + t.Errorf("list accessKeys return no result") + } + aksJsonRes, _ := json.Marshal(accessKeys) + t.Logf(string(aksJsonRes)) + + err = IAM_CLIENT.DeleteAccessKey(name, akRes.Id) + ExpectEqual(t.Errorf, err, nil) + + err = IAM_CLIENT.DeleteUser(name) + ExpectEqual(t.Errorf, err, nil) +} + +func TestAccessKeyDisableAndEnable(t *testing.T) { + name := "test-user-sdk-go-ak" + args := &api.CreateUserArgs{ + Name: name, + Description: "description", + } + res, err := IAM_CLIENT.CreateUser(args) + ExpectEqual(t.Errorf, err, nil) + jsonRes, _ := json.Marshal(res) + t.Logf(string(jsonRes)) + ExpectEqual(t.Errorf, res.Name, args.Name) + ExpectEqual(t.Errorf, res.Description, args.Description) + + akRes, err := IAM_CLIENT.CreateAccessKey(name) + jsonAkRes, _ := json.Marshal(akRes) + t.Logf(string(jsonAkRes)) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, akRes.Enabled, true) + + disAbleAkRes, err := IAM_CLIENT.DisableAccessKey(name, akRes.Id) + ExpectEqual(t.Errorf, err, nil) + jsonDisAbleAkRes, _ := json.Marshal(disAbleAkRes) + t.Logf(string(jsonDisAbleAkRes)) + ExpectEqual(t.Errorf, disAbleAkRes.Enabled, false) + + enAbleAkRes, err := IAM_CLIENT.EnableAccessKey(name, akRes.Id) + ExpectEqual(t.Errorf, err, nil) + jsonEnAbleAkRes, _ := json.Marshal(enAbleAkRes) + t.Logf(string(jsonEnAbleAkRes)) + ExpectEqual(t.Errorf, enAbleAkRes.Enabled, true) + + err = IAM_CLIENT.DeleteAccessKey(name, akRes.Id) + ExpectEqual(t.Errorf, err, nil) + + err = IAM_CLIENT.DeleteUser(name) + ExpectEqual(t.Errorf, err, nil) +} + +func TestRoleCreateAndDelete(t *testing.T) { + name := "test-role-sdk-go" + args := &api.CreateRoleArgs{ + Name: name, + Description: "description", + AssumeRolePolicyDocument: getAssumeRolePolicyDocument(), + } + res, err := IAM_CLIENT.CreateRole(args) + ExpectEqual(t.Errorf, err, nil) + jsonRes, _ := json.Marshal(res) + t.Logf(string(jsonRes)) + ExpectEqual(t.Errorf, res.Name, args.Name) + ExpectEqual(t.Errorf, res.Description, args.Description) + + getRes, err := IAM_CLIENT.GetRole(name) + ExpectEqual(t.Errorf, err, nil) + getJsonRes, _ := json.Marshal(getRes) + t.Logf(string(getJsonRes)) + ExpectEqual(t.Errorf, res.Name, args.Name) + ExpectEqual(t.Errorf, res.Description, args.Description) + + rolesRes, err := IAM_CLIENT.ListRole() + ExpectEqual(t.Errorf, err, nil) + if rolesRes == nil || len(rolesRes.Roles) == 0 { + t.Errorf("list roles return no result") + } + rolesResJson, _ := json.Marshal(rolesRes) + t.Logf(string(rolesResJson)) + + newDescription := "newDescription" + updateArgs := &api.UpdateRoleArgs{ + Description: newDescription, + } + updateRes, err := IAM_CLIENT.UpdateRole(name, updateArgs) + ExpectEqual(t.Errorf, err, nil) + ExpectEqual(t.Errorf, updateRes.Description, newDescription) + + err = IAM_CLIENT.DeleteRole(name) + ExpectEqual(t.Errorf, err, nil) +} + +func TestRoleAttachPolicyAndDetachPolicy(t *testing.T) { + roleName := "test-role-sdk-go" + args := &api.CreateRoleArgs{ + Name: roleName, + Description: "description", + AssumeRolePolicyDocument: getAssumeRolePolicyDocument(), + } + res, err := IAM_CLIENT.CreateRole(args) + ExpectEqual(t.Errorf, err, nil) + jsonRes, _ := json.Marshal(res) + t.Logf(string(jsonRes)) + ExpectEqual(t.Errorf, res.Name, args.Name) + ExpectEqual(t.Errorf, res.Description, args.Description) + + policyName := "test_sdk_go_policy" + policyArgs := &api.CreatePolicyArgs{ + Name: policyName, + Description: "description", + Document: getPolicyDocument(), + } + + _, err = IAM_CLIENT.CreatePolicy(policyArgs) + ExpectEqual(t.Errorf, err, nil) + + attachArgs := &api.AttachPolicyToRoleArgs{ + RoleName: roleName, + PolicyName: policyName, + } + err = IAM_CLIENT.AttachPolicyToRole(attachArgs) + ExpectEqual(t.Errorf, err, nil) + + policies, err := IAM_CLIENT.ListRoleAttachedPolicies(roleName) + ExpectEqual(t.Errorf, err, nil) + if policies == nil || len(policies.Policies) != 1 { + t.Errorf("list policy result is not 1") + } + policy := policies.Policies[0] + ExpectEqual(t.Errorf, policyName, policy.Name) + + detachArgs := &api.DetachPolicyToRoleArgs{ + RoleName: roleName, + PolicyName: policyName, + } + err = IAM_CLIENT.DetachPolicyFromRole(detachArgs) + ExpectEqual(t.Errorf, err, nil) + + err = IAM_CLIENT.DeletePolicy(policyName) + ExpectEqual(t.Errorf, err, nil) + + err = IAM_CLIENT.DeleteRole(roleName) + ExpectEqual(t.Errorf, err, nil) + +} diff --git a/services/sts/client.go b/services/sts/client.go index fe711705..8441d3a5 100644 --- a/services/sts/client.go +++ b/services/sts/client.go @@ -57,9 +57,9 @@ func NewStsClient(ak, sk, endpoint string) (*Client, error) { endpoint = DEFAULT_SERVICE_DOMAIN } defaultSignOptions := &auth.SignOptions{ - auth.DEFAULT_HEADERS_TO_SIGN, - util.NowUTCSeconds(), - auth.DEFAULT_EXPIRE_SECONDS} + HeadersToSign: auth.DEFAULT_HEADERS_TO_SIGN, + Timestamp: util.NowUTCSeconds(), + ExpireSeconds: auth.DEFAULT_EXPIRE_SECONDS} defaultConf := &bce.BceClientConfiguration{ Endpoint: endpoint, Region: bce.DEFAULT_REGION, diff --git a/services/vpn/model.go b/services/vpn/model.go index 3117b9d0..da5f7d56 100644 --- a/services/vpn/model.go +++ b/services/vpn/model.go @@ -176,8 +176,8 @@ type CreateVpnConnResult struct { // UpdateVpnConnArgs defines the structure of input parameters for the UpdateVpnConn api type UpdateVpnConnArgs struct { - vpnConnId string `json:"vpnConnId"` - updateVpnconn *CreateVpnConnArgs `json:"updateVpnconn"` + VpnConnId string `json:"vpnConnId"` + UpdateVpnconn *CreateVpnConnArgs `json:"updateVpnconn"` } // ListVpnConnResult defines the structure of output parameters for the ListVpnConn api diff --git a/services/vpn/vpn.go b/services/vpn/vpn.go index 504f7dd8..0b945362 100644 --- a/services/vpn/vpn.go +++ b/services/vpn/vpn.go @@ -233,9 +233,9 @@ func (c *Client) CreateVpnConn(args *CreateVpnConnArgs) (*CreateVpnConnResult, e // - error: nil if success otherwise the specific error func (c *Client) UpdateVpnConn(args *UpdateVpnConnArgs) error { return bce.NewRequestBuilder(c). - WithURL(getURLForVpnConnId(args.vpnConnId)). + WithURL(getURLForVpnConnId(args.VpnConnId)). WithMethod(http.PUT). - WithBody(args.updateVpnconn). + WithBody(args.UpdateVpnconn). Do() }