github.com/crewjam/saml@v0.4.14/metadata.go (about)

     1  package saml
     2  
     3  import (
     4  	"encoding/xml"
     5  	"fmt"
     6  	"net/url"
     7  	"time"
     8  
     9  	"github.com/beevik/etree"
    10  )
    11  
    12  // HTTPPostBinding is the official URN for the HTTP-POST binding (transport)
    13  const HTTPPostBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    14  
    15  // HTTPRedirectBinding is the official URN for the HTTP-Redirect binding (transport)
    16  const HTTPRedirectBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
    17  
    18  // HTTPArtifactBinding is the official URN for the HTTP-Artifact binding (transport)
    19  const HTTPArtifactBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
    20  
    21  // SOAPBinding is the official URN for the SOAP binding (transport)
    22  const SOAPBinding = "urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
    23  
    24  // SOAPBindingV1 is the URN for the SOAP binding in SAML 1.0
    25  const SOAPBindingV1 = "urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding"
    26  
    27  // EntitiesDescriptor represents the SAML object of the same name.
    28  //
    29  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.1
    30  type EntitiesDescriptor struct {
    31  	XMLName             xml.Name       `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntitiesDescriptor"`
    32  	ID                  *string        `xml:",attr,omitempty"`
    33  	ValidUntil          *time.Time     `xml:"validUntil,attr,omitempty"`
    34  	CacheDuration       *time.Duration `xml:"cacheDuration,attr,omitempty"`
    35  	Name                *string        `xml:",attr,omitempty"`
    36  	Signature           *etree.Element
    37  	EntitiesDescriptors []EntitiesDescriptor `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntitiesDescriptor"`
    38  	EntityDescriptors   []EntityDescriptor   `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"`
    39  }
    40  
    41  // Metadata as been renamed to EntityDescriptor
    42  //
    43  // This change was made to be consistent with the rest of the API which uses names
    44  // from the SAML specification for types.
    45  //
    46  // This is a tombstone to help you discover this fact. You should update references
    47  // to saml.Metadata to be saml.EntityDescriptor.
    48  var Metadata = struct{}{}
    49  
    50  // EntityDescriptor represents the SAML EntityDescriptor object.
    51  //
    52  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2
    53  type EntityDescriptor struct {
    54  	XMLName                       xml.Name      `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"`
    55  	EntityID                      string        `xml:"entityID,attr"`
    56  	ID                            string        `xml:",attr,omitempty"`
    57  	ValidUntil                    time.Time     `xml:"validUntil,attr,omitempty"`
    58  	CacheDuration                 time.Duration `xml:"cacheDuration,attr,omitempty"`
    59  	Signature                     *etree.Element
    60  	RoleDescriptors               []RoleDescriptor               `xml:"RoleDescriptor"`
    61  	IDPSSODescriptors             []IDPSSODescriptor             `xml:"IDPSSODescriptor"`
    62  	SPSSODescriptors              []SPSSODescriptor              `xml:"SPSSODescriptor"`
    63  	AuthnAuthorityDescriptors     []AuthnAuthorityDescriptor     `xml:"AuthnAuthorityDescriptor"`
    64  	AttributeAuthorityDescriptors []AttributeAuthorityDescriptor `xml:"AttributeAuthorityDescriptor"`
    65  	PDPDescriptors                []PDPDescriptor                `xml:"PDPDescriptor"`
    66  	AffiliationDescriptor         *AffiliationDescriptor
    67  	Organization                  *Organization
    68  	ContactPerson                 *ContactPerson
    69  	AdditionalMetadataLocations   []string `xml:"AdditionalMetadataLocation"`
    70  }
    71  
    72  // MarshalXML implements xml.Marshaler
    73  func (m EntityDescriptor) MarshalXML(e *xml.Encoder, _ xml.StartElement) error {
    74  	type Alias EntityDescriptor
    75  	aux := &struct {
    76  		ValidUntil    RelaxedTime `xml:"validUntil,attr,omitempty"`
    77  		CacheDuration Duration    `xml:"cacheDuration,attr,omitempty"`
    78  		*Alias
    79  	}{
    80  		ValidUntil:    RelaxedTime(m.ValidUntil),
    81  		CacheDuration: Duration(m.CacheDuration),
    82  		Alias:         (*Alias)(&m),
    83  	}
    84  	return e.Encode(aux)
    85  }
    86  
    87  // UnmarshalXML implements xml.Unmarshaler
    88  func (m *EntityDescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    89  	type Alias EntityDescriptor
    90  	aux := &struct {
    91  		ValidUntil    RelaxedTime `xml:"validUntil,attr,omitempty"`
    92  		CacheDuration Duration    `xml:"cacheDuration,attr,omitempty"`
    93  		*Alias
    94  	}{
    95  		Alias: (*Alias)(m),
    96  	}
    97  	if err := d.DecodeElement(aux, &start); err != nil {
    98  		return err
    99  	}
   100  	m.ValidUntil = time.Time(aux.ValidUntil)
   101  	m.CacheDuration = time.Duration(aux.CacheDuration)
   102  	return nil
   103  }
   104  
   105  // Organization represents the SAML Organization object.
   106  //
   107  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2.1
   108  type Organization struct {
   109  	OrganizationNames        []LocalizedName `xml:"OrganizationName"`
   110  	OrganizationDisplayNames []LocalizedName `xml:"OrganizationDisplayName"`
   111  	OrganizationURLs         []LocalizedURI  `xml:"OrganizationURL"`
   112  }
   113  
   114  // LocalizedName represents the SAML type localizedNameType.
   115  //
   116  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.4
   117  type LocalizedName struct {
   118  	Lang  string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"`
   119  	Value string `xml:",chardata"`
   120  }
   121  
   122  // LocalizedURI represents the SAML type localizedURIType.
   123  //
   124  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.5
   125  type LocalizedURI struct {
   126  	Lang  string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"`
   127  	Value string `xml:",chardata"`
   128  }
   129  
   130  // ContactPerson represents the SAML element ContactPerson.
   131  //
   132  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2.2
   133  type ContactPerson struct {
   134  	ContactType      string `xml:"contactType,attr"`
   135  	Company          string
   136  	GivenName        string
   137  	SurName          string
   138  	EmailAddresses   []string `xml:"EmailAddress"`
   139  	TelephoneNumbers []string `xml:"TelephoneNumber"`
   140  }
   141  
   142  // RoleDescriptor represents the SAML element RoleDescriptor.
   143  //
   144  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.1
   145  type RoleDescriptor struct {
   146  	ID                         string        `xml:",attr,omitempty"`
   147  	ValidUntil                 *time.Time    `xml:"validUntil,attr,omitempty"`
   148  	CacheDuration              time.Duration `xml:"cacheDuration,attr,omitempty"`
   149  	ProtocolSupportEnumeration string        `xml:"protocolSupportEnumeration,attr"`
   150  	ErrorURL                   string        `xml:"errorURL,attr,omitempty"`
   151  	Signature                  *etree.Element
   152  	KeyDescriptors             []KeyDescriptor `xml:"KeyDescriptor,omitempty"`
   153  	Organization               *Organization   `xml:"Organization,omitempty"`
   154  	ContactPeople              []ContactPerson `xml:"ContactPerson,omitempty"`
   155  }
   156  
   157  // KeyDescriptor represents the XMLSEC object of the same name
   158  type KeyDescriptor struct {
   159  	Use               string             `xml:"use,attr"`
   160  	KeyInfo           KeyInfo            `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"`
   161  	EncryptionMethods []EncryptionMethod `xml:"EncryptionMethod"`
   162  }
   163  
   164  // EncryptionMethod represents the XMLSEC object of the same name
   165  type EncryptionMethod struct {
   166  	Algorithm string `xml:"Algorithm,attr"`
   167  }
   168  
   169  // KeyInfo represents the XMLSEC object of the same name
   170  type KeyInfo struct {
   171  	XMLName  xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"`
   172  	X509Data X509Data `xml:"X509Data"`
   173  }
   174  
   175  // X509Data represents the XMLSEC object of the same name
   176  type X509Data struct {
   177  	XMLName          xml.Name          `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"`
   178  	X509Certificates []X509Certificate `xml:"X509Certificate"`
   179  }
   180  
   181  // X509Certificate represents the XMLSEC object of the same name
   182  type X509Certificate struct {
   183  	XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Certificate"`
   184  	Data    string   `xml:",chardata"`
   185  }
   186  
   187  // Endpoint represents the SAML EndpointType object.
   188  //
   189  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.2
   190  type Endpoint struct {
   191  	Binding          string `xml:"Binding,attr"`
   192  	Location         string `xml:"Location,attr"`
   193  	ResponseLocation string `xml:"ResponseLocation,attr,omitempty"`
   194  }
   195  
   196  func checkEndpointLocation(binding string, location string) (string, error) {
   197  	// Within the SAML standard, the complex type EndpointType describes a
   198  	// SAML protocol binding endpoint at which a SAML entity can be sent
   199  	// protocol messages. In particular, the location of an endpoint type is
   200  	// defined as follows in the Metadata for the OASIS Security Assertion
   201  	// Markup Language (SAML) V2.0 - 2.2.2 Complex Type EndpointType:
   202  	//
   203  	//   Location [Required] A required URI attribute that specifies the
   204  	//   location of the endpoint. The allowable syntax of this URI depends
   205  	//   on the protocol binding.
   206  	switch binding {
   207  	case HTTPPostBinding,
   208  		HTTPRedirectBinding,
   209  		HTTPArtifactBinding,
   210  		SOAPBinding,
   211  		SOAPBindingV1:
   212  		locationURL, err := url.Parse(location)
   213  		if err != nil {
   214  			return "", fmt.Errorf("invalid url %q: %w", location, err)
   215  		}
   216  		switch locationURL.Scheme {
   217  		case "http", "https":
   218  		// ok
   219  		default:
   220  			return "", fmt.Errorf("invalid url scheme %q for binding %q",
   221  				locationURL.Scheme, binding)
   222  		}
   223  	default:
   224  		// We don't know what form location should take, but the protocol
   225  		// requires that we validate its syntax.
   226  		//
   227  		// In practice, lots of metadata contains random bindings, for example
   228  		// "urn:mace:shibboleth:1.0:profiles:AuthnRequest" from our own test suite.
   229  		//
   230  		// We can't fail, but we also can't allow a location parameter whose syntax we
   231  		// cannot verify. The least-bad course of action here is to set location to
   232  		// and empty string, and hope the caller doesn't care need it.
   233  		location = ""
   234  	}
   235  
   236  	return location, nil
   237  }
   238  
   239  // UnmarshalXML implements xml.Unmarshaler
   240  func (m *Endpoint) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   241  	type Alias Endpoint
   242  	aux := &struct {
   243  		*Alias
   244  	}{
   245  		Alias: (*Alias)(m),
   246  	}
   247  	if err := d.DecodeElement(aux, &start); err != nil {
   248  		return err
   249  	}
   250  
   251  	var err error
   252  	m.Location, err = checkEndpointLocation(m.Binding, m.Location)
   253  	if err != nil {
   254  		return err
   255  	}
   256  	if m.ResponseLocation != "" {
   257  		m.ResponseLocation, err = checkEndpointLocation(m.Binding, m.ResponseLocation)
   258  		if err != nil {
   259  			return err
   260  		}
   261  	}
   262  
   263  	return nil
   264  }
   265  
   266  // IndexedEndpoint represents the SAML IndexedEndpointType object.
   267  //
   268  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.3
   269  type IndexedEndpoint struct {
   270  	Binding          string  `xml:"Binding,attr"`
   271  	Location         string  `xml:"Location,attr"`
   272  	ResponseLocation *string `xml:"ResponseLocation,attr,omitempty"`
   273  	Index            int     `xml:"index,attr"`
   274  	IsDefault        *bool   `xml:"isDefault,attr"`
   275  }
   276  
   277  // UnmarshalXML implements xml.Unmarshaler
   278  func (m *IndexedEndpoint) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   279  	type Alias IndexedEndpoint
   280  	aux := &struct {
   281  		*Alias
   282  	}{
   283  		Alias: (*Alias)(m),
   284  	}
   285  	if err := d.DecodeElement(aux, &start); err != nil {
   286  		return err
   287  	}
   288  
   289  	var err error
   290  	m.Location, err = checkEndpointLocation(m.Binding, m.Location)
   291  	if err != nil {
   292  		return err
   293  	}
   294  	if m.ResponseLocation != nil {
   295  		responseLocation, err := checkEndpointLocation(m.Binding, *m.ResponseLocation)
   296  		if err != nil {
   297  			return err
   298  		}
   299  		if responseLocation != "" {
   300  			m.ResponseLocation = &responseLocation
   301  		} else {
   302  			m.ResponseLocation = nil
   303  		}
   304  	}
   305  
   306  	return nil
   307  }
   308  
   309  // SSODescriptor represents the SAML complex type SSODescriptor
   310  //
   311  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.2
   312  type SSODescriptor struct {
   313  	RoleDescriptor
   314  	ArtifactResolutionServices []IndexedEndpoint `xml:"ArtifactResolutionService"`
   315  	SingleLogoutServices       []Endpoint        `xml:"SingleLogoutService"`
   316  	ManageNameIDServices       []Endpoint        `xml:"ManageNameIDService"`
   317  	NameIDFormats              []NameIDFormat    `xml:"NameIDFormat"`
   318  }
   319  
   320  // IDPSSODescriptor represents the SAML IDPSSODescriptorType object.
   321  //
   322  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.3
   323  type IDPSSODescriptor struct {
   324  	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata IDPSSODescriptor"`
   325  	SSODescriptor
   326  	WantAuthnRequestsSigned *bool `xml:",attr"`
   327  
   328  	SingleSignOnServices       []Endpoint  `xml:"SingleSignOnService"`
   329  	ArtifactResolutionServices []Endpoint  `xml:"ArtifactResolutionService"`
   330  	NameIDMappingServices      []Endpoint  `xml:"NameIDMappingService"`
   331  	AssertionIDRequestServices []Endpoint  `xml:"AssertionIDRequestService"`
   332  	AttributeProfiles          []string    `xml:"AttributeProfile"`
   333  	Attributes                 []Attribute `xml:"Attribute"`
   334  }
   335  
   336  // SPSSODescriptor represents the SAML SPSSODescriptorType object.
   337  //
   338  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.2
   339  type SPSSODescriptor struct {
   340  	XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata SPSSODescriptor"`
   341  	SSODescriptor
   342  	AuthnRequestsSigned        *bool                       `xml:",attr"`
   343  	WantAssertionsSigned       *bool                       `xml:",attr"`
   344  	AssertionConsumerServices  []IndexedEndpoint           `xml:"AssertionConsumerService"`
   345  	AttributeConsumingServices []AttributeConsumingService `xml:"AttributeConsumingService"`
   346  }
   347  
   348  // AttributeConsumingService represents the SAML AttributeConsumingService object.
   349  //
   350  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.4.1
   351  type AttributeConsumingService struct {
   352  	Index               int                  `xml:"index,attr"`
   353  	IsDefault           *bool                `xml:"isDefault,attr"`
   354  	ServiceNames        []LocalizedName      `xml:"ServiceName"`
   355  	ServiceDescriptions []LocalizedName      `xml:"ServiceDescription"`
   356  	RequestedAttributes []RequestedAttribute `xml:"RequestedAttribute"`
   357  }
   358  
   359  // RequestedAttribute represents the SAML RequestedAttribute object.
   360  //
   361  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.4.2
   362  type RequestedAttribute struct {
   363  	Attribute
   364  	IsRequired *bool `xml:"isRequired,attr"`
   365  }
   366  
   367  // AuthnAuthorityDescriptor represents the SAML AuthnAuthorityDescriptor object.
   368  //
   369  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.5
   370  type AuthnAuthorityDescriptor struct {
   371  	RoleDescriptor
   372  	AuthnQueryServices         []Endpoint     `xml:"AuthnQueryService"`
   373  	AssertionIDRequestServices []Endpoint     `xml:"AssertionIDRequestService"`
   374  	NameIDFormats              []NameIDFormat `xml:"NameIDFormat"`
   375  }
   376  
   377  // PDPDescriptor represents the SAML PDPDescriptor object.
   378  //
   379  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.6
   380  type PDPDescriptor struct {
   381  	RoleDescriptor
   382  	AuthzServices              []Endpoint     `xml:"AuthzService"`
   383  	AssertionIDRequestServices []Endpoint     `xml:"AssertionIDRequestService"`
   384  	NameIDFormats              []NameIDFormat `xml:"NameIDFormat"`
   385  }
   386  
   387  // AttributeAuthorityDescriptor represents the SAML AttributeAuthorityDescriptor object.
   388  //
   389  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.7
   390  type AttributeAuthorityDescriptor struct {
   391  	RoleDescriptor
   392  	AttributeServices          []Endpoint     `xml:"AttributeService"`
   393  	AssertionIDRequestServices []Endpoint     `xml:"AssertionIDRequestService"`
   394  	NameIDFormats              []NameIDFormat `xml:"NameIDFormat"`
   395  	AttributeProfiles          []string       `xml:"AttributeProfile"`
   396  	Attributes                 []Attribute    `xml:"Attribute"`
   397  }
   398  
   399  // AffiliationDescriptor represents the SAML AffiliationDescriptor object.
   400  //
   401  // See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.5
   402  type AffiliationDescriptor struct {
   403  	AffiliationOwnerID string        `xml:"affiliationOwnerID,attr"`
   404  	ID                 string        `xml:",attr"`
   405  	ValidUntil         time.Time     `xml:"validUntil,attr,omitempty"`
   406  	CacheDuration      time.Duration `xml:"cacheDuration,attr"`
   407  	Signature          *etree.Element
   408  	AffiliateMembers   []string        `xml:"AffiliateMember"`
   409  	KeyDescriptors     []KeyDescriptor `xml:"KeyDescriptor"`
   410  }