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  }