payloads.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 tokens
  15. import (
  16. "bytes"
  17. "encoding/base64"
  18. "strings"
  19. "time"
  20. "github.com/golang-plus/uuid"
  21. "github.com/vmihailenco/msgpack"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/util/netutils"
  24. "yunion.io/x/onecloud/pkg/mcclient"
  25. )
  26. type TScopedPayloadVersion byte
  27. const (
  28. SProjectScopedPayloadVersion = TScopedPayloadVersion(2)
  29. SDomainScopedPayloadVersion = TScopedPayloadVersion(1)
  30. SUnscopedPayloadVersion = TScopedPayloadVersion(0)
  31. SProjectScopedPayloadWithContextVersion = TScopedPayloadVersion(5)
  32. SDomainScopedPayloadWithContextVersion = TScopedPayloadVersion(4)
  33. SUnscopedPayloadWithContextVersion = TScopedPayloadVersion(3)
  34. )
  35. type ITokenPayload interface {
  36. Unmarshal(tk []byte) error
  37. Decode(token *SAuthToken)
  38. Encode() ([]byte, error)
  39. GetVersion() TScopedPayloadVersion
  40. }
  41. type SUuidPayload struct {
  42. IsUuid bool
  43. Payload string
  44. }
  45. func (up *SUuidPayload) parse(hex string) {
  46. u, err := uuid.Parse(hex)
  47. if err != nil {
  48. up.IsUuid = false
  49. up.Payload = hex
  50. } else {
  51. up.IsUuid = true
  52. up.Payload = string(u[:])
  53. }
  54. }
  55. func convertUuidBytesToHex(bs []byte) string {
  56. u := uuid.UUID{}
  57. copy(u[:], bs)
  58. return u.Format(uuid.StyleWithoutDash)
  59. }
  60. func (u *SUuidPayload) getUuid() string {
  61. if u.IsUuid {
  62. return convertUuidBytesToHex([]byte(u.Payload))
  63. } else {
  64. return string(u.Payload)
  65. }
  66. }
  67. type SAuthContextPayload struct {
  68. Source string
  69. Ip uint32
  70. }
  71. func (c *SAuthContextPayload) getAuthContext() mcclient.SAuthContext {
  72. return mcclient.SAuthContext{
  73. Source: c.Source,
  74. Ip: netutils.IPV4Addr(c.Ip).String(),
  75. }
  76. }
  77. func authContext2Payload(c mcclient.SAuthContext) SAuthContextPayload {
  78. ip, _ := netutils.NewIPV4Addr(c.Ip)
  79. return SAuthContextPayload{
  80. Source: c.Source,
  81. Ip: uint32(ip),
  82. }
  83. }
  84. func msgpackDecoder(p ITokenPayload, tk []byte, ver TScopedPayloadVersion) error {
  85. err := msgpack.Unmarshal(tk, p)
  86. if err != nil {
  87. return errors.Wrap(err, "msgpack.Unmarshal")
  88. }
  89. if p.GetVersion() != ver {
  90. return ErrVerMismatch
  91. }
  92. return nil
  93. }
  94. func msgpackEncoder(v interface{}) ([]byte, error) {
  95. var buf bytes.Buffer
  96. enc := msgpack.NewEncoder(&buf).StructAsArray(true).UseCompactEncoding(true)
  97. err := enc.Encode(v)
  98. if err != nil {
  99. return nil, errors.Wrap(err, "msgpack.Encode")
  100. }
  101. return buf.Bytes(), nil
  102. }
  103. /*
  104. * msgpack payload
  105. *
  106. * https://github.com/msgpack/msgpack/blob/master/spec.md
  107. */
  108. type SProjectScopedPayload struct {
  109. Version TScopedPayloadVersion
  110. UserId SUuidPayload
  111. Method byte
  112. ProjectId SUuidPayload
  113. ExpiresAt float64
  114. AuditIds []string
  115. }
  116. type SProjectScopedPayloadWithContext struct {
  117. SProjectScopedPayload
  118. Context SAuthContextPayload
  119. }
  120. func (p *SProjectScopedPayload) GetVersion() TScopedPayloadVersion {
  121. return p.Version
  122. }
  123. func (p *SProjectScopedPayload) Unmarshal(tk []byte) error {
  124. return msgpackDecoder(p, tk, SProjectScopedPayloadVersion)
  125. }
  126. func (p *SProjectScopedPayload) Decode(token *SAuthToken) {
  127. token.UserId = p.UserId.getUuid()
  128. token.Method = authMethodId2Str(p.Method)
  129. token.ProjectId = p.ProjectId.getUuid()
  130. token.ExpiresAt = time.Unix(int64(p.ExpiresAt), 0).UTC()
  131. token.AuditIds = auditBytes2Strings(p.AuditIds)
  132. }
  133. func (p *SProjectScopedPayload) Encode() ([]byte, error) {
  134. return msgpackEncoder(p)
  135. }
  136. func (p *SProjectScopedPayloadWithContext) Unmarshal(tk []byte) error {
  137. return msgpackDecoder(p, tk, SProjectScopedPayloadWithContextVersion)
  138. }
  139. func (p *SProjectScopedPayloadWithContext) Decode(token *SAuthToken) {
  140. p.SProjectScopedPayload.Decode(token)
  141. token.Context = p.Context.getAuthContext()
  142. }
  143. func (p *SProjectScopedPayloadWithContext) Encode() ([]byte, error) {
  144. return msgpackEncoder(p)
  145. }
  146. type SDomainScopedPayload struct {
  147. Version TScopedPayloadVersion
  148. UserId SUuidPayload
  149. Method byte
  150. DomainId SUuidPayload
  151. ExpiresAt float64
  152. AuditIds []string
  153. }
  154. type SDomainScopedPayloadWithContext struct {
  155. SDomainScopedPayload
  156. Context SAuthContextPayload
  157. }
  158. func (p *SDomainScopedPayload) GetVersion() TScopedPayloadVersion {
  159. return p.Version
  160. }
  161. func (p *SDomainScopedPayload) Unmarshal(tk []byte) error {
  162. return msgpackDecoder(p, tk, SDomainScopedPayloadVersion)
  163. }
  164. func (p *SDomainScopedPayload) Decode(token *SAuthToken) {
  165. token.UserId = p.UserId.getUuid()
  166. token.Method = authMethodId2Str(p.Method)
  167. token.DomainId = p.DomainId.getUuid()
  168. token.ExpiresAt = time.Unix(int64(p.ExpiresAt), 0).UTC()
  169. token.AuditIds = auditBytes2Strings(p.AuditIds)
  170. }
  171. func (p *SDomainScopedPayload) Encode() ([]byte, error) {
  172. return msgpackEncoder(p)
  173. }
  174. func (p *SDomainScopedPayloadWithContext) Unmarshal(tk []byte) error {
  175. return msgpackDecoder(p, tk, SDomainScopedPayloadWithContextVersion)
  176. }
  177. func (p *SDomainScopedPayloadWithContext) Decode(token *SAuthToken) {
  178. p.SDomainScopedPayload.Decode(token)
  179. token.Context = p.Context.getAuthContext()
  180. }
  181. func (p *SDomainScopedPayloadWithContext) Encode() ([]byte, error) {
  182. return msgpackEncoder(p)
  183. }
  184. type SUnscopedPayload struct {
  185. Version TScopedPayloadVersion
  186. UserId SUuidPayload
  187. Method byte
  188. ExpiresAt float64
  189. AuditIds []string
  190. }
  191. type SUnscopedPayloadWithContext struct {
  192. SUnscopedPayload
  193. Context SAuthContextPayload
  194. }
  195. func (p *SUnscopedPayload) GetVersion() TScopedPayloadVersion {
  196. return p.Version
  197. }
  198. func (p *SUnscopedPayload) Unmarshal(tk []byte) error {
  199. return msgpackDecoder(p, tk, SUnscopedPayloadVersion)
  200. }
  201. func (p *SUnscopedPayload) Decode(token *SAuthToken) {
  202. token.UserId = p.UserId.getUuid()
  203. token.Method = authMethodId2Str(p.Method)
  204. token.ExpiresAt = time.Unix(int64(p.ExpiresAt), 0).UTC()
  205. token.AuditIds = auditBytes2Strings(p.AuditIds)
  206. }
  207. func (p *SUnscopedPayload) Encode() ([]byte, error) {
  208. return msgpackEncoder(p)
  209. }
  210. func (p *SUnscopedPayloadWithContext) Unmarshal(tk []byte) error {
  211. return msgpackDecoder(p, tk, SUnscopedPayloadWithContextVersion)
  212. }
  213. func (p *SUnscopedPayloadWithContext) Decode(token *SAuthToken) {
  214. p.SUnscopedPayload.Decode(token)
  215. token.Context = p.Context.getAuthContext()
  216. }
  217. func (p *SUnscopedPayloadWithContext) Encode() ([]byte, error) {
  218. return msgpackEncoder(p)
  219. }
  220. func auditString2Bytes(str string) string {
  221. bt, _ := base64.URLEncoding.DecodeString(str + "==")
  222. return string(bt)
  223. }
  224. func auditBytes2String(bs string) string {
  225. return strings.TrimRight(base64.URLEncoding.EncodeToString([]byte(bs)), "=")
  226. }
  227. func auditStrings2Bytes(strs []string) []string {
  228. ret := make([]string, len(strs))
  229. for i := range strs {
  230. ret[i] = auditString2Bytes(strs[i])
  231. }
  232. return ret
  233. }
  234. func auditBytes2Strings(bs []string) []string {
  235. ret := make([]string, len(bs))
  236. for i := range bs {
  237. ret[i] = auditBytes2String(bs[i])
  238. }
  239. return ret
  240. }