certificate.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package qcloud
  15. import (
  16. "crypto/sha1"
  17. "fmt"
  18. "strconv"
  19. "strings"
  20. "time"
  21. "yunion.io/x/jsonutils"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/cloudmux/pkg/apis"
  24. "yunion.io/x/cloudmux/pkg/cloudprovider"
  25. "yunion.io/x/cloudmux/pkg/multicloud"
  26. )
  27. var CERT_STATUS_MAP = map[int]string{
  28. 0: "pending",
  29. 1: "normal",
  30. 2: "deleted",
  31. 3: "expired",
  32. 4: "normal",
  33. 5: "pending",
  34. 6: "deleted",
  35. 7: "deleted",
  36. 8: "pending",
  37. }
  38. type projectInfo struct {
  39. ProjectID string `json:"projectId"`
  40. OwnerUin int64 `json:"ownerUin"`
  41. Name string `json:"name"`
  42. CreatorUin int64 `json:"creatorUin"`
  43. CreateTime string `json:"createTime"`
  44. Info string `json:"info"`
  45. }
  46. // https://cloud.tencent.com/document/api/400/13675
  47. type SCertificate struct {
  48. multicloud.SCertificateBase
  49. QcloudTags
  50. client *SQcloudClient
  51. CertificateID string `json:"CertificateId"`
  52. CertificateType string `json:"CertificateType"`
  53. Deployable bool `json:"Deployable"`
  54. RenewAble bool `json:"RenewAble"`
  55. OwnerUin string `json:"ownerUin"`
  56. ProjectID string `json:"projectId"`
  57. From string `json:"from"`
  58. ProductZhName string `json:"productZhName"`
  59. Domain string `json:"domain"`
  60. Alias string `json:"alias"`
  61. Status int `json:"status"`
  62. VulnerabilityStatus string `json:"vulnerability_status"`
  63. CERTBeginTime time.Time `json:"certBeginTime"`
  64. CERTEndTime time.Time `json:"certEndTime"`
  65. ValidityPeriod string `json:"validityPeriod"`
  66. InsertTime string `json:"insertTime"`
  67. ProjectInfo projectInfo `json:"projectInfo"`
  68. StatusName string `json:"status_name"`
  69. IsVip bool `json:"is_vip"`
  70. IsDv bool `json:"is_dv"`
  71. IsWildcard bool `json:"is_wildcard"`
  72. IsVulnerability bool `json:"is_vulnerability"`
  73. // certificate details
  74. DetailsInitd bool `json:"details_initd"`
  75. SubjectAltName []string `json:"subjectAltName"`
  76. CertificatePrivateKey string `json:"CertificatePrivateKey"`
  77. CertificatePublicKey string `json:"CertificatePublicKey"`
  78. CertFingerprint string `json:"CertFingerprint"`
  79. }
  80. func (self *SCertificate) GetDetails() (*SCertificate, error) {
  81. if !self.DetailsInitd {
  82. var (
  83. cert *SCertificate
  84. err error
  85. )
  86. cert, err = self.client.GetCertificate(self.GetId())
  87. if err != nil {
  88. return nil, err
  89. }
  90. self.DetailsInitd = true
  91. self.SubjectAltName = cert.SubjectAltName
  92. self.CertificatePrivateKey = cert.CertificatePrivateKey
  93. self.CertificatePublicKey = cert.CertificatePublicKey
  94. self.CertFingerprint = cert.CertFingerprint
  95. }
  96. return self, nil
  97. }
  98. func (self *SCertificate) GetPublickKey() string {
  99. self.GetDetails()
  100. return self.CertificatePublicKey
  101. }
  102. func (self *SCertificate) GetPrivateKey() string {
  103. self.GetDetails()
  104. return self.CertificatePrivateKey
  105. }
  106. func (self *SCertificate) GetCert() string {
  107. self.GetDetails()
  108. return self.CertificatePublicKey
  109. }
  110. func (self *SCertificate) GetKey() string {
  111. self.GetDetails()
  112. return self.CertificatePrivateKey
  113. }
  114. func (self *SCertificate) Delete() error {
  115. return self.client.DeleteCertificate(self.GetId())
  116. }
  117. func (self *SCertificate) GetId() string {
  118. return self.CertificateID
  119. }
  120. func (self *SCertificate) GetName() string {
  121. if len(self.Alias) > 0 {
  122. return self.Alias
  123. } else {
  124. return self.Domain
  125. }
  126. }
  127. func (self *SCertificate) GetGlobalId() string {
  128. return self.CertificateID
  129. }
  130. func (self *SCertificate) GetStatus() string {
  131. status, ok := CERT_STATUS_MAP[self.Status]
  132. if !ok {
  133. return apis.STATUS_UNKNOWN
  134. }
  135. switch status {
  136. case "normal":
  137. return apis.STATUS_AVAILABLE
  138. case "deleted":
  139. return apis.STATUS_DELETING
  140. case "pending":
  141. return apis.STATUS_CREATING
  142. default:
  143. return status
  144. }
  145. }
  146. func (self *SCertificate) Refresh() error {
  147. cert, err := self.client.GetCertificate(self.GetId())
  148. if err != nil {
  149. return errors.Wrap(err, "GetCertificate")
  150. }
  151. return jsonutils.Update(self, cert)
  152. }
  153. func (self *SCertificate) GetCommonName() string {
  154. return self.Domain
  155. }
  156. func (self *SCertificate) GetSubjectAlternativeNames() string {
  157. self.GetDetails()
  158. return self.CertFingerprint
  159. }
  160. func (self *SCertificate) GetFingerprint() string {
  161. self.GetDetails()
  162. _fp := sha1.Sum([]byte(self.CertificatePublicKey))
  163. fp := fmt.Sprintf("sha1:% x", _fp)
  164. return strings.Replace(fp, " ", ":", -1)
  165. }
  166. func (self *SCertificate) GetExpireTime() time.Time {
  167. return self.CERTEndTime
  168. }
  169. func (self *SCertificate) GetProjectId() string {
  170. return self.ProjectID
  171. }
  172. func (self *SCertificate) GetSans() string {
  173. return strings.Join(self.SubjectAltName, ",")
  174. }
  175. func (self *SCertificate) GetStartDate() time.Time {
  176. return self.CERTBeginTime
  177. }
  178. func (self *SCertificate) GetProvince() string {
  179. return ""
  180. }
  181. func (self *SCertificate) GetCommon() string {
  182. return self.Domain
  183. }
  184. func (self *SCertificate) GetCountry() string {
  185. return ""
  186. }
  187. func (self *SCertificate) GetIssuer() string {
  188. return self.ProductZhName
  189. }
  190. func (self *SCertificate) GetEndDate() time.Time {
  191. return self.CERTEndTime
  192. }
  193. func (self *SCertificate) GetCity() string {
  194. return ""
  195. }
  196. func (self *SCertificate) GetOrgName() string {
  197. return ""
  198. }
  199. func (self *SCertificate) GetIsUpload() bool {
  200. if self.From == "upload" {
  201. return true
  202. }
  203. return false
  204. }
  205. // https://cloud.tencent.com/document/product/400/41674
  206. func (self *SQcloudClient) GetCertificate(certId string) (*SCertificate, error) {
  207. params := map[string]string{
  208. "CertificateId": certId,
  209. }
  210. resp, err := self.sslRequest("DescribeCertificateDetail", params)
  211. if err != nil {
  212. return nil, errors.Wrap(err, "DescribeCertificateDetail")
  213. }
  214. cert := &SCertificate{client: self}
  215. err = resp.Unmarshal(cert)
  216. if err != nil {
  217. return nil, errors.Wrap(err, "Unmarshal")
  218. }
  219. return cert, nil
  220. }
  221. // https://cloud.tencent.com/document/product/400/41665
  222. // 返回证书ID
  223. func (self *SQcloudClient) CreateCertificate(projectId, publicKey, privateKey, certType, desc string) (string, error) {
  224. params := map[string]string{
  225. "CertificatePublicKey": publicKey,
  226. "CertificateType": certType,
  227. "Alias": desc,
  228. }
  229. if len(privateKey) > 0 {
  230. params["CertificatePrivateKey"] = privateKey
  231. } else {
  232. if certType == "SVR" {
  233. return "", fmt.Errorf("certificate private key required while certificate type is SVR")
  234. }
  235. }
  236. if len(projectId) > 0 {
  237. params["ProjectId"] = projectId
  238. }
  239. resp, err := self.sslRequest("UploadCertificate", params)
  240. if err != nil {
  241. return "", err
  242. }
  243. return resp.GetString("CertificateId")
  244. }
  245. // https://cloud.tencent.com/document/product/400/41675
  246. func (self *SQcloudClient) DeleteCertificate(id string) error {
  247. if len(id) == 0 {
  248. return fmt.Errorf("DelteCertificate certificate id should not be empty")
  249. }
  250. params := map[string]string{"CertificateId": id}
  251. resp, err := self.sslRequest("DeleteCertificate", params)
  252. if err != nil {
  253. return errors.Wrap(err, "DeleteCertificate")
  254. }
  255. if deleted, _ := resp.Bool("DeleteResult"); deleted {
  256. return nil
  257. }
  258. return fmt.Errorf("DeleteCertificate %s", resp)
  259. }
  260. func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) {
  261. if self.Region != QCLOUD_DEFAULT_REGION {
  262. return []cloudprovider.ICloudLoadbalancerCertificate{}, nil
  263. }
  264. certs, err := self.client.GetCertificates("", "", "")
  265. if err != nil {
  266. return nil, errors.Wrap(err, "GetCertificates")
  267. }
  268. icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs))
  269. for i := range certs {
  270. certs[i].client = self.client
  271. icerts[i] = &certs[i]
  272. }
  273. return icerts, nil
  274. }
  275. func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) {
  276. cert, err := self.client.GetCertificate(certId)
  277. if err != nil {
  278. return nil, errors.Wrap(err, "GetCertificate")
  279. }
  280. return cert, nil
  281. }
  282. // todo:目前onecloud端只能指定服务器端证书。需要兼容客户端证书?
  283. // todo:支持指定Project。
  284. // todo: 已过期的证书不能上传也不能关联资源
  285. func (self *SRegion) CreateILoadBalancerCertificate(input *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) {
  286. certId, err := self.client.CreateCertificate("", input.Certificate, input.PrivateKey, "SVR", input.Name)
  287. if err != nil {
  288. return nil, err
  289. }
  290. cert, err := self.client.GetCertificate(certId)
  291. if err != nil {
  292. return nil, errors.Wrapf(err, "GetCertificate")
  293. }
  294. return cert, nil
  295. }
  296. func (self *SQcloudClient) GetCertificates(projectId, certificateStatus, searchKey string) ([]SCertificate, error) {
  297. params := map[string]string{}
  298. params["Limit"] = "100"
  299. if len(projectId) > 0 {
  300. params["ProjectId"] = projectId
  301. }
  302. if len(certificateStatus) > 0 {
  303. params["CertificateStatus.0"] = certificateStatus
  304. }
  305. if len(searchKey) > 0 {
  306. params["SearchKey"] = searchKey
  307. }
  308. certs := []SCertificate{}
  309. offset := 0
  310. total := 100
  311. for total > offset {
  312. params["Offset"] = strconv.Itoa(offset)
  313. resp, err := self.sslRequest("DescribeCertificates", params)
  314. if err != nil {
  315. return nil, errors.Wrap(err, "DescribeCertificates")
  316. }
  317. _certs := []SCertificate{}
  318. err = resp.Unmarshal(&certs, "Certificates")
  319. if err != nil {
  320. return nil, errors.Wrap(err, "Unmarshal.Certificates")
  321. }
  322. err = resp.Unmarshal(&total, "TotalCount")
  323. if err != nil {
  324. return nil, errors.Wrap(err, "Unmarshal.TotalCount")
  325. }
  326. for i := range _certs {
  327. _certs[i].client = self
  328. certs = append(certs, _certs[i])
  329. }
  330. offset += 100
  331. }
  332. return certs, nil
  333. }