auth

Paddy 2015-01-18 Parent:823517aad893 Child:0a1e16b9c141

122:eb9842ae3ff1 Browse Files

Enable the implict grant flow. Add the implicit grant flow. This can't be done in a grant type, because it's not specified through the grant_type parameter, for some absurd reason. Whatever. We basically achieved this by refactoring how we respond to the authorization endpoint, keying off the "response_type" parameter.

oauth2.go

     1.1 --- a/oauth2.go	Sun Jan 18 02:14:41 2015 -0500
     1.2 +++ b/oauth2.go	Sun Jan 18 03:23:20 2015 -0500
     1.3 @@ -7,6 +7,7 @@
     1.4  	"log"
     1.5  	"net/http"
     1.6  	"net/url"
     1.7 +	"strconv"
     1.8  	"sync"
     1.9  	"time"
    1.10  
    1.11 @@ -257,10 +258,11 @@
    1.12  	}
    1.13  	scope := r.URL.Query().Get("scope")
    1.14  	state := r.URL.Query().Get("state")
    1.15 -	if r.URL.Query().Get("response_type") != "code" {
    1.16 -		q := redirectURL.Query()
    1.17 +	responseType := r.URL.Query().Get("response_type")
    1.18 +	q := redirectURL.Query()
    1.19 +	q.Add("state", state)
    1.20 +	if responseType != "code" && responseType != "token" {
    1.21  		q.Add("error", "invalid_request")
    1.22 -		q.Add("state", state)
    1.23  		redirectURL.RawQuery = q.Encode()
    1.24  		http.Redirect(w, r, redirectURL.String(), http.StatusFound)
    1.25  		return
    1.26 @@ -268,45 +270,68 @@
    1.27  	if r.Method == "POST" {
    1.28  		// BUG(paddy): We need to implement CSRF protection when obtaining a grant code.
    1.29  		if r.PostFormValue("grant") == "approved" {
    1.30 -			code := uuid.NewID().String()
    1.31 -			authCode := AuthorizationCode{
    1.32 -				Code:        code,
    1.33 -				Created:     time.Now(),
    1.34 -				ExpiresIn:   defaultAuthorizationCodeExpiration,
    1.35 -				ClientID:    clientID,
    1.36 -				Scope:       scope,
    1.37 -				RedirectURI: r.URL.Query().Get("redirect_uri"),
    1.38 -				State:       state,
    1.39 -				ProfileID:   session.ProfileID,
    1.40 +			var fragment bool
    1.41 +			switch responseType {
    1.42 +			case "code":
    1.43 +				code := uuid.NewID().String()
    1.44 +				authCode := AuthorizationCode{
    1.45 +					Code:        code,
    1.46 +					Created:     time.Now(),
    1.47 +					ExpiresIn:   defaultAuthorizationCodeExpiration,
    1.48 +					ClientID:    clientID,
    1.49 +					Scope:       scope,
    1.50 +					RedirectURI: r.URL.Query().Get("redirect_uri"),
    1.51 +					State:       state,
    1.52 +					ProfileID:   session.ProfileID,
    1.53 +				}
    1.54 +				err := context.SaveAuthorizationCode(authCode)
    1.55 +				if err != nil {
    1.56 +					log.Println("Error saving authorization code:", err)
    1.57 +					q.Add("error", "server_error")
    1.58 +					break
    1.59 +				}
    1.60 +				q.Add("code", code)
    1.61 +			case "token":
    1.62 +				token := Token{
    1.63 +					AccessToken: uuid.NewID().String(),
    1.64 +					Created:     time.Now(),
    1.65 +					CreatedFrom: "",
    1.66 +					ExpiresIn:   defaultTokenExpiration,
    1.67 +					TokenType:   "bearer",
    1.68 +					Scope:       scope,
    1.69 +					ProfileID:   session.ProfileID,
    1.70 +				}
    1.71 +				err := context.SaveToken(token)
    1.72 +				if err != nil {
    1.73 +					log.Println("Error saving token:", err)
    1.74 +					q.Add("error", "server_error")
    1.75 +					break
    1.76 +				}
    1.77 +				q = url.Values{} // we're not altering the querystring, so don't clone it
    1.78 +				q.Add("access_token", token.AccessToken)
    1.79 +				q.Add("token_type", token.TokenType)
    1.80 +				q.Add("expires_in", strconv.FormatInt(int64(token.ExpiresIn), 10))
    1.81 +				q.Add("scope", token.Scope)
    1.82 +				q.Add("state", state) // we wiped out the old values, so we need to set the state again
    1.83 +				fragment = true
    1.84  			}
    1.85 -			err := context.SaveAuthorizationCode(authCode)
    1.86 -			if err != nil {
    1.87 -				q := redirectURL.Query()
    1.88 -				q.Add("error", "server_error")
    1.89 -				q.Add("state", state)
    1.90 +			if fragment {
    1.91 +				redirectURL.Fragment = q.Encode()
    1.92 +			} else {
    1.93  				redirectURL.RawQuery = q.Encode()
    1.94 -				http.Redirect(w, r, redirectURL.String(), http.StatusFound)
    1.95 -				return
    1.96  			}
    1.97 -			q := redirectURL.Query()
    1.98 -			q.Add("code", code)
    1.99 -			q.Add("state", state)
   1.100 -			redirectURL.RawQuery = q.Encode()
   1.101  			http.Redirect(w, r, redirectURL.String(), http.StatusFound)
   1.102  			return
   1.103  		}
   1.104 -		q := redirectURL.Query()
   1.105  		q.Add("error", "access_denied")
   1.106 -		q.Add("state", state)
   1.107  		redirectURL.RawQuery = q.Encode()
   1.108  		http.Redirect(w, r, redirectURL.String(), http.StatusFound)
   1.109  		return
   1.110  	}
   1.111  	profile, err := context.GetProfileByID(session.ProfileID)
   1.112  	if err != nil {
   1.113 -		q := redirectURL.Query()
   1.114 +		log.Println("Error getting profile from session:", err)
   1.115  		q.Add("error", "server_error")
   1.116 -		q.Add("state", state)
   1.117  		redirectURL.RawQuery = q.Encode()
   1.118  		http.Redirect(w, r, redirectURL.String(), http.StatusFound)
   1.119  		return