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