auth
auth/grant.go
Start supporting our pluggable grant_type. Define GrantType as a way to bundle information that can be used to validate requests based on their grant_type parameter. Move our validation of the authorization_code grant_type out of GetTokenHandler and into its own function. Define RegisterGrantType as a way to register new grant_type bundles and associate them with the string passed to grant_type. This enables other packages to define RegisterGrantType in their init() functions and plug in new grant types without forking this code. Implement RegisterGrantType for our authorization_code grant type.
1.1 --- a/grant.go Sat Dec 06 02:03:20 2014 -0500 1.2 +++ b/grant.go Sat Dec 06 03:33:11 2014 -0500 1.3 @@ -1,12 +1,21 @@ 1.4 package auth 1.5 1.6 import ( 1.7 + "encoding/json" 1.8 "errors" 1.9 + "net/http" 1.10 "time" 1.11 1.12 "code.secondbit.org/uuid" 1.13 ) 1.14 1.15 +func init() { 1.16 + RegisterGrantType("authorization_code", GrantType{ 1.17 + Validate: authCodeGrantValidate, 1.18 + IssuesRefresh: true, 1.19 + }) 1.20 +} 1.21 + 1.22 var ( 1.23 // ErrNoGrantStore is returned when a Context tries to act on a grantStore without setting one first. 1.24 ErrNoGrantStore = errors.New("no grantStore was specified for the Context") 1.25 @@ -67,3 +76,69 @@ 1.26 delete(m.grants, code) 1.27 return nil 1.28 } 1.29 + 1.30 +func authCodeGrantValidate(w http.ResponseWriter, r *http.Request, context Context) (scope string, profileID uuid.ID, valid bool) { 1.31 + enc := json.NewEncoder(w) 1.32 + code := r.PostFormValue("code") 1.33 + if code == "" { 1.34 + w.WriteHeader(http.StatusBadRequest) 1.35 + renderJSONError(enc, "invalid_request") 1.36 + return 1.37 + } 1.38 + // BUG(paddy): We really ought to break client verification out into its own helper functions, but I think it may depend on which grant_type is used... 1.39 + redirectURI := r.PostFormValue("redirect_uri") 1.40 + clientIDStr, clientSecret, fromAuthHeader := r.BasicAuth() 1.41 + if !fromAuthHeader { 1.42 + clientIDStr = r.PostFormValue("client_id") 1.43 + } 1.44 + clientID, err := uuid.Parse(clientIDStr) 1.45 + if err != nil { 1.46 + w.WriteHeader(http.StatusUnauthorized) 1.47 + if fromAuthHeader { 1.48 + w.Header().Set("WWW-Authenticate", "Basic") 1.49 + } 1.50 + renderJSONError(enc, "invalid_client") 1.51 + return 1.52 + } 1.53 + client, err := context.GetClient(clientID) 1.54 + if err != nil { 1.55 + if err == ErrClientNotFound { 1.56 + w.WriteHeader(http.StatusUnauthorized) 1.57 + renderJSONError(enc, "invalid_client") 1.58 + } else { 1.59 + w.WriteHeader(http.StatusInternalServerError) 1.60 + renderJSONError(enc, "server_error") 1.61 + } 1.62 + return 1.63 + } 1.64 + if client.Secret != clientSecret { 1.65 + w.WriteHeader(http.StatusUnauthorized) 1.66 + if fromAuthHeader { 1.67 + w.Header().Set("WWW-Authenticate", "Basic") 1.68 + } 1.69 + renderJSONError(enc, "invalid_client") 1.70 + return 1.71 + } 1.72 + grant, err := context.GetGrant(code) 1.73 + if err != nil { 1.74 + if err == ErrGrantNotFound { 1.75 + w.WriteHeader(http.StatusBadRequest) 1.76 + renderJSONError(enc, "invalid_grant") 1.77 + return 1.78 + } 1.79 + w.WriteHeader(http.StatusInternalServerError) 1.80 + renderJSONError(enc, "server_error") 1.81 + return 1.82 + } 1.83 + if grant.RedirectURI != redirectURI { 1.84 + w.WriteHeader(http.StatusBadRequest) 1.85 + renderJSONError(enc, "invalid_grant") 1.86 + return 1.87 + } 1.88 + if !grant.ClientID.Equal(clientID) { 1.89 + w.WriteHeader(http.StatusBadRequest) 1.90 + renderJSONError(enc, "invalid_grant") 1.91 + return 1.92 + } 1.93 + return grant.Scope, grant.ProfileID, true 1.94 +}