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