github.com/vmware/govmomi@v0.43.0/sts/internal/types.go (about) 1 /* 2 Copyright (c) 2018 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package internal 18 19 // The sts/internal package provides the types for invoking the sts.Issue method. 20 // The sts.Issue and SessionManager LoginByToken methods require an XML signature. 21 // Unlike the JRE and .NET runtimes, the Go stdlib does not support XML signing. 22 // We should considering contributing to the goxmldsig package and gosaml2 to meet 23 // the needs of sts.Issue rather than maintaining this package long term. 24 // The tricky part of xmldig is the XML canonicalization (C14N), which is responsible 25 // for most of the make-your-eyes bleed XML formatting in this package. 26 // C14N is also why some structures use xml.Name without a field tag and methods modify the xml.Name directly, 27 // though also working around Go's handling of XML namespace prefixes. 28 // Most of the types in this package were originally generated from the wsdl and hacked up gen/ scripts, 29 // but have since been modified by hand. 30 31 import ( 32 "bytes" 33 "context" 34 "crypto/sha256" 35 "encoding/base64" 36 "fmt" 37 "log" 38 "path" 39 "reflect" 40 "strings" 41 42 "github.com/vmware/govmomi/vim25/soap" 43 "github.com/vmware/govmomi/vim25/types" 44 "github.com/vmware/govmomi/vim25/xml" 45 ) 46 47 const ( 48 XSI = "http://www.w3.org/2001/XMLSchema-instance" 49 WSU = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 50 DSIG = "http://www.w3.org/2000/09/xmldsig#" 51 SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" 52 Time = "2006-01-02T15:04:05.000Z" 53 ) 54 55 // Security is used as soap.Envelope.Header.Security when signing requests. 56 type Security struct { 57 XMLName xml.Name `xml:"wsse:Security"` 58 WSSE string `xml:"xmlns:wsse,attr"` 59 WSU string `xml:"xmlns:wsu,attr"` 60 Timestamp Timestamp 61 BinarySecurityToken *BinarySecurityToken `xml:",omitempty"` 62 UsernameToken *UsernameToken `xml:",omitempty"` 63 Assertion string `xml:",innerxml"` 64 Signature *Signature `xml:",omitempty"` 65 } 66 67 type Timestamp struct { 68 XMLName xml.Name `xml:"wsu:Timestamp"` 69 NS string `xml:"xmlns:wsu,attr"` 70 ID string `xml:"wsu:Id,attr"` 71 Created string `xml:"wsu:Created"` 72 Expires string `xml:"wsu:Expires"` 73 } 74 75 func (t *Timestamp) C14N() string { 76 return Marshal(t) 77 } 78 79 type BinarySecurityToken struct { 80 XMLName xml.Name `xml:"wsse:BinarySecurityToken"` 81 EncodingType string `xml:"EncodingType,attr"` 82 ValueType string `xml:"ValueType,attr"` 83 ID string `xml:"wsu:Id,attr"` 84 Value string `xml:",chardata"` 85 } 86 87 type UsernameToken struct { 88 XMLName xml.Name `xml:"wsse:UsernameToken"` 89 Username string `xml:"wsse:Username"` 90 Password string `xml:"wsse:Password"` 91 } 92 93 type Signature struct { 94 XMLName xml.Name 95 NS string `xml:"xmlns:ds,attr"` 96 ID string `xml:"Id,attr"` 97 SignedInfo SignedInfo 98 SignatureValue Value 99 KeyInfo KeyInfo 100 } 101 102 func (s *Signature) C14N() string { 103 return fmt.Sprintf(`<ds:Signature xmlns:ds="%s">%s%s%s</ds:Signature>`, 104 DSIG, s.SignedInfo.C14N(), s.SignatureValue.C14N(), s.KeyInfo.C14N()) 105 } 106 107 type SignedInfo struct { 108 XMLName xml.Name 109 NS string `xml:"xmlns:ds,attr,omitempty"` 110 CanonicalizationMethod Method 111 SignatureMethod Method 112 Reference []Reference 113 } 114 115 func (s SignedInfo) C14N() string { 116 ns := "" // empty in ActAs c14n form for example 117 if s.NS != "" { 118 ns = fmt.Sprintf(` xmlns:ds="%s"`, s.NS) 119 } 120 121 c14n := []string{fmt.Sprintf("<ds:SignedInfo%s>", ns)} 122 c14n = append(c14n, s.CanonicalizationMethod.C14N(), s.SignatureMethod.C14N()) 123 for i := range s.Reference { 124 c14n = append(c14n, s.Reference[i].C14N()) 125 } 126 c14n = append(c14n, "</ds:SignedInfo>") 127 128 return strings.Join(c14n, "") 129 } 130 131 type Method struct { 132 XMLName xml.Name 133 Algorithm string `xml:",attr"` 134 } 135 136 func (m *Method) C14N() string { 137 return mkns("ds", m, &m.XMLName) 138 } 139 140 type Value struct { 141 XMLName xml.Name 142 Value string `xml:",innerxml"` 143 } 144 145 func (v *Value) C14N() string { 146 return mkns("ds", v, &v.XMLName) 147 } 148 149 type Reference struct { 150 XMLName xml.Name 151 URI string `xml:",attr"` 152 Transforms Transforms 153 DigestMethod Method 154 DigestValue Value 155 } 156 157 func (r Reference) C14N() string { 158 for i := range r.Transforms.Transform { 159 t := &r.Transforms.Transform[i] 160 t.XMLName.Local = "ds:Transform" 161 t.XMLName.Space = "" 162 163 if t.InclusiveNamespaces != nil { 164 name := &t.InclusiveNamespaces.XMLName 165 if !strings.HasPrefix(name.Local, "ec:") { 166 name.Local = "ec:" + name.Local 167 name.Space = "" 168 } 169 t.InclusiveNamespaces.NS = t.Algorithm 170 } 171 } 172 173 c14n := []string{ 174 fmt.Sprintf(`<ds:Reference URI="%s">`, r.URI), 175 r.Transforms.C14N(), 176 r.DigestMethod.C14N(), 177 r.DigestValue.C14N(), 178 "</ds:Reference>", 179 } 180 181 return strings.Join(c14n, "") 182 } 183 184 func NewReference(id string, val string) Reference { 185 sum := sha256.Sum256([]byte(val)) 186 187 return Reference{ 188 XMLName: xml.Name{Local: "ds:Reference"}, 189 URI: "#" + id, 190 Transforms: Transforms{ 191 XMLName: xml.Name{Local: "ds:Transforms"}, 192 Transform: []Transform{ 193 Transform{ 194 XMLName: xml.Name{Local: "ds:Transform"}, 195 Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#", 196 }, 197 }, 198 }, 199 DigestMethod: Method{ 200 XMLName: xml.Name{Local: "ds:DigestMethod"}, 201 Algorithm: "http://www.w3.org/2001/04/xmlenc#sha256", 202 }, 203 DigestValue: Value{ 204 XMLName: xml.Name{Local: "ds:DigestValue"}, 205 Value: base64.StdEncoding.EncodeToString(sum[:]), 206 }, 207 } 208 } 209 210 type Transforms struct { 211 XMLName xml.Name 212 Transform []Transform 213 } 214 215 func (t *Transforms) C14N() string { 216 return mkns("ds", t, &t.XMLName) 217 } 218 219 type Transform struct { 220 XMLName xml.Name 221 Algorithm string `xml:",attr"` 222 InclusiveNamespaces *InclusiveNamespaces `xml:",omitempty"` 223 } 224 225 type InclusiveNamespaces struct { 226 XMLName xml.Name 227 NS string `xml:"xmlns:ec,attr,omitempty"` 228 PrefixList string `xml:",attr"` 229 } 230 231 type X509Data struct { 232 XMLName xml.Name 233 X509Certificate string `xml:",innerxml"` 234 } 235 236 type KeyInfo struct { 237 XMLName xml.Name 238 NS string `xml:"xmlns:ds,attr,omitempty"` 239 SecurityTokenReference *SecurityTokenReference `xml:",omitempty"` 240 X509Data *X509Data `xml:",omitempty"` 241 } 242 243 func (o *KeyInfo) C14N() string { 244 names := []*xml.Name{ 245 &o.XMLName, 246 } 247 248 if o.SecurityTokenReference != nil { 249 names = append(names, &o.SecurityTokenReference.XMLName) 250 } 251 if o.X509Data != nil { 252 names = append(names, &o.X509Data.XMLName) 253 } 254 255 return mkns("ds", o, names...) 256 } 257 258 type SecurityTokenReference struct { 259 XMLName xml.Name `xml:"wsse:SecurityTokenReference"` 260 WSSE11 string `xml:"xmlns:wsse11,attr,omitempty"` 261 TokenType string `xml:"wsse11:TokenType,attr,omitempty"` 262 Reference *SecurityReference `xml:",omitempty"` 263 KeyIdentifier *KeyIdentifier `xml:",omitempty"` 264 } 265 266 type SecurityReference struct { 267 XMLName xml.Name `xml:"wsse:Reference"` 268 URI string `xml:",attr"` 269 ValueType string `xml:",attr"` 270 } 271 272 type KeyIdentifier struct { 273 XMLName xml.Name `xml:"wsse:KeyIdentifier"` 274 ID string `xml:",innerxml"` 275 ValueType string `xml:",attr"` 276 } 277 278 type Issuer struct { 279 XMLName xml.Name 280 Format string `xml:",attr"` 281 Value string `xml:",innerxml"` 282 } 283 284 func (i *Issuer) C14N() string { 285 return mkns("saml2", i, &i.XMLName) 286 } 287 288 type Assertion struct { 289 XMLName xml.Name 290 ID string `xml:",attr"` 291 IssueInstant string `xml:",attr"` 292 Version string `xml:",attr"` 293 Issuer Issuer 294 Signature Signature 295 Subject Subject 296 Conditions Conditions 297 AuthnStatement AuthnStatement 298 AttributeStatement AttributeStatement 299 } 300 301 func (a *Assertion) C14N() string { 302 start := `<saml2:Assertion xmlns:saml2="%s" ID="%s" IssueInstant="%s" Version="%s">` 303 c14n := []string{ 304 fmt.Sprintf(start, a.XMLName.Space, a.ID, a.IssueInstant, a.Version), 305 a.Issuer.C14N(), 306 a.Signature.C14N(), 307 a.Subject.C14N(), 308 a.Conditions.C14N(), 309 a.AuthnStatement.C14N(), 310 a.AttributeStatement.C14N(), 311 `</saml2:Assertion>`, 312 } 313 314 return strings.Join(c14n, "") 315 } 316 317 type NameID struct { 318 XMLName xml.Name 319 Format string `xml:",attr"` 320 ID string `xml:",innerxml"` 321 } 322 323 type Subject struct { 324 XMLName xml.Name 325 NameID NameID 326 SubjectConfirmation SubjectConfirmation 327 } 328 329 func (s *Subject) C14N() string { 330 data := &s.SubjectConfirmation.SubjectConfirmationData 331 names := []*xml.Name{ 332 &s.XMLName, 333 &s.NameID.XMLName, 334 &s.SubjectConfirmation.XMLName, 335 &data.XMLName, 336 } 337 if s.SubjectConfirmation.NameID != nil { 338 names = append(names, &s.SubjectConfirmation.NameID.XMLName) 339 } 340 if data.KeyInfo != nil { 341 data.NS = XSI 342 data.Type = "saml2:KeyInfoConfirmationDataType" 343 data.KeyInfo.XMLName = xml.Name{Local: "ds:KeyInfo"} 344 data.KeyInfo.X509Data.XMLName = xml.Name{Local: "ds:X509Data"} 345 data.KeyInfo.NS = DSIG 346 } 347 return mkns("saml2", s, names...) 348 } 349 350 type SubjectConfirmationData struct { 351 XMLName xml.Name 352 NS string `xml:"xmlns:xsi,attr,omitempty"` 353 Type string `xml:"xsi:type,attr,omitempty"` 354 NotOnOrAfter string `xml:",attr,omitempty"` 355 KeyInfo *KeyInfo 356 } 357 358 type SubjectConfirmation struct { 359 XMLName xml.Name 360 Method string `xml:",attr"` 361 NameID *NameID 362 SubjectConfirmationData SubjectConfirmationData 363 } 364 365 type Condition struct { 366 Type string `xml:"xsi:type,attr,omitempty"` 367 } 368 369 func (c *Condition) GetCondition() *Condition { 370 return c 371 } 372 373 type BaseCondition interface { 374 GetCondition() *Condition 375 } 376 377 func init() { 378 types.Add("BaseCondition", reflect.TypeOf((*Condition)(nil)).Elem()) 379 types.Add("del:DelegationRestrictionType", reflect.TypeOf((*DelegateRestriction)(nil)).Elem()) 380 types.Add("rsa:RenewRestrictionType", reflect.TypeOf((*RenewRestriction)(nil)).Elem()) 381 } 382 383 type Conditions struct { 384 XMLName xml.Name 385 NotBefore string `xml:",attr"` 386 NotOnOrAfter string `xml:",attr"` 387 ProxyRestriction *ProxyRestriction `xml:",omitempty"` 388 Condition []BaseCondition `xml:",omitempty"` 389 } 390 391 func (c *Conditions) C14N() string { 392 names := []*xml.Name{ 393 &c.XMLName, 394 } 395 396 if c.ProxyRestriction != nil { 397 names = append(names, &c.ProxyRestriction.XMLName) 398 } 399 400 for i := range c.Condition { 401 switch r := c.Condition[i].(type) { 402 case *DelegateRestriction: 403 names = append(names, &r.XMLName, &r.Delegate.NameID.XMLName) 404 r.NS = XSI 405 r.Type = "del:DelegationRestrictionType" 406 r.Delegate.NS = r.Delegate.XMLName.Space 407 r.Delegate.XMLName = xml.Name{Local: "del:Delegate"} 408 case *RenewRestriction: 409 names = append(names, &r.XMLName) 410 r.NS = XSI 411 r.Type = "rsa:RenewRestrictionType" 412 } 413 } 414 415 return mkns("saml2", c, names...) 416 } 417 418 type ProxyRestriction struct { 419 XMLName xml.Name 420 Count int32 `xml:",attr"` 421 } 422 423 type RenewRestriction struct { 424 XMLName xml.Name 425 NS string `xml:"xmlns:xsi,attr,omitempty"` 426 Count int32 `xml:",attr"` 427 Condition 428 } 429 430 type Delegate struct { 431 XMLName xml.Name 432 NS string `xml:"xmlns:del,attr,omitempty"` 433 DelegationInstant string `xml:",attr"` 434 NameID NameID 435 } 436 437 type DelegateRestriction struct { 438 XMLName xml.Name 439 NS string `xml:"xmlns:xsi,attr,omitempty"` 440 Condition 441 Delegate Delegate 442 } 443 444 type AuthnStatement struct { 445 XMLName xml.Name 446 AuthnInstant string `xml:",attr"` 447 AuthnContext struct { 448 XMLName xml.Name 449 AuthnContextClassRef struct { 450 XMLName xml.Name 451 Value string `xml:",innerxml"` 452 } 453 } 454 } 455 456 func (a *AuthnStatement) C14N() string { 457 return mkns("saml2", a, &a.XMLName, &a.AuthnContext.XMLName, &a.AuthnContext.AuthnContextClassRef.XMLName) 458 } 459 460 type AttributeStatement struct { 461 XMLName xml.Name 462 Attribute []Attribute 463 } 464 465 func (a *AttributeStatement) C14N() string { 466 c14n := []string{"<saml2:AttributeStatement>"} 467 for i := range a.Attribute { 468 c14n = append(c14n, a.Attribute[i].C14N()) 469 } 470 c14n = append(c14n, "</saml2:AttributeStatement>") 471 return strings.Join(c14n, "") 472 } 473 474 type AttributeValue struct { 475 XMLName xml.Name 476 Type string `xml:"type,attr,typeattr"` 477 Value string `xml:",innerxml"` 478 } 479 480 func (a *AttributeValue) C14N() string { 481 return fmt.Sprintf(`<saml2:AttributeValue xmlns:xsi="%s" xsi:type="%s">%s</saml2:AttributeValue>`, XSI, a.Type, a.Value) 482 } 483 484 type Attribute struct { 485 XMLName xml.Name 486 FriendlyName string `xml:",attr"` 487 Name string `xml:",attr"` 488 NameFormat string `xml:",attr"` 489 AttributeValue []AttributeValue 490 } 491 492 func (a *Attribute) C14N() string { 493 c14n := []string{ 494 fmt.Sprintf(`<saml2:Attribute FriendlyName="%s" Name="%s" NameFormat="%s">`, a.FriendlyName, a.Name, a.NameFormat), 495 } 496 497 for i := range a.AttributeValue { 498 c14n = append(c14n, a.AttributeValue[i].C14N()) 499 } 500 501 c14n = append(c14n, `</saml2:Attribute>`) 502 503 return strings.Join(c14n, "") 504 } 505 506 type Lifetime struct { 507 Created string `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd Created"` 508 Expires string `xml:"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd Expires"` 509 } 510 511 func (t *Lifetime) C14N() string { 512 return fmt.Sprintf(`<Lifetime><wsu:Created>%s</wsu:Created><wsu:Expires>%s</wsu:Expires></Lifetime>`, t.Created, t.Expires) 513 } 514 515 type Renewing struct { 516 Allow bool `xml:",attr"` 517 OK bool `xml:",attr"` 518 } 519 520 type UseKey struct { 521 Sig string `xml:",attr"` 522 } 523 524 type Target struct { 525 Token string `xml:",innerxml"` 526 } 527 528 type RequestSecurityToken struct { 529 TokenType string `xml:",omitempty"` 530 RequestType string `xml:",omitempty"` 531 Lifetime *Lifetime `xml:",omitempty"` 532 Renewing *Renewing `xml:",omitempty"` 533 Delegatable bool `xml:",omitempty"` 534 KeyType string `xml:",omitempty"` 535 SignatureAlgorithm string `xml:",omitempty"` 536 UseKey *UseKey `xml:",omitempty"` 537 ActAs *Target `xml:",omitempty"` 538 ValidateTarget *Target `xml:",omitempty"` 539 RenewTarget *Target `xml:",omitempty"` 540 } 541 542 func Unmarshal(data []byte, v interface{}) error { 543 dec := xml.NewDecoder(bytes.NewReader(data)) 544 dec.TypeFunc = types.TypeFunc() 545 return dec.Decode(v) 546 } 547 548 // toString returns an XML encoded RequestSecurityToken. 549 // When c14n is true, returns the canonicalized ActAs.Assertion which is required to sign the Issue request. 550 // When c14n is false, returns the original content of the ActAs.Assertion. 551 // The original content must be used within the request Body, as it has its own signature. 552 func (r *RequestSecurityToken) toString(c14n bool) string { 553 actas := "" 554 if r.ActAs != nil { 555 token := r.ActAs.Token 556 if c14n { 557 var a Assertion 558 err := Unmarshal([]byte(r.ActAs.Token), &a) 559 if err != nil { 560 log.Printf("decode ActAs: %s", err) 561 } 562 token = a.C14N() 563 } 564 565 actas = fmt.Sprintf(`<wst:ActAs xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200802">%s</wst:ActAs>`, token) 566 } 567 568 body := []string{ 569 fmt.Sprintf(`<RequestSecurityToken xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512">`), 570 fmt.Sprintf(`<TokenType>%s</TokenType>`, r.TokenType), 571 fmt.Sprintf(`<RequestType>%s</RequestType>`, r.RequestType), 572 r.Lifetime.C14N(), 573 } 574 575 if r.RenewTarget == nil { 576 body = append(body, 577 fmt.Sprintf(`<Renewing Allow="%t" OK="%t"></Renewing>`, r.Renewing.Allow, r.Renewing.OK), 578 fmt.Sprintf(`<Delegatable>%t</Delegatable>`, r.Delegatable), 579 actas, 580 fmt.Sprintf(`<KeyType>%s</KeyType>`, r.KeyType), 581 fmt.Sprintf(`<SignatureAlgorithm>%s</SignatureAlgorithm>`, r.SignatureAlgorithm), 582 fmt.Sprintf(`<UseKey Sig="%s"></UseKey>`, r.UseKey.Sig)) 583 } else { 584 token := r.RenewTarget.Token 585 if c14n { 586 var a Assertion 587 err := Unmarshal([]byte(r.RenewTarget.Token), &a) 588 if err != nil { 589 log.Printf("decode Renew: %s", err) 590 } 591 token = a.C14N() 592 } 593 594 body = append(body, 595 fmt.Sprintf(`<UseKey Sig="%s"></UseKey>`, r.UseKey.Sig), 596 fmt.Sprintf(`<RenewTarget>%s</RenewTarget>`, token)) 597 } 598 599 return strings.Join(append(body, `</RequestSecurityToken>`), "") 600 } 601 602 func (r *RequestSecurityToken) C14N() string { 603 return r.toString(true) 604 } 605 606 func (r *RequestSecurityToken) String() string { 607 return r.toString(false) 608 } 609 610 type RequestSecurityTokenResponseCollection struct { 611 RequestSecurityTokenResponse RequestSecurityTokenResponse 612 } 613 614 type RequestSecurityTokenResponse struct { 615 RequestedSecurityToken RequestedSecurityToken 616 Lifetime *Lifetime `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 Lifetime"` 617 } 618 619 type RequestedSecurityToken struct { 620 Assertion string `xml:",innerxml"` 621 } 622 623 type RequestSecurityTokenBody struct { 624 Req *RequestSecurityToken `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityToken,omitempty"` 625 Res *RequestSecurityTokenResponseCollection `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityTokenResponseCollection,omitempty"` 626 Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` 627 } 628 629 func (b *RequestSecurityTokenBody) Fault() *soap.Fault { return b.Fault_ } 630 631 func (b *RequestSecurityTokenBody) RequestSecurityToken() *RequestSecurityToken { return b.Req } 632 633 func (r *RequestSecurityToken) Action() string { 634 kind := path.Base(r.RequestType) 635 return "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/" + kind 636 } 637 638 func Issue(ctx context.Context, r soap.RoundTripper, req *RequestSecurityToken) (*RequestSecurityTokenResponseCollection, error) { 639 var reqBody, resBody RequestSecurityTokenBody 640 641 reqBody.Req = req 642 643 if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { 644 return nil, err 645 } 646 647 return resBody.Res, nil 648 } 649 650 type RenewSecurityTokenBody struct { 651 Req *RequestSecurityToken `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityToken,omitempty"` 652 Res *RequestSecurityTokenResponse `xml:"http://docs.oasis-open.org/ws-sx/ws-trust/200512 RequestSecurityTokenResponse,omitempty"` 653 Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` 654 } 655 656 func (b *RenewSecurityTokenBody) Fault() *soap.Fault { return b.Fault_ } 657 658 func (b *RenewSecurityTokenBody) RequestSecurityToken() *RequestSecurityToken { return b.Req } 659 660 func Renew(ctx context.Context, r soap.RoundTripper, req *RequestSecurityToken) (*RequestSecurityTokenResponse, error) { 661 var reqBody, resBody RenewSecurityTokenBody 662 663 reqBody.Req = req 664 665 if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { 666 return nil, err 667 } 668 669 return resBody.Res, nil 670 } 671 672 // Marshal panics if xml.Marshal returns an error 673 func Marshal(val interface{}) string { 674 b, err := xml.Marshal(val) 675 if err != nil { 676 panic(err) 677 } 678 return string(b) 679 } 680 681 // mkns prepends the given namespace to xml.Name.Local and returns obj encoded as xml. 682 // Note that the namespace is required when encoding, but the namespace prefix must not be 683 // present when decoding as Go's decoding does not handle namespace prefix. 684 func mkns(ns string, obj interface{}, name ...*xml.Name) string { 685 ns += ":" 686 for i := range name { 687 name[i].Space = "" 688 if !strings.HasPrefix(name[i].Local, ns) { 689 name[i].Local = ns + name[i].Local 690 } 691 } 692 693 return Marshal(obj) 694 }