auth

Paddy 2014-10-22 Parent:116342ffc65f Child:e45bfa2abc00

56:a5987795707e Go to Latest

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.

History
     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  }