forked from EmbeddedEnterprises/autobahnkreuz
-
Notifications
You must be signed in to change notification settings - Fork 0
/
resume.go
145 lines (129 loc) · 3.87 KB
/
resume.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package auth
import (
"context"
"crypto/rand"
"encoding/hex"
"errors"
"os"
"time"
"github.com/EmbeddedEnterprises/autobahnkreuz/util"
"github.com/deckarep/golang-set"
"github.com/gammazero/nexus/client"
"github.com/gammazero/nexus/wamp"
)
func randomHex(n int) (string, error) {
bytes := make([]byte, n)
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return hex.EncodeToString(bytes), nil
}
type token struct {
AuthID string
ExpireDate time.Time
}
// ResumeAuthenticator is an authenticator which performs authentication based
// on a previously created one-time-token.
// It is designed to be used with the normal ticket authenticator.
type ResumeAuthenticator struct {
SharedSecretAuthenticator
// Map from token -> Token
Tokens map[string]token
}
// NewResumeAuthenticator creates a new ResumeAuthenticator based on the given parameters
func NewResumeAuthenticator(authrolefunc string, realm string, invalidRoles mapset.Set) (*ResumeAuthenticator, error) {
x := &ResumeAuthenticator{
SharedSecretAuthenticator: SharedSecretAuthenticator{
AuthMethodValue: "resume",
InvalidAuthRoles: invalidRoles,
Realm: realm,
UpstreamGetAuthRolesFunc: authrolefunc,
},
Tokens: make(map[string]token),
}
return x, nil
}
// Initialize registers the create-new-token-endpoint
func (r *ResumeAuthenticator) Initialize() {
// Patched to ee to be similar to featureAuthorizer.
err := util.LocalClient.Register("ee.auth.create-token", r.createNewToken, wamp.Dict{})
if err != nil {
util.Logger.Criticalf("Failed to register create-token method!")
os.Exit(1)
}
}
func (r *ResumeAuthenticator) createNewToken(_ context.Context, args wamp.List, _, _ wamp.Dict) *client.InvokeResult {
if len(args) == 0 {
return &client.InvokeResult{
Err: wamp.ErrInvalidArgument,
}
}
authid, ok := wamp.AsString(args[0])
if !ok || authid == "" {
return &client.InvokeResult{
Err: wamp.ErrInvalidArgument,
}
}
userToken, err := randomHex(64)
if err != nil {
return &client.InvokeResult{
Err: wamp.URI("wamp.error.internal-error"),
}
}
r.Tokens[userToken] = token{
AuthID: authid,
ExpireDate: time.Now().Add(7 * 24 * time.Hour), // one week
}
return &client.InvokeResult{
Args: wamp.List{
userToken,
},
}
}
// Authenticate asks for the users ticket, checks the provided response with the
// list of previously created tokens.
func (r *ResumeAuthenticator) Authenticate(sid wamp.ID, details wamp.Dict, client wamp.Peer) (*wamp.Welcome, error) {
authid := wamp.OptionString(details, "authid")
if authid != "resume" {
return nil, errors.New("wamp.error.wrong-auth-id")
}
// Challenge Extra map is empty since the ticket challenge only asks for a
// ticket (using authmethod) and provides no additional challenge info.
err := client.Send(&wamp.Challenge{
AuthMethod: r.AuthMethod(),
Extra: wamp.Dict{},
})
if err != nil {
return nil, err
}
// Read AUTHENTICATE response from client.
// A timeout of 5 seconds should be enough for slow clients...
msg, err := wamp.RecvTimeout(client, 5*time.Second)
if err != nil {
return nil, err
}
authRsp, ok := msg.(*wamp.Authenticate)
if !ok {
util.Logger.Warningf("Protocol violation from %v: %v", client, msg.MessageType())
return nil, errors.New(string(wamp.ErrProtocolViolation))
}
token := authRsp.Signature
tokenObj, ok := r.Tokens[token]
delete(r.Tokens, token)
if !ok || time.Now().After(tokenObj.ExpireDate) {
return nil, errors.New("wamp.error.invalid-token")
}
authid = tokenObj.AuthID
util.Logger.Infof("Token login for user %v", authid)
newTokenRes := r.createNewToken(context.Background(), wamp.List{
authid,
}, nil, nil)
welcome, err := r.FetchAndFilterAuthRoles(authid)
if err != nil {
return nil, err
}
x, _ := wamp.AsDict(welcome.Details["authextra"])
x["resume-token"] = newTokenRes.Args[0]
welcome.Details["authextra"] = x
return welcome, nil
}