blob: 8e4eefa876fba4eaeee7530f834163fa0aa44bb2 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Jiri Simsa5293dcb2014-05-10 09:56:38 -07005package util
6
7import (
Ankur8eabfa32014-11-04 11:09:01 -08008 "fmt"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07009 "net/http"
10 "net/http/httptest"
11 "strings"
12 "testing"
Cosmos Nicolaoud9229922015-06-24 14:12:24 -070013
14 "v.io/v23/context"
15 "v.io/x/ref/internal/logger"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070016)
17
Suharsh Sivakumar44300662014-09-23 11:35:06 -070018const (
19 cookieName = "VeyronCSRFTestCookie"
20 failCookieName = "FailCookieName"
21)
22
Jiri Simsa5293dcb2014-05-10 09:56:38 -070023func TestCSRFTokenWithoutCookie(t *testing.T) {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -070024 ctx, _ := context.RootContext()
25 ctx = context.WithLogger(ctx, logger.Global())
Jiri Simsa5293dcb2014-05-10 09:56:38 -070026 r := newRequest()
Cosmos Nicolaoud9229922015-06-24 14:12:24 -070027 c, err := NewCSRFCop(ctx)
Suharsh Sivakumar44300662014-09-23 11:35:06 -070028 if err != nil {
Suharsh Sivakumard308c7e2014-10-03 12:46:50 -070029 t.Fatalf("NewCSRFCop failed: %v", err)
Suharsh Sivakumar44300662014-09-23 11:35:06 -070030 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -070031 w := httptest.NewRecorder()
Suharsh Sivakumar44300662014-09-23 11:35:06 -070032 tok, err := c.NewToken(w, r, cookieName, nil)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070033 if err != nil {
34 t.Errorf("NewToken failed: %v", err)
35 }
Ankur8eabfa32014-11-04 11:09:01 -080036 cookie, err := cookieVal(w, cookieName)
37 if err != nil {
38 t.Error(err)
39 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -070040 if len(cookie) == 0 {
41 t.Errorf("Cookie should have been set. Request: [%v], Response: [%v]", r, w)
42 }
43 // Cookie needs to be present for validation
44 r.AddCookie(&http.Cookie{Name: cookieName, Value: cookie})
Suharsh Sivakumar44300662014-09-23 11:35:06 -070045 if err := c.ValidateToken(tok, r, cookieName, nil); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070046 t.Error("CSRF token failed validation:", err)
47 }
Suharsh Sivakumar44300662014-09-23 11:35:06 -070048
49 w = httptest.NewRecorder()
50 if _, err = c.MaybeSetCookie(w, r, failCookieName); err != nil {
51 t.Error("failed to create cookie: ", err)
52 }
Ankur8eabfa32014-11-04 11:09:01 -080053 cookie, err = cookieVal(w, failCookieName)
54 if err != nil {
55 t.Error(err)
56 }
Suharsh Sivakumar44300662014-09-23 11:35:06 -070057 if len(cookie) == 0 {
58 t.Errorf("Cookie should have been set. Request: [%v], Response: [%v]", r, w)
59 }
60
61 if err := c.ValidateToken(tok, r, failCookieName, nil); err == nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070062 t.Error("CSRF token should have failed validation")
63 }
64}
65
66func TestCSRFTokenWithCookie(t *testing.T) {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -070067 ctx, _ := context.RootContext()
68 ctx = context.WithLogger(ctx, logger.Global())
Jiri Simsa5293dcb2014-05-10 09:56:38 -070069 r := newRequest()
Cosmos Nicolaoud9229922015-06-24 14:12:24 -070070 c, err := NewCSRFCop(ctx)
Suharsh Sivakumar44300662014-09-23 11:35:06 -070071 if err != nil {
Suharsh Sivakumard308c7e2014-10-03 12:46:50 -070072 t.Fatalf("NewCSRFCop failed: %v", err)
Suharsh Sivakumar44300662014-09-23 11:35:06 -070073 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -070074 w := httptest.NewRecorder()
75 r.AddCookie(&http.Cookie{Name: cookieName, Value: "u776AC7hf794pTtGVlO50w=="})
Suharsh Sivakumar44300662014-09-23 11:35:06 -070076 tok, err := c.NewToken(w, r, cookieName, nil)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070077 if err != nil {
78 t.Errorf("NewToken failed: %v", err)
79 }
Ankur8eabfa32014-11-04 11:09:01 -080080 cookie, err := cookieVal(w, cookieName)
81 if err != nil {
82 t.Error(err)
83 }
84 if len(cookie) > 0 {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070085 t.Errorf("Cookie should not be set when it is already present. Request: [%v], Response: [%v]", r, w)
86 }
Suharsh Sivakumar44300662014-09-23 11:35:06 -070087 if err := c.ValidateToken(tok, r, cookieName, nil); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070088 t.Error("CSRF token failed validation:", err)
89 }
Suharsh Sivakumar44300662014-09-23 11:35:06 -070090
91 r.AddCookie(&http.Cookie{Name: failCookieName, Value: "u864AC7gf794pTtCAlO40w=="})
92 if err := c.ValidateToken(tok, r, failCookieName, nil); err == nil {
93 t.Error("CSRF token should have failed validation")
94 }
95}
96
97func TestCSRFTokenWithData(t *testing.T) {
Cosmos Nicolaoud9229922015-06-24 14:12:24 -070098 ctx, _ := context.RootContext()
99 ctx = context.WithLogger(ctx, logger.Global())
Suharsh Sivakumar44300662014-09-23 11:35:06 -0700100 r := newRequest()
Cosmos Nicolaoud9229922015-06-24 14:12:24 -0700101 c, err := NewCSRFCop(ctx)
Suharsh Sivakumar44300662014-09-23 11:35:06 -0700102 if err != nil {
Suharsh Sivakumard308c7e2014-10-03 12:46:50 -0700103 t.Fatalf("NewCSRFCop failed: %v", err)
Suharsh Sivakumar44300662014-09-23 11:35:06 -0700104 }
105 w := httptest.NewRecorder()
106 r.AddCookie(&http.Cookie{Name: cookieName, Value: "u776AC7hf794pTtGVlO50w=="})
107 tok, err := c.NewToken(w, r, cookieName, 1)
108 if err != nil {
109 t.Errorf("NewToken failed: %v", err)
110 }
Ankur8eabfa32014-11-04 11:09:01 -0800111 cookie, err := cookieVal(w, cookieName)
112 if err != nil {
113 t.Error(err)
114 }
115 if len(cookie) > 0 {
Suharsh Sivakumar44300662014-09-23 11:35:06 -0700116 t.Errorf("Cookie should not be set when it is already present. Request: [%v], Response: [%v]", r, w)
117 }
118 var got int
119 if err := c.ValidateToken(tok, r, cookieName, &got); err != nil {
120 t.Error("CSRF token failed validation:", err)
121 }
122 if want := 1; got != want {
123 t.Errorf("Got %v, want %v", got, want)
124 }
125
126 r.AddCookie(&http.Cookie{Name: failCookieName, Value: "u864AC7gf794pTtCAlO40w=="})
127 if err := c.ValidateToken(tok, r, failCookieName, &got); err == nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700128 t.Error("CSRF token should have failed validation")
129 }
130}
131
Ankur8eabfa32014-11-04 11:09:01 -0800132func cookieVal(w *httptest.ResponseRecorder, cookieName string) (string, error) {
133 cookie := w.Header().Get("Set-Cookie")
134 if len(cookie) == 0 {
135 return "", nil
136 }
137 var (
138 val string
139 httpOnly, secure bool
140 )
141 for _, part := range strings.Split(cookie, "; ") {
142 switch {
143 case strings.HasPrefix(part, cookieName):
144 val = strings.TrimPrefix(part, cookieName+"=")
145 case part == "HttpOnly":
146 httpOnly = true
147 case part == "Secure":
148 secure = true
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700149 }
150 }
Ankur8eabfa32014-11-04 11:09:01 -0800151 if !httpOnly {
152 return "", fmt.Errorf("cookie for name %v is not HttpOnly", cookieName)
153 }
154 if !secure {
155 return "", fmt.Errorf("cookie for name %v is not Secure", cookieName)
156 }
157 return val, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700158}