system.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. package gold
  2. import (
  3. "crypto/rsa"
  4. "crypto/sha256"
  5. "encoding/base64"
  6. "encoding/json"
  7. "errors"
  8. "fmt"
  9. "io/ioutil"
  10. "net"
  11. "net/http"
  12. "net/url"
  13. "os"
  14. _path "path"
  15. "path/filepath"
  16. "strings"
  17. "time"
  18. "github.com/boltdb/bolt"
  19. )
  20. // SystemReturn is a generic HTTP response specific to system APIs
  21. type SystemReturn struct {
  22. Status int
  23. Body string
  24. Bytes []byte
  25. }
  26. type accountRequest struct {
  27. Method string
  28. AccountName string
  29. }
  30. type accountResponse struct {
  31. AccountURL string `json:"accountURL"`
  32. Available bool `json:"available"`
  33. }
  34. type statusResponse struct {
  35. Method string `json:"method"`
  36. Status string `json:"status"`
  37. FormURL string `json:"formURL"`
  38. LoginURL string `json:"loginURL"`
  39. LogoutURL string `json:"logoutURL"`
  40. Response accountResponse `json:"response"`
  41. }
  42. type accountInformation struct {
  43. DiskUsed string
  44. DiskLimit string
  45. }
  46. // HandleSystem is a router for system specific APIs
  47. func HandleSystem(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  48. if strings.HasSuffix(req.Request.URL.Path, "status") {
  49. // unsupported yet when server is running on one host
  50. return accountStatus(w, req, s)
  51. } else if strings.HasSuffix(req.Request.URL.Path, "new") {
  52. return newAccount(w, req, s)
  53. } else if strings.HasSuffix(req.Request.URL.Path, "cert") {
  54. return newCert(w, req, s)
  55. } else if strings.HasSuffix(req.Request.URL.Path, "login") {
  56. return logIn(w, req, s)
  57. } else if strings.HasSuffix(req.Request.URL.Path, "logout") {
  58. return logOut(w, req, s)
  59. } else if strings.HasSuffix(req.Request.URL.Path, "tokens") {
  60. return accountTokens(w, req, s)
  61. } else if strings.HasSuffix(req.Request.URL.Path, "recovery") {
  62. return accountRecovery(w, req, s)
  63. }
  64. return SystemReturn{Status: 200}
  65. }
  66. func logOut(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  67. s.userCookieDelete(w)
  68. return SystemReturn{Status: 200, Body: "You have been signed out!"}
  69. }
  70. func logIn(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  71. var passL string
  72. redirTo := req.FormValue("redirect")
  73. origin := req.FormValue("origin")
  74. s.debug.Println("Got login request. Optional params: ", redirTo, origin)
  75. // if cookie is set, just redirect
  76. if len(req.User) > 0 {
  77. values := map[string]string{
  78. "webid": req.User,
  79. "origin": origin,
  80. }
  81. // refresh cookie
  82. err := s.userCookieSet(w, req.User)
  83. if err != nil {
  84. s.debug.Println("Error setting new cookie: " + err.Error())
  85. return SystemReturn{Status: 500, Body: err.Error()}
  86. }
  87. // redirect
  88. if len(redirTo) > 0 {
  89. loginRedirect(w, req, s, values, redirTo)
  90. }
  91. return SystemReturn{Status: 200, Body: LogoutTemplate(req.User)}
  92. }
  93. webid := req.FormValue("webid")
  94. passF := req.FormValue("password")
  95. if req.Method == "GET" {
  96. // try to guess WebID from account
  97. webid = req.getAccountWebID()
  98. return SystemReturn{Status: 200, Body: LoginTemplate(redirTo, origin, webid)}
  99. }
  100. if len(webid) == 0 && len(passF) == 0 {
  101. return SystemReturn{Status: 409, Body: "You must supply a valid WebID and password."}
  102. }
  103. resource, err := req.pathInfo(req.BaseURI())
  104. if err != nil {
  105. s.debug.Println("PathInfo error: " + err.Error())
  106. return SystemReturn{Status: 500, Body: err.Error()}
  107. }
  108. // try to fetch hashed password from root ,acl
  109. resource, _ = req.pathInfo(resource.Base)
  110. kb := NewGraph(resource.AclURI)
  111. kb.ReadFile(resource.AclFile)
  112. s.debug.Println("Looking for password in", resource.AclFile)
  113. // find the policy containing root acl
  114. for _, m := range kb.All(nil, ns.acl.Get("mode"), ns.acl.Get("Control")) {
  115. p := kb.One(m.Subject, ns.acl.Get("password"), nil)
  116. if p != nil && kb.One(m.Subject, ns.acl.Get("agent"), NewResource(webid)) != nil {
  117. passL = unquote(p.Object.String())
  118. break
  119. }
  120. }
  121. // exit if no pass
  122. if len(passL) == 0 {
  123. s.debug.Println("Access denied! Could not find a password for WebID: " + webid)
  124. return SystemReturn{Status: 403, Body: "Access denied! Could not find a password for WebID: " + webid}
  125. }
  126. // check if passwords match
  127. passF = saltedPassword(s.Config.Salt, passF)
  128. if passF != passL {
  129. s.debug.Println("Access denied! Bad WebID or password.")
  130. return SystemReturn{Status: 403, Body: "Access denied! Bad WebID or password."}
  131. }
  132. // auth OK
  133. // also set cookie now
  134. err = s.userCookieSet(w, webid)
  135. if err != nil {
  136. s.debug.Println("Error setting new cookie: " + err.Error())
  137. return SystemReturn{Status: 500, Body: err.Error()}
  138. }
  139. // handle redirect
  140. if len(redirTo) > 0 {
  141. values := map[string]string{
  142. "webid": webid,
  143. "origin": origin,
  144. }
  145. loginRedirect(w, req, s, values, redirTo)
  146. }
  147. http.Redirect(w, req.Request, req.RequestURI, 301)
  148. return SystemReturn{Status: 200}
  149. }
  150. func loginRedirect(w http.ResponseWriter, req *httpRequest, s *Server, values map[string]string, redirTo string) SystemReturn {
  151. key := ""
  152. // try to get existing token
  153. key, err := s.getTokenByOrigin("Authorization", req.Host, values["origin"])
  154. if err != nil || len(key) == 0 {
  155. s.debug.Println("Could not find a token for origin:", values["origin"])
  156. key, err = s.newPersistedToken("Authorization", req.Host, values)
  157. if err != nil {
  158. s.debug.Println("Could not generate authorization token for " + values["webid"] + ", err: " + err.Error())
  159. return SystemReturn{Status: 500, Body: "Could not generate auth token for " + values["webid"] + ", err: " + err.Error()}
  160. }
  161. }
  162. s.debug.Println("Generated new token for", values["webid"], "->", key)
  163. redir, err := url.Parse(redirTo)
  164. if err != nil {
  165. return SystemReturn{Status: 400, Body: "Could not parse URL " + redirTo + ". Error: " + err.Error()}
  166. }
  167. q := redir.Query()
  168. q.Set("webid", values["webid"])
  169. q.Set("key", key)
  170. redir.RawQuery = q.Encode()
  171. s.debug.Println("Redirecting user to", redir.String())
  172. http.Redirect(w, req.Request, redir.String(), 301)
  173. return SystemReturn{Status: 200}
  174. }
  175. func accountRecovery(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  176. if len(req.FormValue("webid")) > 0 && strings.HasPrefix(req.FormValue("webid"), "http") {
  177. return sendRecoveryToken(w, req, s)
  178. } else if len(req.FormValue("token")) > 0 {
  179. // validate or issue new password
  180. return validateRecoveryToken(w, req, s)
  181. }
  182. // return default app with form
  183. return SystemReturn{Status: 200, Body: Apps["accountRecovery"]}
  184. }
  185. func sendRecoveryToken(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  186. webid := req.FormValue("webid")
  187. // exit if not a local WebID
  188. // log.Println("Host:" + req.Header.Get("Host"))
  189. resource, err := req.pathInfo(req.BaseURI())
  190. if err != nil {
  191. s.debug.Println("PathInfo error: " + err.Error())
  192. return SystemReturn{Status: 500, Body: err.Error()}
  193. }
  194. // try to fetch recovery email from root ,acl
  195. resource, _ = req.pathInfo(resource.Base)
  196. email := ""
  197. kb := NewGraph(resource.AclURI)
  198. kb.ReadFile(resource.AclFile)
  199. // find the policy containing root acl
  200. for range kb.All(nil, ns.acl.Get("accessTo"), NewResource(resource.AclURI)) {
  201. for _, t := range kb.All(nil, ns.acl.Get("agent"), nil) {
  202. email = debrack(t.Object.String())
  203. if strings.HasPrefix(email, "mailto:") {
  204. email = strings.TrimPrefix(email, "mailto:")
  205. break
  206. }
  207. }
  208. }
  209. // exit if no email
  210. if len(email) == 0 {
  211. s.debug.Println("Access denied! Could not find a recovery email for WebID: " + webid)
  212. return SystemReturn{Status: 403, Body: "Access denied! Could not find a recovery email for WebID: " + webid}
  213. }
  214. values := map[string]string{
  215. "webid": webid,
  216. }
  217. // set validity for now + 5 mins
  218. t := time.Duration(s.Config.TokenAge) * time.Minute
  219. token, err := NewSecureToken("Recovery", values, t, s)
  220. if err != nil {
  221. s.debug.Println("Could not generate recovery token for " + webid + ", err: " + err.Error())
  222. return SystemReturn{Status: 400, Body: "Could not generate recovery token for " + webid + ", err: " + err.Error()}
  223. }
  224. // create recovery URL
  225. IP, _, _ := net.SplitHostPort(req.Request.RemoteAddr)
  226. link := resource.Base + "/" + SystemPrefix + "/recovery?token=" + encodeQuery(token)
  227. // Setup message
  228. params := make(map[string]string)
  229. params["{{.To}}"] = email
  230. params["{{.IP}}"] = IP
  231. params["{{.Host}}"] = resource.Obj.Host
  232. params["{{.From}}"] = s.Config.SMTPConfig.Addr
  233. params["{{.Link}}"] = link
  234. go s.sendRecoveryMail(params)
  235. return SystemReturn{Status: 200, Body: "You should receive an email shortly with further instructions."}
  236. }
  237. func validateRecoveryToken(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  238. token, err := decodeQuery(req.FormValue("token"))
  239. if err != nil {
  240. s.debug.Println("Decode query err: " + err.Error())
  241. return SystemReturn{Status: 500, Body: err.Error()}
  242. }
  243. value := make(map[string]string)
  244. err = s.cookie.Decode("Recovery", token, &value)
  245. if err != nil {
  246. s.debug.Println("Decoding err: " + err.Error())
  247. return SystemReturn{Status: 500, Body: err.Error()}
  248. }
  249. if len(value["valid"]) == 0 {
  250. return SystemReturn{Status: 499, Body: "Missing validity date for token."}
  251. }
  252. err = IsTokenDateValid(value["valid"])
  253. if err != nil {
  254. return SystemReturn{Status: 500, Body: err.Error()}
  255. }
  256. // also set cookie now
  257. webid := value["webid"]
  258. err = s.userCookieSet(w, webid)
  259. if err != nil {
  260. s.debug.Println("Error setting new cookie: " + err.Error())
  261. return SystemReturn{Status: 500, Body: err.Error()}
  262. }
  263. pass := req.FormValue("password")
  264. verif := req.FormValue("verifypass")
  265. if len(pass) > 0 && len(verif) > 0 {
  266. if pass != verif {
  267. // passwords don't match,
  268. return SystemReturn{Status: 200, Body: NewPassTemplate(token, "Passwords do not match!")}
  269. }
  270. // save new password
  271. resource, _ := req.pathInfo(req.BaseURI())
  272. accountBase := resource.Base + "/"
  273. resource, _ = req.pathInfo(accountBase)
  274. g := NewGraph(resource.AclURI)
  275. g.ReadFile(resource.AclFile)
  276. // find the policy containing root acl
  277. for _, m := range g.All(nil, ns.acl.Get("mode"), ns.acl.Get("Control")) {
  278. p := g.One(m.Subject, ns.acl.Get("agent"), NewResource(webid))
  279. if p != nil {
  280. passT := g.One(nil, ns.acl.Get("password"), nil)
  281. // remove old password
  282. if passT != nil {
  283. g.Remove(passT)
  284. }
  285. }
  286. // add new password
  287. g.AddTriple(m.Subject, ns.acl.Get("password"), NewLiteral(saltedPassword(s.Config.Salt, pass)))
  288. // write account acl to disk
  289. // open account acl file
  290. f, err := os.OpenFile(resource.AclFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
  291. if err != nil {
  292. s.debug.Println("Could not open file to save new password. Error: " + err.Error())
  293. return SystemReturn{Status: 500, Body: err.Error()}
  294. }
  295. defer f.Close()
  296. err = g.WriteFile(f, "text/turtle")
  297. if err != nil {
  298. s.debug.Println("Could not save account acl file with new password. Error: " + err.Error())
  299. return SystemReturn{Status: 500, Body: err.Error()}
  300. }
  301. // All set
  302. return SystemReturn{Status: 200, Body: "Password saved!"}
  303. break
  304. }
  305. }
  306. return SystemReturn{Status: 200, Body: NewPassTemplate(token, "")}
  307. }
  308. func newAccount(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  309. resource, _ := req.pathInfo(req.BaseURI())
  310. host, port, _ := net.SplitHostPort(req.Host)
  311. if len(host) == 0 {
  312. host = req.Host
  313. }
  314. if len(port) > 0 {
  315. port = ":" + port
  316. }
  317. accountBase := resource.Base + "/"
  318. username := strings.ToLower(req.FormValue("username"))
  319. if !strings.HasPrefix(host, username) {
  320. accountBase = resource.Base + "/" + username + "/"
  321. if s.Config.Vhosts == true {
  322. accountBase = "https://" + username + "." + host + port + "/"
  323. }
  324. }
  325. webidURL := accountBase + "profile/card"
  326. webidURI := webidURL + "#me"
  327. resource, _ = req.pathInfo(accountBase)
  328. account := webidAccount{
  329. Root: resource.Root,
  330. BaseURI: resource.Base,
  331. Document: resource.File,
  332. WebID: webidURI,
  333. Agent: s.Config.Agent,
  334. PrefURI: accountBase + "Preferences/prefs.ttl",
  335. PubTypeIndex: accountBase + "Preferences/pubTypeIndex.ttl",
  336. PrivTypeIndex: accountBase + "Preferences/privTypeIndex.ttl",
  337. Email: req.FormValue("email"),
  338. Name: req.FormValue("name"),
  339. Img: req.FormValue("img"),
  340. }
  341. if len(s.Config.ProxyTemplate) > 0 {
  342. account.ProxyURI = accountBase + ",proxy?uri="
  343. }
  344. if len(s.Config.QueryTemplate) > 0 {
  345. account.QueryURI = accountBase + ",query"
  346. }
  347. s.debug.Println("Checking if account profile <" + resource.File + "> exists...")
  348. stat, err := os.Stat(resource.File)
  349. if err != nil {
  350. s.debug.Println("Stat error: " + err.Error())
  351. }
  352. if stat != nil && stat.IsDir() {
  353. s.debug.Println("Found " + resource.File)
  354. return SystemReturn{Status: 406, Body: "An account with the same name already exists."}
  355. }
  356. resource, _ = req.pathInfo(webidURL)
  357. // create account space
  358. err = os.MkdirAll(_path.Dir(resource.File), 0755)
  359. if err != nil {
  360. s.debug.Println("MkdirAll error: " + err.Error())
  361. return SystemReturn{Status: 500, Body: err.Error()}
  362. }
  363. // open WebID profile file
  364. f, err := os.OpenFile(resource.File, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
  365. if err != nil {
  366. s.debug.Println("Open profile error: " + err.Error())
  367. return SystemReturn{Status: 500, Body: err.Error()}
  368. }
  369. defer f.Close()
  370. // Generate WebID profile graph for this account
  371. g := NewWebIDProfile(account)
  372. // write WebID profile to disk
  373. err = g.WriteFile(f, "text/turtle")
  374. if err != nil {
  375. s.debug.Println("Saving profile error: " + err.Error())
  376. return SystemReturn{Status: 500, Body: err.Error()}
  377. }
  378. // Write ACL for the profile
  379. aclTerm := NewResource(resource.AclURI + "#owner")
  380. g = NewGraph(resource.AclURI)
  381. g.AddTriple(aclTerm, ns.rdf.Get("type"), ns.acl.Get("Authorization"))
  382. g.AddTriple(aclTerm, ns.acl.Get("accessTo"), NewResource(webidURL))
  383. g.AddTriple(aclTerm, ns.acl.Get("accessTo"), NewResource(resource.AclURI))
  384. g.AddTriple(aclTerm, ns.acl.Get("agent"), NewResource(webidURI))
  385. g.AddTriple(aclTerm, ns.acl.Get("mode"), ns.acl.Get("Read"))
  386. g.AddTriple(aclTerm, ns.acl.Get("mode"), ns.acl.Get("Write"))
  387. g.AddTriple(aclTerm, ns.acl.Get("mode"), ns.acl.Get("Control"))
  388. readAllTerm := NewResource(resource.AclURI + "#readall")
  389. g.AddTriple(readAllTerm, ns.rdf.Get("type"), ns.acl.Get("Authorization"))
  390. g.AddTriple(readAllTerm, ns.acl.Get("accessTo"), NewResource(webidURL))
  391. g.AddTriple(readAllTerm, ns.acl.Get("agentClass"), ns.foaf.Get("Agent"))
  392. g.AddTriple(readAllTerm, ns.acl.Get("mode"), ns.acl.Get("Read"))
  393. // open profile acl file
  394. f, err = os.OpenFile(resource.AclFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
  395. if err != nil {
  396. s.debug.Println("Open profile acl error: " + err.Error())
  397. return SystemReturn{Status: 500, Body: err.Error()}
  398. }
  399. defer f.Close()
  400. // write profile acl to disk
  401. err = g.WriteFile(f, "text/turtle")
  402. if err != nil {
  403. s.debug.Println("Saving profile acl error: " + err.Error())
  404. return SystemReturn{Status: 500, Body: err.Error()}
  405. }
  406. // Link from root meta file to the WebID
  407. err = req.LinkToWebID(account)
  408. if err != nil {
  409. s.debug.Println("Error setting up workspaces: " + err.Error())
  410. return SystemReturn{Status: 500, Body: err.Error()}
  411. }
  412. // Create workspaces and preferencesFile
  413. err = req.AddWorkspaces(account, g)
  414. if err != nil {
  415. s.debug.Println("Error setting up workspaces: " + err.Error())
  416. return SystemReturn{Status: 500, Body: err.Error()}
  417. }
  418. // Write default ACL for the whole account space
  419. // No one but the user is allowed access by default
  420. resource, _ = req.pathInfo(accountBase)
  421. aclTerm = NewResource(resource.AclURI + "#owner")
  422. g = NewGraph(resource.AclURI)
  423. g.AddTriple(aclTerm, ns.rdf.Get("type"), ns.acl.Get("Authorization"))
  424. g.AddTriple(aclTerm, ns.acl.Get("accessTo"), NewResource(resource.URI))
  425. g.AddTriple(aclTerm, ns.acl.Get("accessTo"), NewResource(resource.AclURI))
  426. g.AddTriple(aclTerm, ns.acl.Get("agent"), NewResource(webidURI))
  427. if len(req.FormValue("password")) > 0 {
  428. g.AddTriple(aclTerm, ns.acl.Get("password"), NewLiteral(saltedPassword(s.Config.Salt, req.FormValue("password"))))
  429. }
  430. if len(req.FormValue("email")) > 0 {
  431. g.AddTriple(aclTerm, ns.acl.Get("agent"), NewResource("mailto:"+req.FormValue("email")))
  432. }
  433. g.AddTriple(aclTerm, ns.acl.Get("defaultForNew"), NewResource(resource.URI))
  434. g.AddTriple(aclTerm, ns.acl.Get("mode"), ns.acl.Get("Read"))
  435. g.AddTriple(aclTerm, ns.acl.Get("mode"), ns.acl.Get("Write"))
  436. g.AddTriple(aclTerm, ns.acl.Get("mode"), ns.acl.Get("Control"))
  437. // open account acl file
  438. f, err = os.OpenFile(resource.AclFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
  439. if err != nil {
  440. s.debug.Println("Create account acl error: " + err.Error())
  441. return SystemReturn{Status: 500, Body: err.Error()}
  442. }
  443. defer f.Close()
  444. // write account acl to disk
  445. err = g.WriteFile(f, "text/turtle")
  446. if err != nil {
  447. s.debug.Println("Saving account acl error: " + err.Error())
  448. return SystemReturn{Status: 500, Body: err.Error()}
  449. }
  450. // Authenticate the user (set cookie)
  451. err = s.userCookieSet(w, webidURI)
  452. if err != nil {
  453. s.debug.Println("Error setting new cookie: " + err.Error())
  454. return SystemReturn{Status: 500, Body: err.Error()}
  455. }
  456. w.Header().Set("User", webidURI)
  457. // Send welcome email
  458. if len(req.FormValue("email")) > 0 {
  459. // Setup message
  460. params := make(map[string]string)
  461. params["{{.To}}"] = req.FormValue("email")
  462. params["{{.From}}"] = s.Config.SMTPConfig.Addr
  463. params["{{.Name}}"] = account.Name
  464. params["{{.Host}}"] = resource.Obj.Host
  465. params["{{.Account}}"] = account.BaseURI
  466. params["{{.WebID}}"] = account.WebID
  467. go s.sendWelcomeMail(params)
  468. }
  469. // Generate cert
  470. // TODO to be deprecated soon
  471. spkac := req.FormValue("spkac")
  472. if len(spkac) > 0 {
  473. // create a new x509 cert based on the SPKAC public key
  474. certName := account.Name + " [on " + resource.Obj.Host + "]"
  475. newSpkac, err := NewSPKACx509(webidURI, certName, spkac)
  476. if err != nil {
  477. s.debug.Println("NewSPKACx509 error: " + err.Error())
  478. return SystemReturn{Status: 500, Body: err.Error()}
  479. }
  480. pubKey, err := ParseSPKAC(spkac)
  481. if err != nil {
  482. s.debug.Println("ParseSPKAC error: " + err.Error())
  483. }
  484. rsaPub := pubKey.(*rsa.PublicKey)
  485. mod := fmt.Sprintf("%x", rsaPub.N)
  486. exp := fmt.Sprintf("%d", rsaPub.E)
  487. err = req.AddCertKeys(webidURI, mod, exp)
  488. if err != nil {
  489. s.debug.Println("Couldn't add cert keys to profile: " + err.Error())
  490. }
  491. ua := req.Header.Get("User-Agent")
  492. if strings.Contains(ua, "Chrome") {
  493. w.Header().Set(HCType, "application/x-x509-user-cert; charset=utf-8")
  494. return SystemReturn{Status: 200, Bytes: newSpkac}
  495. }
  496. // Prefer loading cert in iframe, to access onLoad events in the browser for the iframe
  497. body := `<iframe width="0" height="0" style="display: none;" src="data:application/x-x509-user-cert;base64,` + base64.StdEncoding.EncodeToString(newSpkac) + `"></iframe>`
  498. return SystemReturn{Status: 200, Body: body}
  499. }
  500. return SystemReturn{Status: 200, Body: ""}
  501. }
  502. func newCert(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  503. resource, _ := req.pathInfo(req.BaseURI())
  504. name := req.FormValue("name")
  505. webidURI := req.FormValue("webid")
  506. spkac := req.FormValue("spkac")
  507. if len(webidURI) > 0 && len(spkac) > 0 {
  508. // create a new x509 cert based on the SPKAC public key
  509. certName := name + " [on " + resource.Obj.Host + "]"
  510. newSpkac, err := NewSPKACx509(webidURI, certName, spkac)
  511. if err != nil {
  512. s.debug.Println("NewSPKACx509 error: " + err.Error())
  513. return SystemReturn{Status: 500, Body: err.Error()}
  514. }
  515. s.debug.Println("Generated new cert for " + webidURI)
  516. // Append cert to profile if it's the case
  517. loggedUser := w.Header().Get("User")
  518. s.debug.Println("Checking if request is authenticated: " + loggedUser)
  519. if len(loggedUser) > 0 && loggedUser == webidURI && strings.HasPrefix(webidURI, resource.Base) {
  520. acl := NewWAC(req, s, w, loggedUser, "")
  521. aclStatus, err := acl.AllowWrite(strings.Split(webidURI, "#")[0])
  522. if aclStatus > 200 || err != nil {
  523. return SystemReturn{Status: aclStatus, Body: err.Error()}
  524. }
  525. pubKey, err := ParseSPKAC(spkac)
  526. if err != nil {
  527. s.debug.Println("ParseSPKAC error: " + err.Error())
  528. return SystemReturn{Status: 500, Body: err.Error()}
  529. }
  530. rsaPub := pubKey.(*rsa.PublicKey)
  531. mod := fmt.Sprintf("%x", rsaPub.N)
  532. exp := fmt.Sprintf("%d", rsaPub.E)
  533. err = req.AddCertKeys(webidURI, mod, exp)
  534. if err != nil {
  535. s.debug.Println("Couldn't add cert keys to profile: " + err.Error())
  536. return SystemReturn{Status: 500, Body: err.Error()}
  537. }
  538. s.debug.Println("Also added cert public key to " + webidURI)
  539. } else {
  540. s.debug.Println("Not authenticated / local user: " + loggedUser + " != " + webidURI + " on " + resource.Base)
  541. }
  542. s.debug.Println("Done issuing new cert for " + webidURI)
  543. ua := req.Header.Get("User-Agent")
  544. if strings.Contains(ua, "Chrome") {
  545. w.Header().Set(HCType, "application/x-x509-user-cert; charset=utf-8")
  546. return SystemReturn{Status: 200, Bytes: newSpkac}
  547. }
  548. // Prefer loading cert in iframe, to access onLoad events in the browser for the iframe
  549. body := `<iframe width="0" height="0" style="display: none;" src="data:application/x-x509-user-cert;base64,` + base64.StdEncoding.EncodeToString(newSpkac) + `"></iframe>`
  550. return SystemReturn{Status: 200, Body: body}
  551. } else if strings.Contains(req.Header.Get("Accept"), "text/html") {
  552. return SystemReturn{Status: 200, Body: Apps["newCert"]}
  553. }
  554. return SystemReturn{Status: 500, Body: "Your request could not be processed. Either no WebID or no SPKAC value was provided."}
  555. }
  556. // accountStatus implements a basic API to check whether a user account exists on the server
  557. // Response object example:
  558. // {
  559. // method: "accountStatus",
  560. // status: "success",
  561. // formURL: "https://example.org/,system/spkac",
  562. // loginURL: "https://example.org/,system/login/",
  563. // response: {
  564. // accountURL: "user",
  565. // available: true
  566. // }
  567. // }
  568. // @@TODO treat exceptions
  569. func accountStatus(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  570. resource, _ := req.pathInfo(req.BaseURI())
  571. host, port, _ := net.SplitHostPort(req.Host)
  572. if len(host) == 0 {
  573. host = req.Host
  574. }
  575. if len(port) > 0 {
  576. port = ":" + port
  577. }
  578. data, err := ioutil.ReadAll(req.Body)
  579. if err != nil {
  580. s.debug.Println("Read body error: " + err.Error())
  581. return SystemReturn{Status: 500, Body: err.Error()}
  582. }
  583. if len(data) == 0 {
  584. s.debug.Println("Empty request for accountStatus API")
  585. return SystemReturn{Status: 500, Body: "Empty request for accountStatus API"}
  586. }
  587. var accReq accountRequest
  588. err = json.Unmarshal(data, &accReq)
  589. if err != nil {
  590. s.debug.Println("Unmarshal error: " + err.Error())
  591. return SystemReturn{Status: 500, Body: err.Error()}
  592. }
  593. accReq.AccountName = strings.ToLower(accReq.AccountName)
  594. w.Header().Set(HCType, "application/json")
  595. status := "success"
  596. accName := accReq.AccountName
  597. accURL := resource.Base + "/" + accName + "/"
  598. if s.Config.Vhosts {
  599. accURL = resource.Obj.Scheme + "://" + accName + "." + host + port + "/"
  600. }
  601. isAvailable := true
  602. resource, _ = req.pathInfo(accURL)
  603. s.debug.Println("Checking if account <" + accReq.AccountName + "> exists...")
  604. stat, err := os.Stat(resource.File)
  605. if err != nil {
  606. s.debug.Println("Stat error: " + err.Error())
  607. }
  608. if stat != nil && stat.IsDir() {
  609. s.debug.Println("Found " + s.Config.DataRoot + accName + "." + resource.Root)
  610. isAvailable = false
  611. }
  612. res := statusResponse{
  613. Method: "status",
  614. Status: status,
  615. FormURL: resource.Obj.Scheme + "://" + req.Host + "/" + SystemPrefix + "/new",
  616. LoginURL: accURL + SystemPrefix + "/login",
  617. LogoutURL: accURL + SystemPrefix + "/logout",
  618. Response: accountResponse{
  619. AccountURL: accURL,
  620. Available: isAvailable,
  621. },
  622. }
  623. jsonData, err := json.Marshal(res)
  624. if err != nil {
  625. s.debug.Println("Marshal error: " + err.Error())
  626. }
  627. return SystemReturn{Status: 200, Body: string(jsonData)}
  628. }
  629. func accountTokens(w http.ResponseWriter, req *httpRequest, s *Server) SystemReturn {
  630. if len(req.User) == 0 {
  631. return SystemReturn{Status: 401, Body: UnauthorizedTemplate(req.FormValue("redirect"), "")}
  632. }
  633. if !req.IsOwner {
  634. return SystemReturn{Status: 403, Body: "You are not allowed to view this page"}
  635. }
  636. tokensHtml := "<div>"
  637. if len(req.FormValue("revokeAuthz")) > 0 {
  638. delStatus := "<p style=\"color: green;\">Successfully revoked token!</p>"
  639. err := s.deletePersistedToken("Authorization", req.Host, req.FormValue("revokeAuthz"))
  640. if err != nil {
  641. delStatus = "<p>Could not revoke token. Error: " + err.Error() + "</p>"
  642. }
  643. tokensHtml += delStatus
  644. }
  645. tokens, err := s.getTokensByType("Authorization", req.Host)
  646. tokensHtml += "<h2>Authorization tokens for applications</h2>\n"
  647. tokensHtml += "<div>"
  648. if err == nil {
  649. for token, values := range tokens {
  650. tokensHtml += "<p>Token: " + string(token) + "<br>\n"
  651. tokensHtml += "Application: <strong>" + values["origin"] + "</strong>"
  652. tokensHtml += " <a href=\"" + req.BaseURI() + "?revokeAuthz=" + encodeQuery(token) + "\">Revoke</a></p>\n"
  653. }
  654. tokensHtml += "</ul>\n"
  655. if len(tokens) == 0 {
  656. tokensHtml += "No authorization tokens found."
  657. }
  658. }
  659. tokensHtml += "</div>"
  660. return SystemReturn{Status: 200, Body: TokensTemplate(tokensHtml)}
  661. }
  662. // DiskUsage returns the total size occupied by dir and contents
  663. func DiskUsage(dirPath string) (int64, error) {
  664. var totalSize int64
  665. walkpath := func(path string, f os.FileInfo, err error) error {
  666. if err == nil && f != nil {
  667. totalSize += f.Size()
  668. }
  669. return err
  670. }
  671. err := filepath.Walk(dirPath, walkpath)
  672. return totalSize, err
  673. }
  674. func (s *Server) StartBolt() error {
  675. var err error
  676. s.BoltDB, err = bolt.Open(s.Config.BoltPath, 0644, nil)
  677. if err != nil {
  678. return err
  679. }
  680. return nil
  681. }
  682. // NewToken saves an API token to the bolt db. It returns the API token and a possible error
  683. func (s *Server) newPersistedToken(tokenType, host string, values map[string]string) (string, error) {
  684. var token string
  685. if len(tokenType) == 0 || len(host) == 0 {
  686. return token, errors.New("Can't retrieve token from db. Missing values for token or host.")
  687. }
  688. // bucket(host) -> bucket(type) -> values
  689. err := s.BoltDB.Update(func(tx *bolt.Tx) error {
  690. userBucket, err := tx.CreateBucketIfNotExists([]byte(host))
  691. if err != nil {
  692. return err
  693. }
  694. bucket, err := userBucket.CreateBucketIfNotExists([]byte(tokenType))
  695. id, _ := bucket.NextSequence()
  696. values["id"] = fmt.Sprintf("%d", id)
  697. // set validity if not alreay set
  698. if len(values["valid"]) == 0 {
  699. // age times the duration of 6 month
  700. values["valid"] = fmt.Sprintf("%d",
  701. time.Now().Add(time.Duration(s.Config.TokenAge)*time.Hour*5040).Unix())
  702. }
  703. // marshal values to JSON
  704. tokenJson, err := json.Marshal(values)
  705. if err != nil {
  706. return err
  707. }
  708. token = fmt.Sprintf("%x", sha256.Sum256(tokenJson))
  709. err = bucket.Put([]byte(token), tokenJson)
  710. if err != nil {
  711. return err
  712. }
  713. return nil
  714. })
  715. return token, err
  716. }
  717. func (s *Server) getPersistedToken(tokenType, host, token string) (map[string]string, error) {
  718. tokenValues := map[string]string{}
  719. if len(tokenType) == 0 || len(host) == 0 || len(token) == 0 {
  720. return tokenValues, errors.New("Can't retrieve token from db. tokenType, host and token value are requrired.")
  721. }
  722. err := s.BoltDB.View(func(tx *bolt.Tx) error {
  723. userBucket := tx.Bucket([]byte(host))
  724. if userBucket == nil {
  725. return errors.New(host + " bucket not found!")
  726. }
  727. bucket := userBucket.Bucket([]byte(tokenType))
  728. if bucket == nil {
  729. return errors.New(tokenType + " bucket not found!")
  730. }
  731. // unmarshal
  732. b := bucket.Get([]byte(token))
  733. err := json.Unmarshal(b, &tokenValues)
  734. return err
  735. })
  736. return tokenValues, err
  737. }
  738. func (s *Server) getTokenByOrigin(tokenType, host, origin string) (string, error) {
  739. token := ""
  740. if len(tokenType) == 0 || len(host) == 0 || len(origin) == 0 {
  741. return token, errors.New("Can't retrieve token from db. tokenType, host and token value are requrired.")
  742. }
  743. s.debug.Println("Checking existing tokens for host:", host, "and origin:", origin)
  744. err := s.BoltDB.View(func(tx *bolt.Tx) error {
  745. userBucket := tx.Bucket([]byte(host))
  746. if userBucket == nil {
  747. return errors.New(host + " bucket not found!")
  748. }
  749. bucket := userBucket.Bucket([]byte(tokenType))
  750. if bucket == nil {
  751. return errors.New(tokenType + " bucket not found!")
  752. }
  753. // unmarshal
  754. c := bucket.Cursor()
  755. for k, _ := c.First(); k != nil; k, _ = c.Next() {
  756. key := string(k)
  757. values, err := s.getPersistedToken(tokenType, host, key)
  758. if err == nil && values["origin"] == origin {
  759. token = key
  760. break
  761. }
  762. }
  763. return nil
  764. })
  765. return token, err
  766. }
  767. func (s *Server) deletePersistedToken(tokenType, host, token string) error {
  768. if len(tokenType) == 0 || len(host) == 0 || len(token) == 0 {
  769. return errors.New("Can't retrieve token from db. tokenType, host and token value are requrired.")
  770. }
  771. err := s.BoltDB.Update(func(tx *bolt.Tx) error {
  772. return tx.Bucket([]byte(host)).Bucket([]byte(tokenType)).Delete([]byte(token))
  773. })
  774. return err
  775. }
  776. func (s *Server) getTokensByType(tokenType, host string) (map[string]map[string]string, error) {
  777. tokens := make(map[string]map[string]string)
  778. err := s.BoltDB.View(func(tx *bolt.Tx) error {
  779. // Assume bucket exists and has keys
  780. b := tx.Bucket([]byte(host))
  781. if b == nil {
  782. return errors.New("No bucket for host " + host)
  783. }
  784. ba := b.Bucket([]byte(tokenType))
  785. if ba == nil {
  786. return errors.New("No bucket for type " + tokenType)
  787. }
  788. c := ba.Cursor()
  789. for k, _ := c.First(); k != nil; k, _ = c.Next() {
  790. key := string(k)
  791. token, err := s.getPersistedToken(tokenType, host, key)
  792. if err == nil {
  793. tokens[key] = token
  794. }
  795. }
  796. return nil
  797. })
  798. return tokens, err
  799. }