// Html2SAMLResponse extracts the SAMLResponse from a html document func Html2SAMLResponse(tp *Testparams) (samlresponse *gosaml.Xp) { response := gosaml.NewHtmlXp(tp.Responsebody) samlbase64 := response.Query1(nil, `//input[@name="SAMLResponse"]/@value`) samlxml, _ := base64.StdEncoding.DecodeString(samlbase64) samlresponse = gosaml.NewXp(samlxml) if _, err := samlresponse.SchemaValidate(samlSchema); err != nil { fmt.Println("SchemaError") } certs := tp.Firstidpmd.Query(nil, `//md:KeyDescriptor[@use="signing" or not(@use)]/ds:KeyInfo/ds:X509Data/ds:X509Certificate`) if len(certs) == 0 { fmt.Printf("Could not find signing cert for: %s", tp.Firstidpmd.Query1(nil, "/@entityID")) log.Printf("Could not find signing cert for: %s", tp.Firstidpmd.Query1(nil, "/@entityID")) } _, pub, _ := gosaml.PublicKeyInfo(tp.Firstidpmd.NodeGetContent(certs[0])) assertion := samlresponse.Query(nil, "saml:Assertion[1]") if assertion == nil { fmt.Println("no assertion found") } if err := samlresponse.VerifySignature(assertion[0], pub); err != nil { fmt.Printf("SignatureVerificationError %s", err) } return }
// DoRunTestHub runs a test on the hub - applying the necessary modifications on the way. // Returns a *Testparams which can be analyzed func DoRunTestHub(m modsset, overwrite *Testparams) (tp *Testparams) { if *dokrib { return DoRunTestKrib(m, overwrite) } if !*dohub { return } tp = Newtp(overwrite) defer xxx(tp.Trace) ApplyMods(tp.Attributestmt, m["attributemods"]) tp.SSOCreateInitialRequest() ApplyMods(tp.Initialrequest, m["requestmods"]) tp.SSOSendRequest() if tp.Resp.StatusCode == 500 { response := gosaml.NewHtmlXp(tp.Responsebody) fmt.Println(strings.Trim(response.Query1(nil, `//a[@id="errormsg"]/text()`), "\n ")) return } ApplyMods(tp.Newresponse, m["responsemods"]) tp.SSOSendResponse() if tp.Resp.StatusCode == 500 { response := gosaml.NewHtmlXp(tp.Responsebody) fmt.Println(strings.Trim(response.Query1(nil, `//a[@id="errormsg"]/text()`), "\n ")) return } if tp.Logxml { log.Println("idp response", tp.Newresponse.Pp()) } err := ValidateSignature(tp.Hubidpmd, tp.Newresponse) if err != nil { fmt.Printf("signature errors: %s\n", err) } return }
// SendRequest sends a http request - GET or POST using the supplied url, server, method and cookies // It updates the cookies and returns a http.Response and a posssible response body and error // The server parameter contains the dns name of the actual server, which should respond to the host part of the url func (tp *Testparams) sendRequest(url *url.URL, server, method, body string, cookies map[string]map[string]*http.Cookie) (resp *http.Response, responsebody []byte, err error) { if server == "" { server = url.Host } server += ":443" tr := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, Dial: func(network, addr string) (net.Conn, error) { return net.Dial("tcp", server) }, DisableCompression: true, } client := &http.Client{ Transport: tr, CheckRedirect: func(req *http.Request, via []*http.Request) error { return errors.New("redirect-not-allowed") }, } var payload io.Reader if method == "POST" { payload = strings.NewReader(body) } host := url.Host cookiedomain := "wayf.dk" req, err := http.NewRequest(method, url.String(), payload) for _, cookie := range cookies[cookiedomain] { req.AddCookie(cookie) } if method == "POST" { req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.Header.Add("Content-Length", strconv.Itoa(len(body))) } req.Header.Add("Host", host) resp, err = client.Do(req) if err != nil && !strings.HasSuffix(err.Error(), "redirect-not-allowed") { // we need to do the redirect ourselves so a self inflicted redirect "error" is not an error debug.PrintStack() log.Fatalln("client.do", err) } location, _ := resp.Location() loc := "" if location != nil { loc = location.Host + location.Path } setcookies := resp.Cookies() for _, cookie := range setcookies { if cookies[cookiedomain] == nil { cookies[cookiedomain] = make(map[string]*http.Cookie) } cookies[cookiedomain][cookie.Name] = cookie } // We can't get to the body if we got a redirect pseudo error above if err == nil { responsebody, err = ioutil.ReadAll(resp.Body) defer resp.Body.Close() } // We didn't get a Location: header - we are POST'ing a SAMLResponse if loc == "" { response := gosaml.NewHtmlXp(responsebody) samlbase64 := response.Query1(nil, `//input[@name="SAMLResponse"]/@value`) if samlbase64 != "" { samlxml, _ := base64.StdEncoding.DecodeString(samlbase64) samlresponse := gosaml.NewXp(samlxml) u, _ := url.Parse(samlresponse.Query1(nil, "@Destination")) loc = u.Host + u.Path } } if tp.Trace { log.Printf("%-4s %-70s %s %-15s %s\n", req.Method, host+req.URL.Path, resp.Proto, resp.Status, loc) } // we need to nullify the damn redirec-not-allowed error from above err = nil return }