auth
auth/http.go
Actually validate grant requests. Write the logic to validate grant requests and stub out the rendering/error handling/redirecting locations. Finally, we get to the good stuff: implementing the specification. Write some tests to verify that granting requests works the way we think it does.
1.1 --- a/http.go Wed Oct 22 00:29:05 2014 -0400 1.2 +++ b/http.go Wed Oct 22 00:30:28 2014 -0400 1.3 @@ -1,16 +1,113 @@ 1.4 package auth 1.5 1.6 import ( 1.7 - "log" 1.8 "net/http" 1.9 + 1.10 + "code.secondbit.org/uuid" 1.11 ) 1.12 1.13 const getGrantTemplateName = "get_grant" 1.14 1.15 func GetGrantHandler(w http.ResponseWriter, r *http.Request, context Context) { 1.16 + if r.URL.Query().Get("client_id") == "" { 1.17 + w.WriteHeader(http.StatusBadRequest) 1.18 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.19 + "error": "Client ID must be specified in the request.", 1.20 + }) 1.21 + return 1.22 + } 1.23 + clientID, err := uuid.Parse(r.URL.Query().Get("client_id")) 1.24 + if err != nil { 1.25 + w.WriteHeader(http.StatusBadRequest) 1.26 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.27 + "error": "client_id is not a valid Client ID.", 1.28 + }) 1.29 + return 1.30 + } 1.31 + client, err := context.GetClient(clientID) 1.32 + if err != nil { 1.33 + w.WriteHeader(http.StatusInternalServerError) 1.34 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.35 + "internal_error": err, 1.36 + }) 1.37 + return 1.38 + } 1.39 + // whether a redirect URI is valid or not depends on the number of endpoints 1.40 + // the client has registered 1.41 + numEndpoints, err := context.CountEndpoints(clientID) 1.42 + if err != nil { 1.43 + w.WriteHeader(http.StatusInternalServerError) 1.44 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.45 + "internal_error": err, 1.46 + }) 1.47 + return 1.48 + } 1.49 + redirectURI := r.URL.Query().Get("redirect_uri") 1.50 + var validURI bool 1.51 + if redirectURI != "" && numEndpoints > 1 { 1.52 + // if there's more than one registered endpoint, we need to match the 1.53 + // entire thing, character for character. So use strict checking. 1.54 + validURI, err = context.CheckEndpoint(clientID, redirectURI, true) 1.55 + if err != nil { 1.56 + w.WriteHeader(http.StatusInternalServerError) 1.57 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.58 + "internal_error": err, 1.59 + }) 1.60 + return 1.61 + } 1.62 + } else if redirectURI != "" && numEndpoints == 1 { 1.63 + // if there's exactly one endpoint, we can match only the prefix of it, 1.64 + // so don't use strict checking. 1.65 + validURI, err = context.CheckEndpoint(clientID, redirectURI, false) 1.66 + if err != nil { 1.67 + w.WriteHeader(http.StatusInternalServerError) 1.68 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.69 + "internal_error": err, 1.70 + }) 1.71 + return 1.72 + } 1.73 + } else if redirectURI == "" && numEndpoints == 1 { 1.74 + // if we don't specify the endpoint and there's only one endpoint, the 1.75 + // request is valid, and we're redirecting to that one endpoint 1.76 + validURI = true 1.77 + endpoints, err := context.ListEndpoints(clientID, 1, 0) 1.78 + if err != nil { 1.79 + w.WriteHeader(http.StatusInternalServerError) 1.80 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.81 + "internal_error": err, 1.82 + }) 1.83 + return 1.84 + } 1.85 + if len(endpoints) != 1 { 1.86 + validURI = false 1.87 + } else { 1.88 + redirectURI = endpoints[0].URI.String() 1.89 + } 1.90 + } else { 1.91 + validURI = false 1.92 + } 1.93 + if !validURI { 1.94 + w.WriteHeader(http.StatusBadRequest) 1.95 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.96 + "error": "The redirect_uri specified is not valid.", 1.97 + }) 1.98 + return 1.99 + } 1.100 + if r.URL.Query().Get("response_type") != "code" { 1.101 + // TODO: redirect error 1.102 + } 1.103 + //scope := r.URL.Query().Get("scope") 1.104 + //state := r.URL.Query().Get("state") 1.105 + if r.Method == "POST" { 1.106 + // TODO: CSRF protection 1.107 + if r.PostFormValue("grant") == "approved" { 1.108 + // TODO: redirect 1.109 + } else { 1.110 + // TODO: redirect error 1.111 + } 1.112 + } 1.113 w.WriteHeader(http.StatusOK) 1.114 - err := context.Render(w, getGrantTemplateName, nil) 1.115 - if err != nil { 1.116 - log.Println("Error rendering template for GetGrantHandler:", err) 1.117 - } 1.118 + context.Render(w, getGrantTemplateName, map[string]interface{}{ 1.119 + "client": client, 1.120 + }) 1.121 }