@@ -103,12 +103,13 @@ type userInteractiveFlow struct {
103
103
// the user already has a valid access token, but we want to double-check
104
104
// that it isn't stolen by re-authenticating them.
105
105
type UserInteractive struct {
106
- sync.RWMutex
107
- Flows []userInteractiveFlow
106
+ flows []userInteractiveFlow
108
107
// Map of login type to implementation
109
- Types map [string ]Type
108
+ types map [string ]Type
110
109
// Map of session ID to completed login types, will need to be extended in future
111
- Sessions map [string ][]string
110
+
111
+ mutex sync.RWMutex
112
+ sessions map [string ][]string
112
113
}
113
114
114
115
func NewUserInteractive (userAccountAPI api.UserLoginAPI , cfg * config.ClientAPI ) * UserInteractive {
@@ -117,22 +118,20 @@ func NewUserInteractive(userAccountAPI api.UserLoginAPI, cfg *config.ClientAPI)
117
118
Config : cfg ,
118
119
}
119
120
return & UserInteractive {
120
- Flows : []userInteractiveFlow {
121
+ flows : []userInteractiveFlow {
121
122
{
122
123
Stages : []string {typePassword .Name ()},
123
124
},
124
125
},
125
- Types : map [string ]Type {
126
+ types : map [string ]Type {
126
127
typePassword .Name (): typePassword ,
127
128
},
128
- Sessions : make (map [string ][]string ),
129
+ sessions : make (map [string ][]string ),
129
130
}
130
131
}
131
132
132
133
func (u * UserInteractive ) IsSingleStageFlow (authType string ) bool {
133
- u .RLock ()
134
- defer u .RUnlock ()
135
- for _ , f := range u .Flows {
134
+ for _ , f := range u .flows {
136
135
if len (f .Stages ) == 1 && f .Stages [0 ] == authType {
137
136
return true
138
137
}
@@ -141,10 +140,10 @@ func (u *UserInteractive) IsSingleStageFlow(authType string) bool {
141
140
}
142
141
143
142
func (u * UserInteractive ) AddCompletedStage (sessionID , authType string ) {
144
- u .Lock ()
143
+ u .mutex . Lock ()
145
144
// TODO: Handle multi-stage flows
146
- delete (u .Sessions , sessionID )
147
- u .Unlock ()
145
+ delete (u .sessions , sessionID )
146
+ u .mutex . Unlock ()
148
147
}
149
148
150
149
type Challenge struct {
@@ -157,10 +156,11 @@ type Challenge struct {
157
156
158
157
// Challenge returns an HTTP 401 with the supported flows for authenticating
159
158
func (u * UserInteractive ) challenge (sessionID string ) * util.JSONResponse {
160
- u .RLock ()
161
- completed := u .Sessions [sessionID ]
162
- flows := u .Flows
163
- u .RUnlock ()
159
+ u .mutex .RLock ()
160
+ completed := u .sessions [sessionID ]
161
+ u .mutex .RUnlock ()
162
+
163
+ flows := u .flows
164
164
165
165
return & util.JSONResponse {
166
166
Code : 401 ,
@@ -183,9 +183,9 @@ func (u *UserInteractive) NewSession() *util.JSONResponse {
183
183
JSON : spec.InternalServerError {},
184
184
}
185
185
}
186
- u .Lock ()
187
- u .Sessions [sessionID ] = []string {}
188
- u .Unlock ()
186
+ u .mutex . Lock ()
187
+ u .sessions [sessionID ] = []string {}
188
+ u .mutex . Unlock ()
189
189
return u .challenge (sessionID )
190
190
}
191
191
@@ -233,9 +233,7 @@ func (u *UserInteractive) Verify(ctx context.Context, bodyBytes []byte, device *
233
233
// extract the type so we know which login type to use
234
234
authType := gjson .GetBytes (bodyBytes , "auth.type" ).Str
235
235
236
- u .RLock ()
237
- loginType , ok := u .Types [authType ]
238
- u .RUnlock ()
236
+ loginType , ok := u .types [authType ]
239
237
240
238
if ! ok {
241
239
return nil , & util.JSONResponse {
@@ -247,9 +245,9 @@ func (u *UserInteractive) Verify(ctx context.Context, bodyBytes []byte, device *
247
245
// retrieve the session
248
246
sessionID := gjson .GetBytes (bodyBytes , "auth.session" ).Str
249
247
250
- u .RLock ()
251
- _ , ok = u .Sessions [sessionID ]
252
- u .RUnlock ()
248
+ u .mutex . RLock ()
249
+ _ , ok = u .sessions [sessionID ]
250
+ u .mutex . RUnlock ()
253
251
254
252
if ! ok {
255
253
// if the login type is part of a single stage flow then allow them to omit the session ID
0 commit comments