auth

Paddy 2014-11-02 Parent:c29c7df35905 Child:55d5107e8805

65:f97ca45d5657 Go to Latest

auth/http_test.go

Fix bug with response_type redirect, add tests. Test that we redirect with an error when an invalid response_type is supplied. Fix a bug that would not add any of our parameters to the redirect URL.

History
paddy@52 1 package auth
paddy@52 2
paddy@52 3 import (
paddy@52 4 "html/template"
paddy@52 5 "net/http"
paddy@52 6 "net/http/httptest"
paddy@53 7 "net/url"
paddy@52 8 "testing"
paddy@56 9 "time"
paddy@56 10
paddy@56 11 "code.secondbit.org/uuid"
paddy@52 12 )
paddy@52 13
paddy@53 14 const (
paddy@53 15 scopeSet = 1 << iota
paddy@53 16 stateSet
paddy@53 17 uriSet
paddy@53 18 )
paddy@53 19
paddy@65 20 func stripParam(param string, u *url.URL) {
paddy@65 21 q := u.Query()
paddy@65 22 q.Del(param)
paddy@65 23 u.RawQuery = q.Encode()
paddy@65 24 }
paddy@65 25
paddy@52 26 func TestGetGrantCodeSuccess(t *testing.T) {
paddy@52 27 t.Parallel()
paddy@52 28 store := NewMemstore()
paddy@52 29 testContext := Context{
paddy@52 30 template: template.Must(template.New(getGrantTemplateName).Parse("Get auth grant")),
paddy@52 31 clients: store,
paddy@52 32 grants: store,
paddy@52 33 profiles: store,
paddy@52 34 tokens: store,
paddy@52 35 }
paddy@56 36 client := Client{
paddy@56 37 ID: uuid.NewID(),
paddy@56 38 Secret: "super secret!",
paddy@56 39 OwnerID: uuid.NewID(),
paddy@56 40 Name: "My test client",
paddy@56 41 Logo: "https://secondbit.org/logo.png",
paddy@56 42 Website: "https://secondbit.org",
paddy@56 43 Type: "public",
paddy@56 44 }
paddy@56 45 uri, err := url.Parse("https://test.secondbit.org/redirect")
paddy@56 46 if err != nil {
paddy@56 47 t.Fatal("Can't parse URL:", err)
paddy@56 48 }
paddy@56 49 endpoint := Endpoint{
paddy@56 50 ID: uuid.NewID(),
paddy@56 51 ClientID: client.ID,
paddy@56 52 URI: *uri,
paddy@56 53 Added: time.Now(),
paddy@56 54 }
paddy@56 55 err = testContext.SaveClient(client)
paddy@56 56 if err != nil {
paddy@56 57 t.Fatal("Can't store client:", err)
paddy@56 58 }
paddy@56 59 err = testContext.AddEndpoint(client.ID, endpoint)
paddy@56 60 if err != nil {
paddy@56 61 t.Fatal("Can't store endpoint:", err)
paddy@56 62 }
paddy@52 63 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
paddy@52 64 if err != nil {
paddy@52 65 t.Fatal("Can't build request:", err)
paddy@52 66 }
paddy@58 67 for i := 0; i < 1<<3; i++ {
paddy@53 68 w := httptest.NewRecorder()
paddy@53 69 params := url.Values{}
paddy@53 70 // see OAuth 2.0 spec, section 4.1.1
paddy@53 71 params.Set("response_type", "code")
paddy@56 72 params.Set("client_id", client.ID.String())
paddy@53 73 if i&uriSet != 0 {
paddy@58 74 params.Set("redirect_uri", endpoint.URI.String())
paddy@53 75 }
paddy@53 76 if i&scopeSet != 0 {
paddy@53 77 params.Set("scope", "testscope")
paddy@53 78 }
paddy@53 79 if i&stateSet != 0 {
paddy@53 80 params.Set("state", "my super secure state string")
paddy@53 81 }
paddy@53 82 req.URL.RawQuery = params.Encode()
paddy@53 83 GetGrantHandler(w, req, testContext)
paddy@53 84 if w.Code != http.StatusOK {
paddy@53 85 t.Errorf("Expected status code to be %d, got %d for %s", http.StatusOK, w.Code, req.URL.String())
paddy@53 86 }
paddy@53 87 if w.Body.String() != "Get auth grant" {
paddy@53 88 t.Errorf("Expected body to be `%s`, got `%s` for %s", "Get auth grant", w.Body.String(), req.URL.String())
paddy@53 89 }
paddy@52 90 }
paddy@52 91 }
paddy@56 92
paddy@62 93 func TestGetGrantCodeInvalidClient(t *testing.T) {
paddy@62 94 t.Parallel()
paddy@62 95 store := NewMemstore()
paddy@62 96 testContext := Context{
paddy@62 97 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
paddy@62 98 clients: store,
paddy@62 99 grants: store,
paddy@62 100 profiles: store,
paddy@62 101 tokens: store,
paddy@62 102 }
paddy@62 103 client := Client{
paddy@62 104 ID: uuid.NewID(),
paddy@62 105 Secret: "super secret!",
paddy@62 106 OwnerID: uuid.NewID(),
paddy@62 107 Name: "My test client",
paddy@62 108 Type: "public",
paddy@62 109 }
paddy@62 110 err := testContext.SaveClient(client)
paddy@62 111 if err != nil {
paddy@62 112 t.Fatal("Can't store client:", err)
paddy@62 113 }
paddy@62 114 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
paddy@62 115 if err != nil {
paddy@62 116 t.Fatal("Can't build request:", err)
paddy@62 117 }
paddy@62 118 w := httptest.NewRecorder()
paddy@62 119 params := url.Values{}
paddy@62 120 params.Set("response_type", "code")
paddy@62 121 params.Set("redirect_uri", "https://test.secondbit.org/")
paddy@62 122 req.URL.RawQuery = params.Encode()
paddy@62 123 GetGrantHandler(w, req, testContext)
paddy@62 124 if w.Code != http.StatusBadRequest {
paddy@62 125 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
paddy@62 126 }
paddy@62 127 if w.Body.String() != "Client ID must be specified in the request." {
paddy@62 128 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "Client ID must be specified in the request.", w.Body.String())
paddy@62 129 }
paddy@62 130 w = httptest.NewRecorder()
paddy@62 131 params.Set("client_id", "Not an ID")
paddy@62 132 req.URL.RawQuery = params.Encode()
paddy@62 133 GetGrantHandler(w, req, testContext)
paddy@62 134 if w.Code != http.StatusBadRequest {
paddy@62 135 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
paddy@62 136 }
paddy@62 137 if w.Body.String() != "client_id is not a valid Client ID." {
paddy@62 138 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "client_id is not a valid Client ID.", w.Body.String())
paddy@62 139 }
paddy@62 140 w = httptest.NewRecorder()
paddy@62 141 params.Set("client_id", uuid.NewID().String())
paddy@62 142 req.URL.RawQuery = params.Encode()
paddy@62 143 GetGrantHandler(w, req, testContext)
paddy@62 144 if w.Code != http.StatusBadRequest {
paddy@62 145 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
paddy@62 146 }
paddy@62 147 if w.Body.String() != "The specified Client couldn&rsquo;t be found." {
paddy@62 148 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The specified Client couldn&rsquo;t be found.", w.Body.String())
paddy@62 149 }
paddy@62 150 }
paddy@62 151
paddy@56 152 func TestGetGrantCodeInvalidURI(t *testing.T) {
paddy@56 153 t.Parallel()
paddy@56 154 store := NewMemstore()
paddy@56 155 testContext := Context{
paddy@56 156 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
paddy@56 157 clients: store,
paddy@56 158 grants: store,
paddy@56 159 profiles: store,
paddy@56 160 tokens: store,
paddy@56 161 }
paddy@56 162 client := Client{
paddy@56 163 ID: uuid.NewID(),
paddy@56 164 Secret: "super secret!",
paddy@56 165 OwnerID: uuid.NewID(),
paddy@56 166 Name: "My test client",
paddy@56 167 Type: "public",
paddy@56 168 }
paddy@56 169 uri, err := url.Parse("https://test.secondbit.org/redirect")
paddy@56 170 if err != nil {
paddy@56 171 t.Fatal("Can't parse URL:", err)
paddy@56 172 }
paddy@56 173 err = testContext.SaveClient(client)
paddy@56 174 if err != nil {
paddy@56 175 t.Fatal("Can't store client:", err)
paddy@56 176 }
paddy@56 177 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
paddy@56 178 if err != nil {
paddy@56 179 t.Fatal("Can't build request:", err)
paddy@56 180 }
paddy@56 181 w := httptest.NewRecorder()
paddy@56 182 params := url.Values{}
paddy@56 183 params.Set("response_type", "code")
paddy@56 184 params.Set("client_id", client.ID.String())
paddy@64 185 req.URL.RawQuery = params.Encode()
paddy@64 186 GetGrantHandler(w, req, testContext)
paddy@64 187 if w.Code != http.StatusBadRequest {
paddy@64 188 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
paddy@64 189 }
paddy@64 190 if w.Body.String() != "The redirect_uri specified is not valid." {
paddy@64 191 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
paddy@64 192 }
paddy@64 193 endpoint := Endpoint{
paddy@64 194 ID: uuid.NewID(),
paddy@64 195 ClientID: client.ID,
paddy@64 196 URI: *uri,
paddy@64 197 Added: time.Now(),
paddy@64 198 }
paddy@64 199 err = testContext.AddEndpoint(client.ID, endpoint)
paddy@64 200 if err != nil {
paddy@64 201 t.Fatal("Can't store endpoint:", err)
paddy@64 202 }
paddy@64 203 w = httptest.NewRecorder()
paddy@56 204 params.Set("redirect_uri", "https://test.secondbit.org/wrong")
paddy@56 205 req.URL.RawQuery = params.Encode()
paddy@56 206 GetGrantHandler(w, req, testContext)
paddy@56 207 if w.Code != http.StatusBadRequest {
paddy@56 208 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
paddy@56 209 }
paddy@56 210 if w.Body.String() != "The redirect_uri specified is not valid." {
paddy@56 211 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
paddy@56 212 }
paddy@64 213 endpoint2 := Endpoint{
paddy@64 214 ID: uuid.NewID(),
paddy@64 215 ClientID: client.ID,
paddy@64 216 URI: *uri,
paddy@64 217 Added: time.Now(),
paddy@64 218 }
paddy@64 219 err = testContext.AddEndpoint(client.ID, endpoint2)
paddy@60 220 if err != nil {
paddy@64 221 t.Fatal("Can't store endpoint:", err)
paddy@60 222 }
paddy@60 223 w = httptest.NewRecorder()
paddy@64 224 params.Set("redirect_uri", "")
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 w = httptest.NewRecorder()
paddy@64 234 params.Set("redirect_uri", "://not a URL")
paddy@60 235 req.URL.RawQuery = params.Encode()
paddy@60 236 GetGrantHandler(w, req, testContext)
paddy@60 237 if w.Code != http.StatusBadRequest {
paddy@60 238 t.Errorf("Expected status code to be %d, got %d", http.StatusBadRequest, w.Code)
paddy@60 239 }
paddy@60 240 if w.Body.String() != "The redirect_uri specified is not valid." {
paddy@60 241 t.Errorf(`Expected output to be "%s", got "%s" instead.`, "The redirect_uri specified is not valid.", w.Body.String())
paddy@60 242 }
paddy@56 243 }
paddy@65 244
paddy@65 245 func TestGetGrantCodeInvalidResponseType(t *testing.T) {
paddy@65 246 t.Parallel()
paddy@65 247 store := NewMemstore()
paddy@65 248 testContext := Context{
paddy@65 249 template: template.Must(template.New(getGrantTemplateName).Parse("{{ .error }}")),
paddy@65 250 clients: store,
paddy@65 251 grants: store,
paddy@65 252 profiles: store,
paddy@65 253 tokens: store,
paddy@65 254 }
paddy@65 255 client := Client{
paddy@65 256 ID: uuid.NewID(),
paddy@65 257 Secret: "super secret!",
paddy@65 258 OwnerID: uuid.NewID(),
paddy@65 259 Name: "My test client",
paddy@65 260 Logo: "https://secondbit.org/logo.png",
paddy@65 261 Website: "https://secondbit.org",
paddy@65 262 Type: "public",
paddy@65 263 }
paddy@65 264 uri, err := url.Parse("https://test.secondbit.org/redirect")
paddy@65 265 if err != nil {
paddy@65 266 t.Fatal("Can't parse URL:", err)
paddy@65 267 }
paddy@65 268 endpoint := Endpoint{
paddy@65 269 ID: uuid.NewID(),
paddy@65 270 ClientID: client.ID,
paddy@65 271 URI: *uri,
paddy@65 272 Added: time.Now(),
paddy@65 273 }
paddy@65 274 err = testContext.SaveClient(client)
paddy@65 275 if err != nil {
paddy@65 276 t.Fatal("Can't store client:", err)
paddy@65 277 }
paddy@65 278 err = testContext.AddEndpoint(client.ID, endpoint)
paddy@65 279 if err != nil {
paddy@65 280 t.Fatal("Can't store endpoint:", err)
paddy@65 281 }
paddy@65 282 req, err := http.NewRequest("GET", "https://test.auth.secondbit.org/oauth2/grant", nil)
paddy@65 283 if err != nil {
paddy@65 284 t.Fatal("Can't build request:", err)
paddy@65 285 }
paddy@65 286 params := url.Values{}
paddy@65 287 params.Set("response_type", "totally not code")
paddy@65 288 params.Set("client_id", client.ID.String())
paddy@65 289 params.Set("redirect_uri", endpoint.URI.String())
paddy@65 290 params.Set("scope", "testscope")
paddy@65 291 params.Set("state", "my super secure state string")
paddy@65 292 req.URL.RawQuery = params.Encode()
paddy@65 293 w := httptest.NewRecorder()
paddy@65 294 GetGrantHandler(w, req, testContext)
paddy@65 295 if w.Code != http.StatusFound {
paddy@65 296 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
paddy@65 297 }
paddy@65 298 redirectedTo := w.Header().Get("Location")
paddy@65 299 red, err := url.Parse(redirectedTo)
paddy@65 300 if err != nil {
paddy@65 301 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
paddy@65 302 }
paddy@65 303 if red.Query().Get("error") != "invalid_request" {
paddy@65 304 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error"))
paddy@65 305 }
paddy@65 306 stripParam("error", red)
paddy@65 307 if red.Query().Get("state") != params.Get("state") {
paddy@65 308 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
paddy@65 309 }
paddy@65 310 stripParam("state", red)
paddy@65 311 if red.String() != endpoint.URI.String() {
paddy@65 312 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String())
paddy@65 313 }
paddy@65 314 stripParam("response_type", req.URL)
paddy@65 315 w = httptest.NewRecorder()
paddy@65 316 GetGrantHandler(w, req, testContext)
paddy@65 317 if w.Code != http.StatusFound {
paddy@65 318 t.Errorf("Expected status code to be %d, got %d", http.StatusFound, w.Code)
paddy@65 319 }
paddy@65 320 redirectedTo = w.Header().Get("Location")
paddy@65 321 red, err = url.Parse(redirectedTo)
paddy@65 322 if err != nil {
paddy@65 323 t.Fatalf("Being redirected to a non-URL (%s) threw error: %s\n", redirectedTo, err)
paddy@65 324 }
paddy@65 325 if red.Query().Get("error") != "invalid_request" {
paddy@65 326 t.Errorf(`Expected error param in redirect URL to be "%s", got "%s"`, "invalid_request", red.Query().Get("error"))
paddy@65 327 }
paddy@65 328 stripParam("error", red)
paddy@65 329 if red.Query().Get("state") != params.Get("state") {
paddy@65 330 t.Errorf(`Expected state param in redirect URL to be "%s", got "%s"`, params.Get("state"), red.Query().Get("state"))
paddy@65 331 }
paddy@65 332 stripParam("state", red)
paddy@65 333 if red.String() != endpoint.URI.String() {
paddy@65 334 t.Errorf(`Expected redirect URL to be "%s", got "%s"`, endpoint.URI.String(), red.String())
paddy@65 335 }
paddy@65 336 }