Skip to content

Commit 0cda546

Browse files
committed
Merge branch 'v2-alpha'
2 parents d9638a2 + 91bb3ed commit 0cda546

File tree

15 files changed

+465
-227
lines changed

15 files changed

+465
-227
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ Copyright (c) 2013-2014 Antoine Imbert
88

99
[MIT License](https://github.com/ant0ine/go-json-rest-examples/blob/master/LICENSE)
1010

11-
[![Analytics](https://ga-beacon.appspot.com/UA-309210-4/go-json-rest-examples/readme)](https://github.com/igrigorik/ga-beacon)
11+
[![Analytics](https://ga-beacon.appspot.com/UA-309210-4/go-json-rest-examples/v2-alpha/readme)](https://github.com/igrigorik/ga-beacon)

auth-basic-custom/main.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* Demonstrate how to implement a custom AuthBasic middleware, used to protect all endpoints.
2+
3+
This is a very simple version supporting only one user.
4+
5+
The curl demo:
6+
7+
curl -i http://127.0.0.1:8080/countries
8+
9+
*/
10+
package main
11+
12+
import (
13+
"encoding/base64"
14+
"errors"
15+
"github.com/ant0ine/go-json-rest/rest"
16+
"net/http"
17+
"strings"
18+
)
19+
20+
type MyAuthBasicMiddleware struct {
21+
Realm string
22+
UserId string
23+
Password string
24+
}
25+
26+
func (mw *MyAuthBasicMiddleware) MiddlewareFunc(handler rest.HandlerFunc) rest.HandlerFunc {
27+
return func(writer rest.ResponseWriter, request *rest.Request) {
28+
29+
authHeader := request.Header.Get("Authorization")
30+
if authHeader == "" {
31+
mw.unauthorized(writer)
32+
return
33+
}
34+
35+
providedUserId, providedPassword, err := mw.decodeBasicAuthHeader(authHeader)
36+
37+
if err != nil {
38+
rest.Error(writer, "Invalid authentication", http.StatusBadRequest)
39+
return
40+
}
41+
42+
if !(providedUserId == mw.UserId && providedPassword == mw.Password) {
43+
mw.unauthorized(writer)
44+
return
45+
}
46+
47+
handler(writer, request)
48+
}
49+
}
50+
51+
func (mw *MyAuthBasicMiddleware) unauthorized(writer rest.ResponseWriter) {
52+
writer.Header().Set("WWW-Authenticate", "Basic realm="+mw.Realm)
53+
rest.Error(writer, "Not Authorized", http.StatusUnauthorized)
54+
}
55+
56+
func (mw *MyAuthBasicMiddleware) decodeBasicAuthHeader(header string) (user string, password string, err error) {
57+
58+
parts := strings.SplitN(header, " ", 2)
59+
if !(len(parts) == 2 && parts[0] == "Basic") {
60+
return "", "", errors.New("Invalid authentication")
61+
}
62+
63+
decoded, err := base64.StdEncoding.DecodeString(parts[1])
64+
if err != nil {
65+
return "", "", errors.New("Invalid base64")
66+
}
67+
68+
creds := strings.SplitN(string(decoded), ":", 2)
69+
if len(creds) != 2 {
70+
return "", "", errors.New("Invalid authentication")
71+
}
72+
73+
return creds[0], creds[1], nil
74+
}
75+
76+
func main() {
77+
78+
handler := rest.ResourceHandler{
79+
PreRoutingMiddlewares: []rest.Middleware{
80+
&MyAuthBasicMiddleware{
81+
Realm: "Administration",
82+
UserId: "admin",
83+
Password: "admin",
84+
},
85+
},
86+
}
87+
handler.SetRoutes(
88+
&rest.Route{"GET", "/countries", GetAllCountries},
89+
)
90+
http.ListenAndServe(":8080", &handler)
91+
}
92+
93+
type Country struct {
94+
Code string
95+
Name string
96+
}
97+
98+
func GetAllCountries(w rest.ResponseWriter, r *rest.Request) {
99+
w.WriteJson(
100+
[]Country{
101+
Country{
102+
Code: "FR",
103+
Name: "France",
104+
},
105+
Country{
106+
Code: "US",
107+
Name: "United States",
108+
},
109+
},
110+
)
111+
}

auth-basic/main.go

Lines changed: 16 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,45 @@
1-
/* Demonstrate a possible global Basic Auth implementation
1+
/* Demonstrate how to setup AuthBasicMiddleware as a pre-routing middleware.
22
3-
The Curl Demo:
3+
The curl demo:
44
55
curl -i http://127.0.0.1:8080/countries
6+
curl -i -u admin:admin http://127.0.0.1:8080/countries
67
78
*/
89
package main
910

1011
import (
11-
"encoding/base64"
12-
"errors"
13-
"github.com/ant0ine/go-json-rest"
12+
"github.com/ant0ine/go-json-rest/rest"
1413
"net/http"
15-
"strings"
1614
)
1715

1816
func main() {
1917

2018
handler := rest.ResourceHandler{
21-
PreRoutingMiddleware: func(handler rest.HandlerFunc) rest.HandlerFunc {
22-
23-
realm := "Administration"
24-
userId := "admin"
25-
password := "admin"
26-
27-
return func(writer *rest.ResponseWriter, request *rest.Request) {
28-
29-
authHeader := request.Header.Get("Authorization")
30-
if authHeader == "" {
31-
Unauthorized(writer, realm)
32-
return
33-
}
34-
35-
providedUserId, providedPassword, err := DecodeBasicAuthHeader(authHeader)
36-
37-
if err != nil {
38-
rest.Error(writer, "Invalid authentication", http.StatusBadRequest)
39-
return
40-
}
41-
42-
if !(providedUserId == userId && providedPassword == password) {
43-
Unauthorized(writer, realm)
44-
return
45-
}
46-
47-
handler(writer, request)
48-
}
19+
PreRoutingMiddlewares: []rest.Middleware{
20+
&rest.AuthBasicMiddleware{
21+
Realm: "test zone",
22+
Authenticator: func(userId string, password string) bool {
23+
if userId == "admin" && password == "admin" {
24+
return true
25+
}
26+
return false
27+
},
28+
},
4929
},
5030
}
5131
handler.SetRoutes(
52-
rest.Route{"GET", "/countries", GetAllCountries},
32+
&rest.Route{"GET", "/countries", GetAllCountries},
5333
)
5434
http.ListenAndServe(":8080", &handler)
5535
}
5636

57-
func Unauthorized(writer *rest.ResponseWriter, realm string) {
58-
writer.Header().Set("WWW-Authenticate", "Basic realm="+realm)
59-
rest.Error(writer, "Not Authorized", http.StatusUnauthorized)
60-
}
61-
62-
func DecodeBasicAuthHeader(header string) (user string, password string, err error) {
63-
64-
parts := strings.SplitN(header, " ", 2)
65-
if !(len(parts) == 2 && parts[0] == "Basic") {
66-
return "", "", errors.New("Invalid authentication")
67-
}
68-
69-
decoded, err := base64.StdEncoding.DecodeString(parts[1])
70-
if err != nil {
71-
return "", "", errors.New("Invalid base64")
72-
}
73-
74-
creds := strings.SplitN(string(decoded), ":", 2)
75-
if len(creds) != 2 {
76-
return "", "", errors.New("Invalid authentication")
77-
}
78-
79-
return creds[0], creds[1], nil
80-
}
81-
8237
type Country struct {
8338
Code string
8439
Name string
8540
}
8641

87-
func GetAllCountries(w *rest.ResponseWriter, r *rest.Request) {
42+
func GetAllCountries(w rest.ResponseWriter, r *rest.Request) {
8843
w.WriteJson(
8944
[]Country{
9045
Country{

cors-custom/main.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/* Demonstrate how to implement a custom CORS middleware, used to on all endpoints.
2+
3+
The curl demo:
4+
5+
curl -i http://127.0.0.1:8080/countries
6+
7+
*/
8+
package main
9+
10+
import (
11+
"github.com/ant0ine/go-json-rest/rest"
12+
"net/http"
13+
)
14+
15+
type MyCorsMiddleware struct{}
16+
17+
func (mw *MyCorsMiddleware) MiddlewareFunc(handler rest.HandlerFunc) rest.HandlerFunc {
18+
return func(writer rest.ResponseWriter, request *rest.Request) {
19+
20+
corsInfo := request.GetCorsInfo()
21+
22+
// Be nice with non CORS requests, continue
23+
// Alternatively, you may also chose to only allow CORS requests, and return an error.
24+
if !corsInfo.IsCors {
25+
// continure, execute the wrapped middleware
26+
handler(writer, request)
27+
return
28+
}
29+
30+
// Validate the Origin
31+
// More sophisticated validations can be implemented, regexps, DB lookups, ...
32+
if corsInfo.Origin != "http://my.other.host" {
33+
rest.Error(writer, "Invalid Origin", http.StatusForbidden)
34+
return
35+
}
36+
37+
if corsInfo.IsPreflight {
38+
// check the request methods
39+
allowedMethods := map[string]bool{
40+
"GET": true,
41+
"POST": true,
42+
"PUT": true,
43+
// don't allow DELETE, for instance
44+
}
45+
if !allowedMethods[corsInfo.AccessControlRequestMethod] {
46+
rest.Error(writer, "Invalid Preflight Request", http.StatusForbidden)
47+
return
48+
}
49+
// check the request headers
50+
allowedHeaders := map[string]bool{
51+
"Accept": true,
52+
"Content-Type": true,
53+
"X-Custom-Header": true,
54+
}
55+
for _, requestedHeader := range corsInfo.AccessControlRequestHeaders {
56+
if !allowedHeaders[requestedHeader] {
57+
rest.Error(writer, "Invalid Preflight Request", http.StatusForbidden)
58+
return
59+
}
60+
}
61+
62+
for allowedMethod, _ := range allowedMethods {
63+
writer.Header().Add("Access-Control-Allow-Methods", allowedMethod)
64+
}
65+
for allowedHeader, _ := range allowedHeaders {
66+
writer.Header().Add("Access-Control-Allow-Headers", allowedHeader)
67+
}
68+
writer.Header().Set("Access-Control-Allow-Origin", corsInfo.Origin)
69+
writer.Header().Set("Access-Control-Allow-Credentials", "true")
70+
writer.Header().Set("Access-Control-Max-Age", "3600")
71+
writer.WriteHeader(http.StatusOK)
72+
return
73+
} else {
74+
writer.Header().Set("Access-Control-Expose-Headers", "X-Powered-By")
75+
writer.Header().Set("Access-Control-Allow-Origin", corsInfo.Origin)
76+
writer.Header().Set("Access-Control-Allow-Credentials", "true")
77+
// continure, execute the wrapped middleware
78+
handler(writer, request)
79+
return
80+
}
81+
}
82+
}
83+
84+
func main() {
85+
86+
handler := rest.ResourceHandler{
87+
PreRoutingMiddlewares: []rest.Middleware{
88+
&MyCorsMiddleware{},
89+
},
90+
}
91+
handler.SetRoutes(
92+
&rest.Route{"GET", "/countries", GetAllCountries},
93+
)
94+
http.ListenAndServe(":8080", &handler)
95+
}
96+
97+
type Country struct {
98+
Code string
99+
Name string
100+
}
101+
102+
func GetAllCountries(w rest.ResponseWriter, r *rest.Request) {
103+
w.WriteJson(
104+
[]Country{
105+
Country{
106+
Code: "FR",
107+
Name: "France",
108+
},
109+
Country{
110+
Code: "US",
111+
Name: "United States",
112+
},
113+
},
114+
)
115+
}

0 commit comments

Comments
 (0)