Skip to content

Commit 0875114

Browse files
committed
Added configuration options and route exemptions
1 parent 2ec83ef commit 0875114

File tree

3 files changed

+225
-0
lines changed

3 files changed

+225
-0
lines changed

exemptions.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Management of routes exempted from CSRF checks.
2+
package csrf
3+
4+
import (
5+
"github.com/golang/glog"
6+
"fmt"
7+
pathPackage "path"
8+
"sync"
9+
)
10+
11+
// I'm not cetain that we need a mutex because exempted routes are generally
12+
// configured when the application starts and the list is read-only after.
13+
type globPath struct {
14+
sync.RWMutex
15+
list []string
16+
}
17+
18+
var (
19+
exemptionsFullPath = struct {
20+
sync.RWMutex
21+
list map[string]struct{}
22+
} {
23+
list: make(map[string]struct{}),
24+
}
25+
26+
exemptionsGlobs globPath
27+
)
28+
29+
// Checks if given path is exempt from CSRF checks.
30+
func IsExempted(path string) bool {
31+
exemptionsFullPath.RLock()
32+
_, found := exemptionsFullPath.list[path]
33+
exemptionsFullPath.RUnlock()
34+
if found {
35+
glog.V(2).Infof("REVEL-CSRF: Ignoring exempted route '%s'...", path)
36+
return true
37+
}
38+
39+
for _, glob := range exemptionsGlobs.list {
40+
exemptionsGlobs.RLock()
41+
found, err := pathPackage.Match(glob, path)
42+
exemptionsGlobs.RUnlock()
43+
if err != nil {
44+
// See http://golang.org/pkg/path/#Match for error description.
45+
panic(fmt.Sprintf("REVEL-CSRF: malformed glob pattern: %#v", err))
46+
}
47+
if found {
48+
glog.V(2).Infof("REVEL-CSRF: Ignoring exempted route '%s'...", path)
49+
return true
50+
}
51+
}
52+
return false
53+
}
54+
55+
// Exempts an exact path from CSRF checks.
56+
func ExemptedFullPath(path string) {
57+
glog.V(2).Infof("REVEL-CSRF: Adding exemption '%s'...", path)
58+
exemptionsFullPath.Lock()
59+
exemptionsFullPath.list[path] = struct{}{}
60+
exemptionsFullPath.Unlock()
61+
}
62+
63+
func ExemptedFullPaths(paths ...string) {
64+
for _, v := range paths {
65+
ExemptedFullPath(v)
66+
}
67+
}
68+
69+
// Exempts a path from CSRF checks using pattern matching.
70+
// See http://golang.org/pkg/path/#Match
71+
func ExemptedGlob(path string) {
72+
glog.V(2).Infof("REVEL-CSRF: Adding exemption GLOB '%s'...", path)
73+
exemptionsGlobs.Lock()
74+
exemptionsGlobs.list = append(exemptionsGlobs.list, path)
75+
exemptionsGlobs.Unlock()
76+
}
77+
78+
func ExemptedGlobs(paths ...string) {
79+
for _, v := range paths {
80+
ExemptedGlob(v)
81+
}
82+
}

exemptions_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package csrf
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestExemptedFullPath(t *testing.T) {
8+
//hand := New(nil)
9+
path := "/Hello"
10+
11+
ExemptedFullPath(path)
12+
if !IsExempted(path) {
13+
t.Errorf("%v is not exempted, but it should be", path)
14+
}
15+
16+
other := "/Goodbye"
17+
if IsExempted(other) {
18+
t.Errorf("%v is exempted, but it shouldn't be", other)
19+
}
20+
}
21+
22+
func TestExemptedFullPaths(t *testing.T) {
23+
//hand := New(nil)
24+
paths := []string{"/home", "/news", "/help"}
25+
ExemptedFullPaths(paths...)
26+
27+
for _, v := range paths {
28+
if !IsExempted(v) {
29+
t.Errorf("%v should be exempted, but it isn't", v)
30+
}
31+
}
32+
33+
other := "/accounts"
34+
35+
if IsExempted(other) {
36+
t.Errorf("%v is exempted, but it shouldn't be")
37+
}
38+
}
39+
40+
func TestExemptedGlob(t *testing.T) {
41+
//hand := New(nil)
42+
glob := "/[m-n]ail"
43+
44+
ExemptedGlob(glob)
45+
46+
test := "/mail"
47+
if !IsExempted(test) {
48+
t.Errorf("%v should be exempted, but it isn't.", test)
49+
}
50+
51+
test = "/nail"
52+
if !IsExempted(test) {
53+
t.Errorf("%v should be exempted, but it isn't.", test)
54+
}
55+
56+
test = "/snail"
57+
if IsExempted(test) {
58+
t.Errorf("%v should not be exempted, but it is.", test)
59+
}
60+
61+
test = "/mail/outbox"
62+
if IsExempted(test) {
63+
t.Errorf("%v should not be exempted, but it is.", test)
64+
}
65+
}
66+
67+
func TestExemptedGlobs(t *testing.T) {
68+
slice := []string{"/", "/accounts/*", "/post/?*"}
69+
matching := []string{"/", "/accounts/", "/accounts/johndoe", "/post/1", "/post/123"}
70+
71+
nonMatching := []string{"", "/accounts",
72+
// Glob's * and ? don't match a forward slash.
73+
"/accounts/johndoe/posts",
74+
"/post/",
75+
}
76+
77+
//hand := New(nil)
78+
ExemptedGlobs(slice...)
79+
80+
for _, v := range matching {
81+
if !IsExempted(v) {
82+
t.Error("%v should be exempted, but it isn't.")
83+
}
84+
}
85+
86+
for _, v := range nonMatching {
87+
if IsExempted(v) {
88+
t.Error("%v shouldn't be exempted, but it is")
89+
}
90+
}
91+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{{set . "title" "Home"}}
2+
{{template "header.html" .}}
3+
4+
<header class="hero-unit" style="background-color:#A9F16C">
5+
<div class="container">
6+
<div class="row">
7+
<div class="hero-text">
8+
<h1>{{if .name}}Hello {{ .name }}{{else}}Hello anonymous user{{end}}</h1>
9+
<p></p>
10+
</div>
11+
</div>
12+
</div>
13+
</header>
14+
15+
<div class="container">
16+
<div class="row">
17+
<div class="span6">
18+
{{template "flash.html" .}}
19+
</div>
20+
</div>
21+
<div class="row">
22+
<h2>This route is exempted from CSRF checks.</h2>
23+
<p>
24+
See <b>app/init.go</b>: csrf.ExemptedGlob("/Hello[0-9]?3/Exempted")
25+
</p>
26+
</div>
27+
<div class="row">
28+
<p>
29+
Clicking on the Go Back link will trigger generation of a new index
30+
page and reset the CSRF token to a valid value. Click on your browser's
31+
Back button if you want to keep the altered CSRF token. This behaviour
32+
is caused by the demo implementation and does not exhibits any bug in
33+
revel-csrf.
34+
</p>
35+
<p>
36+
<b>Note:</b> Clicking on Go Back is your best option if you reached
37+
this page through an AJAX call. But that will reset the CSRF token to
38+
a valid value!
39+
</p>
40+
</div>
41+
<div class="row">
42+
<p>{{.help1}}</p>
43+
<p>{{.help2}}</p>
44+
</div>
45+
<div class="row">
46+
<div class="span12">
47+
<a href="/">Go Back</a>
48+
</div>
49+
</div>
50+
</div>
51+
52+
{{template "footer.html" .}}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy