// 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 }
/** One at a time - not that fast - only use for testing Filtered by xpath for testing purposes */ func (mdq *MDQ) MDQFilter(xpathfilter string) (xp *gosaml.Xp, numberOfEntities int, err error) { recs, err := mdq.getEntityList() if err != nil { return } // get the entities into an ordered slice index := make([]string, len(recs)) i := 0 for k, _ := range recs { index[i] = k i++ } sort.Strings(index) //log.Println(xpathfilter) xp = gosaml.NewXp([]byte(`<md:EntitiesDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" />`)) for _, entityID := range index { ent, _ := mdq.dbget(entityID, false) if xpathfilter == "" || len(ent.Query(nil, xpathfilter)) > 0 { xp.DocGetRootElement().AddChild(xp.CopyNode(ent.DocGetRootElement(), 1)) numberOfEntities++ } } return }
func ExampleWayfAttributeHandler() { hub_md := gosaml.NewXp(wayfrequestedattributes) idp := sourceResponse.Query1(nil, "/samlp:Response/saml:Issuer") hub_op, _ := new(lMDQ.MDQ).Open(HUB_OP_MDQ) idp_md, _, _ := hub_op.MDQ(idp) WayfAttributeHandler(idp_md, hub_md, sourceResponse) log.Println(sourceResponse.Pp()) // output: hi }
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 }
func main() { // logwriter, e := syslog.New(syslog.LOG_NOTICE, "goeleven") // if e == nil { // log.SetOutput(logwriter) // } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) signal.Notify(c, syscall.SIGTERM) go func() { <-c f, err := os.Create("hybrid.pprof") if err != nil { log.Fatal(err) } pprof.WriteHeapProfile(f) f.Close() os.Exit(1) }() var err error if hub, err = lMDQ.Open("/home/mz/test_hub.mddb"); err != nil { log.Println(err) } if hub_ops, err = lMDQ.Open("/home/mz/test_hub_ops.mddb"); err != nil { log.Println(err) } if edugain, err = lMDQ.Open("/home/mz/test_edugain.mddb"); err != nil { log.Println(err) } hubmd, _ = hub.MDQ(config["HYBRID_HUB"]) attrs := gosaml.NewXp(Wayfrequestedattributes) for _, attr := range attrs.Query(nil, "./md:SPSSODescriptor/md:AttributeConsumingService/md:RequestedAttribute") { basic2uri[attr.GetAttr("FriendlyName")] = attr.GetAttr("Name") } //http.HandleFunc("/status", statushandler) http.Handle(config["HYBRID_PUBLIC_PREFIX"], http.FileServer(http.Dir(config["HYBRID_PUBLIC"]))) http.Handle(config["HYBRID_SSO_SERVICE"], appHandler(ssoService)) http.Handle(config["HYBRID_ACS"], appHandler(acsService)) http.Handle(config["HYBRID_BIRK"], appHandler(birkService)) http.Handle(config["HYBRID_KRIB"], appHandler(kribService)) log.Println("listening on ", config["HYBRID_INTERFACE"]) err = http.ListenAndServeTLS(config["HYBRID_INTERFACE"], config["HYBRID_HTTPS_CERT"], config["HYBRID_HTTPS_KEY"], nil) //err = openssl.ListenAndServeTLS(config["HYBRID_INTERFACE"], config["HYBRID_HTTPS_CERT"], config["HYBRID_HTTPS_KEY"], nil) if err != nil { log.Printf("main(): %s\n", err) } }
func b(attrs map[string][]string) (ats *gosaml.Xp) { template := []byte(`<saml:AttributeStatement xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>`) ats = gosaml.NewXp(template) i := 1 for attr, attrvals := range attrs { attrelement := ats.QueryDashP(nil, `saml:Attribute[`+strconv.Itoa(i)+`]`, "", nil) ats.QueryDashP(attrelement, "@Name", attr, nil) ats.QueryDashP(attrelement, "@NameFormat", "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", nil) j := 1 for _, attrval := range attrvals { attrvalelement := ats.QueryDashP(attrelement, `saml:AttributeValue[`+strconv.Itoa(j)+`]`, attrval, nil) ats.QueryDashP(attrvalelement, "@xsi:type", "xs:string", nil) j = j + 1 } i = i + 1 } return }
func (mdq *MDQ) dbget(key string, cache bool) (xp *gosaml.Xp, err error) { if mdq.stmt == nil { mdq.stmt, err = mdq.db.Prepare(`select e.md from entity e, lookup l, validuntil v where l.hash = $1 and l.entity_id_fk = e.id and v.validuntil >= $2`) if err != nil { return } } k := key const prefix = "{sha1}" if strings.HasPrefix(key, prefix) { key = key[6:] } else { key = hex.EncodeToString(gosaml.Hash(crypto.SHA1, key)) } mdq.Lock.Lock() defer mdq.Lock.Unlock() cachedxp := mdq.Cache[key] if cachedxp != nil && cachedxp.Valid(cacheduration) { xp = cachedxp.Xp.CpXp() return } var xml []byte err = mdq.stmt.QueryRow(key, time.Now().Unix()).Scan(&xml) if err != nil { //log.Println("query", mdq.path, k, key, err, string(xml)) err = fmt.Errorf("Metadata not found for entity: %s", k) //debug.PrintStack() return } xp = gosaml.NewXp(xml) if cache { mdxp := new(MdXp) mdxp.Xp = xp mdxp.created = time.Now() mdq.Cache[key] = mdxp } 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 }
// 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 }
func (mdq *MDQ) Update() (err error) { start := time.Now() log.Println("lMDQ updating", mdq.Url, mdq.Path) _, err = mdq.db.Exec(lMDQSchema) if err != nil { return } recs, err := mdq.getEntityList() if err != nil { return err } var md []byte if md, err = get(mdq.Url); err != nil { return } dom := gosaml.NewXp(md) if _, err := dom.SchemaValidate(mdq.MetadataSchemaPath); err != nil { log.Println("feed", "SchemaError") } certificate := dom.Query(nil, "/md:EntitiesDescriptor/ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate") if len(certificate) != 1 { err = errors.New("Metadata not signed") return } keyname, key, err := gosaml.PublicKeyInfo(dom.NodeGetContent(certificate[0])) if err != nil { return } ok := dom.VerifySignature(nil, key) if ok != nil || keyname != mdq.Hash { return fmt.Errorf("Signature check failed. Signature %s, %s = %s", ok, keyname, mdq.Hash) } tx, err := mdq.db.Begin() if err != nil { return } defer func() { if err != nil { tx.Rollback() return } err = tx.Commit() }() entityInsertStmt, err := tx.Prepare("insert into entity (entityid, md, hash) values ($1, $2, $3)") if err != nil { return } defer entityInsertStmt.Close() lookupInsertStmt, err := tx.Prepare("insert or ignore into lookup (hash, entity_id_fk) values (?, ?)") if err != nil { return err } defer lookupInsertStmt.Close() entityDeleteStmt, err := tx.Prepare("delete from entity where id = $1") if err != nil { return err } defer entityDeleteStmt.Close() vu, err := time.Parse(time.RFC3339Nano, dom.Query1(nil, "@validUntil")) if err != nil { return err } validUntil := vu.Unix() var new, updated, nochange, deleted int seen := map[string]bool{} entities := dom.Query(nil, "./md:EntityDescriptor") for _, entity := range entities { entityID := dom.Query1(entity, "@entityID") if seen[entityID] { log.Printf("lMDQ duplicate entityID: %s", entityID) continue } seen[entityID] = true md := gosaml.NewXpFromNode(entity).X2s() rec := recs[entityID] id := rec.id hash := hex.EncodeToString(gosaml.Hash(crypto.SHA1, md)) oldhash := rec.hash if rec.hash == hash { // no changes delete(recs, entityID) // remove so it won't be deleted nochange++ continue } else if oldhash != "" { // update is delete + insert - then the cascading delete will also delete the potential stale lookup entries _, err = entityDeleteStmt.Exec(rec.id) if err != nil { return } updated++ log.Printf("lMDQ updated entityID: %s", entityID) delete(recs, entityID) // updated - remove so it won't be deleted } else { new++ if !mdq.Silent { log.Printf("lMDQ new entityID: %s", entityID) } } var res sql.Result res, err = entityInsertStmt.Exec(entityID, md, hash) if err != nil { return err } id, _ = res.LastInsertId() _, err = lookupInsertStmt.Exec(hex.EncodeToString(gosaml.Hash(crypto.SHA1, entityID)), id) if err != nil { return } for _, target := range indextargets { locations := dom.Query(entity, target) for i, location := range locations { if !mdq.Silent { log.Println(i, dom.NodeGetContent(location)) } _, err = lookupInsertStmt.Exec(hex.EncodeToString(gosaml.Hash(crypto.SHA1, dom.NodeGetContent(location))), id) if err != nil { return } } } } for entid, ent := range recs { // delete entities no longer in feed _, err = entityDeleteStmt.Exec(ent.id) if err != nil { return } deleted++ log.Printf("lMDQ deleted entityID: %s", entid) } _, err = tx.Exec("update validuntil set validuntil = $1 where id = 1", validUntil) if err != nil { return } log.Printf("lMDQ finished %d new, %d updated, %d unchanged, %d deleted validUntil: %s duration: %.1f", new, updated, nochange, deleted, time.Unix(validUntil, 0).Format(time.RFC3339), time.Since(start).Seconds()) return }
sourceResponse = gosaml.NewXp([]byte(`<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_336333b557cf99d44124c2c2b02b1cc2d4efb4fe2c" Version="2.0" IssueInstant="2016-02-02T21:33:10Z" Destination="https://wayf.wayf.dk/module.php/saml/sp/saml2-acs.php/wayf.wayf.dk" InResponseTo="_be2b06534490f9b658487041f1f011348c2834f8aa" > <saml:Issuer>https://wayf.ait.dtu.dk/saml2/idp/metadata.php</saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">" <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> <ds:Reference URI="#_336333b557cf99d44124c2c2b02b1cc2d4efb4fe2c"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>CLUJqLbuMsvHggz9sqJqm5PRjBE=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>WKizpTmuMFUN3jv5c1DC4v7XVDOv4i8VrbcF9BCWNGb8BhMpVSar+Z6cwaL91fCtNwrAwq5quloImTjkjWcHi7XY2YEVgC2C3IB7yulhkkz8RxbI6HoLT04wjXcv6PW6kpZQszCMw5Y9zliRuRSk1b90nzuUhvEJWh3v3zFRR52E6jhpwW277ANMHK5AOWTtYuWfocmy6J9JPOKPlxs1fRbO1y9X9+tJ7jABltNMYfXJSoblsFGag/nAadg8ChuDsxzQ+ZNnBRjLjf6+TWclqVj1W7M6hDWJRpAHUotvMYRh2/wpvRzGx30mEcMOkgGP5a21A4BGWBIPJGA5Z6oi5Q==</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIIEszCCA5ugAwIBAgIQBuU97081jlKyFb1aYH7wSTANBgkqhkiG9w0BAQUFADA2MQswCQYDVQQGEwJOTDEPMA0GA1UEChMGVEVSRU5BMRYwFAYDVQQDEw1URVJFTkEgU1NMIENBMB4XDTExMTIxMzAwMDAwMFoXDTE0MTIxMjIzNTk1OVowgY4xCzAJBgNVBAYTAkRLMRAwDgYDVQQIEwdEZW5tYXJrMRQwEgYDVQQHEwtLZ3MuIEx5bmdieTEoMCYGA1UEChMfVGVjaG5pY2FsIFVuaXZlcnNpdHkgb2YgRGVubWFyazETMBEGA1UECxMKSVQgU2VydmljZTEYMBYGA1UEAxMPd2F5Zi5haXQuZHR1LmRrMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA18irEcMKn0RAI8+kxMKMj1vpESz3qLgcILOmzGaHkYCYsiUtAqrHTsmOUYdnE+BfWGEFsngneCoMW/Ct34YCj9CCl9yNqNRXXHnr7+ASMipB7aPODaAfOlxC/W+QNxOgkwfUAcKKA/B2nJ56uPUdtrM3OyQvtcOdkEiCrMTZKb/T5BDOXhM/IeDd2pTPiJUE5WwzanW0RXP7EmLQkygTTFcb2Fh0ARQ+hdZV200U/ERI5MDGj5IR/lurclKcbP9Bdw0/bgwAfVx7bf+XpuxdQN54NuB91Y7kYIiFT66qkN7ST/ZQjdZqU2F5uAtxdCaSTd2taSgKwoClOX4t32QGBwIDAQABo4IBYjCCAV4wHwYDVR0jBBgwFoAUDL2TaAzz3qujSWsrN1dH6pDjue0wHQYDVR0OBBYEFG3N9C92Cr7eyc1EWE4bY+rcdDReMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgIdMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwudGNzLnRlcmVuYS5vcmcvVEVSRU5BU1NMQ0EuY3JsMG0GCCsGAQUFBwEBBGEwXzA1BggrBgEFBQcwAoYpaHR0cDovL2NydC50Y3MudGVyZW5hLm9yZy9URVJFTkFTU0xDQS5jcnQwJgYIKwYBBQUHMAGGGmh0dHA6Ly9vY3NwLnRjcy50ZXJlbmEub3JnMBoGA1UdEQQTMBGCD3dheWYuYWl0LmR0dS5kazANBgkqhkiG9w0BAQUFAAOCAQEAmWq3MGe1fKFbmtPYc77grgVEi+n5jJHFHKFv/RTCqVrpLE52Z+wKT15HtKQ1ZfQ0hRvoPcmgDzWj1gc1Y33fG/VYxhJNN7TNwxm61PWpgHDaU63KkPxli6oY6DnKixn4QY6tAmEykB88T2qlj2kYGTBPMj5ndHHKVk9QTVcAsTSI1rXrCjtehtN9my2OFVEy7yapM9d6RO7NjxMJnmnqjjiZoRtgmOSOqCXLpn3bAEqzmdTnn8VNS2i8B1tNWOf4nFpoTLhEuOR4n8MwvA+/mf9uknKyvWOysDsBEjM+M1IG25DzC6T+aYx27niBhygDOFRLI+gIr3Odb9ODe+2yqw==</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /> </samlp:Status> <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="_c5897a405e2fe06cfb8212f22ae143f949a0e18f2b" Version="2.0" IssueInstant="2016-02-02T21:33:10Z" > <saml:Issuer>https://wayf.ait.dtu.dk/saml2/idp/metadata.php</saml:Issuer> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> <ds:Reference URI="#_c5897a405e2fe06cfb8212f22ae143f949a0e18f2b"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>XnR0pWAy72jA02bAXqjAUmwa9RU=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>n9xvr50GYOtx3G068EeD6o2F5PPHttEuxZYBeUwzcNr8fuCQue9Ee3uAcuWYGvq2BcylCOyubYqNyqh9aACK0Eewtn0cJoVP0mtrmTXBbn5wFwPpodRM5Vk08t/+rxKxT03kyfaVyHy0IdERDDgtNbY49nIQXdgiSD+pEizqrjbKh8UXXyX/0oM+q7u1FuhQpPt3vx8DWtaiz5eekoTfIjki87agd+cSJT92uhQq3rBRmQadjGGVpVrK/VHjExHa5ar9N+8xcps/ml8QqVlzK8Jkd9WFsIsKv5CEYJdVn3LlokHm2OobRdw2/F0Wa2FN1mzWxQY6amaBqx3jygd0Jg==</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>MIIEszCCA5ugAwIBAgIQBuU97081jlKyFb1aYH7wSTANBgkqhkiG9w0BAQUFADA2MQswCQYDVQQGEwJOTDEPMA0GA1UEChMGVEVSRU5BMRYwFAYDVQQDEw1URVJFTkEgU1NMIENBMB4XDTExMTIxMzAwMDAwMFoXDTE0MTIxMjIzNTk1OVowgY4xCzAJBgNVBAYTAkRLMRAwDgYDVQQIEwdEZW5tYXJrMRQwEgYDVQQHEwtLZ3MuIEx5bmdieTEoMCYGA1UEChMfVGVjaG5pY2FsIFVuaXZlcnNpdHkgb2YgRGVubWFyazETMBEGA1UECxMKSVQgU2VydmljZTEYMBYGA1UEAxMPd2F5Zi5haXQuZHR1LmRrMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA18irEcMKn0RAI8+kxMKMj1vpESz3qLgcILOmzGaHkYCYsiUtAqrHTsmOUYdnE+BfWGEFsngneCoMW/Ct34YCj9CCl9yNqNRXXHnr7+ASMipB7aPODaAfOlxC/W+QNxOgkwfUAcKKA/B2nJ56uPUdtrM3OyQvtcOdkEiCrMTZKb/T5BDOXhM/IeDd2pTPiJUE5WwzanW0RXP7EmLQkygTTFcb2Fh0ARQ+hdZV200U/ERI5MDGj5IR/lurclKcbP9Bdw0/bgwAfVx7bf+XpuxdQN54NuB91Y7kYIiFT66qkN7ST/ZQjdZqU2F5uAtxdCaSTd2taSgKwoClOX4t32QGBwIDAQABo4IBYjCCAV4wHwYDVR0jBBgwFoAUDL2TaAzz3qujSWsrN1dH6pDjue0wHQYDVR0OBBYEFG3N9C92Cr7eyc1EWE4bY+rcdDReMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAYBgNVHSAEETAPMA0GCysGAQQBsjEBAgIdMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwudGNzLnRlcmVuYS5vcmcvVEVSRU5BU1NMQ0EuY3JsMG0GCCsGAQUFBwEBBGEwXzA1BggrBgEFBQcwAoYpaHR0cDovL2NydC50Y3MudGVyZW5hLm9yZy9URVJFTkFTU0xDQS5jcnQwJgYIKwYBBQUHMAGGGmh0dHA6Ly9vY3NwLnRjcy50ZXJlbmEub3JnMBoGA1UdEQQTMBGCD3dheWYuYWl0LmR0dS5kazANBgkqhkiG9w0BAQUFAAOCAQEAmWq3MGe1fKFbmtPYc77grgVEi+n5jJHFHKFv/RTCqVrpLE52Z+wKT15HtKQ1ZfQ0hRvoPcmgDzWj1gc1Y33fG/VYxhJNN7TNwxm61PWpgHDaU63KkPxli6oY6DnKixn4QY6tAmEykB88T2qlj2kYGTBPMj5ndHHKVk9QTVcAsTSI1rXrCjtehtN9my2OFVEy7yapM9d6RO7NjxMJnmnqjjiZoRtgmOSOqCXLpn3bAEqzmdTnn8VNS2i8B1tNWOf4nFpoTLhEuOR4n8MwvA+/mf9uknKyvWOysDsBEjM+M1IG25DzC6T+aYx27niBhygDOFRLI+gIr3Odb9ODe+2yqw==</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> <saml:Subject> <saml:NameID SPNameQualifier="https://wayf.wayf.dk" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" >_470f3e8bd3430425c2a962310b4a8d0a79d3fcf23e</saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData NotOnOrAfter="2016-02-02T21:38:10Z" Recipient="https://wayf.wayf.dk/module.php/saml/sp/saml2-acs.php/wayf.wayf.dk" InResponseTo="_be2b06534490f9b658487041f1f011348c2834f8aa" /> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2016-02-02T21:32:40Z" NotOnOrAfter="2016-02-02T21:38:10Z" > <saml:AudienceRestriction> <saml:Audience>https://wayf.wayf.dk</saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2016-02-02T21:09:08Z" SessionNotOnOrAfter="2016-02-03T05:33:10Z" SessionIndex="_ba4740cce62d7b571aa13ff862d1242b37984f4d82" > <saml:AuthnContext> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> <saml:AttributeStatement> <saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">madpe</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="gn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">Mads Freek</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">Petersen</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="cn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">Mads Freek Petersen</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="preferredLanguage" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">da-DK</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="organizationName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">Danmarks Tekniske Universitet</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="eduPersonPrincipalName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="eduPersonPrimaryAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">staff</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="eduPersonScopedAffiliation" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="schacPersonalUniqueID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">urn:mace:terena.org:schac:personalUniqueID:dk:CPR:2408586234</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="eduPersonAssurance" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">2</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="eduPersonEntitlement" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" > <saml:AttributeValue xsi:type="xs:string">urn:mace:terena.org:tcs:escience-user</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> </saml:Assertion> </samlp:Response> `))
"displayName": {"Anton Banton Cantonsen"}, } hub = flag.String("hub", "wayf.wayf.dk", "the hostname for the hub server to be tested") hubbe = flag.String("hubbe", "", "the hub backend server") birk = flag.String("birk", "birk.wayf.dk", "the hostname for the BIRK server to be tested") birkbe = flag.String("birkbe", "", "the birk backend server") trace = flag.Bool("xtrace", false, "trace the request/response flow") logxml = flag.Bool("logxml", false, "dump requests/responses in xml") dohub = flag.Bool("dohub", false, "do test the hub") dobirk = flag.Bool("dobirk", false, "do test BIRK") dokrib = flag.Bool("dokrib", false, "do (only) test KRIB - implies !birk and !hub") env = flag.String("env", "dev", "which environment to test dev, hybrid, prod - if not dev") refreshmd = flag.Bool("refreshmd", true, "update local metadatcache before testing") testcertpath = flag.String("testcertpath", "/etc/ssl/wayf/certs/wildcard.test.lan.pem", "path to the testing cert") wayfAttCSDoc = gosaml.NewXp(main.Wayfrequestedattributes) wayfAttCSElement = wayfAttCSDoc.Query(nil, "./md:SPSSODescriptor/md:AttributeConsumingService")[0] testSPs *gosaml.Xp old, r, w *os.File outC = make(chan string) templatevalues = map[string]map[string]string{ "prod": { "eptid": "WAYF-DK-c52a92a5467ae336a2be77cd06719c645e72dfd2", "pnameid": "WAYF-DK-c52a92a5467ae336a2be77cd06719c645e72dfd2", }, "dev": { "eptid": "WAYF-DK-a7379f69e957371dc49350a27b704093c0b813f1", "pnameid": "WAYF-DK-a7379f69e957371dc49350a27b704093c0b813f1", },