func acsService(w http.ResponseWriter, r *http.Request) (err error) { defer r.Body.Close() birk, err := r.Cookie("BIRK") if err != nil { return err } // to-do: check hmac // we checked the request when we received in birkService - we can use it without fear request, err := gosaml.DecodeSAMLMsg(birk.Value, true) sp_md, err := hub_ops.MDQ(request.Query1(nil, "/samlp:AuthnRequest/saml:Issuer")) // spmd, _, err := edugain.MDQ(request.Query1(nil, "/samlp:AuthnRequest/saml:Issuer")) //http.SetCookie(w, &http.Cookie{Name: "BIRK", Value: "", MaxAge: -1, Domain: config["HYBRID_DOMAIN"], Path: "/", Secure: true, HttpOnly: true}) response, idp_md, _, err := gosaml.GetSAMLMsg(r, "SAMLResponse", hub_ops, hub, hubmd) if err != nil { return } hub_md := gosaml.NewXp(Wayfrequestedattributes) err = WayfAttributeHandler(idp_md, hub_md, sp_md, response) if err != nil { return } birkmd, err := edugain.MDQ(request.Query1(nil, "@Destination")) nameid := response.Query(nil, "./saml:Assertion/saml:Subject/saml:NameID")[0] // respect nameID in req, give persistent id + all computed attributes + nameformat conversion nameidformat := sp_md.Query1(nil, "./md:SPSSODescriptor/md:NameIDFormat") if nameidformat == persistent { response.QueryDashP(nameid, "@Format", persistent, nil) eptid := response.Query1(nil, `./saml:Assertion/saml:AttributeStatement/saml:Attribute[@FriendlyName="eduPersonTargetedID"]/saml:AttributeValue`) response.QueryDashP(nameid, ".", eptid, nil) } else if nameidformat == transient { response.QueryDashP(nameid, ".", gosaml.Id(), nil) } newresponse := gosaml.NewResponse(stdtiming.Refresh(), birkmd, sp_md, request, response) for _, q := range elementsToSign { err = gosaml.SignResponse(newresponse, q, birkmd) if err != nil { return } } // when consent as a service is ready - we will post to that acs := newresponse.Query1(nil, "@Destination") data := formdata{Acs: acs, Samlresponse: base64.StdEncoding.EncodeToString([]byte(newresponse.X2s()))} postform.Execute(w, data) return }
// SSOSendRequest2 does the 2nd part of sending the request to the final IdP. // Creates the response and signs and optionally encrypts it func (tp *Testparams) SSOSendRequest2() { u, _ := tp.Resp.Location() // if going via birk we now got a scoped request to the hub if tp.Usedoubleproxy { if tp.Logxml { query := u.Query() req, _ := base64.StdEncoding.DecodeString(query["SAMLRequest"][0]) authnrequest := gosaml.NewXp(gosaml.Inflate(req)) log.Println("birkrequest", authnrequest.Pp()) } tp.Resp, tp.Responsebody, _ = tp.sendRequest(u, tp.Resolv[u.Host], "GET", "", tp.Cookiejar) u, _ = tp.Resp.Location() } // We still expect to be redirected // if we are not at our final IdP something is rotten eid := tp.Idpmd.Query1(nil, "@entityID") idp, _ := url.Parse(eid) if u.Host != idp.Host { //log.Println("u.host != idp.Host", u, idp) // Errors from HUB is 302 to https://wayf.wayf.dk/displayerror.php ... which is a 500 with html content u, _ = tp.Resp.Location() tp.Resp, tp.Responsebody, tp.Err = tp.sendRequest(u, tp.Resolv[u.Host], "GET", "", tp.Cookiejar) return } // get the SAMLRequest query := u.Query() req, _ := base64.StdEncoding.DecodeString(query["SAMLRequest"][0]) authnrequest := gosaml.NewXp(gosaml.Inflate(req)) if tp.Logxml { log.Println("idprequest", authnrequest.Pp()) } // create a response tp.Newresponse = gosaml.NewResponse(gosaml.IdAndTiming{time.Now(), 4 * time.Minute, 4 * time.Hour, "", ""}, tp.Idpmd, tp.Hubspmd, authnrequest, tp.Attributestmt) if tp.Logxml { log.Println("response", tp.Newresponse.Pp()) } // and sign it assertion := tp.Newresponse.Query(nil, "saml:Assertion[1]")[0] // use cert to calculate key name err := tp.Newresponse.Sign(assertion, tp.Privatekey, tp.Privatekeypw, tp.Certificate, tp.Hashalgorithm) if err != nil { log.Fatal(err) } if tp.Encryptresponse { certs := tp.Hubspmd.Query(nil, `//md:KeyDescriptor[@use="encryption" or not(@use)]/ds:KeyInfo/ds:X509Data/ds:X509Certificate`) if len(certs) == 0 { fmt.Errorf("Could not find encryption cert for: %s", tp.Hubspmd.Query1(nil, "/@entityID")) } _, publickey, _ := gosaml.PublicKeyInfo(tp.Hubspmd.NodeGetContent(certs[0])) if tp.Env == "xdev" { cert, err := ioutil.ReadFile(*testcertpath) pk, err := x509.ParseCertificate(cert) if err != nil { return } publickey = pk.PublicKey.(*rsa.PublicKey) } tp.Newresponse.Encrypt(assertion, publickey) tp.Encryptresponse = false // for now only possible for idp -> hub } return }