auth

Paddy 2014-10-26 Parent:e45bfa2abc00 Child:03c9890f99c5

58:b3cd7765a7c8 Go to Latest

auth/http.go

Require full URLs for Endpoints. The spec says that we SHOULD require full URLs for redirection, but we _can_ offer the ability to set a URL as a "partial URL" if we really must. I see no particular reason to do this, so I've simplified the code by pulling that option out. This means that URLs (as long as they're normalized, which I've filed a bug in the codebase to do) can be checked using simple string comparison, which makes the likelihood of bugs across clientStorage implementations a lot lower.

History
1 package auth
3 import (
4 "net/http"
6 "code.secondbit.org/uuid"
7 )
9 const getGrantTemplateName = "get_grant"
11 // GetGrantHandler presents and processes the page for asking a user to grant access
12 // to their data. See RFC 6749, Section 4.1.
13 func GetGrantHandler(w http.ResponseWriter, r *http.Request, context Context) {
14 if r.URL.Query().Get("client_id") == "" {
15 w.WriteHeader(http.StatusBadRequest)
16 context.Render(w, getGrantTemplateName, map[string]interface{}{
17 "error": "Client ID must be specified in the request.",
18 })
19 return
20 }
21 clientID, err := uuid.Parse(r.URL.Query().Get("client_id"))
22 if err != nil {
23 w.WriteHeader(http.StatusBadRequest)
24 context.Render(w, getGrantTemplateName, map[string]interface{}{
25 "error": "client_id is not a valid Client ID.",
26 })
27 return
28 }
29 client, err := context.GetClient(clientID)
30 if err != nil {
31 w.WriteHeader(http.StatusInternalServerError)
32 context.Render(w, getGrantTemplateName, map[string]interface{}{
33 "internal_error": err,
34 })
35 return
36 }
37 // whether a redirect URI is valid or not depends on the number of endpoints
38 // the client has registered
39 numEndpoints, err := context.CountEndpoints(clientID)
40 if err != nil {
41 w.WriteHeader(http.StatusInternalServerError)
42 context.Render(w, getGrantTemplateName, map[string]interface{}{
43 "internal_error": err,
44 })
45 return
46 }
47 redirectURI := r.URL.Query().Get("redirect_uri")
48 var validURI bool
49 if redirectURI != "" {
50 // BUG(paddy): We really should normalize URIs before trying to compare them.
51 validURI, err = context.CheckEndpoint(clientID, redirectURI)
52 if err != nil {
53 w.WriteHeader(http.StatusInternalServerError)
54 context.Render(w, getGrantTemplateName, map[string]interface{}{
55 "internal_error": err,
56 })
57 return
58 }
59 } else if redirectURI == "" && numEndpoints == 1 {
60 // if we don't specify the endpoint and there's only one endpoint, the
61 // request is valid, and we're redirecting to that one endpoint
62 validURI = true
63 endpoints, err := context.ListEndpoints(clientID, 1, 0)
64 if err != nil {
65 w.WriteHeader(http.StatusInternalServerError)
66 context.Render(w, getGrantTemplateName, map[string]interface{}{
67 "internal_error": err,
68 })
69 return
70 }
71 if len(endpoints) != 1 {
72 validURI = false
73 } else {
74 redirectURI = endpoints[0].URI.String()
75 }
76 } else {
77 validURI = false
78 }
79 if !validURI {
80 w.WriteHeader(http.StatusBadRequest)
81 context.Render(w, getGrantTemplateName, map[string]interface{}{
82 "error": "The redirect_uri specified is not valid.",
83 })
84 return
85 }
86 if r.URL.Query().Get("response_type") != "code" {
87 // TODO: redirect error
88 }
89 //scope := r.URL.Query().Get("scope")
90 //state := r.URL.Query().Get("state")
91 if r.Method == "POST" {
92 // TODO: CSRF protection
93 if r.PostFormValue("grant") == "approved" {
94 // TODO: redirect
95 } else {
96 // TODO: redirect error
97 }
98 }
99 w.WriteHeader(http.StatusOK)
100 context.Render(w, getGrantTemplateName, map[string]interface{}{
101 "client": client,
102 })
103 }