auth
81:11ad5eca2f82 Browse Files
Update TODOs with error messages and test obtaining a token. Update the TODOs about returning errors when obtaining a token with the actual error code that should be returned. Write a unit test that covers obtaining a token from a grant code, but doesn't cover any of the error conditions or states.
1.1 --- a/oauth2.go Thu Nov 20 01:32:15 2014 -0500 1.2 +++ b/oauth2.go Sat Dec 06 00:35:03 2014 -0500 1.3 @@ -319,7 +319,7 @@ 1.4 redirectURI := r.PostFormValue("redirect_uri") 1.5 clientIDStr, clientSecret, err := getBasicAuth(r) 1.6 if err != nil { 1.7 - // TODO(paddy): render access denied 1.8 + // TODO(paddy): render invalid client JSON 1.9 return 1.10 } 1.11 if clientIDStr == "" && err == nil { 1.12 @@ -327,48 +327,52 @@ 1.13 } 1.14 clientID, err := uuid.Parse(clientIDStr) 1.15 if err != nil { 1.16 - // TODO(paddy): render invalid request JSON 1.17 + // TODO(paddy): render invalid client JSONN 1.18 return 1.19 } 1.20 client, err := context.GetClient(clientID) 1.21 if err != nil { 1.22 if err == ErrClientNotFound { 1.23 - // TODO(paddy): render invalid request JSON 1.24 + // TODO(paddy): render invalid client JSON 1.25 } else { 1.26 // TODO(paddy): render internal server error JSON 1.27 } 1.28 return 1.29 } 1.30 if client.Secret != clientSecret { 1.31 - // TODO(paddy): render invalid request JSON 1.32 + // TODO(paddy): render invalid client JSON 1.33 return 1.34 } 1.35 grant, err := context.GetGrant(code) 1.36 if err != nil { 1.37 if err == ErrGrantNotFound { 1.38 - // TODO(paddy): return error 1.39 + // TODO(paddy): return invalid grant JSON 1.40 return 1.41 } 1.42 - // TODO(paddy): return error 1.43 + // TODO(paddy): return internal server error JSON 1.44 + return 1.45 } 1.46 if grant.RedirectURI != redirectURI { 1.47 - // TODO(paddy): return error 1.48 + // TODO(paddy): return invalid grant JSON 1.49 + return 1.50 } 1.51 if !grant.ClientID.Equal(clientID) { 1.52 - // TODO(paddy): return error 1.53 + // TODO(paddy): return invalid grant JSON 1.54 + return 1.55 } 1.56 token := Token{ 1.57 AccessToken: uuid.NewID().String(), 1.58 RefreshToken: uuid.NewID().String(), 1.59 Created: time.Now(), 1.60 ExpiresIn: defaultTokenExpiration, 1.61 - TokenType: "", // TODO(paddy): fill in token type 1.62 + TokenType: "bearer", 1.63 Scope: grant.Scope, 1.64 ProfileID: grant.ProfileID, 1.65 } 1.66 err = context.SaveToken(token) 1.67 if err != nil { 1.68 - // TODO(paddy): return error 1.69 + // TODO(paddy): return internal server error JSON 1.70 + return 1.71 } 1.72 resp := tokenResponse{ 1.73 AccessToken: token.AccessToken, 1.74 @@ -381,6 +385,7 @@ 1.75 // TODO(paddy): log this or something 1.76 return 1.77 } 1.78 + // BUG(paddy): we need to invalidate the grant for future requests 1.79 } 1.80 1.81 // TODO(paddy): exchange user credentials for access token
2.1 --- a/oauth2_test.go Thu Nov 20 01:32:15 2014 -0500 2.2 +++ b/oauth2_test.go Sat Dec 06 00:35:03 2014 -0500 2.3 @@ -2,6 +2,7 @@ 2.4 2.5 import ( 2.6 "bytes" 2.7 + "encoding/json" 2.8 "html/template" 2.9 "io/ioutil" 2.10 "net/http" 2.11 @@ -771,3 +772,89 @@ 2.12 t.Error("Expected ErrIncorrectAuth, got", err) 2.13 } 2.14 } 2.15 + 2.16 +func TestGetTokenHandler(t *testing.T) { 2.17 + t.Parallel() 2.18 + store := NewMemstore() 2.19 + context := Context{ 2.20 + clients: store, 2.21 + grants: store, 2.22 + tokens: store, 2.23 + } 2.24 + client := Client{ 2.25 + ID: uuid.NewID(), 2.26 + Secret: "sometimes I feel like I don't know what I'm doing", 2.27 + OwnerID: uuid.NewID(), 2.28 + Name: "A Super Awesome Client!", 2.29 + Logo: "https://logos.secondbit.org/client.png", 2.30 + Website: "https://client.secondbit.org/", 2.31 + Type: "confidential", 2.32 + } 2.33 + grant := Grant{ 2.34 + Code: "testcode", 2.35 + Created: time.Now(), 2.36 + ExpiresIn: 600, 2.37 + ClientID: client.ID, 2.38 + Scope: "testscope", 2.39 + RedirectURI: "https://client.secondbit.org/", 2.40 + State: "teststate", 2.41 + ProfileID: uuid.NewID(), 2.42 + } 2.43 + err := context.SaveGrant(grant) 2.44 + if err != nil { 2.45 + t.Error("Error saving grant:", err) 2.46 + } 2.47 + err = context.SaveClient(client) 2.48 + if err != nil { 2.49 + t.Error("Error saving client:", err) 2.50 + } 2.51 + data := url.Values{} 2.52 + data.Set("grant_type", "authorization_code") 2.53 + data.Set("code", grant.Code) 2.54 + data.Set("redirect_uri", grant.RedirectURI) 2.55 + body := bytes.NewBufferString(data.Encode()) 2.56 + req, err := http.NewRequest("POST", "https://auth.secondbit.org/", ioutil.NopCloser(body)) 2.57 + if err != nil { 2.58 + t.Error("Error constructing request:", err) 2.59 + } 2.60 + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 2.61 + req.SetBasicAuth(client.ID.String(), client.Secret) 2.62 + w := httptest.NewRecorder() 2.63 + GetTokenHandler(w, req, context) 2.64 + resp := tokenResponse{} 2.65 + err = json.Unmarshal(w.Body.Bytes(), &resp) 2.66 + if err != nil { 2.67 + t.Error("Error unmarshalling response:", err) 2.68 + } 2.69 + if resp.AccessToken == "" { 2.70 + t.Error("Got blank access token back") 2.71 + } 2.72 + if resp.RefreshToken == "" { 2.73 + t.Error("Got blank refresh token back") 2.74 + } 2.75 + if resp.TokenType == "" { 2.76 + t.Error("Got blank token type back") 2.77 + } 2.78 + if resp.ExpiresIn == 0 { 2.79 + t.Error("Got blank expires in back") 2.80 + } 2.81 + tokens, err := context.GetTokensByProfileID(grant.ProfileID, 1, 0) 2.82 + if err != nil { 2.83 + t.Error("Error retrieving token:", err) 2.84 + } 2.85 + if len(tokens) != 1 { 2.86 + t.Errorf("Expected %d tokens, got %d", 1, len(tokens)) 2.87 + } 2.88 + if tokens[0].AccessToken != resp.AccessToken { 2.89 + t.Errorf(`Expected access token to be "%s", got "%s"`, tokens[0].AccessToken, resp.AccessToken) 2.90 + } 2.91 + if tokens[0].RefreshToken != resp.RefreshToken { 2.92 + t.Errorf(`Expected refresh token to be "%s", got "%s"`, tokens[0].RefreshToken, resp.RefreshToken) 2.93 + } 2.94 + if tokens[0].ExpiresIn != resp.ExpiresIn { 2.95 + t.Errorf(`Expected expires in to be %d, got %d`, tokens[0].ExpiresIn, resp.ExpiresIn) 2.96 + } 2.97 + if tokens[0].TokenType != resp.TokenType { 2.98 + t.Errorf(`Expected token type to be %s, got %s`, tokens[0].TokenType, resp.TokenType) 2.99 + } 2.100 +}