blob: 7cb3b50171067a5db3d9198b30ec0f05d5d44974 [file] [log] [blame]
package endpoints
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"testing"
"golang.org/x/net/context"
"appengine/aetest"
)
const (
tokeinfoUserID = "12345"
tokeninfoEmail = "dude@gmail.com"
)
var (
tokeninfoValid = `{
"issued_to": "my-client-id",
"audience": "my-client-id",
"user_id": "` + tokeinfoUserID + `",
"scope": "scope.one scope.two",
"expires_in": 3600,
"email": "` + tokeninfoEmail + `",
"verified_email": true,
"access_type": "online"
}`
tokeninfoUnverified = `{
"expires_in": 3600,
"verified_email": false,
"email": "user@example.org"
}`
// is this even possible for email to be "" and verified == true?
tokeninfoInvalidEmail = `{
"expires_in": 3600,
"verified_email": true,
"email": ""
}`
tokeninfoError = `{
"error_description": "Invalid value"
}`
)
func TestTokeninfoContextCurrentOAuthClientID(t *testing.T) {
rt := newTestRoundTripper()
origTransport := httpTransportFactory
defer func() { httpTransportFactory = origTransport }()
httpTransportFactory = func(c context.Context) http.RoundTripper {
return rt
}
inst, err := aetest.NewInstance(nil)
if err != nil {
t.Fatalf("failed to create instance: %v", err)
}
defer inst.Close()
tts := []*struct {
token, scope, clientID string
httpStatus int
content string
}{
// token, scope, clientID, httpStatus, content
{"some_token0", "scope.one", "my-client-id", 200, tokeninfoValid},
{"some_token1", "scope.two", "my-client-id", 200, tokeninfoValid},
{"some_token2", "scope.one", "", 200, tokeninfoUnverified},
{"some_token3", "scope.one", "", 200, tokeninfoInvalidEmail},
{"some_token4", "scope.one", "", 401, tokeninfoError},
{"some_token5", "invalid.scope", "", 200, tokeninfoValid},
{"some_token6", "scope.one", "", 400, "{}"},
{"some_token7", "scope.one", "", 200, ""},
{"", "scope.one", "", 200, tokeninfoValid},
{"some_token9", "scope.one", "", -1, ""},
}
for i, tt := range tts {
r, err := inst.NewRequest("GET", "/", nil)
if err != nil {
t.Fatalf("Error creating a req: %v", err)
}
r.Header.Set("authorization", "bearer "+tt.token)
if tt.token != "" && tt.httpStatus > 0 {
rt.Add(&http.Response{
Status: fmt.Sprintf("%d", tt.httpStatus),
StatusCode: tt.httpStatus,
Body: ioutil.NopCloser(strings.NewReader(tt.content)),
})
}
c := newContext(r, tokeninfoAuthenticatorFactory)
auth := authenticator(c)
if auth == nil {
t.Errorf("%d: context authenticator missing", i)
continue
}
id, err := auth.CurrentOAuthClientID(c, tt.scope)
switch {
case err != nil && tt.clientID != "":
t.Errorf("%d: CurrentOAuthClientID(%v) = %v; want %q",
i, tt.scope, err, tt.clientID)
case err == nil && tt.clientID == "":
t.Errorf("%d: CurrentOAuthClientID(%v) = %v; want error",
i, tt.scope, id)
case err == nil && id != tt.clientID:
t.Errorf("%d: CurrentOAuthClientID(%v) = %v; want %q",
i, tt.scope, id, tt.clientID)
}
}
}
func TestTokeninfoCurrentOAuthUser(t *testing.T) {
origTransport := httpTransportFactory
defer func() {
httpTransportFactory = origTransport
}()
httpTransportFactory = func(c context.Context) http.RoundTripper {
return newTestRoundTripper(&http.Response{
Status: "200 OK",
StatusCode: 200,
Body: ioutil.NopCloser(strings.NewReader(tokeninfoValid)),
})
}
r, _, closer := newTestRequest(t, "GET", "/", nil)
defer closer()
r.Header.Set("authorization", "bearer some_token")
const scope = "scope.one"
c := newContext(r, tokeninfoAuthenticatorFactory)
auth := authenticator(c)
if auth == nil {
t.Fatal("context authenticator missing")
}
user, err := auth.CurrentOAuthUser(c, scope)
if err != nil {
t.Fatalf("CurrentOAuthUser(%q) = %v", scope, err)
}
if user.Email != tokeninfoEmail {
t.Errorf("CurrentOAuthUser(%q) = %#v; want email = %q", scope, user, tokeninfoEmail)
}
}