/
auth.go
156 lines (141 loc) · 4.59 KB
/
auth.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
146
147
148
149
150
151
152
153
154
155
156
package rpc2
import (
"context"
"github.com/netauth/netauth/pkg/token"
types "github.com/netauth/protocol"
pb "github.com/netauth/protocol/v2"
)
// AuthEntity handles the process of actually authenticating an
// entity, but does not issue a token.
func (s *Server) AuthEntity(ctx context.Context, r *pb.AuthRequest) (*pb.Empty, error) {
e := r.GetEntity()
if err := s.ValidateSecret(ctx, e.GetID(), r.GetSecret()); err != nil {
s.log.Info("Authentication Failed",
"entity", e.GetID(),
"service", getServiceName(ctx),
"client", getClientName(ctx))
return &pb.Empty{}, ErrUnauthenticated
}
s.log.Info("Authentication Succeeded",
"entity", e.GetID(),
"service", getServiceName(ctx),
"client", getClientName(ctx))
return &pb.Empty{}, nil
}
// AuthGetToken performs entity authentication and issues a token if
// this authentication is successful.
func (s *Server) AuthGetToken(ctx context.Context, r *pb.AuthRequest) (*pb.AuthResult, error) {
// Check Authentication using the same flow as above.
_, err := s.AuthEntity(ctx, r)
if err != nil {
return &pb.AuthResult{}, err
}
caps := s.getCapabilitiesForEntity(ctx, *r.Entity.ID)
// Generate Token
tkn, err := s.Generate(
token.Claims{
EntityID: r.GetEntity().GetID(),
Capabilities: caps,
},
token.GetConfig(),
)
if err != nil {
s.log.Warn("Error Issuing Token",
"entity", r.GetEntity().GetID(),
"capabilities", caps,
"service", getServiceName(ctx),
"client", getClientName(ctx),
"error", err,
)
return &pb.AuthResult{}, ErrInternal
}
s.log.Info("Token Issued",
"entity", r.GetEntity().GetID(),
"capabilities", caps,
"service", getServiceName(ctx),
"client", getClientName(ctx),
)
return &pb.AuthResult{Token: &tkn}, nil
}
// AuthValidateToken performs server-side verification of a previously
// issued token. This allows symmetric token algorithms to be used.
func (s *Server) AuthValidateToken(ctx context.Context, r *pb.AuthRequest) (*pb.Empty, error) {
if _, err := s.Validate(r.GetToken()); err != nil {
return &pb.Empty{}, ErrUnauthenticated
}
return &pb.Empty{}, nil
}
// AuthChangeSecret handles the process of rotating out a stored
// secret for an entity. This is only appropriate for use in the case
// where NetAuth is maintaining total knowledge of secrets, if this is
// not the case you may need to alter secrets in an external system.
// There are two possible flows depending on if the entity is trying
// to change its own secret or not. In the first case, the entity
// must be in possession of the original secret, not just a token. In
// the latter case, the token must have CHANGE_ENTITY_SECRET to
// succeed.
func (s *Server) AuthChangeSecret(ctx context.Context, r *pb.AuthRequest) (*pb.Empty, error) {
e := r.GetEntity()
// While technically a non-local secret database would allow
// this to proceed, we instead require that mutating requests
// always hit a fully writeable server.
if s.readonly {
s.log.Warn("Mutable request in read-only mode!",
"method", "AuthChangeSecret",
"client", getClientName(ctx),
"service", getServiceName(ctx),
)
return &pb.Empty{}, ErrReadOnly
}
// Token validation and authorization
var err error
ctx, err = s.checkToken(ctx)
if err != nil {
s.log.Warn("Permissions Denied for AuthChangeSecret",
"entity", e.GetID(),
"service", getServiceName(ctx),
"client", getClientName(ctx),
"error", err)
return &pb.Empty{}, err
}
// Changing for self, must have the original secret
if getTokenClaims(ctx).EntityID == e.GetID() {
if err := s.ValidateSecret(ctx, e.GetID(), e.GetSecret()); err != nil {
s.log.Info("Permission Denied for AuthChangeSecret",
"modself", true,
"entity", e.GetID(),
"authority", getTokenClaims(ctx).EntityID,
"service", getServiceName(ctx),
"client", getClientName(ctx),
)
return &pb.Empty{}, ErrUnauthenticated
}
} else {
if err := s.isAuthorized(ctx, types.Capability_CHANGE_ENTITY_SECRET); err != nil {
s.log.Info("Permission Denied for AuthChangeSecret",
"modself", false,
"entity", e.GetID(),
"authority", getTokenClaims(ctx).EntityID,
"service", getServiceName(ctx),
"client", getClientName(ctx),
)
return &pb.Empty{}, err
}
}
// Set the secret
if err := s.SetSecret(ctx, e.GetID(), r.GetSecret()); err != nil {
s.log.Warn("Secret Manipulation Error",
"entity", e.GetID(),
"service", getServiceName(ctx),
"client", getClientName(ctx),
"error", err,
)
return &pb.Empty{}, ErrInternal
}
s.log.Info("Secret Changed",
"entity", e.GetID(),
"service", getServiceName(ctx),
"client", getClientName(ctx),
)
return &pb.Empty{}, nil
}