github.com/crewjam/saml@v0.4.14/schema.go (about) 1 package saml 2 3 import ( 4 "bytes" 5 "compress/flate" 6 "encoding/xml" 7 "strconv" 8 "time" 9 10 "github.com/beevik/etree" 11 "github.com/russellhaering/goxmldsig/etreeutils" 12 ) 13 14 // RequestedAuthnContext represents the SAML object of the same name, an indication of the 15 // requirements on the authentication process. 16 type RequestedAuthnContext struct { 17 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol RequestedAuthnContext"` 18 Comparison string `xml:",attr"` 19 AuthnContextClassRef string `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthnContextClassRef"` 20 } 21 22 // Element returns an etree.Element representing the object in XML form. 23 func (r *RequestedAuthnContext) Element() *etree.Element { 24 el := etree.NewElement("samlp:RequestedAuthnContext") 25 el.CreateAttr("Comparison", r.Comparison) 26 elContext := etree.NewElement("saml:AuthnContextClassRef") 27 elContext.SetText(r.AuthnContextClassRef) 28 el.AddChild(elContext) 29 return el 30 } 31 32 // AuthnRequest represents the SAML object of the same name, a request from a service provider 33 // to authenticate a user. 34 // 35 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf 36 type AuthnRequest struct { 37 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol AuthnRequest"` 38 39 ID string `xml:",attr"` 40 Version string `xml:",attr"` 41 IssueInstant time.Time `xml:",attr"` 42 Destination string `xml:",attr"` 43 Consent string `xml:",attr"` 44 Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` 45 Signature *etree.Element 46 47 Subject *Subject 48 NameIDPolicy *NameIDPolicy `xml:"urn:oasis:names:tc:SAML:2.0:protocol NameIDPolicy"` 49 Conditions *Conditions 50 RequestedAuthnContext *RequestedAuthnContext 51 // Scoping *Scoping // TODO 52 53 ForceAuthn *bool `xml:",attr"` 54 IsPassive *bool `xml:",attr"` 55 AssertionConsumerServiceIndex string `xml:",attr"` 56 AssertionConsumerServiceURL string `xml:",attr"` 57 ProtocolBinding string `xml:",attr"` 58 AttributeConsumingServiceIndex string `xml:",attr"` 59 ProviderName string `xml:",attr"` 60 } 61 62 // LogoutRequest represents the SAML object of the same name, a request from an IDP 63 // to destroy a user's session. 64 // 65 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf 66 type LogoutRequest struct { 67 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol LogoutRequest"` 68 69 ID string `xml:",attr"` 70 Version string `xml:",attr"` 71 IssueInstant time.Time `xml:",attr"` 72 NotOnOrAfter *time.Time `xml:",attr"` 73 Destination string `xml:",attr"` 74 Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` 75 NameID *NameID 76 Signature *etree.Element 77 78 SessionIndex *SessionIndex `xml:"SessionIndex"` 79 } 80 81 // Element returns an etree.Element representing the object in XML form. 82 func (r *LogoutRequest) Element() *etree.Element { 83 el := etree.NewElement("samlp:LogoutRequest") 84 el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") 85 el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") 86 el.CreateAttr("ID", r.ID) 87 el.CreateAttr("Version", r.Version) 88 el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) 89 if r.NotOnOrAfter != nil { 90 el.CreateAttr("NotOnOrAfter", r.NotOnOrAfter.Format(timeFormat)) 91 } 92 if r.Destination != "" { 93 el.CreateAttr("Destination", r.Destination) 94 } 95 if r.Issuer != nil { 96 el.AddChild(r.Issuer.Element()) 97 } 98 if r.Signature != nil { 99 el.AddChild(r.Signature) 100 } 101 if r.NameID != nil { 102 el.AddChild(r.NameID.Element()) 103 } 104 if r.SessionIndex != nil { 105 el.AddChild(r.SessionIndex.Element()) 106 } 107 return el 108 } 109 110 // MarshalXML implements xml.Marshaler 111 func (r *LogoutRequest) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { 112 type Alias LogoutRequest 113 aux := &struct { 114 IssueInstant RelaxedTime `xml:",attr"` 115 NotOnOrAfter *RelaxedTime `xml:",attr"` 116 *Alias 117 }{ 118 IssueInstant: RelaxedTime(r.IssueInstant), 119 NotOnOrAfter: (*RelaxedTime)(r.NotOnOrAfter), 120 Alias: (*Alias)(r), 121 } 122 return e.Encode(aux) 123 } 124 125 // UnmarshalXML implements xml.Unmarshaler 126 func (r *LogoutRequest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 127 type Alias LogoutRequest 128 aux := &struct { 129 IssueInstant RelaxedTime `xml:",attr"` 130 NotOnOrAfter *RelaxedTime `xml:",attr"` 131 *Alias 132 }{ 133 Alias: (*Alias)(r), 134 } 135 if err := d.DecodeElement(&aux, &start); err != nil { 136 return err 137 } 138 r.IssueInstant = time.Time(aux.IssueInstant) 139 r.NotOnOrAfter = (*time.Time)(aux.NotOnOrAfter) 140 return nil 141 } 142 143 // Bytes returns a byte array representation of the LogoutRequest 144 func (r *LogoutRequest) Bytes() ([]byte, error) { 145 doc := etree.NewDocument() 146 doc.SetRoot(r.Element()) 147 148 buf, err := doc.WriteToBytes() 149 if err != nil { 150 return nil, err 151 } 152 153 return buf, nil 154 } 155 156 // Deflate returns a compressed byte array of the LogoutRequest 157 func (r *LogoutRequest) Deflate() ([]byte, error) { 158 buf, err := r.Bytes() 159 if err != nil { 160 return nil, err 161 } 162 163 var b bytes.Buffer 164 writer, err := flate.NewWriter(&b, flate.DefaultCompression) 165 if err != nil { 166 return nil, err 167 } 168 169 if _, err := writer.Write(buf); err != nil { 170 return nil, err 171 } 172 173 if err := writer.Close(); err != nil { 174 return nil, err 175 } 176 177 return b.Bytes(), nil 178 } 179 180 // Element returns an etree.Element representing the object in XML form. 181 func (r *AuthnRequest) Element() *etree.Element { 182 el := etree.NewElement("samlp:AuthnRequest") 183 el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") 184 el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") 185 el.CreateAttr("ID", r.ID) 186 el.CreateAttr("Version", r.Version) 187 el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) 188 if r.Destination != "" { 189 el.CreateAttr("Destination", r.Destination) 190 } 191 if r.Consent != "" { 192 el.CreateAttr("Consent", r.Consent) 193 } 194 if r.Issuer != nil { 195 el.AddChild(r.Issuer.Element()) 196 } 197 if r.Signature != nil { 198 el.AddChild(r.Signature) 199 } 200 if r.Subject != nil { 201 el.AddChild(r.Subject.Element()) 202 } 203 if r.NameIDPolicy != nil { 204 el.AddChild(r.NameIDPolicy.Element()) 205 } 206 if r.Conditions != nil { 207 el.AddChild(r.Conditions.Element()) 208 } 209 if r.RequestedAuthnContext != nil { 210 el.AddChild(r.RequestedAuthnContext.Element()) 211 } 212 // if r.Scoping != nil { 213 // el.AddChild(r.Scoping.Element()) 214 // } 215 if r.ForceAuthn != nil { 216 el.CreateAttr("ForceAuthn", strconv.FormatBool(*r.ForceAuthn)) 217 } 218 if r.IsPassive != nil { 219 el.CreateAttr("IsPassive", strconv.FormatBool(*r.IsPassive)) 220 } 221 if r.AssertionConsumerServiceIndex != "" { 222 el.CreateAttr("AssertionConsumerServiceIndex", r.AssertionConsumerServiceIndex) 223 } 224 if r.AssertionConsumerServiceURL != "" { 225 el.CreateAttr("AssertionConsumerServiceURL", r.AssertionConsumerServiceURL) 226 } 227 if r.ProtocolBinding != "" { 228 el.CreateAttr("ProtocolBinding", r.ProtocolBinding) 229 } 230 if r.AttributeConsumingServiceIndex != "" { 231 el.CreateAttr("AttributeConsumingServiceIndex", r.AttributeConsumingServiceIndex) 232 } 233 if r.ProviderName != "" { 234 el.CreateAttr("ProviderName", r.ProviderName) 235 } 236 return el 237 } 238 239 // MarshalXML implements xml.Marshaler 240 func (r *AuthnRequest) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { 241 type Alias AuthnRequest 242 aux := &struct { 243 IssueInstant RelaxedTime `xml:",attr"` 244 *Alias 245 }{ 246 IssueInstant: RelaxedTime(r.IssueInstant), 247 Alias: (*Alias)(r), 248 } 249 return e.Encode(aux) 250 } 251 252 // UnmarshalXML implements xml.Unmarshaler 253 func (r *AuthnRequest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 254 type Alias AuthnRequest 255 aux := &struct { 256 IssueInstant RelaxedTime `xml:",attr"` 257 *Alias 258 }{ 259 Alias: (*Alias)(r), 260 } 261 if err := d.DecodeElement(&aux, &start); err != nil { 262 return err 263 } 264 r.IssueInstant = time.Time(aux.IssueInstant) 265 return nil 266 } 267 268 // Issuer represents the SAML object of the same name. 269 // 270 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf 271 type Issuer struct { 272 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` 273 NameQualifier string `xml:",attr"` 274 SPNameQualifier string `xml:",attr"` 275 Format string `xml:",attr"` 276 SPProvidedID string `xml:",attr"` 277 Value string `xml:",chardata"` 278 } 279 280 // Element returns an etree.Element representing the object in XML form. 281 func (a *Issuer) Element() *etree.Element { 282 el := etree.NewElement("saml:Issuer") 283 if a.NameQualifier != "" { 284 el.CreateAttr("NameQualifier", a.NameQualifier) 285 } 286 if a.SPNameQualifier != "" { 287 el.CreateAttr("SPNameQualifier", a.SPNameQualifier) 288 } 289 if a.Format != "" { 290 el.CreateAttr("Format", a.Format) 291 } 292 if a.SPProvidedID != "" { 293 el.CreateAttr("SPProvidedID", a.SPProvidedID) 294 } 295 el.SetText(a.Value) 296 return el 297 } 298 299 // NameIDPolicy represents the SAML object of the same name. 300 // 301 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf 302 type NameIDPolicy struct { 303 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol NameIDPolicy"` 304 Format *string `xml:",attr"` 305 SPNameQualifier *string `xml:",attr"` 306 AllowCreate *bool `xml:",attr"` 307 } 308 309 // Element returns an etree.Element representing the object in XML form. 310 func (a *NameIDPolicy) Element() *etree.Element { 311 el := etree.NewElement("samlp:NameIDPolicy") 312 if a.Format != nil && *a.Format != "" { 313 el.CreateAttr("Format", *a.Format) 314 } 315 if a.SPNameQualifier != nil { 316 el.CreateAttr("SPNameQualifier", *a.SPNameQualifier) 317 } 318 if a.AllowCreate != nil { 319 el.CreateAttr("AllowCreate", strconv.FormatBool(*a.AllowCreate)) 320 } 321 return el 322 } 323 324 // ArtifactResolve represents the SAML object of the same name. 325 type ArtifactResolve struct { 326 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol ArtifactResolve"` 327 ID string `xml:",attr"` 328 Version string `xml:",attr"` 329 IssueInstant time.Time `xml:",attr"` 330 Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` 331 Signature *etree.Element 332 Artifact string `xml:"urn:oasis:names:tc:SAML:2.0:protocol Artifact"` 333 } 334 335 // Element returns an etree.Element representing the object in XML form. 336 func (r *ArtifactResolve) Element() *etree.Element { 337 el := etree.NewElement("samlp:ArtifactResolve") 338 el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") 339 el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") 340 341 // Note: This namespace is not used by any element or attribute name, but 342 // is required so that the AttributeValue type element can have a value like 343 // "xs:string". If we don't declare it here, then it will be stripped by the 344 // cannonicalizer. This could be avoided by providing a prefix list to the 345 // cannonicalizer, but prefix lists do not appear to be implemented correctly 346 // in some libraries, so the safest action is to always produce XML that is 347 // (a) in canonical form and (b) does not require prefix lists. 348 el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") 349 350 el.CreateAttr("ID", r.ID) 351 el.CreateAttr("Version", r.Version) 352 el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) 353 if r.Issuer != nil { 354 el.AddChild(r.Issuer.Element()) 355 } 356 artifact := etree.NewElement("samlp:Artifact") 357 artifact.SetText(r.Artifact) 358 el.AddChild(artifact) 359 if r.Signature != nil { 360 el.AddChild(r.Signature) 361 } 362 return el 363 } 364 365 // SoapRequest returns a SOAP Envelope contining the ArtifactResolve request 366 func (r *ArtifactResolve) SoapRequest() *etree.Element { 367 envelope := etree.NewElement("soapenv:Envelope") 368 envelope.CreateAttr("xmlns:soapenv", "http://schemas.xmlsoap.org/soap/envelope/") 369 envelope.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") 370 body := etree.NewElement("soapenv:Body") 371 envelope.AddChild(body) 372 body.AddChild(r.Element()) 373 return envelope 374 } 375 376 // MarshalXML implements xml.Marshaler 377 func (r *ArtifactResolve) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { 378 type Alias ArtifactResolve 379 aux := &struct { 380 IssueInstant RelaxedTime `xml:",attr"` 381 *Alias 382 }{ 383 IssueInstant: RelaxedTime(r.IssueInstant), 384 Alias: (*Alias)(r), 385 } 386 return e.Encode(aux) 387 } 388 389 // UnmarshalXML implements xml.Unmarshaler 390 func (r *ArtifactResolve) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 391 type Alias ArtifactResolve 392 aux := &struct { 393 IssueInstant RelaxedTime `xml:",attr"` 394 *Alias 395 }{ 396 Alias: (*Alias)(r), 397 } 398 if err := d.DecodeElement(&aux, &start); err != nil { 399 return err 400 } 401 r.IssueInstant = time.Time(aux.IssueInstant) 402 return nil 403 } 404 405 // ArtifactResponse represents the SAML object of the same name. 406 type ArtifactResponse struct { 407 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol ArtifactResponse"` 408 ID string `xml:",attr"` 409 InResponseTo string `xml:",attr"` 410 Version string `xml:",attr"` 411 IssueInstant time.Time `xml:",attr"` 412 Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` 413 Signature *etree.Element 414 Status Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"` 415 Response Response `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"` 416 } 417 418 // Element returns an etree.Element representing the object in XML form. 419 func (r *ArtifactResponse) Element() *etree.Element { 420 el := etree.NewElement("samlp:ArtifactResponse") 421 el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") 422 el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") 423 424 // Note: This namespace is not used by any element or attribute name, but 425 // is required so that the AttributeValue type element can have a value like 426 // "xs:string". If we don't declare it here, then it will be stripped by the 427 // cannonicalizer. This could be avoided by providing a prefix list to the 428 // cannonicalizer, but prefix lists do not appear to be implemented correctly 429 // in some libraries, so the safest action is to always produce XML that is 430 // (a) in canonical form and (b) does not require prefix lists. 431 el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") 432 433 el.CreateAttr("ID", r.ID) 434 if r.InResponseTo != "" { 435 el.CreateAttr("InResponseTo", r.InResponseTo) 436 } 437 el.CreateAttr("Version", r.Version) 438 el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) 439 if r.Issuer != nil { 440 el.AddChild(r.Issuer.Element()) 441 } 442 if r.Signature != nil { 443 el.AddChild(r.Signature) 444 } 445 el.AddChild(r.Status.Element()) 446 el.AddChild(r.Response.Element()) 447 return el 448 } 449 450 // MarshalXML implements xml.Marshaler 451 func (r *ArtifactResponse) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { 452 type Alias ArtifactResponse 453 aux := &struct { 454 IssueInstant RelaxedTime `xml:",attr"` 455 *Alias 456 }{ 457 IssueInstant: RelaxedTime(r.IssueInstant), 458 Alias: (*Alias)(r), 459 } 460 return e.Encode(aux) 461 } 462 463 // UnmarshalXML implements xml.Unmarshaler 464 func (r *ArtifactResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 465 type Alias ArtifactResponse 466 aux := &struct { 467 IssueInstant RelaxedTime `xml:",attr"` 468 *Alias 469 }{ 470 Alias: (*Alias)(r), 471 } 472 if err := d.DecodeElement(&aux, &start); err != nil { 473 return err 474 } 475 r.IssueInstant = time.Time(aux.IssueInstant) 476 return nil 477 } 478 479 // Response represents the SAML object of the same name. 480 // 481 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf 482 type Response struct { 483 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"` 484 ID string `xml:",attr"` 485 InResponseTo string `xml:",attr"` 486 Version string `xml:",attr"` 487 IssueInstant time.Time `xml:",attr"` 488 Destination string `xml:",attr"` 489 Consent string `xml:",attr"` 490 Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` 491 Signature *etree.Element 492 Status Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"` 493 494 // TODO(ross): more than one EncryptedAssertion is allowed 495 EncryptedAssertion *etree.Element `xml:"urn:oasis:names:tc:SAML:2.0:assertion EncryptedAssertion"` 496 497 // TODO(ross): more than one Assertion is allowed 498 Assertion *Assertion `xml:"urn:oasis:names:tc:SAML:2.0:assertion Assertion"` 499 } 500 501 // Element returns an etree.Element representing the object in XML form. 502 func (r *Response) Element() *etree.Element { 503 el := etree.NewElement("samlp:Response") 504 el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") 505 el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") 506 507 // Note: This namespace is not used by any element or attribute name, but 508 // is required so that the AttributeValue type element can have a value like 509 // "xs:string". If we don't declare it here, then it will be stripped by the 510 // cannonicalizer. This could be avoided by providing a prefix list to the 511 // cannonicalizer, but prefix lists do not appear to be implemented correctly 512 // in some libraries, so the safest action is to always produce XML that is 513 // (a) in canonical form and (b) does not require prefix lists. 514 el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") 515 516 el.CreateAttr("ID", r.ID) 517 if r.InResponseTo != "" { 518 el.CreateAttr("InResponseTo", r.InResponseTo) 519 } 520 el.CreateAttr("Version", r.Version) 521 el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) 522 if r.Destination != "" { 523 el.CreateAttr("Destination", r.Destination) 524 } 525 if r.Consent != "" { 526 el.CreateAttr("Consent", r.Consent) 527 } 528 if r.Issuer != nil { 529 el.AddChild(r.Issuer.Element()) 530 } 531 if r.Signature != nil { 532 el.AddChild(r.Signature) 533 } 534 el.AddChild(r.Status.Element()) 535 if r.EncryptedAssertion != nil { 536 el.AddChild(r.EncryptedAssertion) 537 } 538 if r.Assertion != nil { 539 el.AddChild(r.Assertion.Element()) 540 } 541 return el 542 } 543 544 // MarshalXML implements xml.Marshaler 545 func (r *Response) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { 546 type Alias Response 547 aux := &struct { 548 IssueInstant RelaxedTime `xml:",attr"` 549 *Alias 550 }{ 551 IssueInstant: RelaxedTime(r.IssueInstant), 552 Alias: (*Alias)(r), 553 } 554 return e.Encode(aux) 555 } 556 557 // UnmarshalXML implements xml.Unmarshaler 558 func (r *Response) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 559 type Alias Response 560 aux := &struct { 561 IssueInstant RelaxedTime `xml:",attr"` 562 *Alias 563 }{ 564 Alias: (*Alias)(r), 565 } 566 if err := d.DecodeElement(&aux, &start); err != nil { 567 return err 568 } 569 r.IssueInstant = time.Time(aux.IssueInstant) 570 return nil 571 } 572 573 // Status represents the SAML object of the same name. 574 // 575 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf 576 type Status struct { 577 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"` 578 StatusCode StatusCode 579 StatusMessage *StatusMessage 580 StatusDetail *StatusDetail 581 } 582 583 // Element returns an etree.Element representing the object in XML form. 584 func (s *Status) Element() *etree.Element { 585 el := etree.NewElement("samlp:Status") 586 el.AddChild(s.StatusCode.Element()) 587 if s.StatusMessage != nil { 588 el.AddChild(s.StatusMessage.Element()) 589 } 590 if s.StatusDetail != nil { 591 el.AddChild(s.StatusDetail.Element()) 592 } 593 return el 594 } 595 596 // StatusCode represents the SAML object of the same name. 597 // 598 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf 599 type StatusCode struct { 600 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol StatusCode"` 601 Value string `xml:",attr"` 602 StatusCode *StatusCode 603 } 604 605 // Element returns an etree.Element representing the object in XML form. 606 func (s *StatusCode) Element() *etree.Element { 607 el := etree.NewElement("samlp:StatusCode") 608 el.CreateAttr("Value", s.Value) 609 if s.StatusCode != nil { 610 el.AddChild(s.StatusCode.Element()) 611 } 612 return el 613 } 614 615 // StatusSuccess means the request succeeded. Additional information MAY be returned in the <StatusMessage> and/or <StatusDetail> elements. 616 // 617 // TODO(ross): this value is mostly constant, but is mutated in tests. Fix the hacky test so this can be const. 618 var StatusSuccess = "urn:oasis:names:tc:SAML:2.0:status:Success" 619 620 const ( 621 // The permissible top-level <StatusCode> values are as follows: 622 623 // StatusRequester means the request could not be performed due to an error on the part of the requester. 624 StatusRequester = "urn:oasis:names:tc:SAML:2.0:status:Requester" 625 626 // StatusResponder means the request could not be performed due to an error on the part of the SAML responder or SAML authority. 627 StatusResponder = "urn:oasis:names:tc:SAML:2.0:status:Responder" 628 629 // StatusVersionMismatch means the SAML responder could not process the request because the version of the request message was incorrect. 630 StatusVersionMismatch = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch" 631 632 // The following second-level status codes are referenced at various places in this specification. Additional 633 // second-level status codes MAY be defined in future versions of the SAML specification. System entities 634 // are free to define more specific status codes by defining appropriate URI references. 635 636 // StatusAuthnFailed means the responding provider was unable to successfully authenticate the principal. 637 StatusAuthnFailed = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed" 638 639 // StatusInvalidAttrNameOrValue means Unexpected or invalid content was encountered within a <saml:Attribute> or <saml:AttributeValue> element. 640 StatusInvalidAttrNameOrValue = "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue" 641 642 // StatusInvalidNameIDPolicy means the responding provider cannot or will not support the requested name identifier policy. 643 StatusInvalidNameIDPolicy = "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy" 644 645 // StatusNoAuthnContext means the specified authentication context requirements cannot be met by the responder. 646 StatusNoAuthnContext = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext" 647 648 // StatusNoAvailableIDP is used by an intermediary to indicate that none of the supported identity provider <Loc> elements in an <IDPList> can be resolved or that none of the supported identity providers are available. 649 StatusNoAvailableIDP = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP" 650 651 // StatusNoPassive means Indicates the responding provider cannot authenticate the principal passively, as has been requested. 652 StatusNoPassive = "urn:oasis:names:tc:SAML:2.0:status:NoPassive" //nolint:gosec 653 654 // StatusNoSupportedIDP is used by an intermediary to indicate that none of the identity providers in an <IDPList> are supported by the intermediary. 655 StatusNoSupportedIDP = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP" 656 657 // StatusPartialLogout is used by a session authority to indicate to a session participant that it was not able to propagate logout to all other session participants. 658 StatusPartialLogout = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout" 659 660 // StatusProxyCountExceeded means Indicates that a responding provider cannot authenticate the principal directly and is not permitted to proxy the request further. 661 StatusProxyCountExceeded = "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded" 662 663 // StatusRequestDenied means the SAML responder or SAML authority is able to process the request but has chosen not to respond. This status code MAY be used when there is concern about the security context of the request message or the sequence of request messages received from a particular requester. 664 StatusRequestDenied = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied" 665 666 // StatusRequestUnsupported means the SAML responder or SAML authority does not support the request. 667 StatusRequestUnsupported = "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported" 668 669 // StatusRequestVersionDeprecated means the SAML responder cannot process any requests with the protocol version specified in the request. 670 StatusRequestVersionDeprecated = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated" //nolint:gosec 671 672 // StatusRequestVersionTooHigh means the SAML responder cannot process the request because the protocol version specified in the request message is a major upgrade from the highest protocol version supported by the responder. 673 StatusRequestVersionTooHigh = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh" 674 675 // StatusRequestVersionTooLow means the SAML responder cannot process the request because the protocol version specified in the request message is too low. 676 StatusRequestVersionTooLow = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow" 677 678 // StatusResourceNotRecognized means the resource value provided in the request message is invalid or unrecognized. 679 StatusResourceNotRecognized = "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized" 680 681 // StatusTooManyResponses means the response message would contain more elements than the SAML responder is able to return. 682 StatusTooManyResponses = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses" 683 684 // StatusUnknownAttrProfile means an entity that has no knowledge of a particular attribute profile has been presented with an attribute means drawn from that profile. 685 StatusUnknownAttrProfile = "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile" 686 687 // StatusUnknownPrincipal means the responding provider does not recognize the principal specified or implied by the request. 688 StatusUnknownPrincipal = "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal" 689 690 // StatusUnsupportedBinding means the SAML responder cannot properly fulfill the request using the protocol binding specified in the request. 691 StatusUnsupportedBinding = "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding" 692 ) 693 694 // StatusMessage represents the SAML element StatusMessage. 695 // 696 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.2.2.3 697 type StatusMessage struct { 698 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol StatusMessage"` 699 Value string `xml:",chardata"` 700 } 701 702 // Element returns an etree.Element representing the object in XML form. 703 func (sm StatusMessage) Element() *etree.Element { 704 el := etree.NewElement("samlp:StatusMessage") 705 el.SetText(sm.Value) 706 return el 707 } 708 709 // StatusDetail represents the SAML element StatusDetail. 710 // 711 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.2.2.4 712 type StatusDetail struct { 713 Children []*etree.Element 714 } 715 716 // Element returns an etree.Element representing the object in XML form. 717 func (sm StatusDetail) Element() *etree.Element { 718 el := etree.NewElement("samlp:StatusDetail") 719 for _, child := range sm.Children { 720 el.AddChild(child) 721 } 722 return el 723 } 724 725 // Assertion represents the SAML element Assertion. 726 // 727 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.3.3 728 type Assertion struct { 729 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Assertion"` 730 ID string `xml:",attr"` 731 IssueInstant time.Time `xml:",attr"` 732 Version string `xml:",attr"` 733 Issuer Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` 734 Signature *etree.Element 735 Subject *Subject 736 Conditions *Conditions 737 // Advice *Advice 738 // Statements []Statement 739 AuthnStatements []AuthnStatement `xml:"AuthnStatement"` 740 // AuthzDecisionStatements []AuthzDecisionStatement 741 AttributeStatements []AttributeStatement `xml:"AttributeStatement"` 742 } 743 744 // Element returns an etree.Element representing the object in XML form. 745 func (a *Assertion) Element() *etree.Element { 746 el := etree.NewElement("saml:Assertion") 747 el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") 748 el.CreateAttr("Version", "2.0") 749 el.CreateAttr("ID", a.ID) 750 el.CreateAttr("IssueInstant", a.IssueInstant.Format(timeFormat)) 751 el.AddChild(a.Issuer.Element()) 752 if a.Signature != nil { 753 el.AddChild(a.Signature) 754 } 755 if a.Subject != nil { 756 el.AddChild(a.Subject.Element()) 757 } 758 if a.Conditions != nil { 759 el.AddChild(a.Conditions.Element()) 760 } 761 for _, authnStatement := range a.AuthnStatements { 762 el.AddChild(authnStatement.Element()) 763 } 764 for _, attributeStatement := range a.AttributeStatements { 765 el.AddChild(attributeStatement.Element()) 766 } 767 err := etreeutils.TransformExcC14n(el, canonicalizerPrefixList, false) 768 if err != nil { 769 panic(err) 770 } 771 return el 772 } 773 774 // UnmarshalXML implements xml.Unmarshaler 775 func (a *Assertion) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 776 type Alias Assertion 777 aux := &struct { 778 IssueInstant RelaxedTime `xml:",attr"` 779 *Alias 780 }{ 781 Alias: (*Alias)(a), 782 } 783 if err := d.DecodeElement(&aux, &start); err != nil { 784 return err 785 } 786 a.IssueInstant = time.Time(aux.IssueInstant) 787 return nil 788 } 789 790 // Subject represents the SAML element Subject. 791 // 792 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1 793 type Subject struct { 794 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Subject"` 795 // BaseID *BaseID ... TODO 796 NameID *NameID 797 // EncryptedID *EncryptedID ... TODO 798 SubjectConfirmations []SubjectConfirmation `xml:"SubjectConfirmation"` 799 } 800 801 // Element returns an etree.Element representing the object in XML form. 802 func (a *Subject) Element() *etree.Element { 803 el := etree.NewElement("saml:Subject") 804 if a.NameID != nil { 805 el.AddChild(a.NameID.Element()) 806 } 807 for _, v := range a.SubjectConfirmations { 808 el.AddChild(v.Element()) 809 } 810 return el 811 } 812 813 // NameID represents the SAML element NameID. 814 // 815 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.2.3 816 type NameID struct { 817 NameQualifier string `xml:",attr"` 818 SPNameQualifier string `xml:",attr"` 819 Format string `xml:",attr"` 820 SPProvidedID string `xml:",attr"` 821 Value string `xml:",chardata"` 822 } 823 824 // Element returns an etree.Element representing the object in XML form. 825 func (a *NameID) Element() *etree.Element { 826 el := etree.NewElement("saml:NameID") 827 if a.NameQualifier != "" { 828 el.CreateAttr("NameQualifier", a.NameQualifier) 829 } 830 if a.SPNameQualifier != "" { 831 el.CreateAttr("SPNameQualifier", a.SPNameQualifier) 832 } 833 if a.Format != "" { 834 el.CreateAttr("Format", a.Format) 835 } 836 if a.SPProvidedID != "" { 837 el.CreateAttr("SPProvidedID", a.SPProvidedID) 838 } 839 if a.Value != "" { 840 el.SetText(a.Value) 841 } 842 return el 843 } 844 845 // SessionIndex represents the SAML element SessionIndex. 846 // 847 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.7.1 848 type SessionIndex struct { 849 Value string `xml:",chardata"` 850 } 851 852 // Element returns an etree.Element representing the object in XML form. 853 func (s *SessionIndex) Element() *etree.Element { 854 el := etree.NewElement("samlp:SessionIndex") 855 el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") 856 if s.Value != "" { 857 el.SetText(s.Value) 858 } 859 return el 860 } 861 862 // SubjectConfirmation represents the SAML element SubjectConfirmation. 863 // 864 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1.1 865 type SubjectConfirmation struct { 866 Method string `xml:",attr"` 867 // BaseID *BaseID ... TODO 868 NameID *NameID 869 // EncryptedID *EncryptedID ... TODO 870 SubjectConfirmationData *SubjectConfirmationData 871 } 872 873 // Element returns an etree.Element representing the object in XML form. 874 func (a *SubjectConfirmation) Element() *etree.Element { 875 el := etree.NewElement("saml:SubjectConfirmation") 876 el.CreateAttr("Method", a.Method) 877 if a.NameID != nil { 878 el.AddChild(a.NameID.Element()) 879 } 880 if a.SubjectConfirmationData != nil { 881 el.AddChild(a.SubjectConfirmationData.Element()) 882 } 883 return el 884 } 885 886 // SubjectConfirmationData represents the SAML element SubjectConfirmationData. 887 // 888 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1.2 889 type SubjectConfirmationData struct { 890 NotBefore time.Time `xml:",attr"` 891 NotOnOrAfter time.Time `xml:",attr"` 892 Recipient string `xml:",attr"` 893 InResponseTo string `xml:",attr"` 894 Address string `xml:",attr"` 895 } 896 897 // Element returns an etree.Element representing the object in XML form. 898 func (s *SubjectConfirmationData) Element() *etree.Element { 899 el := etree.NewElement("saml:SubjectConfirmationData") 900 if !s.NotBefore.IsZero() { 901 el.CreateAttr("NotBefore", s.NotBefore.Format(timeFormat)) 902 } 903 if !s.NotOnOrAfter.IsZero() { 904 el.CreateAttr("NotOnOrAfter", s.NotOnOrAfter.Format(timeFormat)) 905 } 906 if s.Recipient != "" { 907 el.CreateAttr("Recipient", s.Recipient) 908 } 909 if s.InResponseTo != "" { 910 el.CreateAttr("InResponseTo", s.InResponseTo) 911 } 912 if s.Address != "" { 913 el.CreateAttr("Address", s.Address) 914 } 915 return el 916 } 917 918 // MarshalXML implements xml.Marshaler 919 func (s *SubjectConfirmationData) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 920 type Alias SubjectConfirmationData 921 aux := &struct { 922 NotOnOrAfter RelaxedTime `xml:",attr"` 923 *Alias 924 }{ 925 NotOnOrAfter: RelaxedTime(s.NotOnOrAfter), 926 Alias: (*Alias)(s), 927 } 928 return e.EncodeElement(aux, start) 929 } 930 931 // UnmarshalXML implements xml.Unmarshaler 932 func (s *SubjectConfirmationData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 933 type Alias SubjectConfirmationData 934 aux := &struct { 935 NotOnOrAfter RelaxedTime `xml:",attr"` 936 *Alias 937 }{ 938 Alias: (*Alias)(s), 939 } 940 if err := d.DecodeElement(&aux, &start); err != nil { 941 return err 942 } 943 s.NotOnOrAfter = time.Time(aux.NotOnOrAfter) 944 return nil 945 } 946 947 // Conditions represents the SAML element Conditions. 948 // 949 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1 950 type Conditions struct { 951 NotBefore time.Time `xml:",attr"` 952 NotOnOrAfter time.Time `xml:",attr"` 953 AudienceRestrictions []AudienceRestriction `xml:"AudienceRestriction"` 954 OneTimeUse *OneTimeUse 955 ProxyRestriction *ProxyRestriction 956 } 957 958 // Element returns an etree.Element representing the object in XML form. 959 func (c *Conditions) Element() *etree.Element { 960 el := etree.NewElement("saml:Conditions") 961 if !c.NotBefore.IsZero() { 962 el.CreateAttr("NotBefore", c.NotBefore.Format(timeFormat)) 963 } 964 if !c.NotOnOrAfter.IsZero() { 965 el.CreateAttr("NotOnOrAfter", c.NotOnOrAfter.Format(timeFormat)) 966 } 967 for _, v := range c.AudienceRestrictions { 968 el.AddChild(v.Element()) 969 } 970 if c.OneTimeUse != nil { 971 el.AddChild(c.OneTimeUse.Element()) 972 } 973 if c.ProxyRestriction != nil { 974 el.AddChild(c.ProxyRestriction.Element()) 975 } 976 return el 977 } 978 979 // MarshalXML implements xml.Marshaler 980 func (c *Conditions) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 981 type Alias Conditions 982 aux := &struct { 983 NotBefore RelaxedTime `xml:",attr"` 984 NotOnOrAfter RelaxedTime `xml:",attr"` 985 *Alias 986 }{ 987 NotBefore: RelaxedTime(c.NotBefore), 988 NotOnOrAfter: RelaxedTime(c.NotOnOrAfter), 989 Alias: (*Alias)(c), 990 } 991 return e.EncodeElement(aux, start) 992 } 993 994 // UnmarshalXML implements xml.Unmarshaler 995 func (c *Conditions) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 996 type Alias Conditions 997 aux := &struct { 998 NotBefore RelaxedTime `xml:",attr"` 999 NotOnOrAfter RelaxedTime `xml:",attr"` 1000 *Alias 1001 }{ 1002 Alias: (*Alias)(c), 1003 } 1004 if err := d.DecodeElement(&aux, &start); err != nil { 1005 return err 1006 } 1007 c.NotBefore = time.Time(aux.NotBefore) 1008 c.NotOnOrAfter = time.Time(aux.NotOnOrAfter) 1009 return nil 1010 } 1011 1012 // AudienceRestriction represents the SAML element AudienceRestriction. 1013 // 1014 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.4 1015 type AudienceRestriction struct { 1016 Audience Audience 1017 } 1018 1019 // Element returns an etree.Element representing the object in XML form. 1020 func (a *AudienceRestriction) Element() *etree.Element { 1021 el := etree.NewElement("saml:AudienceRestriction") 1022 el.AddChild(a.Audience.Element()) 1023 return el 1024 } 1025 1026 // Audience represents the SAML element Audience. 1027 // 1028 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.4 1029 type Audience struct { 1030 Value string `xml:",chardata"` 1031 } 1032 1033 // Element returns an etree.Element representing the object in XML form. 1034 func (a *Audience) Element() *etree.Element { 1035 el := etree.NewElement("saml:Audience") 1036 el.SetText(a.Value) 1037 return el 1038 } 1039 1040 // OneTimeUse represents the SAML element OneTimeUse. 1041 // 1042 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.5 1043 type OneTimeUse struct{} 1044 1045 // Element returns an etree.Element representing the object in XML form. 1046 func (a *OneTimeUse) Element() *etree.Element { 1047 return etree.NewElement("saml:OneTimeUse") 1048 } 1049 1050 // ProxyRestriction represents the SAML element ProxyRestriction. 1051 // 1052 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.6 1053 type ProxyRestriction struct { 1054 Count *int 1055 Audiences []Audience 1056 } 1057 1058 // Element returns an etree.Element representing the object in XML form. 1059 func (a *ProxyRestriction) Element() *etree.Element { 1060 el := etree.NewElement("saml:ProxyRestriction") 1061 if a.Count != nil { 1062 el.CreateAttr("Count", strconv.Itoa(*a.Count)) 1063 } 1064 for _, v := range a.Audiences { 1065 el.AddChild(v.Element()) 1066 } 1067 return el 1068 } 1069 1070 // AuthnStatement represents the SAML element AuthnStatement. 1071 // 1072 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2 1073 type AuthnStatement struct { 1074 AuthnInstant time.Time `xml:",attr"` 1075 SessionIndex string `xml:",attr"` 1076 SessionNotOnOrAfter *time.Time `xml:",attr,omitempty"` 1077 SubjectLocality *SubjectLocality 1078 AuthnContext AuthnContext 1079 } 1080 1081 // Element returns an etree.Element representing the object in XML form. 1082 func (a *AuthnStatement) Element() *etree.Element { 1083 el := etree.NewElement("saml:AuthnStatement") 1084 el.CreateAttr("AuthnInstant", a.AuthnInstant.Format(timeFormat)) 1085 if a.SessionIndex != "" { 1086 el.CreateAttr("SessionIndex", a.SessionIndex) 1087 } 1088 if a.SessionNotOnOrAfter != nil { 1089 el.CreateAttr("SessionNotOnOrAfter", a.SessionNotOnOrAfter.Format(timeFormat)) 1090 } 1091 if a.SubjectLocality != nil { 1092 el.AddChild(a.SubjectLocality.Element()) 1093 } 1094 el.AddChild(a.AuthnContext.Element()) 1095 return el 1096 } 1097 1098 // MarshalXML implements xml.Marshaler 1099 func (a *AuthnStatement) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 1100 type Alias AuthnStatement 1101 aux := &struct { 1102 AuthnInstant RelaxedTime `xml:",attr"` 1103 SessionNotOnOrAfter *RelaxedTime `xml:",attr,omitempty"` 1104 *Alias 1105 }{ 1106 AuthnInstant: RelaxedTime(a.AuthnInstant), 1107 SessionNotOnOrAfter: (*RelaxedTime)(a.SessionNotOnOrAfter), 1108 Alias: (*Alias)(a), 1109 } 1110 return e.EncodeElement(aux, start) 1111 } 1112 1113 // UnmarshalXML implements xml.Unmarshaler 1114 func (a *AuthnStatement) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 1115 type Alias AuthnStatement 1116 aux := &struct { 1117 AuthnInstant RelaxedTime `xml:",attr"` 1118 SessionNotOnOrAfter *RelaxedTime `xml:",attr,omitempty"` 1119 *Alias 1120 }{ 1121 Alias: (*Alias)(a), 1122 } 1123 if err := d.DecodeElement(&aux, &start); err != nil { 1124 return err 1125 } 1126 a.AuthnInstant = time.Time(aux.AuthnInstant) 1127 a.SessionNotOnOrAfter = (*time.Time)(aux.SessionNotOnOrAfter) 1128 return nil 1129 } 1130 1131 // SubjectLocality represents the SAML element SubjectLocality. 1132 // 1133 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.1 1134 type SubjectLocality struct { 1135 Address string `xml:",attr"` 1136 DNSName string `xml:",attr"` 1137 } 1138 1139 // Element returns an etree.Element representing the object in XML form. 1140 func (a *SubjectLocality) Element() *etree.Element { 1141 el := etree.NewElement("saml:SubjectLocality") 1142 if a.Address != "" { 1143 el.CreateAttr("Address", a.Address) 1144 } 1145 if a.DNSName != "" { 1146 el.CreateAttr("DNSName", a.DNSName) 1147 } 1148 return el 1149 } 1150 1151 // AuthnContext represents the SAML element AuthnContext. 1152 // 1153 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2 1154 type AuthnContext struct { 1155 AuthnContextClassRef *AuthnContextClassRef 1156 // AuthnContextDecl *AuthnContextDecl ... TODO 1157 // AuthnContextDeclRef *AuthnContextDeclRef ... TODO 1158 // AuthenticatingAuthorities []AuthenticatingAuthority... TODO 1159 } 1160 1161 // Element returns an etree.Element representing the object in XML form. 1162 func (a *AuthnContext) Element() *etree.Element { 1163 el := etree.NewElement("saml:AuthnContext") 1164 if a.AuthnContextClassRef != nil { 1165 el.AddChild(a.AuthnContextClassRef.Element()) 1166 } 1167 return el 1168 } 1169 1170 // AuthnContextClassRef represents the SAML element AuthnContextClassRef. 1171 // 1172 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2 1173 type AuthnContextClassRef struct { 1174 Value string `xml:",chardata"` 1175 } 1176 1177 // Element returns an etree.Element representing the object in XML form. 1178 func (a *AuthnContextClassRef) Element() *etree.Element { 1179 el := etree.NewElement("saml:AuthnContextClassRef") 1180 el.SetText(a.Value) 1181 return el 1182 } 1183 1184 // AttributeStatement represents the SAML element AttributeStatement. 1185 // 1186 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3 1187 type AttributeStatement struct { 1188 Attributes []Attribute `xml:"Attribute"` 1189 } 1190 1191 // Element returns an etree.Element representing the object in XML form. 1192 func (a *AttributeStatement) Element() *etree.Element { 1193 el := etree.NewElement("saml:AttributeStatement") 1194 for _, v := range a.Attributes { 1195 el.AddChild(v.Element()) 1196 } 1197 return el 1198 } 1199 1200 // Attribute represents the SAML element Attribute. 1201 // 1202 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3.1 1203 type Attribute struct { 1204 FriendlyName string `xml:",attr"` 1205 Name string `xml:",attr"` 1206 NameFormat string `xml:",attr"` 1207 Values []AttributeValue `xml:"AttributeValue"` 1208 } 1209 1210 // Element returns an etree.Element representing the object in XML form. 1211 func (a *Attribute) Element() *etree.Element { 1212 el := etree.NewElement("saml:Attribute") 1213 if a.FriendlyName != "" { 1214 el.CreateAttr("FriendlyName", a.FriendlyName) 1215 } 1216 if a.Name != "" { 1217 el.CreateAttr("Name", a.Name) 1218 } 1219 if a.NameFormat != "" { 1220 el.CreateAttr("NameFormat", a.NameFormat) 1221 } 1222 for _, v := range a.Values { 1223 el.AddChild(v.Element()) 1224 } 1225 return el 1226 } 1227 1228 // AttributeValue represents the SAML element AttributeValue. 1229 // 1230 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3.1.1 1231 type AttributeValue struct { 1232 Type string `xml:"http://www.w3.org/2001/XMLSchema-instance type,attr"` 1233 Value string `xml:",chardata"` 1234 NameID *NameID 1235 } 1236 1237 // Element returns an etree.Element representing the object in XML form. 1238 func (a *AttributeValue) Element() *etree.Element { 1239 el := etree.NewElement("saml:AttributeValue") 1240 el.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") 1241 el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") 1242 el.CreateAttr("xsi:type", a.Type) 1243 if a.NameID != nil { 1244 el.AddChild(a.NameID.Element()) 1245 } 1246 el.SetText(a.Value) 1247 return el 1248 } 1249 1250 // LogoutResponse represents the SAML object of the same name. 1251 // 1252 // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf 1253 type LogoutResponse struct { 1254 XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol LogoutResponse"` 1255 ID string `xml:",attr"` 1256 InResponseTo string `xml:",attr"` 1257 Version string `xml:",attr"` 1258 IssueInstant time.Time `xml:",attr"` 1259 Destination string `xml:",attr"` 1260 Consent string `xml:",attr"` 1261 Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` 1262 Signature *etree.Element 1263 Status Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"` 1264 } 1265 1266 // Element returns an etree.Element representing the object in XML form. 1267 func (r *LogoutResponse) Element() *etree.Element { 1268 el := etree.NewElement("samlp:LogoutResponse") 1269 el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") 1270 el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") 1271 1272 el.CreateAttr("ID", r.ID) 1273 if r.InResponseTo != "" { 1274 el.CreateAttr("InResponseTo", r.InResponseTo) 1275 } 1276 el.CreateAttr("Version", r.Version) 1277 el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) 1278 if r.Destination != "" { 1279 el.CreateAttr("Destination", r.Destination) 1280 } 1281 if r.Consent != "" { 1282 el.CreateAttr("Consent", r.Consent) 1283 } 1284 if r.Issuer != nil { 1285 el.AddChild(r.Issuer.Element()) 1286 } 1287 if r.Signature != nil { 1288 el.AddChild(r.Signature) 1289 } 1290 el.AddChild(r.Status.Element()) 1291 return el 1292 } 1293 1294 // MarshalXML implements xml.Marshaler 1295 func (r *LogoutResponse) MarshalXML(e *xml.Encoder, _ xml.StartElement) error { 1296 type Alias LogoutResponse 1297 aux := &struct { 1298 IssueInstant RelaxedTime `xml:",attr"` 1299 *Alias 1300 }{ 1301 IssueInstant: RelaxedTime(r.IssueInstant), 1302 Alias: (*Alias)(r), 1303 } 1304 return e.Encode(aux) 1305 } 1306 1307 // UnmarshalXML implements xml.Unmarshaler 1308 func (r *LogoutResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 1309 type Alias LogoutResponse 1310 aux := &struct { 1311 IssueInstant RelaxedTime `xml:",attr"` 1312 *Alias 1313 }{ 1314 Alias: (*Alias)(r), 1315 } 1316 if err := d.DecodeElement(&aux, &start); err != nil { 1317 return err 1318 } 1319 r.IssueInstant = time.Time(aux.IssueInstant) 1320 return nil 1321 }