auth

Paddy 2014-12-06 Parent:42bc3e44f4fe Child:1dc4e152e3b0

84:4cb65cf90217 Go to Latest

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.

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