You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

555 lines
17 KiB

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