@@ -98,7 +98,7 @@ func (kc *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error)
98
98
}
99
99
100
100
func (kc * Client ) doAuthenticate (authCtx * authContext , loginDetails * creds.LoginDetails ) (string , error ) {
101
- authSubmitURL , authForm , err := kc .getLoginForm (loginDetails )
101
+ authSubmitURL , authForm , authCookies , err := kc .getLoginForm (loginDetails )
102
102
if err != nil {
103
103
return "" , errors .Wrap (err , "error retrieving login form from idp" )
104
104
}
@@ -131,18 +131,16 @@ func (kc *Client) doAuthenticate(authCtx *authContext, loginDetails *creds.Login
131
131
if err != nil {
132
132
return "" , errors .Wrap (err , "could not extract Webauthn parameters" )
133
133
}
134
-
135
134
webauthnSubmitURL , err := extractSubmitURL (doc )
136
135
if err != nil {
137
136
return "" , errors .Wrap (err , "unable to locate IDP Webauthn form submit URL" )
138
137
}
139
138
140
- doc , err = kc .postWebauthnForm (webauthnSubmitURL , credentialIDs , challenge , rpId )
139
+ doc , err = kc .postWebauthnForm (webauthnSubmitURL , credentialIDs , challenge , rpId , authCookies )
141
140
if err != nil {
142
141
return "" , errors .Wrap (err , "error posting Webauthn form" )
143
142
}
144
143
}
145
-
146
144
samlResponse , err := extractSamlResponse (doc )
147
145
if err != nil && authCtx .authenticatorIndexValid && passwordValid (doc , kc .authErrorValidator ) {
148
146
return kc .doAuthenticate (authCtx , loginDetails )
@@ -187,22 +185,58 @@ func extractWebauthnParameters(doc *goquery.Document) (credentialIDs []string, c
187
185
return credentialIDs , challenge , rpID , nil
188
186
}
189
187
190
- func (kc * Client ) getLoginForm (loginDetails * creds.LoginDetails ) (string , url.Values , error ) {
188
+ func (kc * Client ) getLoginForm (loginDetails * creds.LoginDetails ) (string , url.Values , [] * http. Cookie , error ) {
191
189
192
190
res , err := kc .client .Get (loginDetails .URL )
191
+
193
192
if err != nil {
194
- return "" , nil , errors .Wrap (err , "error retrieving form" )
193
+ return "" , nil , nil , errors .Wrap (err , "error retrieving form" )
195
194
}
196
195
197
196
doc , err := goquery .NewDocumentFromReader (res .Body )
198
197
if err != nil {
199
- return "" , nil , errors .Wrap (err , "failed to build document from response" )
198
+ return "" , nil , nil , errors .Wrap (err , "failed to build document from response" )
200
199
}
201
200
201
+ if loginDetails .KCBroker != "" {
202
+ log .Printf ("Attempting to parse federation chain using keycloak broker %v" , loginDetails .KCBroker )
203
+ KCFederationID := "#social-" + loginDetails .KCBroker
204
+ var path string
205
+ doc .Find (KCFederationID ).Each (func (i int , s * goquery.Selection ) {
206
+ href , ok := s .Attr ("href" )
207
+ if ! ok {
208
+ return
209
+ }
210
+ path = href
211
+ })
212
+ url , err := url .Parse (loginDetails .URL )
213
+ if err != nil {
214
+ return "" , nil , nil , errors .Wrap (err , "error parsing url for federation" )
215
+ }
216
+ new_url := "https://" + url .Hostname () + path
217
+ req , err := http .NewRequest ("GET" , new_url , nil )
218
+ if err != nil {
219
+ return "" , nil , nil , errors .Wrap (err , "error building federated request" )
220
+ }
221
+ for _ , cookie := range res .Cookies () {
222
+ req .AddCookie (cookie )
223
+ // log.Println("added cookie: %v to request", cookie)
224
+ }
225
+ res2 , err := kc .client .Get (new_url )
226
+ if err != nil {
227
+ return "" , nil , nil , errors .Wrap (err , "error retrieving federated form" )
228
+ }
229
+ doc2 , err := goquery .NewDocumentFromReader (res2 .Body )
230
+ if err != nil {
231
+ return "" , nil , nil , errors .Wrap (err , "failed to build federated document from response" )
232
+ }
233
+ doc = doc2
234
+ res = res2
235
+ }
202
236
if res .StatusCode == http .StatusUnauthorized {
203
237
authSubmitURL , err := extractSubmitURL (doc )
204
238
if err != nil {
205
- return "" , nil , errors .Wrap (err , "unable to locate IDP authentication form submit URL" )
239
+ return "" , nil , nil , errors .Wrap (err , "unable to locate IDP authentication form submit URL" )
206
240
}
207
241
loginDetails .URL = authSubmitURL
208
242
return kc .getLoginForm (loginDetails )
@@ -213,13 +247,13 @@ func (kc *Client) getLoginForm(loginDetails *creds.LoginDetails) (string, url.Va
213
247
doc .Find ("input" ).Each (func (i int , s * goquery.Selection ) {
214
248
updateKeyCloakFormData (authForm , s , loginDetails )
215
249
})
216
-
250
+ authCookies := res . Cookies ()
217
251
authSubmitURL , err := extractSubmitURL (doc )
218
252
if err != nil {
219
- return "" , nil , errors .Wrap (err , "unable to locate IDP authentication form submit URL" )
253
+ return "" , nil , nil , errors .Wrap (err , "unable to locate IDP authentication form submit URL" )
220
254
}
221
255
222
- return authSubmitURL , authForm , nil
256
+ return authSubmitURL , authForm , authCookies , nil
223
257
}
224
258
225
259
func (kc * Client ) postLoginForm (authSubmitURL string , authForm url.Values ) ([]byte , error ) {
@@ -281,9 +315,8 @@ func (kc *Client) postTotpForm(authCtx *authContext, totpSubmitURL string, doc *
281
315
return doc , nil
282
316
}
283
317
284
- func (kc * Client ) postWebauthnForm (webauthnSubmitURL string , credentialIDs []string , challenge , rpId string ) (* goquery.Document , error ) {
318
+ func (kc * Client ) postWebauthnForm (webauthnSubmitURL string , credentialIDs []string , challenge , rpId string , cookies [] * http. Cookie ) (* goquery.Document , error ) {
285
319
webauthnForm := url.Values {}
286
-
287
320
var assertion * okta.SignedAssertion
288
321
var pickedCredentialID string
289
322
for i , credentialID := range credentialIDs {
@@ -328,14 +361,14 @@ func (kc *Client) postWebauthnForm(webauthnSubmitURL string, credentialIDs []str
328
361
webauthnForm .Set ("credentialId" , pickedCredentialID )
329
362
webauthnForm .Set ("userHandle" , "" )
330
363
webauthnForm .Set ("error" , "" )
331
-
332
364
req , err := http .NewRequest ("POST" , webauthnSubmitURL , strings .NewReader (webauthnForm .Encode ()))
333
365
if err != nil {
334
366
return nil , errors .Wrap (err , "error building MFA request" )
335
367
}
336
-
337
368
req .Header .Add ("Content-Type" , "application/x-www-form-urlencoded" )
338
-
369
+ for _ , cookie := range cookies {
370
+ req .AddCookie (cookie )
371
+ }
339
372
res , err := kc .client .Do (req )
340
373
if err != nil {
341
374
return nil , errors .Wrap (err , "error retrieving content" )
@@ -345,7 +378,6 @@ func (kc *Client) postWebauthnForm(webauthnSubmitURL string, credentialIDs []str
345
378
if err != nil {
346
379
return nil , errors .Wrap (err , "error reading webauthn form response" )
347
380
}
348
-
349
381
return doc , nil
350
382
}
351
383
@@ -368,7 +400,6 @@ func extractSubmitURL(doc *goquery.Document) (string, error) {
368
400
}
369
401
submitURL = action
370
402
})
371
-
372
403
if submitURL == "" {
373
404
return "" , fmt .Errorf ("unable to locate form submit URL" )
374
405
}
@@ -379,7 +410,6 @@ func extractSubmitURL(doc *goquery.Document) (string, error) {
379
410
func extractSamlResponse (doc * goquery.Document ) (string , error ) {
380
411
var samlAssertion = ""
381
412
var err = fmt .Errorf ("unable to locate saml response field" )
382
-
383
413
doc .Find ("input" ).Each (func (i int , s * goquery.Selection ) {
384
414
name , ok := s .Attr ("name" )
385
415
if ok && name == "SAMLResponse" {
0 commit comments