Skip to content

Commit bdf5801

Browse files
committed
general: add init version
1 parent c29dc0d commit bdf5801

File tree

14 files changed

+966
-0
lines changed

14 files changed

+966
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.idea
2+
vendor

Gopkg.lock

Lines changed: 70 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Gopkg.toml example
2+
#
3+
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
4+
# for detailed Gopkg.toml documentation.
5+
#
6+
# required = ["github.com/user/thing/cmd/thing"]
7+
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
8+
#
9+
# [[constraint]]
10+
# name = "github.com/user/project"
11+
# version = "1.0.0"
12+
#
13+
# [[constraint]]
14+
# name = "github.com/user/project2"
15+
# branch = "dev"
16+
# source = "github.com/myfork/project2"
17+
#
18+
# [[override]]
19+
# name = "github.com/x/y"
20+
# version = "2.4.0"
21+
#
22+
# [prune]
23+
# non-go = false
24+
# go-tests = true
25+
# unused-packages = true
26+
27+
28+
[[constraint]]
29+
name = "github.com/AndrewSamokhvalov/go-spew"
30+
version = "1.1.0"
31+
32+
[[constraint]]
33+
branch = "master"
34+
name = "github.com/bitlum/backend"
35+
36+
[[constraint]]
37+
name = "github.com/go-errors/errors"
38+
version = "1.0.0"
39+
40+
[[constraint]]
41+
name = "gopkg.in/macaroon-bakery.v2"
42+
version = "2.0.1"
43+
44+
[[constraint]]
45+
branch = "v1"
46+
name = "gopkg.in/macaroon.v1"
47+
48+
[[constraint]]
49+
name = "gopkg.in/macaroon.v2"
50+
version = "2.0.0"
51+
52+
[prune]
53+
go-tests = true
54+
unused-packages = true

auth.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package auth
2+
3+
import (
4+
"strconv"
5+
"encoding/binary"
6+
"gopkg.in/macaroon.v2"
7+
)
8+
9+
const (
10+
UserPrefix = "user"
11+
NoncePrefix = "nonce"
12+
DisabledOperationPrefix = "disops"
13+
TimePrefix = "time"
14+
)
15+
16+
// Auth is an application authenticator which implements the auth.
17+
// Auth and used for issuing and checking the validity of third-party tokens.
18+
// Third-party token usually is used by trading bots, and wallet applications,
19+
// they not have expiration time, but do have a set of permitted operations,
20+
// which might be or might be not restricted down to read operations,
21+
// or info operations. This type of token by default do not have a right to
22+
// issue another applications tokens.
23+
type Auth struct {
24+
rootKey []byte
25+
nonceDB NonceDB
26+
location string
27+
28+
// TODO(andrew.shvv) Add token revocation.
29+
}
30+
31+
// NewAuth creates new instance of application auth.
32+
func NewAuth(location string, nonceDB NonceDB) *Auth {
33+
return &Auth{
34+
nonceDB: nonceDB,
35+
location: location,
36+
// TODO(andrew.shvv) add root recycling.
37+
rootKey: []byte("2871tgylio"),
38+
}
39+
}
40+
41+
// GenerateToken issues the token with the user id and operations
42+
// constraints, this token do not have a nonce and time by default,
43+
// so it could be used by client infinitely. Client in other hand is responsible
44+
// for adding the nonce and time constraints to ensure that even if token
45+
// will be intercepted by an attacker he/she couldn't use it for replay attack.
46+
// Token without nonce and time will be discarded during validation operation.
47+
func (a *Auth) GenerateToken(userID uint32,
48+
disabledOperations []string) (string, error) {
49+
50+
// TODO(andrew.shvv) Use application id instead,
51+
// but that would require some form of database.
52+
var macaroonID [4]byte
53+
binary.BigEndian.PutUint32(macaroonID[:], userID)
54+
55+
m, err := macaroon.New(a.rootKey, macaroonID[:], a.location,
56+
macaroon.LatestVersion)
57+
if err != nil {
58+
return "", err
59+
}
60+
61+
if disabledOperations != nil {
62+
m, err = DisableOperations(m, disabledOperations)
63+
if err != nil {
64+
return "", err
65+
}
66+
}
67+
68+
// Convert macaroon to check that it not contains any duplicate fields and
69+
// also in order to put the user id in it.
70+
md, err := NewMacaroonDictionary(m)
71+
if err != nil {
72+
return "", nil
73+
}
74+
75+
// Put user id so that latter extract it from macaroon. As far as macaroon
76+
// is signed and later validated by us with our root key we treat user id
77+
// information as something which couldn't be changed.
78+
userIDStr := strconv.FormatUint(uint64(userID), 10)
79+
if err := md.Put(UserPrefix, userIDStr); err != nil {
80+
return "", err
81+
}
82+
83+
return EncodeMacaroon(m)
84+
}

auth_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package auth
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestMacaroon(t *testing.T) {
8+
auth := NewAuth("", InMemoryNonceDB{})
9+
10+
// Emulate generation token on the server, with the user id taken from other
11+
// token, for example jwt.
12+
tokenStr, err := auth.GenerateToken(100, []string{"disabled"})
13+
if err != nil {
14+
t.Fatalf("unable to generate macaroon token: %v", err)
15+
}
16+
17+
// Emulate that client received the token, and now want to make some
18+
// operation on the server, he has to add time and nonce constraints,
19+
// before making an operation, otherwise he/she under threat of replay-attack.
20+
m, err := DecodeMacaroon(tokenStr)
21+
if err != nil {
22+
t.Fatalf("unable to decode macaroon: %v", err)
23+
}
24+
25+
m, err = AddNonce(m, 10)
26+
if err != nil {
27+
t.Fatalf("unable to add nonce: %v", err)
28+
}
29+
30+
m, err = AddCurrentTime(m)
31+
if err != nil {
32+
t.Fatalf("unable to add current time: %v", err)
33+
}
34+
35+
tokenStr, err = EncodeMacaroon(m)
36+
if err != nil {
37+
t.Fatalf("unable to encode macaroon")
38+
}
39+
40+
// Emulate that server received the macaroon and validating it and also
41+
// check that operation is permitted.
42+
token, err := auth.ExtractToken(tokenStr)
43+
if err != nil {
44+
t.Fatalf("operation should be not allowed")
45+
}
46+
47+
if err = token.IsAuthorized("disabled"); err != ErrOperNotAllowed {
48+
t.Fatalf("operation should be not allowed")
49+
}
50+
}

errors.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package auth
2+
3+
import "github.com/go-errors/errors"
4+
5+
var (
6+
ErrFieldNotFound = errors.Errorf("unable to find field")
7+
ErrFieldExist = errors.Errorf("field already exist")
8+
ErrRepeatedField = errors.Errorf("repeated conditions")
9+
10+
ErrMacaroonExpired = errors.Errorf("macaroon expired")
11+
ErrNonceRepeated = errors.Errorf("nonce is used already")
12+
13+
ErrOperNotAllowed = errors.Errorf("operation not allowed")
14+
)

0 commit comments

Comments
 (0)