auth
auth/oauth2_test.go
I'm on a typo roll. ErrInvalidSession, not ErrInvalidSessior. Also, we want comparison, not assignment.
| paddy@52 | 1 package auth |
| paddy@52 | 2 |
| paddy@52 | 3 import ( |
| paddy@66 | 4 "bytes" |
| paddy@52 | 5 "html/template" |
| paddy@66 | 6 "io/ioutil" |
| paddy@52 | 7 "net/http" |
| paddy@52 | 8 "net/http/httptest" |
| paddy@53 | 9 "net/url" |
| paddy@52 | 10 "testing" |
| paddy@56 | 11 "time" |
| paddy@56 | 12 |
| paddy@56 | 13 "code.secondbit.org/uuid" |
| paddy@52 | 14 ) |
| paddy@52 | 15 |
| paddy@53 | 16 const ( |
| paddy@53 | 17 scopeSet = 1 << iota |
| paddy@53 | 18 stateSet |
| paddy@53 | 19 uriSet |
| paddy@53 | 20 ) |
| paddy@53 | 21 |
| paddy@65 | 22 func stripParam(param string, u *url.URL) { |
| paddy@65 | 23 q := u.Query() |
| paddy@65 | 24 q.Del(param) |
| paddy@65 | 25 u.RawQuery = q.Encode() |
| paddy@65 | 26 } |
| paddy@65 | 27 |
| paddy@52 | 28 func TestGetGrantCodeSuccess(t *testing.T) { |
| paddy@52 | 29 t.Parallel() |
| paddy@52 | 30 store := NewMemstore() |
| paddy@52 | 31 testContext := Context{ |
| paddy@52 | 32 template: template.Must(template.New(getGrantTemplateName).Parse("Get auth grant")), |
| paddy@52 | 33 clients: store, |
| paddy@52 | 34 grants: store, |
| paddy@52 | 35 profiles: store, |
| paddy@52 | 36 tokens: store, |
| paddy@52 | 37 } |
| paddy@56 | 38 client := Client{ |
| paddy@56 | 39 ID: uuid.NewID(), |
| paddy@56 | 40 Secret: "super secret!", |
| paddy@56 | 41 OwnerID: uuid.NewID(), |
| paddy@56 | 42 Name: "My test client", |
| paddy@56 | 43 Logo: "https://secondbit.org/logo.png", |
| paddy@56 | 44 Website: "https://secondbit.org", |
| paddy@56 | 45 Type: "public", |
| paddy@56 | 46 } |
| paddy@56 | 47 uri, err := url.Parse("https://test.secondbit.org/redirect") |
| paddy@56 | 48 if err != nil { |
| paddy@56 | 49 t.Fatal("Can't parse URL:", err) |
| paddy@56 | 50 } |
| paddy@56 | 51 endpoint := Endpoint{ |
| paddy@56 | 52 ID: uuid.NewID(), |
| paddy@56 | 53 ClientID: client.ID, |
| paddy@56 | 54 URI: *uri, |
| paddy@56 | 55 Added: time.Now(), |
| paddy@56 | 56 } |
| paddy@56 | 57 err = testContext.SaveClient(client) |
| paddy@56 | 58 if err != nil { |
| paddy@56 | 59 t.Fatal("Can't store client:", err) |
| paddy@56 | 60 } |
| paddy@56 | 61 err = testContext.AddEndpoint(client.ID, endpoint) |
| paddy@56 | 62 if err != nil { |
| paddy@56 | 63 t.Fatal("Can't store endpoint:", err) |
| paddy@56 | 64 } |
| paddy@52 | 65 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@52 | 66 if err != nil { |
| paddy@52 | 67 t.Fatal("Can't build request:", err) |
| paddy@52 | 68 } |
| paddy@58 | 69 for i := 0; i < 1<<3; i++ { |
| paddy@53 | 70 w := httptest.NewRecorder() |
| paddy@53 | 71 params := url.Values{} |
| paddy@53 | 72 // see OAuth 2.0 spec, section 4.1.1 |
| paddy@53 | 73 params.Set("response_type", "code") |
| paddy@56 | 74 params.Set("client_id", client.ID.String()) |
| paddy@53 | 75 if i&uriSet != 0 { |
| paddy@58 | 76 params.Set("redirect_uri", endpoint.URI.String()) |
| paddy@53 | 77 } |
| paddy@53 | 78 if i&scopeSet != 0 { |
| paddy@53 | 79 params.Set("scope", "testscope") |
| paddy@53 | 80 } |
| paddy@53 | 81 if i&stateSet != 0 { |
| paddy@53 | 82 params.Set("state", "my super secure state string") |
| paddy@53 | 83 } |
| paddy@53 | 84 req.URL.RawQuery = params.Encode() |
| paddy@66 | 85 req.Method = "GET" |
| paddy@66 | 86 req.Body = nil |
| paddy@66 | 87 req.Header.Del("Content-Type") |
| paddy@53 | 88 GetGrantHandler(w, req, testContext) |
| paddy@53 | 89 if w.Code != http.StatusOK { |
| paddy@53 | 90 t.Errorf("Expected status code to be %d, got %d for %s", http.StatusOK, w.Code, req.URL.String()) |
| paddy@53 | 91 } |
| paddy@53 | 92 if w.Body.String() != "Get auth grant" { |
| paddy@53 | 93 t.Errorf("Expected body to be `%s`, got `%s` for %s", "Get auth grant", w.Body.String(), req.URL.String()) |
| paddy@53 | 94 } |
| paddy@66 | 95 req.Method = "POST" |
| paddy@66 | 96 req.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
| paddy@66 | 97 w = httptest.NewRecorder() |
| paddy@66 | 98 data := url.Values{} |
| paddy@66 | 99 data.Set("grant", "approved") |
| paddy@66 | 100 body := bytes.NewBufferString(data.Encode()) |
| paddy@66 | 101 req.Body = ioutil.NopCloser(body) |
| paddy@66 | 102 GetGrantHandler(w, req, testContext) |
| paddy@66 | 103 if w.Code != http.StatusFound { |
| paddy@66 | 104 t.Errorf("Expected status code to be %d, got %d for %s", http.StatusFound, w.Code, req.URL.String()) |
| paddy@66 | 105 } |
| paddy@66 | 106 redirectedTo := w.Header().Get("Location") |
| paddy@66 | 107 red, err := url.Parse(redirectedTo) |
| paddy@66 | 108 if err != nil { |
| paddy@66 | 109 t.Fatalf(`Being redirected to a non-URL "%s" threw error "%s" for "%s"\n`, redirectedTo, err, req.URL.String()) |
| paddy@66 | 110 } |
| paddy@66 | 111 t.Log("Redirected to", redirectedTo) |
| paddy@66 | 112 if red.Query().Get("code") == "" { |
| paddy@66 | 113 t.Fatalf(`Expected code param in redirect URL to be set, but it wasn't for %s`, req.URL.String()) |
| paddy@66 | 114 } |
| paddy@67 | 115 if _, err := testContext.GetGrant(red.Query().Get("code")); err != nil { |
| paddy@67 | 116 t.Fatalf(`Unexpected error "%s: retrieving the grant "%s" supplied in the redirect URL for %s`, err, red.Query().Get("code"), req.URL.String()) |
| paddy@66 | 117 } |
| paddy@66 | 118 err = testContext.DeleteGrant(red.Query().Get("code")) |
| paddy@66 | 119 if err != nil { |
| paddy@66 | 120 t.Log(`Unexpected error "%s" deleting grant "%s" for %s`, err, red.Query().Get("code"), req.URL.String()) |
| paddy@66 | 121 } |
| paddy@66 | 122 stripParam("code", red) |
| paddy@66 | 123 if red.Query().Get("state") != params.Get("state") { |
| paddy@66 | 124 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s" for %s`, params.Get("state"), red.Query().Get("state"), req.URL.String()) |
| paddy@66 | 125 } |
| paddy@66 | 126 stripParam("state", red) |
| paddy@66 | 127 if red.String() != endpoint.URI.String() { |
| paddy@66 | 128 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String()) |
| paddy@66 | 129 } |
| paddy@52 | 130 } |
| paddy@52 | 131 } |
| paddy@56 | 132 |
| paddy@62 | 133 func TestGetGrantCodeInvalidClient(t *testing.T) { |
| paddy@62 | 134 t.Parallel() |
| paddy@62 | 135 store := NewMemstore() |
| paddy@62 | 136 testContext := Context{ |
| paddy@62 | 137 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")), |
| paddy@62 | 138 clients: store, |
| paddy@62 | 139 grants: store, |
| paddy@62 | 140 profiles: store, |
| paddy@62 | 141 tokens: store, |
| paddy@62 | 142 } |
| paddy@62 | 143 client := Client{ |
| paddy@62 | 144 ID: uuid.NewID(), |
| paddy@62 | 145 Secret: "super secret!", |
| paddy@62 | 146 OwnerID: uuid.NewID(), |
| paddy@62 | 147 Name: "My test client", |
| paddy@62 | 148 Type: "public", |
| paddy@62 | 149 } |
| paddy@62 | 150 err := testContext.SaveClient(client) |
| paddy@62 | 151 if err != nil { |
| paddy@62 | 152 t.Fatal("Can't store client:", err) |
| paddy@62 | 153 } |
| paddy@62 | 154 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@62 | 155 if err != nil { |
| paddy@62 | 156 t.Fatal("Can't build request:", err) |
| paddy@62 | 157 } |
| paddy@62 | 158 w := httptest.NewRecorder() |
| paddy@62 | 159 params := url.Values{} |
| paddy@62 | 160 params.Set("response_type", "code") |
| paddy@62 | 161 params.Set("redirect_uri", "https://test.secondbit.org/") |
| paddy@62 | 162 req.URL.RawQuery = params.Encode() |
| paddy@62 | 163 GetGrantHandler(w, req, testContext) |
| paddy@62 | 164 if w.Code != http.StatusBadRequest { |
| paddy@62 | 165 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@62 | 166 } |
| paddy@62 | 167 if w.Body.String() != "Client ID must be specified in the request." { |
| paddy@62 | 168 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "Client ID must be specified in the request.", w.Body.String()) |
| paddy@62 | 169 } |
| paddy@62 | 170 w = httptest.NewRecorder() |
| paddy@62 | 171 params.Set("client_id", "Not an ID") |
| paddy@62 | 172 req.URL.RawQuery = params.Encode() |
| paddy@62 | 173 GetGrantHandler(w, req, testContext) |
| paddy@62 | 174 if w.Code != http.StatusBadRequest { |
| paddy@62 | 175 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@62 | 176 } |
| paddy@62 | 177 if w.Body.String() != "client_id is not a valid Client ID." { |
| paddy@62 | 178 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "client_id is not a valid Client ID.", w.Body.String()) |
| paddy@62 | 179 } |
| paddy@62 | 180 w = httptest.NewRecorder() |
| paddy@62 | 181 params.Set("client_id", uuid.NewID().String()) |
| paddy@62 | 182 req.URL.RawQuery = params.Encode() |
| paddy@62 | 183 GetGrantHandler(w, req, testContext) |
| paddy@62 | 184 if w.Code != http.StatusBadRequest { |
| paddy@62 | 185 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@62 | 186 } |
| paddy@62 | 187 if w.Body.String() != "The specified Client couldn’t be found." { |
| paddy@62 | 188 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The specified Client couldn’t be found.", w.Body.String()) |
| paddy@62 | 189 } |
| paddy@62 | 190 } |
| paddy@62 | 191 |
| paddy@56 | 192 func TestGetGrantCodeInvalidURI(t *testing.T) { |
| paddy@56 | 193 t.Parallel() |
| paddy@56 | 194 store := NewMemstore() |
| paddy@56 | 195 testContext := Context{ |
| paddy@56 | 196 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")), |
| paddy@56 | 197 clients: store, |
| paddy@56 | 198 grants: store, |
| paddy@56 | 199 profiles: store, |
| paddy@56 | 200 tokens: store, |
| paddy@56 | 201 } |
| paddy@56 | 202 client := Client{ |
| paddy@56 | 203 ID: uuid.NewID(), |
| paddy@56 | 204 Secret: "super secret!", |
| paddy@56 | 205 OwnerID: uuid.NewID(), |
| paddy@56 | 206 Name: "My test client", |
| paddy@56 | 207 Type: "public", |
| paddy@56 | 208 } |
| paddy@56 | 209 uri, err := url.Parse("https://test.secondbit.org/redirect") |
| paddy@56 | 210 if err != nil { |
| paddy@56 | 211 t.Fatal("Can't parse URL:", err) |
| paddy@56 | 212 } |
| paddy@56 | 213 err = testContext.SaveClient(client) |
| paddy@56 | 214 if err != nil { |
| paddy@56 | 215 t.Fatal("Can't store client:", err) |
| paddy@56 | 216 } |
| paddy@56 | 217 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@56 | 218 if err != nil { |
| paddy@56 | 219 t.Fatal("Can't build request:", err) |
| paddy@56 | 220 } |
| paddy@56 | 221 w := httptest.NewRecorder() |
| paddy@56 | 222 params := url.Values{} |
| paddy@56 | 223 params.Set("response_type", "code") |
| paddy@56 | 224 params.Set("client_id", client.ID.String()) |
| paddy@64 | 225 req.URL.RawQuery = params.Encode() |
| paddy@64 | 226 GetGrantHandler(w, req, testContext) |
| paddy@64 | 227 if w.Code != http.StatusBadRequest { |
| paddy@64 | 228 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@64 | 229 } |
| paddy@64 | 230 if w.Body.String() != "The redirect_uri specified is not valid." { |
| paddy@64 | 231 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String()) |
| paddy@64 | 232 } |
| paddy@64 | 233 endpoint := Endpoint{ |
| paddy@64 | 234 ID: uuid.NewID(), |
| paddy@64 | 235 ClientID: client.ID, |
| paddy@64 | 236 URI: *uri, |
| paddy@64 | 237 Added: time.Now(), |
| paddy@64 | 238 } |
| paddy@64 | 239 err = testContext.AddEndpoint(client.ID, endpoint) |
| paddy@64 | 240 if err != nil { |
| paddy@64 | 241 t.Fatal("Can't store endpoint:", err) |
| paddy@64 | 242 } |
| paddy@64 | 243 w = httptest.NewRecorder() |
| paddy@56 | 244 params.Set("redirect_uri", "https://test.secondbit.org/wrong") |
| paddy@56 | 245 req.URL.RawQuery = params.Encode() |
| paddy@56 | 246 GetGrantHandler(w, req, testContext) |
| paddy@56 | 247 if w.Code != http.StatusBadRequest { |
| paddy@56 | 248 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@56 | 249 } |
| paddy@56 | 250 if w.Body.String() != "The redirect_uri specified is not valid." { |
| paddy@56 | 251 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String()) |
| paddy@56 | 252 } |
| paddy@64 | 253 endpoint2 := Endpoint{ |
| paddy@64 | 254 ID: uuid.NewID(), |
| paddy@64 | 255 ClientID: client.ID, |
| paddy@64 | 256 URI: *uri, |
| paddy@64 | 257 Added: time.Now(), |
| paddy@64 | 258 } |
| paddy@64 | 259 err = testContext.AddEndpoint(client.ID, endpoint2) |
| paddy@60 | 260 if err != nil { |
| paddy@64 | 261 t.Fatal("Can't store endpoint:", err) |
| paddy@60 | 262 } |
| paddy@60 | 263 w = httptest.NewRecorder() |
| paddy@64 | 264 params.Set("redirect_uri", "") |
| paddy@64 | 265 req.URL.RawQuery = params.Encode() |
| paddy@64 | 266 GetGrantHandler(w, req, testContext) |
| paddy@64 | 267 if w.Code != http.StatusBadRequest { |
| paddy@64 | 268 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@64 | 269 } |
| paddy@64 | 270 if w.Body.String() != "The redirect_uri specified is not valid." { |
| paddy@64 | 271 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String()) |
| paddy@64 | 272 } |
| paddy@64 | 273 w = httptest.NewRecorder() |
| paddy@64 | 274 params.Set("redirect_uri", "://not a URL") |
| paddy@60 | 275 req.URL.RawQuery = params.Encode() |
| paddy@60 | 276 GetGrantHandler(w, req, testContext) |
| paddy@60 | 277 if w.Code != http.StatusBadRequest { |
| paddy@60 | 278 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code) |
| paddy@60 | 279 } |
| paddy@60 | 280 if w.Body.String() != "The redirect_uri specified is not valid." { |
| paddy@60 | 281 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String()) |
| paddy@60 | 282 } |
| paddy@56 | 283 } |
| paddy@65 | 284 |
| paddy@65 | 285 func TestGetGrantCodeInvalidResponseType(t *testing.T) { |
| paddy@65 | 286 t.Parallel() |
| paddy@65 | 287 store := NewMemstore() |
| paddy@65 | 288 testContext := Context{ |
| paddy@65 | 289 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")), |
| paddy@65 | 290 clients: store, |
| paddy@65 | 291 grants: store, |
| paddy@65 | 292 profiles: store, |
| paddy@65 | 293 tokens: store, |
| paddy@65 | 294 } |
| paddy@65 | 295 client := Client{ |
| paddy@65 | 296 ID: uuid.NewID(), |
| paddy@65 | 297 Secret: "super secret!", |
| paddy@65 | 298 OwnerID: uuid.NewID(), |
| paddy@65 | 299 Name: "My test client", |
| paddy@65 | 300 Logo: "https://secondbit.org/logo.png", |
| paddy@65 | 301 Website: "https://secondbit.org", |
| paddy@65 | 302 Type: "public", |
| paddy@65 | 303 } |
| paddy@65 | 304 uri, err := url.Parse("https://test.secondbit.org/redirect") |
| paddy@65 | 305 if err != nil { |
| paddy@65 | 306 t.Fatal("Can't parse URL:", err) |
| paddy@65 | 307 } |
| paddy@65 | 308 endpoint := Endpoint{ |
| paddy@65 | 309 ID: uuid.NewID(), |
| paddy@65 | 310 ClientID: client.ID, |
| paddy@65 | 311 URI: *uri, |
| paddy@65 | 312 Added: time.Now(), |
| paddy@65 | 313 } |
| paddy@65 | 314 err = testContext.SaveClient(client) |
| paddy@65 | 315 if err != nil { |
| paddy@65 | 316 t.Fatal("Can't store client:", err) |
| paddy@65 | 317 } |
| paddy@65 | 318 err = testContext.AddEndpoint(client.ID, endpoint) |
| paddy@65 | 319 if err != nil { |
| paddy@65 | 320 t.Fatal("Can't store endpoint:", err) |
| paddy@65 | 321 } |
| paddy@65 | 322 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@65 | 323 if err != nil { |
| paddy@65 | 324 t.Fatal("Can't build request:", err) |
| paddy@65 | 325 } |
| paddy@65 | 326 params := url.Values{} |
| paddy@65 | 327 params.Set("response_type", "totally not code") |
| paddy@65 | 328 params.Set("client_id", client.ID.String()) |
| paddy@65 | 329 params.Set("redirect_uri", endpoint.URI.String()) |
| paddy@65 | 330 params.Set("scope", "testscope") |
| paddy@65 | 331 params.Set("state", "my super secure state string") |
| paddy@65 | 332 req.URL.RawQuery = params.Encode() |
| paddy@65 | 333 w := httptest.NewRecorder() |
| paddy@65 | 334 GetGrantHandler(w, req, testContext) |
| paddy@65 | 335 if w.Code != http.StatusFound { |
| paddy@65 | 336 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code) |
| paddy@65 | 337 } |
| paddy@65 | 338 redirectedTo := w.Header().Get("Location") |
| paddy@65 | 339 red, err := url.Parse(redirectedTo) |
| paddy@65 | 340 if err != nil { |
| paddy@65 | 341 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err) |
| paddy@65 | 342 } |
| paddy@65 | 343 if red.Query().Get("error") != "invalid_request" { |
| paddy@65 | 344 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error")) |
| paddy@65 | 345 } |
| paddy@65 | 346 stripParam("error", red) |
| paddy@65 | 347 if red.Query().Get("state") != params.Get("state") { |
| paddy@65 | 348 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state")) |
| paddy@65 | 349 } |
| paddy@65 | 350 stripParam("state", red) |
| paddy@65 | 351 if red.String() != endpoint.URI.String() { |
| paddy@65 | 352 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String()) |
| paddy@65 | 353 } |
| paddy@65 | 354 stripParam("response_type", req.URL) |
| paddy@65 | 355 w = httptest.NewRecorder() |
| paddy@65 | 356 GetGrantHandler(w, req, testContext) |
| paddy@65 | 357 if w.Code != http.StatusFound { |
| paddy@65 | 358 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code) |
| paddy@65 | 359 } |
| paddy@65 | 360 redirectedTo = w.Header().Get("Location") |
| paddy@65 | 361 red, err = url.Parse(redirectedTo) |
| paddy@65 | 362 if err != nil { |
| paddy@65 | 363 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err) |
| paddy@65 | 364 } |
| paddy@65 | 365 if red.Query().Get("error") != "invalid_request" { |
| paddy@65 | 366 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error")) |
| paddy@65 | 367 } |
| paddy@65 | 368 stripParam("error", red) |
| paddy@65 | 369 if red.Query().Get("state") != params.Get("state") { |
| paddy@65 | 370 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state")) |
| paddy@65 | 371 } |
| paddy@65 | 372 stripParam("state", red) |
| paddy@65 | 373 if red.String() != endpoint.URI.String() { |
| paddy@65 | 374 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String()) |
| paddy@65 | 375 } |
| paddy@65 | 376 } |
| paddy@66 | 377 |
| paddy@66 | 378 func TestGetGrantCodeDenied(t *testing.T) { |
| paddy@66 | 379 t.Parallel() |
| paddy@66 | 380 store := NewMemstore() |
| paddy@66 | 381 testContext := Context{ |
| paddy@66 | 382 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")), |
| paddy@66 | 383 clients: store, |
| paddy@66 | 384 grants: store, |
| paddy@66 | 385 profiles: store, |
| paddy@66 | 386 tokens: store, |
| paddy@66 | 387 } |
| paddy@66 | 388 client := Client{ |
| paddy@66 | 389 ID: uuid.NewID(), |
| paddy@66 | 390 Secret: "super secret!", |
| paddy@66 | 391 OwnerID: uuid.NewID(), |
| paddy@66 | 392 Name: "My test client", |
| paddy@66 | 393 Logo: "https://secondbit.org/logo.png", |
| paddy@66 | 394 Website: "https://secondbit.org", |
| paddy@66 | 395 Type: "public", |
| paddy@66 | 396 } |
| paddy@66 | 397 uri, err := url.Parse("https://test.secondbit.org/redirect") |
| paddy@66 | 398 if err != nil { |
| paddy@66 | 399 t.Fatal("Can't parse URL:", err) |
| paddy@66 | 400 } |
| paddy@66 | 401 endpoint := Endpoint{ |
| paddy@66 | 402 ID: uuid.NewID(), |
| paddy@66 | 403 ClientID: client.ID, |
| paddy@66 | 404 URI: *uri, |
| paddy@66 | 405 Added: time.Now(), |
| paddy@66 | 406 } |
| paddy@66 | 407 err = testContext.SaveClient(client) |
| paddy@66 | 408 if err != nil { |
| paddy@66 | 409 t.Fatal("Can't store client:", err) |
| paddy@66 | 410 } |
| paddy@66 | 411 err = testContext.AddEndpoint(client.ID, endpoint) |
| paddy@66 | 412 if err != nil { |
| paddy@66 | 413 t.Fatal("Can't store endpoint:", err) |
| paddy@66 | 414 } |
| paddy@66 | 415 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil) |
| paddy@66 | 416 if err != nil { |
| paddy@66 | 417 t.Fatal("Can't build request:", err) |
| paddy@66 | 418 } |
| paddy@66 | 419 params := url.Values{} |
| paddy@66 | 420 params.Set("response_type", "code") |
| paddy@66 | 421 params.Set("client_id", client.ID.String()) |
| paddy@66 | 422 params.Set("redirect_uri", endpoint.URI.String()) |
| paddy@66 | 423 params.Set("scope", "testscope") |
| paddy@66 | 424 params.Set("state", "my super secure state string") |
| paddy@66 | 425 data := url.Values{} |
| paddy@66 | 426 data.Set("grant", "denied") |
| paddy@66 | 427 req.URL.RawQuery = params.Encode() |
| paddy@66 | 428 req.Body = ioutil.NopCloser(bytes.NewBufferString(data.Encode())) |
| paddy@66 | 429 req.Method = "POST" |
| paddy@66 | 430 w := httptest.NewRecorder() |
| paddy@66 | 431 GetGrantHandler(w, req, testContext) |
| paddy@66 | 432 if w.Code != http.StatusFound { |
| paddy@66 | 433 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code) |
| paddy@66 | 434 } |
| paddy@66 | 435 redirectedTo := w.Header().Get("Location") |
| paddy@66 | 436 red, err := url.Parse(redirectedTo) |
| paddy@66 | 437 if err != nil { |
| paddy@66 | 438 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err) |
| paddy@66 | 439 } |
| paddy@66 | 440 if red.Query().Get("error") != "access_denied" { |
| paddy@66 | 441 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "access_denied", red.Query().Get("error")) |
| paddy@66 | 442 } |
| paddy@66 | 443 stripParam("error", red) |
| paddy@66 | 444 if red.Query().Get("state") != params.Get("state") { |
| paddy@66 | 445 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state")) |
| paddy@66 | 446 } |
| paddy@66 | 447 stripParam("state", red) |
| paddy@66 | 448 if red.String() != endpoint.URI.String() { |
| paddy@66 | 449 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String()) |
| paddy@66 | 450 } |
| paddy@66 | 451 } |