acl.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package gold
  2. import (
  3. "errors"
  4. "log"
  5. "net/http"
  6. "strings"
  7. "time"
  8. )
  9. // WAC WebAccessControl object
  10. type WAC struct {
  11. req *httpRequest
  12. srv *Server
  13. w http.ResponseWriter
  14. user string
  15. key string
  16. }
  17. // NewWAC creates a new WAC object
  18. func NewWAC(req *httpRequest, srv *Server, w http.ResponseWriter, user string, key string) *WAC {
  19. return &WAC{req: req, srv: srv, w: w, user: user, key: key}
  20. }
  21. // Return an HTTP code and error (200 if authd, 401 if auth required, 403 if not authorized, 500 if error)
  22. func (acl *WAC) allow(mode string, path string) (int, error) {
  23. origin := acl.req.Header.Get("Origin")
  24. accessType := "accessTo"
  25. p, err := acl.req.pathInfo(path)
  26. if err != nil {
  27. return 500, err
  28. }
  29. depth := strings.Split(p.Path, "/")
  30. for d := len(depth); d >= 0; d-- {
  31. p, err := acl.req.pathInfo(path)
  32. if err != nil {
  33. return 500, err
  34. }
  35. acl.srv.debug.Println("Checking " + accessType + " <" + mode + "> to " + p.URI + " for WebID: " + acl.user)
  36. acl.srv.debug.Println("Looking for policies in " + p.AclFile)
  37. aclGraph := NewGraph(p.AclURI)
  38. aclGraph.ReadFile(p.AclFile)
  39. if aclGraph.Len() > 0 {
  40. acl.srv.debug.Println("Found policies in " + p.AclFile)
  41. // TODO make it more elegant instead of duplicating code
  42. for _, i := range aclGraph.All(nil, ns.acl.Get("mode"), ns.acl.Get("Control")) {
  43. for range aclGraph.All(i.Subject, ns.acl.Get(accessType), NewResource(p.URI)) {
  44. //@@TODO add resourceKey to ACL vocab
  45. if len(acl.user) > 0 {
  46. acl.srv.debug.Println("Looking for policy matching user:", acl.user)
  47. for range aclGraph.All(i.Subject, ns.acl.Get("owner"), NewResource(acl.user)) {
  48. acl.srv.debug.Println(mode + " access allowed (as owner) for: " + acl.user)
  49. return 200, nil
  50. }
  51. for range aclGraph.All(i.Subject, ns.acl.Get("agent"), NewResource(acl.user)) {
  52. acl.srv.debug.Println(mode + " access allowed (as agent) for: " + acl.user)
  53. return 200, nil
  54. }
  55. }
  56. if len(acl.key) > 0 {
  57. acl.srv.debug.Println("Looking for policy matching key:", acl.key)
  58. for range aclGraph.All(i.Subject, ns.acl.Get("resourceKey"), NewLiteral(acl.key)) {
  59. acl.srv.debug.Println(mode + " access allowed based on matching resource key")
  60. return 200, nil
  61. }
  62. }
  63. for _, t := range aclGraph.All(i.Subject, ns.acl.Get("agentClass"), nil) {
  64. // check for foaf groups
  65. acl.srv.debug.Println("Found agentClass policy")
  66. if t.Object.Equal(ns.foaf.Get("Agent")) {
  67. acl.srv.debug.Println(mode + " access allowed as FOAF Agent")
  68. return 200, nil
  69. }
  70. groupURI := debrack(t.Object.String())
  71. groupGraph := NewGraph(groupURI)
  72. groupGraph.LoadURI(groupURI)
  73. if groupGraph.Len() > 0 && groupGraph.One(t.Object, ns.rdf.Get("type"), ns.foaf.Get("Group")) != nil {
  74. for range groupGraph.All(t.Object, ns.foaf.Get("member"), NewResource(acl.user)) {
  75. acl.srv.debug.Println(acl.user + " listed as a member of the group " + groupURI)
  76. return 200, nil
  77. }
  78. }
  79. }
  80. }
  81. }
  82. for _, i := range aclGraph.All(nil, ns.acl.Get("mode"), ns.acl.Get(mode)) {
  83. acl.srv.debug.Println("Found " + accessType + " policy for <" + mode + ">")
  84. for range aclGraph.All(i.Subject, ns.acl.Get(accessType), NewResource(p.URI)) {
  85. origins := aclGraph.All(i.Subject, ns.acl.Get("origin"), nil)
  86. if len(origin) > 0 && len(origins) > 0 {
  87. acl.srv.debug.Println("Origin set to: " + brack(origin))
  88. for _, o := range origins {
  89. if brack(origin) == o.Object.String() {
  90. acl.srv.debug.Println("Found policy for origin: " + o.Object.String())
  91. goto allowOrigin
  92. }
  93. }
  94. continue
  95. } else {
  96. acl.srv.debug.Println("No origin found, moving on")
  97. }
  98. allowOrigin:
  99. if len(acl.user) > 0 {
  100. acl.srv.debug.Println("Looking for policy matching user:", acl.user)
  101. for range aclGraph.All(i.Subject, ns.acl.Get("owner"), NewResource(acl.user)) {
  102. acl.srv.debug.Println(mode + " access allowed (as owner) for: " + acl.user)
  103. return 200, nil
  104. }
  105. for range aclGraph.All(i.Subject, ns.acl.Get("agent"), NewResource(acl.user)) {
  106. acl.srv.debug.Println(mode + " access allowed (as agent) for: " + acl.user)
  107. return 200, nil
  108. }
  109. }
  110. if len(acl.key) > 0 {
  111. acl.srv.debug.Println("Looking for policy matching key:", acl.key)
  112. for range aclGraph.All(i.Subject, ns.acl.Get("resourceKey"), NewLiteral(acl.key)) {
  113. acl.srv.debug.Println(mode + " access allowed based on matching resource key")
  114. return 200, nil
  115. }
  116. }
  117. for _, t := range aclGraph.All(i.Subject, ns.acl.Get("agentClass"), nil) {
  118. // check for foaf groups
  119. acl.srv.debug.Println("Found agentClass policy")
  120. if t.Object.Equal(ns.foaf.Get("Agent")) {
  121. acl.srv.debug.Println(mode + " access allowed as FOAF Agent")
  122. return 200, nil
  123. }
  124. groupURI := debrack(t.Object.String())
  125. groupGraph := NewGraph(groupURI)
  126. groupGraph.LoadURI(groupURI)
  127. if groupGraph.Len() > 0 && groupGraph.One(t.Object, ns.rdf.Get("type"), ns.foaf.Get("Group")) != nil {
  128. for range groupGraph.All(t.Object, ns.foaf.Get("member"), NewResource(acl.user)) {
  129. acl.srv.debug.Println(acl.user + " listed as a member of the group " + groupURI)
  130. return 200, nil
  131. }
  132. }
  133. }
  134. }
  135. }
  136. if len(acl.user) == 0 && len(acl.key) == 0 {
  137. acl.srv.debug.Println("Authentication required")
  138. tokenValues := map[string]string{
  139. "secret": string(acl.srv.cookieSalt),
  140. }
  141. // set validity for now + 1 min
  142. validity := 1 * time.Minute
  143. token, err := NewSecureToken("WWW-Authenticate", tokenValues, validity, acl.srv)
  144. if err != nil {
  145. acl.srv.debug.Println("Error generating Auth token: ", err)
  146. return 500, err
  147. }
  148. wwwAuth := `WebID-RSA source="` + acl.req.BaseURI() + `", nonce="` + token + `"`
  149. acl.w.Header().Set("WWW-Authenticate", wwwAuth)
  150. return 401, errors.New("Access to " + p.URI + " requires authentication")
  151. }
  152. acl.srv.debug.Println(mode + " access denied for: " + acl.user)
  153. return 403, errors.New("Access denied for: " + acl.user)
  154. }
  155. accessType = "defaultForNew"
  156. // cd one level: walkPath("/foo/bar/baz") => /foo/bar/
  157. // decrement depth
  158. if len(depth) > 0 {
  159. depth = depth[:len(depth)-1]
  160. } else {
  161. depth = depth[:1]
  162. }
  163. path = walkPath(p.Base, depth)
  164. }
  165. acl.srv.debug.Println("No ACL policies present - access allowed")
  166. return 200, nil
  167. }
  168. func walkPath(base string, depth []string) string {
  169. path := base + "/"
  170. if len(depth) > 0 {
  171. path += strings.Join(depth, "/") + "/"
  172. }
  173. return path
  174. }
  175. // AllowRead checks if Read access is allowed
  176. func (acl *WAC) AllowRead(path string) (int, error) {
  177. return acl.allow("Read", path)
  178. }
  179. // AllowWrite checks if Write access is allowed
  180. func (acl *WAC) AllowWrite(path string) (int, error) {
  181. return acl.allow("Write", path)
  182. }
  183. // AllowAppend checks if Append access is allowed
  184. func (acl *WAC) AllowAppend(path string) (int, error) {
  185. return acl.allow("Append", path)
  186. }
  187. // AllowControl checks if Control access is allowed
  188. func (acl *WAC) AllowControl(path string) (int, error) {
  189. return acl.allow("Control", path)
  190. }
  191. func verifyDelegator(delegator string, delegatee string) bool {
  192. g := NewGraph(delegator)
  193. err := g.LoadURI(delegator)
  194. if err != nil {
  195. log.Println("Error loading graph for " + delegator)
  196. }
  197. for _, val := range g.All(NewResource(delegator), NewResource("http://www.w3.org/ns/auth/acl#delegates"), nil) {
  198. if debrack(val.Object.String()) == delegatee {
  199. return true
  200. }
  201. }
  202. return false
  203. }