s3api_acl_helper.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. package s3api
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
  6. "github.com/aws/aws-sdk-go/service/s3"
  7. "github.com/seaweedfs/seaweedfs/weed/glog"
  8. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  9. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  10. "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
  11. "net/http"
  12. "strings"
  13. util_http "github.com/seaweedfs/seaweedfs/weed/util/http"
  14. )
  15. type AccountManager interface {
  16. GetAccountNameById(canonicalId string) string
  17. GetAccountIdByEmail(email string) string
  18. }
  19. // GetAccountId get AccountId from request headers, AccountAnonymousId will be return if not presen
  20. func GetAccountId(r *http.Request) string {
  21. id := r.Header.Get(s3_constants.AmzAccountId)
  22. if len(id) == 0 {
  23. return s3_constants.AccountAnonymousId
  24. } else {
  25. return id
  26. }
  27. }
  28. // ExtractAcl extracts the acl from the request body, or from the header if request body is empty
  29. func ExtractAcl(r *http.Request, accountManager AccountManager, ownership, bucketOwnerId, ownerId, accountId string) (grants []*s3.Grant, errCode s3err.ErrorCode) {
  30. if r.Body != nil && r.Body != http.NoBody {
  31. defer util_http.CloseRequest(r)
  32. var acp s3.AccessControlPolicy
  33. err := xmlutil.UnmarshalXML(&acp, xml.NewDecoder(r.Body), "")
  34. if err != nil || acp.Owner == nil || acp.Owner.ID == nil {
  35. return nil, s3err.ErrInvalidRequest
  36. }
  37. //owner should present && owner is immutable
  38. if *acp.Owner.ID != ownerId {
  39. glog.V(3).Infof("set acl denied! owner account is not consistent, request account id: %s, expect account id: %s", accountId, ownerId)
  40. return nil, s3err.ErrAccessDenied
  41. }
  42. return ValidateAndTransferGrants(accountManager, acp.Grants)
  43. } else {
  44. _, grants, errCode = ParseAndValidateAclHeadersOrElseDefault(r, accountManager, ownership, bucketOwnerId, accountId, true)
  45. return grants, errCode
  46. }
  47. }
  48. // ParseAndValidateAclHeadersOrElseDefault will callParseAndValidateAclHeaders to get Grants, if empty, it will return Grant that grant `accountId` with `FullControl` permission
  49. func ParseAndValidateAclHeadersOrElseDefault(r *http.Request, accountManager AccountManager, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
  50. ownerId, grants, errCode = ParseAndValidateAclHeaders(r, accountManager, ownership, bucketOwnerId, accountId, putAcl)
  51. if errCode != s3err.ErrNone {
  52. return
  53. }
  54. if len(grants) == 0 {
  55. //if no acl(both customAcl and cannedAcl) specified, grant accountId(object writer) with full control permission
  56. grants = append(grants, &s3.Grant{
  57. Grantee: &s3.Grantee{
  58. Type: &s3_constants.GrantTypeCanonicalUser,
  59. ID: &accountId,
  60. },
  61. Permission: &s3_constants.PermissionFullControl,
  62. })
  63. }
  64. return
  65. }
  66. // ParseAndValidateAclHeaders parse and validate acl from header
  67. func ParseAndValidateAclHeaders(r *http.Request, accountManager AccountManager, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
  68. ownerId, grants, errCode = ParseAclHeaders(r, ownership, bucketOwnerId, accountId, putAcl)
  69. if errCode != s3err.ErrNone {
  70. return
  71. }
  72. if len(grants) > 0 {
  73. grants, errCode = ValidateAndTransferGrants(accountManager, grants)
  74. }
  75. return
  76. }
  77. // ParseAclHeaders parse acl headers
  78. // When `putAcl` is true, only `CannedAcl` is parsed, such as `PutBucketAcl` or `PutObjectAcl`
  79. // is requested, `CustomAcl` is parsed from the request body not from headers, and only if the
  80. // request body is empty, `CannedAcl` is parsed from the header, and will not parse `CustomAcl` from the header
  81. //
  82. // Since `CustomAcl` has higher priority, it will be parsed first; if `CustomAcl` does not exist, `CannedAcl` will be parsed
  83. func ParseAclHeaders(r *http.Request, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
  84. if !putAcl {
  85. errCode = ParseCustomAclHeaders(r, &grants)
  86. if errCode != s3err.ErrNone {
  87. return "", nil, errCode
  88. }
  89. }
  90. if len(grants) > 0 {
  91. return accountId, grants, s3err.ErrNone
  92. }
  93. cannedAcl := r.Header.Get(s3_constants.AmzCannedAcl)
  94. if len(cannedAcl) == 0 {
  95. return accountId, grants, s3err.ErrNone
  96. }
  97. //if canned acl specified, parse cannedAcl (lower priority to custom acl)
  98. ownerId, grants, errCode = ParseCannedAclHeader(ownership, bucketOwnerId, accountId, cannedAcl, putAcl)
  99. if errCode != s3err.ErrNone {
  100. return "", nil, errCode
  101. }
  102. return ownerId, grants, errCode
  103. }
  104. func ParseCustomAclHeaders(r *http.Request, grants *[]*s3.Grant) s3err.ErrorCode {
  105. customAclHeaders := []string{s3_constants.AmzAclFullControl, s3_constants.AmzAclRead, s3_constants.AmzAclReadAcp, s3_constants.AmzAclWrite, s3_constants.AmzAclWriteAcp}
  106. var errCode s3err.ErrorCode
  107. for _, customAclHeader := range customAclHeaders {
  108. headerValue := r.Header.Get(customAclHeader)
  109. switch customAclHeader {
  110. case s3_constants.AmzAclRead:
  111. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionRead, grants)
  112. case s3_constants.AmzAclWrite:
  113. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionWrite, grants)
  114. case s3_constants.AmzAclReadAcp:
  115. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionReadAcp, grants)
  116. case s3_constants.AmzAclWriteAcp:
  117. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionWriteAcp, grants)
  118. case s3_constants.AmzAclFullControl:
  119. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionFullControl, grants)
  120. }
  121. if errCode != s3err.ErrNone {
  122. return errCode
  123. }
  124. }
  125. return s3err.ErrNone
  126. }
  127. func ParseCustomAclHeader(headerValue, permission string, grants *[]*s3.Grant) s3err.ErrorCode {
  128. if len(headerValue) > 0 {
  129. split := strings.Split(headerValue, ", ")
  130. for _, grantStr := range split {
  131. kv := strings.Split(grantStr, "=")
  132. if len(kv) != 2 {
  133. return s3err.ErrInvalidRequest
  134. }
  135. switch kv[0] {
  136. case "id":
  137. var accountId string
  138. _ = json.Unmarshal([]byte(kv[1]), &accountId)
  139. *grants = append(*grants, &s3.Grant{
  140. Grantee: &s3.Grantee{
  141. Type: &s3_constants.GrantTypeCanonicalUser,
  142. ID: &accountId,
  143. },
  144. Permission: &permission,
  145. })
  146. case "emailAddress":
  147. var emailAddress string
  148. _ = json.Unmarshal([]byte(kv[1]), &emailAddress)
  149. *grants = append(*grants, &s3.Grant{
  150. Grantee: &s3.Grantee{
  151. Type: &s3_constants.GrantTypeAmazonCustomerByEmail,
  152. EmailAddress: &emailAddress,
  153. },
  154. Permission: &permission,
  155. })
  156. case "uri":
  157. var groupName string
  158. _ = json.Unmarshal([]byte(kv[1]), &groupName)
  159. *grants = append(*grants, &s3.Grant{
  160. Grantee: &s3.Grantee{
  161. Type: &s3_constants.GrantTypeGroup,
  162. URI: &groupName,
  163. },
  164. Permission: &permission,
  165. })
  166. }
  167. }
  168. }
  169. return s3err.ErrNone
  170. }
  171. func ParseCannedAclHeader(bucketOwnership, bucketOwnerId, accountId, cannedAcl string, putAcl bool) (ownerId string, grants []*s3.Grant, err s3err.ErrorCode) {
  172. err = s3err.ErrNone
  173. ownerId = accountId
  174. //objectWrite automatically has full control on current object
  175. objectWriterFullControl := &s3.Grant{
  176. Grantee: &s3.Grantee{
  177. ID: &accountId,
  178. Type: &s3_constants.GrantTypeCanonicalUser,
  179. },
  180. Permission: &s3_constants.PermissionFullControl,
  181. }
  182. switch cannedAcl {
  183. case s3_constants.CannedAclPrivate:
  184. grants = append(grants, objectWriterFullControl)
  185. case s3_constants.CannedAclPublicRead:
  186. grants = append(grants, objectWriterFullControl)
  187. grants = append(grants, s3_constants.PublicRead...)
  188. case s3_constants.CannedAclPublicReadWrite:
  189. grants = append(grants, objectWriterFullControl)
  190. grants = append(grants, s3_constants.PublicReadWrite...)
  191. case s3_constants.CannedAclAuthenticatedRead:
  192. grants = append(grants, objectWriterFullControl)
  193. grants = append(grants, s3_constants.AuthenticatedRead...)
  194. case s3_constants.CannedAclLogDeliveryWrite:
  195. grants = append(grants, objectWriterFullControl)
  196. grants = append(grants, s3_constants.LogDeliveryWrite...)
  197. case s3_constants.CannedAclBucketOwnerRead:
  198. grants = append(grants, objectWriterFullControl)
  199. if bucketOwnerId != "" && bucketOwnerId != accountId {
  200. grants = append(grants,
  201. &s3.Grant{
  202. Grantee: &s3.Grantee{
  203. Type: &s3_constants.GrantTypeCanonicalUser,
  204. ID: &bucketOwnerId,
  205. },
  206. Permission: &s3_constants.PermissionRead,
  207. })
  208. }
  209. case s3_constants.CannedAclBucketOwnerFullControl:
  210. if bucketOwnerId != "" {
  211. // if set ownership to 'BucketOwnerPreferred' when upload object, the bucket owner will be the object owner
  212. if !putAcl && bucketOwnership == s3_constants.OwnershipBucketOwnerPreferred {
  213. ownerId = bucketOwnerId
  214. grants = append(grants,
  215. &s3.Grant{
  216. Grantee: &s3.Grantee{
  217. Type: &s3_constants.GrantTypeCanonicalUser,
  218. ID: &bucketOwnerId,
  219. },
  220. Permission: &s3_constants.PermissionFullControl,
  221. })
  222. } else {
  223. grants = append(grants, objectWriterFullControl)
  224. if accountId != bucketOwnerId {
  225. grants = append(grants,
  226. &s3.Grant{
  227. Grantee: &s3.Grantee{
  228. Type: &s3_constants.GrantTypeCanonicalUser,
  229. ID: &bucketOwnerId,
  230. },
  231. Permission: &s3_constants.PermissionFullControl,
  232. })
  233. }
  234. }
  235. }
  236. case s3_constants.CannedAclAwsExecRead:
  237. err = s3err.ErrNotImplemented
  238. default:
  239. err = s3err.ErrInvalidRequest
  240. }
  241. return
  242. }
  243. // ValidateAndTransferGrants validate grant & transfer Email-Grant to Id-Grant
  244. func ValidateAndTransferGrants(accountManager AccountManager, grants []*s3.Grant) ([]*s3.Grant, s3err.ErrorCode) {
  245. var result []*s3.Grant
  246. for _, grant := range grants {
  247. grantee := grant.Grantee
  248. if grantee == nil || grantee.Type == nil {
  249. glog.Warning("invalid grantee! grantee or granteeType is nil")
  250. return nil, s3err.ErrInvalidRequest
  251. }
  252. switch *grantee.Type {
  253. case s3_constants.GrantTypeGroup:
  254. if grantee.URI == nil {
  255. glog.Warning("invalid group grantee! group URI is nil")
  256. return nil, s3err.ErrInvalidRequest
  257. }
  258. ok := s3_constants.ValidateGroup(*grantee.URI)
  259. if !ok {
  260. glog.Warningf("invalid group grantee! group name[%s] is not valid", *grantee.URI)
  261. return nil, s3err.ErrInvalidRequest
  262. }
  263. result = append(result, grant)
  264. case s3_constants.GrantTypeCanonicalUser:
  265. if grantee.ID == nil {
  266. glog.Warning("invalid canonical grantee! account id is nil")
  267. return nil, s3err.ErrInvalidRequest
  268. }
  269. name := accountManager.GetAccountNameById(*grantee.ID)
  270. if len(name) == 0 {
  271. glog.Warningf("invalid canonical grantee! account id[%s] is not exists", *grantee.ID)
  272. return nil, s3err.ErrInvalidRequest
  273. }
  274. result = append(result, grant)
  275. case s3_constants.GrantTypeAmazonCustomerByEmail:
  276. if grantee.EmailAddress == nil {
  277. glog.Warning("invalid email grantee! email address is nil")
  278. return nil, s3err.ErrInvalidRequest
  279. }
  280. accountId := accountManager.GetAccountIdByEmail(*grantee.EmailAddress)
  281. if len(accountId) == 0 {
  282. glog.Warningf("invalid email grantee! email address[%s] is not exists", *grantee.EmailAddress)
  283. return nil, s3err.ErrInvalidRequest
  284. }
  285. result = append(result, &s3.Grant{
  286. Grantee: &s3.Grantee{
  287. Type: &s3_constants.GrantTypeCanonicalUser,
  288. ID: &accountId,
  289. },
  290. Permission: grant.Permission,
  291. })
  292. default:
  293. return nil, s3err.ErrInvalidRequest
  294. }
  295. }
  296. return result, s3err.ErrNone
  297. }
  298. // DetermineReqGrants generates the grant set (Grants) according to accountId and reqPermission.
  299. func DetermineReqGrants(accountId, aclAction string) (grants []*s3.Grant) {
  300. // group grantee (AllUsers)
  301. grants = append(grants, &s3.Grant{
  302. Grantee: &s3.Grantee{
  303. Type: &s3_constants.GrantTypeGroup,
  304. URI: &s3_constants.GranteeGroupAllUsers,
  305. },
  306. Permission: &aclAction,
  307. })
  308. grants = append(grants, &s3.Grant{
  309. Grantee: &s3.Grantee{
  310. Type: &s3_constants.GrantTypeGroup,
  311. URI: &s3_constants.GranteeGroupAllUsers,
  312. },
  313. Permission: &s3_constants.PermissionFullControl,
  314. })
  315. // canonical grantee (accountId)
  316. grants = append(grants, &s3.Grant{
  317. Grantee: &s3.Grantee{
  318. Type: &s3_constants.GrantTypeCanonicalUser,
  319. ID: &accountId,
  320. },
  321. Permission: &aclAction,
  322. })
  323. grants = append(grants, &s3.Grant{
  324. Grantee: &s3.Grantee{
  325. Type: &s3_constants.GrantTypeCanonicalUser,
  326. ID: &accountId,
  327. },
  328. Permission: &s3_constants.PermissionFullControl,
  329. })
  330. // group grantee (AuthenticateUsers)
  331. if accountId != s3_constants.AccountAnonymousId {
  332. grants = append(grants, &s3.Grant{
  333. Grantee: &s3.Grantee{
  334. Type: &s3_constants.GrantTypeGroup,
  335. URI: &s3_constants.GranteeGroupAuthenticatedUsers,
  336. },
  337. Permission: &aclAction,
  338. })
  339. grants = append(grants, &s3.Grant{
  340. Grantee: &s3.Grantee{
  341. Type: &s3_constants.GrantTypeGroup,
  342. URI: &s3_constants.GranteeGroupAuthenticatedUsers,
  343. },
  344. Permission: &s3_constants.PermissionFullControl,
  345. })
  346. }
  347. return
  348. }
  349. func SetAcpOwnerHeader(r *http.Request, acpOwnerId string) {
  350. r.Header.Set(s3_constants.ExtAmzOwnerKey, acpOwnerId)
  351. }
  352. func GetAcpOwner(entryExtended map[string][]byte, defaultOwner string) string {
  353. ownerIdBytes, ok := entryExtended[s3_constants.ExtAmzOwnerKey]
  354. if ok && len(ownerIdBytes) > 0 {
  355. return string(ownerIdBytes)
  356. }
  357. return defaultOwner
  358. }
  359. func SetAcpGrantsHeader(r *http.Request, acpGrants []*s3.Grant) {
  360. if len(acpGrants) > 0 {
  361. a, err := json.Marshal(acpGrants)
  362. if err == nil {
  363. r.Header.Set(s3_constants.ExtAmzAclKey, string(a))
  364. } else {
  365. glog.Warning("Marshal acp grants err", err)
  366. }
  367. }
  368. }
  369. // GetAcpGrants return grants parsed from entry
  370. func GetAcpGrants(entryExtended map[string][]byte) []*s3.Grant {
  371. acpBytes, ok := entryExtended[s3_constants.ExtAmzAclKey]
  372. if ok && len(acpBytes) > 0 {
  373. var grants []*s3.Grant
  374. err := json.Unmarshal(acpBytes, &grants)
  375. if err == nil {
  376. return grants
  377. }
  378. }
  379. return nil
  380. }
  381. // AssembleEntryWithAcp fill entry with owner and grants
  382. func AssembleEntryWithAcp(objectEntry *filer_pb.Entry, objectOwner string, grants []*s3.Grant) s3err.ErrorCode {
  383. if objectEntry.Extended == nil {
  384. objectEntry.Extended = make(map[string][]byte)
  385. }
  386. if len(objectOwner) > 0 {
  387. objectEntry.Extended[s3_constants.ExtAmzOwnerKey] = []byte(objectOwner)
  388. } else {
  389. delete(objectEntry.Extended, s3_constants.ExtAmzOwnerKey)
  390. }
  391. if len(grants) > 0 {
  392. grantsBytes, err := json.Marshal(grants)
  393. if err != nil {
  394. glog.Warning("assemble acp to entry:", err)
  395. return s3err.ErrInvalidRequest
  396. }
  397. objectEntry.Extended[s3_constants.ExtAmzAclKey] = grantsBytes
  398. } else {
  399. delete(objectEntry.Extended, s3_constants.ExtAmzAclKey)
  400. }
  401. return s3err.ErrNone
  402. }
  403. // GrantEquals Compare whether two Grants are equal in meaning, not completely
  404. // equal (compare Grantee.Type and the corresponding Value for equality, other
  405. // fields of Grantee are ignored)
  406. func GrantEquals(a, b *s3.Grant) bool {
  407. // grant
  408. if a == b {
  409. return true
  410. }
  411. if a == nil || b == nil {
  412. return false
  413. }
  414. // grant.Permission
  415. if a.Permission != b.Permission {
  416. if a.Permission == nil || b.Permission == nil {
  417. return false
  418. }
  419. if *a.Permission != *b.Permission {
  420. return false
  421. }
  422. }
  423. // grant.Grantee
  424. ag := a.Grantee
  425. bg := b.Grantee
  426. if ag != bg {
  427. if ag == nil || bg == nil {
  428. return false
  429. }
  430. // grantee.Type
  431. if ag.Type != bg.Type {
  432. if ag.Type == nil || bg.Type == nil {
  433. return false
  434. }
  435. if *ag.Type != *bg.Type {
  436. return false
  437. }
  438. }
  439. // value corresponding to granteeType
  440. if ag.Type != nil {
  441. switch *ag.Type {
  442. case s3_constants.GrantTypeGroup:
  443. if ag.URI != bg.URI {
  444. if ag.URI == nil || bg.URI == nil {
  445. return false
  446. }
  447. if *ag.URI != *bg.URI {
  448. return false
  449. }
  450. }
  451. case s3_constants.GrantTypeCanonicalUser:
  452. if ag.ID != bg.ID {
  453. if ag.ID == nil || bg.ID == nil {
  454. return false
  455. }
  456. if *ag.ID != *bg.ID {
  457. return false
  458. }
  459. }
  460. case s3_constants.GrantTypeAmazonCustomerByEmail:
  461. if ag.EmailAddress != bg.EmailAddress {
  462. if ag.EmailAddress == nil || bg.EmailAddress == nil {
  463. return false
  464. }
  465. if *ag.EmailAddress != *bg.EmailAddress {
  466. return false
  467. }
  468. }
  469. }
  470. }
  471. }
  472. return true
  473. }