Refactor verifyClient, implement refresh tokens.
Refactor verifyClient into verifyClient and getClientAuth. We moved verifyClient
out of each of the GrantType's validation functions and into the access token
endpoint, where it will be called before the GrantType's validation function.
Yay, less code repetition. And seeing as we always want to verify the client,
that seems like a good way to prevent things like 118a69954621 from happening.
This did, however, force us to add an AllowsPublic property to the GrantType, so
the token endpoint knows whether or not a public Client is valid for any given
GrantType.
We also implemented the refresh token grant type, which required adding ClientID
and RefreshRevoked as properties on the Token type. We need ClientID because we
need to constrain refresh tokens to the client that issued them. We also should
probably keep track of which tokens belong to which clients, just as a general
rule of thumb. RefreshRevoked had to be created, next to Revoked, because the
AccessToken could be revoked and the RefreshToken still valid, or vice versa.
Notably, when you issue a new refresh token, the old one is revoked, but the
access token is still valid. It remains to be seen whether this is a good way to
track things or not. The number of duplicated properties lead me to believe our
type is not a great representation of the underlying concepts.
5 func compareErrors(err1, err2 requestError) (success bool, field string, val1, val2 interface{}) {
6 if err1.Slug != err2.Slug {
7 return false, "Slug", err1.Slug, err2.Slug
9 if err1.Field != err2.Field {
10 return false, "Field", err1.Field, err2.Field
12 if err1.Param != err2.Param {
13 return false, "Param", err1.Param, err2.Param
15 if err1.Header != err2.Header {
16 return false, "Header", err1.Header, err2.Header
18 return true, "", nil, nil
21 func compareResponses(resp1, resp2 response) (success bool, field string, val1, val2 interface{}) {
22 if len(resp1.Errors) != len(resp2.Errors) {
23 return false, "Errors", resp1.Errors, resp2.Errors
25 if len(resp1.Logins) != len(resp2.Logins) {
26 return false, "Logins", resp1.Logins, resp2.Logins
28 if len(resp1.Profiles) != len(resp2.Profiles) {
29 return false, "Profiles", resp1.Profiles, resp2.Profiles
31 if len(resp1.Clients) != len(resp2.Clients) {
32 return false, "Clients", resp1.Clients, resp2.Clients
34 if len(resp1.Endpoints) != len(resp2.Endpoints) {
35 return false, "Endpoints", resp1.Endpoints, resp2.Endpoints
37 for pos := range resp1.Errors {
38 success, field, val1, val2 = compareErrors(resp1.Errors[pos], resp2.Errors[pos])
40 field = fmt.Sprintf("Error %d %s", pos, field)
44 for pos := range resp1.Logins {
45 success, field, val1, val2 = compareLogins(resp1.Logins[pos], resp2.Logins[pos])
47 field = fmt.Sprintf("Login %d %s", pos, field)
51 for pos := range resp1.Profiles {
52 success, field, val1, val2 = compareProfiles(resp1.Profiles[pos], resp2.Profiles[pos])
54 field = fmt.Sprintf("Profile %d %s", pos, field)
58 for pos := range resp1.Clients {
59 success, field, val1, val2 = compareClients(resp1.Clients[pos], resp2.Clients[pos])
61 field = fmt.Sprintf("Client %d %s", pos, field)
65 for pos := range resp1.Endpoints {
66 success, field, val1, val2 = compareEndpoints(resp1.Endpoints[pos], resp2.Endpoints[pos])
68 field = fmt.Sprintf("Endpoint %d %s", pos, field)
72 return true, "", nil, nil
75 func fillInServerGenerated(expectation, result response) {
76 if len(expectation.Profiles) > 0 {
77 for pos, profile := range expectation.Profiles {
78 profile.ID = result.Profiles[pos].ID
79 profile.Created = result.Profiles[pos].Created
80 profile.LastSeen = result.Profiles[pos].LastSeen
81 expectation.Profiles[pos] = profile
84 if len(expectation.Logins) > 0 {
85 for pos, login := range expectation.Logins {
86 login.ProfileID = result.Logins[pos].ProfileID
87 login.Created = result.Logins[pos].Created
88 login.LastUsed = result.Logins[pos].LastUsed
89 expectation.Logins[pos] = login
92 if len(expectation.Clients) > 0 {
93 for pos, client := range expectation.Clients {
94 client.ID = result.Clients[pos].ID
95 client.Secret = result.Clients[pos].Secret
96 client.OwnerID = result.Clients[pos].OwnerID
97 expectation.Clients[pos] = client
100 if len(expectation.Endpoints) > 0 {
101 for pos, endpoint := range expectation.Endpoints {
102 endpoint.ID = result.Endpoints[pos].ID
103 endpoint.ClientID = result.Endpoints[pos].ClientID
104 endpoint.Added = result.Endpoints[pos].Added
105 expectation.Endpoints[pos] = endpoint