Ejemplo n.º 1
0
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
}