forked from goadesign/goa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
security.go
223 lines (202 loc) · 5.66 KB
/
security.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
package expr
import (
"fmt"
"net/url"
"goa.design/goa/eval"
)
// SchemeKind is a type of security scheme.
type SchemeKind int
const (
// OAuth2Kind identifies a "OAuth2" security scheme.
OAuth2Kind SchemeKind = iota + 1
// BasicAuthKind means "basic" security scheme.
BasicAuthKind
// APIKeyKind means "apiKey" security scheme.
APIKeyKind
// JWTKind means an "JWT" security scheme, with support for
// TokenPath and Scopes.
JWTKind
// NoKind means to have no security for this endpoint.
NoKind
)
// FlowKind is a type of OAuth2 flow.
type FlowKind int
const (
// AuthorizationCodeFlowKind identifies a OAuth2 authorization code
// flow.
AuthorizationCodeFlowKind FlowKind = iota + 1
// ImplicitFlowKind identifiers a OAuth2 implicit flow.
ImplicitFlowKind
// PasswordFlowKind identifies a Resource Owner Password flow.
PasswordFlowKind
// ClientCredentialsFlowKind identifies a OAuth Client Credentials flow.
ClientCredentialsFlowKind
)
type (
// SecurityExpr defines a security requirement.
SecurityExpr struct {
// Schemes is the list of security schemes used for this
// requirement.
Schemes []*SchemeExpr
// Scopes list the required scopes if any.
Scopes []string
}
// SchemeExpr defines a security scheme used to authenticate against the
// method being designed.
SchemeExpr struct {
// Kind is the sort of security scheme this object represents.
Kind SchemeKind
// SchemeName is the name of the security scheme, e.g. "googAuth",
// "my_big_token", "jwt".
SchemeName string
// Description describes the security scheme e.g. "Google OAuth2"
Description string
// In determines the location of the API key, one of "header" or
// "query".
In string
// Name refers to a header or parameter name, based on In's
// value.
Name string
// Scopes lists the Basic, APIKey, JWT or OAuth2 scopes.
Scopes []*ScopeExpr
// Flows determine the oauth2 flows supported by this scheme.
Flows []*FlowExpr
// Meta is a list of key/value pairs
Meta MetaExpr
}
// FlowExpr describes a specific OAuth2 flow.
FlowExpr struct {
// Kind is the kind of flow.
Kind FlowKind
// AuthorizationURL to be used for implicit or authorizationCode
// flows.
AuthorizationURL string
// TokenURL to be used for password, clientCredentials or
// authorizationCode flows.
TokenURL string
// RefreshURL to be used for obtaining refresh token.
RefreshURL string
}
// ScopeExpr defines a security scope.
ScopeExpr struct {
// Name of the scope.
Name string
// Description is the description of the scope.
Description string
}
)
// EvalName returns the generic definition name used in error messages.
func (s *SecurityExpr) EvalName() string {
var suffix string
if len(s.Schemes) > 0 && len(s.Schemes[0].SchemeName) > 0 {
suffix = "scheme " + s.Schemes[0].SchemeName
}
return "Security" + suffix
}
// DupRequirement creates a copy of the given security requirement.
func DupRequirement(req *SecurityExpr) *SecurityExpr {
dup := &SecurityExpr{
Scopes: req.Scopes,
Schemes: make([]*SchemeExpr, 0, len(req.Schemes)),
}
for _, s := range req.Schemes {
dup.Schemes = append(dup.Schemes, DupScheme(s))
}
return dup
}
// DupScheme creates a copy of the given scheme expression.
func DupScheme(sch *SchemeExpr) *SchemeExpr {
dup := SchemeExpr{
Kind: sch.Kind,
SchemeName: sch.SchemeName,
Description: sch.Description,
In: sch.In,
Scopes: sch.Scopes,
Flows: sch.Flows,
Meta: sch.Meta,
}
return &dup
}
// Type returns the type of the scheme.
func (s *SchemeExpr) Type() string {
switch s.Kind {
case OAuth2Kind:
return "OAuth2"
case BasicAuthKind:
return "BasicAuth"
case APIKeyKind:
return "APIKey"
case JWTKind:
return "JWT"
default:
panic(fmt.Sprintf("unknown scheme kind: %#v", s.Kind)) // bug
}
}
// EvalName returns the generic definition name used in error messages.
func (s *SchemeExpr) EvalName() string {
return s.Type() + "Security"
}
// Hash returns a unique hash value for s.
func (s *SchemeExpr) Hash() string {
return fmt.Sprintf("%s_%s_%s", s.SchemeName, s.In, s.Name)
}
// Validate ensures that the method payload contains attributes required
// by the scheme.
func (s *SchemeExpr) Validate() *eval.ValidationErrors {
verr := new(eval.ValidationErrors)
for _, f := range s.Flows {
if err := f.Validate(); err != nil {
verr.Merge(err)
}
}
return verr
}
// EvalName returns the name of the expression used in error messages.
func (f *FlowExpr) EvalName() string {
return "flow " + f.Type()
}
// Validate ensures that TokenURL and AuthorizationURL are valid URLs.
func (f *FlowExpr) Validate() *eval.ValidationErrors {
verr := new(eval.ValidationErrors)
if _, err := url.Parse(f.TokenURL); err != nil {
verr.Add(f, "invalid token URL %q: %s", f.TokenURL, err)
}
if _, err := url.Parse(f.AuthorizationURL); err != nil {
verr.Add(f, "invalid authorization URL %q: %s", f.AuthorizationURL, err)
}
if _, err := url.Parse(f.RefreshURL); err != nil {
verr.Add(f, "invalid refresh URL %q: %s", f.RefreshURL, err)
}
return verr
}
// Type returns the grant type of the OAuth2 grant.
func (f *FlowExpr) Type() string {
switch f.Kind {
case AuthorizationCodeFlowKind:
return "authorization_code"
case ImplicitFlowKind:
return "implicit"
case PasswordFlowKind:
return "password"
case ClientCredentialsFlowKind:
return "client_credentials"
default:
panic(fmt.Sprintf("unknown flow kind: %#v", f.Kind)) // bug
}
}
func (k SchemeKind) String() string {
switch k {
case BasicAuthKind:
return "Basic"
case APIKeyKind:
return "APIKey"
case JWTKind:
return "JWT"
case OAuth2Kind:
return "OAuth2"
case NoKind:
return "None"
default:
panic("unknown kind") // bug
}
}