in pkg/provider/akamai/akamai.go [101:254]
func (oc *Client) Authenticate(loginDetails *creds.LoginDetails) (string, error) {
var samlAssertion string
akamaiURL, err := url.Parse(loginDetails.URL)
if err != nil {
return samlAssertion, errors.Wrap(err, "error building akamaiURL")
}
akamaiOrgHost := akamaiURL.Host
akamaiQuery := akamaiURL.Query()
akamaiSamlApp := string(akamaiQuery.Get("app"))
// Get xsrf data and cookie by doing get request
akamaiLoginURL := fmt.Sprintf("https://%s/", akamaiOrgHost)
req, err := http.NewRequest("GET", akamaiLoginURL, nil)
if err != nil {
return samlAssertion, errors.Wrap(err, "error building authentication request")
}
res, err := oc.client.Do(req)
if err != nil {
return samlAssertion, errors.Wrap(err, "error retrieving login request")
}
doc, err := goquery.NewDocumentFromResponse(res)
if err != nil {
return samlAssertion, errors.Wrap(err, "error parsing document")
}
xsrfToken, ok := doc.Find("input[id=\"xsrf\"]").Attr("value")
if !ok {
return samlAssertion, errors.Wrap(err, "unable to locate xsrf token in html")
}
// Send login request to Akamai
authReq := AuthRequest{Username: loginDetails.Username, Password: loginDetails.Password}
authBody := new(bytes.Buffer)
err = json.NewEncoder(authBody).Encode(authReq)
if err != nil {
return samlAssertion, errors.Wrap(err, "error encoding authreq")
}
authSubmitURL := fmt.Sprintf("https://%s/api/v1/login", akamaiOrgHost)
loginReq, err := http.NewRequest("POST", authSubmitURL, authBody)
if err != nil {
return samlAssertion, errors.Wrap(err, "error building authentication request")
}
loginReq.Header.Add("Content-Type", "application/json")
loginReq.Header.Add("Accept", "application/json")
loginReq.Header.Add("xsrf", string(xsrfToken))
res, err = oc.client.Do(loginReq)
if err != nil {
return samlAssertion, errors.Wrap(err, "error login to EAA IDP")
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return samlAssertion, errors.Wrap(err, "error retrieving body from response")
}
resp := string(body)
authStatus := gjson.Get(resp, "status").String()
if authStatus != "200" {
authFailReason := gjson.Get(resp, "msg").String()
fmt.Printf("Login Failed %s\n", authFailReason)
logger.Debug("Login Failed:", authFailReason)
return samlAssertion, errors.Wrap(err, "Login Failure")
}
// Send saml navigate request to Akamai
navReq := NavRequest{Hostname: akamaiSamlApp}
navBody := new(bytes.Buffer)
err = json.NewEncoder(navBody).Encode(navReq)
if err != nil {
return samlAssertion, errors.Wrap(err, "error encoding navreq")
}
navSubmitURL := fmt.Sprintf("https://%s/api/v2/apps/navigate", akamaiOrgHost)
navloginReq, err := http.NewRequest("POST", navSubmitURL, navBody)
if err != nil {
return samlAssertion, errors.Wrap(err, "error building navigation request")
}
navloginReq.Header.Add("Content-Type", "application/json")
navloginReq.Header.Add("Accept", "application/json")
navloginReq.Header.Add("xsrf", string(xsrfToken))
res, err = oc.client.Do(navloginReq)
if err != nil {
return samlAssertion, errors.Wrap(err, "error while navigation request to EAA ")
}
body, err = ioutil.ReadAll(res.Body)
if err != nil {
return samlAssertion, errors.Wrap(err, "error retrieving response from navigate request")
}
mfaStatus := gjson.GetBytes(body, "mfa.status").String()
if mfaStatus == "verify" {
err = verifyMfa(oc, akamaiOrgHost, loginDetails, xsrfToken)
if err != nil {
return samlAssertion, errors.Wrap(err, "error verifying MFA")
}
} else if mfaStatus == "register" {
fmt.Printf("MFA is enabled but not registered for user. Register MFA by accessing EAA IDP from Browser\n")
logger.Debug("MFA is enabled but not registered for user")
return samlAssertion, errors.Wrap(err, "register mfa by logging to IDP")
}
/* MFA is done call navigate again */
navReq = NavRequest{Hostname: akamaiSamlApp}
navBody = new(bytes.Buffer)
err = json.NewEncoder(navBody).Encode(navReq)
if err != nil {
return samlAssertion, errors.Wrap(err, "error encoding authreq")
}
navSubmitURL = fmt.Sprintf("https://%s/api/v2/apps/navigate", akamaiOrgHost)
navloginReq, err = http.NewRequest("POST", navSubmitURL, navBody)
if err != nil {
return samlAssertion, errors.Wrap(err, "error sending final navigate request")
}
navloginReq.Header.Add("Content-Type", "application/json")
navloginReq.Header.Add("Accept", "application/json")
navloginReq.Header.Add("xsrf", string(xsrfToken))
res, err = oc.client.Do(navloginReq)
if err != nil {
return samlAssertion, errors.Wrap(err, "error navigate request to EAA ")
}
body, err = ioutil.ReadAll(res.Body)
if err != nil {
return samlAssertion, errors.Wrap(err, "error retrieving body from response")
}
/* saml assertion response from json of navigate */
samlResponseHtml := gjson.GetBytes(body, "navigate.body").String()
doc, err = goquery.NewDocumentFromReader(strings.NewReader(samlResponseHtml))
if err != nil {
return samlAssertion, errors.Wrap(err, "error parsing saml response in document")
}
samlAssertion, ok = doc.Find("input[name=\"SAMLResponse\"]").Attr("value")
if !ok {
return samlAssertion, errors.Wrap(err, "unable to locate SAMLResponse in html")
}
logger.Debug("auth complete")
return samlAssertion, nil
}