schema.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. package saml
  2. import (
  3. "encoding/xml"
  4. "strconv"
  5. "time"
  6. "github.com/beevik/etree"
  7. "github.com/russellhaering/goxmldsig/etreeutils"
  8. )
  9. // AuthnRequest represents the SAML object of the same name, a request from a service provider
  10. // to authenticate a user.
  11. //
  12. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
  13. type AuthnRequest struct {
  14. XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol AuthnRequest"`
  15. ID string `xml:",attr"`
  16. Version string `xml:",attr"`
  17. IssueInstant time.Time `xml:",attr"`
  18. Destination string `xml:",attr"`
  19. Consent string `xml:",attr"`
  20. Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
  21. Signature *etree.Element
  22. Subject *Subject
  23. NameIDPolicy *NameIDPolicy `xml:"urn:oasis:names:tc:SAML:2.0:protocol NameIDPolicy"`
  24. Conditions *Conditions
  25. //RequestedAuthnContext *RequestedAuthnContext // TODO
  26. //Scoping *Scoping // TODO
  27. ForceAuthn *bool `xml:",attr"`
  28. IsPassive *bool `xml:",attr"`
  29. AssertionConsumerServiceIndex string `xml:",attr"`
  30. AssertionConsumerServiceURL string `xml:",attr"`
  31. ProtocolBinding string `xml:",attr"`
  32. AttributeConsumingServiceIndex string `xml:",attr"`
  33. ProviderName string `xml:",attr"`
  34. }
  35. // Element returns an etree.Element representing the object
  36. // Element returns an etree.Element representing the object in XML form.
  37. func (r *AuthnRequest) Element() *etree.Element {
  38. el := etree.NewElement("samlp:AuthnRequest")
  39. el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")
  40. el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol")
  41. el.CreateAttr("ID", r.ID)
  42. el.CreateAttr("Version", r.Version)
  43. el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat))
  44. if r.Destination != "" {
  45. el.CreateAttr("Destination", r.Destination)
  46. }
  47. if r.Consent != "" {
  48. el.CreateAttr("Consent", r.Consent)
  49. }
  50. if r.Issuer != nil {
  51. el.AddChild(r.Issuer.Element())
  52. }
  53. if r.Signature != nil {
  54. el.AddChild(r.Signature)
  55. }
  56. if r.Subject != nil {
  57. el.AddChild(r.Subject.Element())
  58. }
  59. if r.NameIDPolicy != nil {
  60. el.AddChild(r.NameIDPolicy.Element())
  61. }
  62. if r.Conditions != nil {
  63. el.AddChild(r.Conditions.Element())
  64. }
  65. //if r.RequestedAuthnContext != nil {
  66. // el.AddChild(r.RequestedAuthnContext.Element())
  67. //}
  68. //if r.Scoping != nil {
  69. // el.AddChild(r.Scoping.Element())
  70. //}
  71. if r.ForceAuthn != nil {
  72. el.CreateAttr("ForceAuthn", strconv.FormatBool(*r.ForceAuthn))
  73. }
  74. if r.IsPassive != nil {
  75. el.CreateAttr("IsPassive", strconv.FormatBool(*r.IsPassive))
  76. }
  77. if r.AssertionConsumerServiceIndex != "" {
  78. el.CreateAttr("AssertionConsumerServiceIndex", r.AssertionConsumerServiceIndex)
  79. }
  80. if r.AssertionConsumerServiceURL != "" {
  81. el.CreateAttr("AssertionConsumerServiceURL", r.AssertionConsumerServiceURL)
  82. }
  83. if r.ProtocolBinding != "" {
  84. el.CreateAttr("ProtocolBinding", r.ProtocolBinding)
  85. }
  86. if r.AttributeConsumingServiceIndex != "" {
  87. el.CreateAttr("AttributeConsumingServiceIndex", r.AttributeConsumingServiceIndex)
  88. }
  89. if r.ProviderName != "" {
  90. el.CreateAttr("ProviderName", r.ProviderName)
  91. }
  92. return el
  93. }
  94. // MarshalXML implements xml.Marshaler
  95. func (r *AuthnRequest) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  96. type Alias AuthnRequest
  97. aux := &struct {
  98. IssueInstant RelaxedTime `xml:",attr"`
  99. *Alias
  100. }{
  101. IssueInstant: RelaxedTime(r.IssueInstant),
  102. Alias: (*Alias)(r),
  103. }
  104. return e.Encode(aux)
  105. }
  106. // UnmarshalXML implements xml.Unmarshaler
  107. func (r *AuthnRequest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  108. type Alias AuthnRequest
  109. aux := &struct {
  110. IssueInstant RelaxedTime `xml:",attr"`
  111. *Alias
  112. }{
  113. Alias: (*Alias)(r),
  114. }
  115. if err := d.DecodeElement(&aux, &start); err != nil {
  116. return err
  117. }
  118. r.IssueInstant = time.Time(aux.IssueInstant)
  119. return nil
  120. }
  121. // Issuer represents the SAML object of the same name.
  122. //
  123. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
  124. type Issuer struct {
  125. XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
  126. NameQualifier string `xml:",attr"`
  127. SPNameQualifier string `xml:",attr"`
  128. Format string `xml:",attr"`
  129. SPProvidedID string `xml:",attr"`
  130. Value string `xml:",chardata"`
  131. }
  132. // Element returns an etree.Element representing the object in XML form.
  133. func (a *Issuer) Element() *etree.Element {
  134. el := etree.NewElement("saml:Issuer")
  135. if a.NameQualifier != "" {
  136. el.CreateAttr("NameQualifier", a.NameQualifier)
  137. }
  138. if a.SPNameQualifier != "" {
  139. el.CreateAttr("SPNameQualifier", a.SPNameQualifier)
  140. }
  141. if a.Format != "" {
  142. el.CreateAttr("Format", a.Format)
  143. }
  144. if a.SPProvidedID != "" {
  145. el.CreateAttr("SPProvidedID", a.SPProvidedID)
  146. }
  147. el.SetText(a.Value)
  148. return el
  149. }
  150. // NameIDPolicy represents the SAML object of the same name.
  151. //
  152. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
  153. type NameIDPolicy struct {
  154. XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol NameIDPolicy"`
  155. Format *string `xml:",attr"`
  156. SPNameQualifier *string `xml:",attr"`
  157. AllowCreate *bool `xml:",attr"`
  158. }
  159. // Element returns an etree.Element representing the object in XML form.
  160. func (a *NameIDPolicy) Element() *etree.Element {
  161. el := etree.NewElement("samlp:NameIDPolicy")
  162. if a.Format != nil {
  163. el.CreateAttr("Format", *a.Format)
  164. }
  165. if a.SPNameQualifier != nil {
  166. el.CreateAttr("SPNameQualifier", *a.SPNameQualifier)
  167. }
  168. if a.AllowCreate != nil {
  169. el.CreateAttr("AllowCreate", strconv.FormatBool(*a.AllowCreate))
  170. }
  171. return el
  172. }
  173. // Response represents the SAML object of the same name.
  174. //
  175. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
  176. type Response struct {
  177. XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"`
  178. ID string `xml:",attr"`
  179. InResponseTo string `xml:",attr"`
  180. Version string `xml:",attr"`
  181. IssueInstant time.Time `xml:",attr"`
  182. Destination string `xml:",attr"`
  183. Consent string `xml:",attr"`
  184. Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
  185. Signature *etree.Element
  186. Status Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"`
  187. // TODO(ross): more than one EncryptedAssertion is allowed
  188. EncryptedAssertion *etree.Element `xml:"urn:oasis:names:tc:SAML:2.0:assertion EncryptedAssertion"`
  189. // TODO(ross): more than one Assertion is allowed
  190. Assertion *Assertion `xml:"urn:oasis:names:tc:SAML:2.0:assertion Assertion"`
  191. }
  192. // Element returns an etree.Element representing the object in XML form.
  193. func (r *Response) Element() *etree.Element {
  194. el := etree.NewElement("samlp:Response")
  195. el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")
  196. el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol")
  197. // Note: This namespace is not used by any element or attribute name, but
  198. // is required so that the AttributeValue type element can have a value like
  199. // "xs:string". If we don't declare it here, then it will be stripped by the
  200. // cannonicalizer. This could be avoided by providing a prefix list to the
  201. // cannonicalizer, but prefix lists do not appear to be implemented correctly
  202. // in some libraries, so the safest action is to always produce XML that is
  203. // (a) in cannonical form and (b) does not require prefix lists.
  204. el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema")
  205. el.CreateAttr("ID", r.ID)
  206. if r.InResponseTo != "" {
  207. el.CreateAttr("InResponseTo", r.InResponseTo)
  208. }
  209. el.CreateAttr("Version", r.Version)
  210. el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat))
  211. if r.Destination != "" {
  212. el.CreateAttr("Destination", r.Destination)
  213. }
  214. if r.Consent != "" {
  215. el.CreateAttr("Consent", r.Consent)
  216. }
  217. if r.Issuer != nil {
  218. el.AddChild(r.Issuer.Element())
  219. }
  220. if r.Signature != nil {
  221. el.AddChild(r.Signature)
  222. }
  223. el.AddChild(r.Status.Element())
  224. if r.EncryptedAssertion != nil {
  225. el.AddChild(r.EncryptedAssertion)
  226. }
  227. if r.Assertion != nil {
  228. el.AddChild(r.Assertion.Element())
  229. }
  230. return el
  231. }
  232. // MarshalXML implements xml.Marshaler
  233. func (r *Response) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  234. type Alias Response
  235. aux := &struct {
  236. IssueInstant RelaxedTime `xml:",attr"`
  237. *Alias
  238. }{
  239. IssueInstant: RelaxedTime(r.IssueInstant),
  240. Alias: (*Alias)(r),
  241. }
  242. return e.Encode(aux)
  243. }
  244. // UnmarshalXML implements xml.Unmarshaler
  245. func (r *Response) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  246. type Alias Response
  247. aux := &struct {
  248. IssueInstant RelaxedTime `xml:",attr"`
  249. *Alias
  250. }{
  251. Alias: (*Alias)(r),
  252. }
  253. if err := d.DecodeElement(&aux, &start); err != nil {
  254. return err
  255. }
  256. r.IssueInstant = time.Time(aux.IssueInstant)
  257. return nil
  258. }
  259. // Status represents the SAML object of the same name.
  260. //
  261. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
  262. type Status struct {
  263. XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"`
  264. StatusCode StatusCode
  265. StatusMessage *StatusMessage
  266. StatusDetail *StatusDetail
  267. }
  268. // Element returns an etree.Element representing the object in XML form.
  269. func (s *Status) Element() *etree.Element {
  270. el := etree.NewElement("samlp:Status")
  271. el.AddChild(s.StatusCode.Element())
  272. if s.StatusMessage != nil {
  273. el.AddChild(s.StatusMessage.Element())
  274. }
  275. if s.StatusDetail != nil {
  276. el.AddChild(s.StatusDetail.Element())
  277. }
  278. return el
  279. }
  280. // StatusCode represents the SAML object of the same name.
  281. //
  282. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf
  283. type StatusCode struct {
  284. XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol StatusCode"`
  285. Value string `xml:",attr"`
  286. StatusCode *StatusCode
  287. }
  288. // Element returns an etree.Element representing the object in XML form.
  289. func (s *StatusCode) Element() *etree.Element {
  290. el := etree.NewElement("samlp:StatusCode")
  291. el.CreateAttr("Value", s.Value)
  292. if s.StatusCode != nil {
  293. el.AddChild(s.StatusCode.Element())
  294. }
  295. return el
  296. }
  297. // StatusSuccess means the request succeeded. Additional information MAY be returned in the <StatusMessage> and/or <StatusDetail> elements.
  298. //
  299. // TODO(ross): this value is mostly constant, but is mutated in tests. Fix the hacky test so this can be const.
  300. var StatusSuccess = "urn:oasis:names:tc:SAML:2.0:status:Success"
  301. const (
  302. // The permissible top-level <StatusCode> values are as follows:
  303. // StatusRequester means the request could not be performed due to an error on the part of the requester.
  304. StatusRequester = "urn:oasis:names:tc:SAML:2.0:status:Requester"
  305. // StatusResponder means the request could not be performed due to an error on the part of the SAML responder or SAML authority.
  306. StatusResponder = "urn:oasis:names:tc:SAML:2.0:status:Responder"
  307. // StatusVersionMismatch means the SAML responder could not process the request because the version of the request message was incorrect.
  308. StatusVersionMismatch = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"
  309. // The following second-level status codes are referenced at various places in this specification. Additional
  310. // second-level status codes MAY be defined in future versions of the SAML specification. System entities
  311. // are free to define more specific status codes by defining appropriate URI references.
  312. // StatusAuthnFailed means the responding provider was unable to successfully authenticate the principal.
  313. StatusAuthnFailed = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed"
  314. // StatusInvalidAttrNameOrValue means Unexpected or invalid content was encountered within a <saml:Attribute> or <saml:AttributeValue> element.
  315. StatusInvalidAttrNameOrValue = "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue"
  316. // StatusInvalidNameIDPolicy means the responding provider cannot or will not support the requested name identifier policy.
  317. StatusInvalidNameIDPolicy = "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"
  318. // StatusNoAuthnContext means the specified authentication context requirements cannot be met by the responder.
  319. StatusNoAuthnContext = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext"
  320. // 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.
  321. StatusNoAvailableIDP = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP"
  322. // StatusNoPassive means Indicates the responding provider cannot authenticate the principal passively, as has been requested.
  323. StatusNoPassive = "urn:oasis:names:tc:SAML:2.0:status:NoPassive"
  324. // StatusNoSupportedIDP is used by an intermediary to indicate that none of the identity providers in an <IDPList> are supported by the intermediary.
  325. StatusNoSupportedIDP = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP"
  326. // 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.
  327. StatusPartialLogout = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout"
  328. // StatusProxyCountExceeded means Indicates that a responding provider cannot authenticate the principal directly and is not permitted to proxy the request further.
  329. StatusProxyCountExceeded = "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded"
  330. // 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.
  331. StatusRequestDenied = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied"
  332. // StatusRequestUnsupported means the SAML responder or SAML authority does not support the request.
  333. StatusRequestUnsupported = "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported"
  334. // StatusRequestVersionDeprecated means the SAML responder cannot process any requests with the protocol version specified in the request.
  335. StatusRequestVersionDeprecated = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated"
  336. // 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.
  337. StatusRequestVersionTooHigh = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh"
  338. // StatusRequestVersionTooLow means the SAML responder cannot process the request because the protocol version specified in the request message is too low.
  339. StatusRequestVersionTooLow = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow"
  340. // StatusResourceNotRecognized means the resource value provided in the request message is invalid or unrecognized.
  341. StatusResourceNotRecognized = "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized"
  342. // StatusTooManyResponses means the response message would contain more elements than the SAML responder is able to return.
  343. StatusTooManyResponses = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses"
  344. // StatusUnknownAttrProfile means an entity that has no knowledge of a particular attribute profile has been presented with an attribute means drawn from that profile.
  345. StatusUnknownAttrProfile = "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile"
  346. // StatusUnknownPrincipal means the responding provider does not recognize the principal specified or implied by the request.
  347. StatusUnknownPrincipal = "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal"
  348. // StatusUnsupportedBinding means the SAML responder cannot properly fulfill the request using the protocol binding specified in the request.
  349. StatusUnsupportedBinding = "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding"
  350. )
  351. // StatusMessage represents the SAML element StatusMessage.
  352. //
  353. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.2.2.3
  354. type StatusMessage struct {
  355. Value string
  356. }
  357. // Element returns an etree.Element representing the object in XML form.
  358. func (sm StatusMessage) Element() *etree.Element {
  359. el := etree.NewElement("samlp:StatusMessage")
  360. el.SetText(sm.Value)
  361. return el
  362. }
  363. // StatusDetail represents the SAML element StatusDetail.
  364. //
  365. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.2.2.4
  366. type StatusDetail struct {
  367. Children []*etree.Element
  368. }
  369. // Element returns an etree.Element representing the object in XML form.
  370. func (sm StatusDetail) Element() *etree.Element {
  371. el := etree.NewElement("samlp:StatusDetail")
  372. for _, child := range sm.Children {
  373. el.AddChild(child)
  374. }
  375. return el
  376. }
  377. // Assertion represents the SAML element Assertion.
  378. //
  379. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.3.3
  380. type Assertion struct {
  381. XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Assertion"`
  382. ID string `xml:",attr"`
  383. IssueInstant time.Time `xml:",attr"`
  384. Version string `xml:",attr"`
  385. Issuer Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"`
  386. Signature *etree.Element
  387. Subject *Subject
  388. Conditions *Conditions
  389. // Advice *Advice
  390. // Statements []Statement
  391. AuthnStatements []AuthnStatement `xml:"AuthnStatement"`
  392. // AuthzDecisionStatements []AuthzDecisionStatement
  393. AttributeStatements []AttributeStatement `xml:"AttributeStatement"`
  394. }
  395. // Element returns an etree.Element representing the object in XML form.
  396. func (a *Assertion) Element() *etree.Element {
  397. el := etree.NewElement("saml:Assertion")
  398. el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")
  399. el.CreateAttr("Version", "2.0")
  400. el.CreateAttr("ID", a.ID)
  401. el.CreateAttr("IssueInstant", a.IssueInstant.Format(timeFormat))
  402. el.AddChild(a.Issuer.Element())
  403. if a.Signature != nil {
  404. el.AddChild(a.Signature)
  405. }
  406. if a.Subject != nil {
  407. el.AddChild(a.Subject.Element())
  408. }
  409. if a.Conditions != nil {
  410. el.AddChild(a.Conditions.Element())
  411. }
  412. for _, authnStatement := range a.AuthnStatements {
  413. el.AddChild(authnStatement.Element())
  414. }
  415. for _, attributeStatement := range a.AttributeStatements {
  416. el.AddChild(attributeStatement.Element())
  417. }
  418. err := etreeutils.TransformExcC14n(el, canonicalizerPrefixList)
  419. if err != nil {
  420. panic(err)
  421. }
  422. return el
  423. }
  424. // UnmarshalXML implements xml.Unmarshaler
  425. func (a *Assertion) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  426. type Alias Assertion
  427. aux := &struct {
  428. IssueInstant RelaxedTime `xml:",attr"`
  429. *Alias
  430. }{
  431. Alias: (*Alias)(a),
  432. }
  433. if err := d.DecodeElement(&aux, &start); err != nil {
  434. return err
  435. }
  436. a.IssueInstant = time.Time(aux.IssueInstant)
  437. return nil
  438. }
  439. // Subject represents the SAML element Subject.
  440. //
  441. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1
  442. type Subject struct {
  443. XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Subject"`
  444. // BaseID *BaseID ... TODO
  445. NameID *NameID
  446. // EncryptedID *EncryptedID ... TODO
  447. SubjectConfirmations []SubjectConfirmation `xml:"SubjectConfirmation"`
  448. }
  449. // Element returns an etree.Element representing the object in XML form.
  450. func (a *Subject) Element() *etree.Element {
  451. el := etree.NewElement("saml:Subject")
  452. if a.NameID != nil {
  453. el.AddChild(a.NameID.Element())
  454. }
  455. for _, v := range a.SubjectConfirmations {
  456. el.AddChild(v.Element())
  457. }
  458. return el
  459. }
  460. // NameID represents the SAML element NameID.
  461. //
  462. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.2.3
  463. type NameID struct {
  464. NameQualifier string `xml:",attr"`
  465. SPNameQualifier string `xml:",attr"`
  466. Format string `xml:",attr"`
  467. SPProvidedID string `xml:",attr"`
  468. Value string `xml:",chardata"`
  469. }
  470. // Element returns an etree.Element representing the object in XML form.
  471. func (a *NameID) Element() *etree.Element {
  472. el := etree.NewElement("saml:NameID")
  473. if a.NameQualifier != "" {
  474. el.CreateAttr("NameQualifier", a.NameQualifier)
  475. }
  476. if a.SPNameQualifier != "" {
  477. el.CreateAttr("SPNameQualifier", a.SPNameQualifier)
  478. }
  479. if a.Format != "" {
  480. el.CreateAttr("Format", a.Format)
  481. }
  482. if a.SPProvidedID != "" {
  483. el.CreateAttr("SPProvidedID", a.SPProvidedID)
  484. }
  485. if a.Value != "" {
  486. el.SetText(a.Value)
  487. }
  488. return el
  489. }
  490. // SubjectConfirmation represents the SAML element SubjectConfirmation.
  491. //
  492. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1.1
  493. type SubjectConfirmation struct {
  494. Method string `xml:",attr"`
  495. // BaseID *BaseID ... TODO
  496. NameID *NameID
  497. // EncryptedID *EncryptedID ... TODO
  498. SubjectConfirmationData *SubjectConfirmationData
  499. }
  500. // Element returns an etree.Element representing the object in XML form.
  501. func (a *SubjectConfirmation) Element() *etree.Element {
  502. el := etree.NewElement("saml:SubjectConfirmation")
  503. el.CreateAttr("Method", a.Method)
  504. if a.NameID != nil {
  505. el.AddChild(a.NameID.Element())
  506. }
  507. if a.SubjectConfirmationData != nil {
  508. el.AddChild(a.SubjectConfirmationData.Element())
  509. }
  510. return el
  511. }
  512. // SubjectConfirmationData represents the SAML element SubjectConfirmationData.
  513. //
  514. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1.2
  515. type SubjectConfirmationData struct {
  516. NotBefore time.Time `xml:",attr"`
  517. NotOnOrAfter time.Time `xml:",attr"`
  518. Recipient string `xml:",attr"`
  519. InResponseTo string `xml:",attr"`
  520. Address string `xml:",attr"`
  521. }
  522. // Element returns an etree.Element representing the object in XML form.
  523. func (s *SubjectConfirmationData) Element() *etree.Element {
  524. el := etree.NewElement("saml:SubjectConfirmationData")
  525. if !s.NotBefore.IsZero() {
  526. el.CreateAttr("NotBefore", s.NotBefore.Format(timeFormat))
  527. }
  528. if !s.NotOnOrAfter.IsZero() {
  529. el.CreateAttr("NotOnOrAfter", s.NotOnOrAfter.Format(timeFormat))
  530. }
  531. if s.Recipient != "" {
  532. el.CreateAttr("Recipient", s.Recipient)
  533. }
  534. if s.InResponseTo != "" {
  535. el.CreateAttr("InResponseTo", s.InResponseTo)
  536. }
  537. if s.Address != "" {
  538. el.CreateAttr("Address", s.Address)
  539. }
  540. return el
  541. }
  542. // MarshalXML implements xml.Marshaler
  543. func (s *SubjectConfirmationData) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  544. type Alias SubjectConfirmationData
  545. aux := &struct {
  546. NotOnOrAfter RelaxedTime `xml:",attr"`
  547. *Alias
  548. }{
  549. NotOnOrAfter: RelaxedTime(s.NotOnOrAfter),
  550. Alias: (*Alias)(s),
  551. }
  552. return e.EncodeElement(aux, start)
  553. }
  554. // UnmarshalXML implements xml.Unmarshaler
  555. func (s *SubjectConfirmationData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  556. type Alias SubjectConfirmationData
  557. aux := &struct {
  558. NotOnOrAfter RelaxedTime `xml:",attr"`
  559. *Alias
  560. }{
  561. Alias: (*Alias)(s),
  562. }
  563. if err := d.DecodeElement(&aux, &start); err != nil {
  564. return err
  565. }
  566. s.NotOnOrAfter = time.Time(aux.NotOnOrAfter)
  567. return nil
  568. }
  569. // Conditions represents the SAML element Conditions.
  570. //
  571. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1
  572. type Conditions struct {
  573. NotBefore time.Time `xml:",attr"`
  574. NotOnOrAfter time.Time `xml:",attr"`
  575. AudienceRestrictions []AudienceRestriction `xml:"AudienceRestriction"`
  576. OneTimeUse *OneTimeUse
  577. ProxyRestriction *ProxyRestriction
  578. }
  579. // Element returns an etree.Element representing the object in XML form.
  580. func (c *Conditions) Element() *etree.Element {
  581. el := etree.NewElement("saml:Conditions")
  582. if !c.NotBefore.IsZero() {
  583. el.CreateAttr("NotBefore", c.NotBefore.Format(timeFormat))
  584. }
  585. if !c.NotOnOrAfter.IsZero() {
  586. el.CreateAttr("NotOnOrAfter", c.NotOnOrAfter.Format(timeFormat))
  587. }
  588. for _, v := range c.AudienceRestrictions {
  589. el.AddChild(v.Element())
  590. }
  591. if c.OneTimeUse != nil {
  592. el.AddChild(c.OneTimeUse.Element())
  593. }
  594. if c.ProxyRestriction != nil {
  595. el.AddChild(c.ProxyRestriction.Element())
  596. }
  597. return el
  598. }
  599. // MarshalXML implements xml.Marshaler
  600. func (c *Conditions) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  601. type Alias Conditions
  602. aux := &struct {
  603. NotBefore RelaxedTime `xml:",attr"`
  604. NotOnOrAfter RelaxedTime `xml:",attr"`
  605. *Alias
  606. }{
  607. NotBefore: RelaxedTime(c.NotBefore),
  608. NotOnOrAfter: RelaxedTime(c.NotOnOrAfter),
  609. Alias: (*Alias)(c),
  610. }
  611. return e.EncodeElement(aux, start)
  612. }
  613. // UnmarshalXML implements xml.Unmarshaler
  614. func (c *Conditions) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  615. type Alias Conditions
  616. aux := &struct {
  617. NotBefore RelaxedTime `xml:",attr"`
  618. NotOnOrAfter RelaxedTime `xml:",attr"`
  619. *Alias
  620. }{
  621. Alias: (*Alias)(c),
  622. }
  623. if err := d.DecodeElement(&aux, &start); err != nil {
  624. return err
  625. }
  626. c.NotBefore = time.Time(aux.NotBefore)
  627. c.NotOnOrAfter = time.Time(aux.NotOnOrAfter)
  628. return nil
  629. }
  630. // AudienceRestriction represents the SAML element AudienceRestriction.
  631. //
  632. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.4
  633. type AudienceRestriction struct {
  634. Audience Audience
  635. }
  636. // Element returns an etree.Element representing the object in XML form.
  637. func (a *AudienceRestriction) Element() *etree.Element {
  638. el := etree.NewElement("saml:AudienceRestriction")
  639. el.AddChild(a.Audience.Element())
  640. return el
  641. }
  642. // Audience represents the SAML element Audience.
  643. //
  644. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.4
  645. type Audience struct {
  646. Value string `xml:",chardata"`
  647. }
  648. // Element returns an etree.Element representing the object in XML form.
  649. func (a *Audience) Element() *etree.Element {
  650. el := etree.NewElement("saml:Audience")
  651. el.SetText(a.Value)
  652. return el
  653. }
  654. // OneTimeUse represents the SAML element OneTimeUse.
  655. //
  656. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.5
  657. type OneTimeUse struct{}
  658. // Element returns an etree.Element representing the object in XML form.
  659. func (a *OneTimeUse) Element() *etree.Element {
  660. return etree.NewElement("saml:OneTimeUse")
  661. }
  662. // ProxyRestriction represents the SAML element ProxyRestriction.
  663. //
  664. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.6
  665. type ProxyRestriction struct {
  666. Count *int
  667. Audiences []Audience
  668. }
  669. // Element returns an etree.Element representing the object in XML form.
  670. func (a *ProxyRestriction) Element() *etree.Element {
  671. el := etree.NewElement("saml:ProxyRestriction")
  672. if a.Count != nil {
  673. el.CreateAttr("Count", strconv.Itoa(*a.Count))
  674. }
  675. for _, v := range a.Audiences {
  676. el.AddChild(v.Element())
  677. }
  678. return el
  679. }
  680. // AuthnStatement represents the SAML element AuthnStatement.
  681. //
  682. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2
  683. type AuthnStatement struct {
  684. AuthnInstant time.Time `xml:",attr"`
  685. SessionIndex string `xml:",attr"`
  686. SessionNotOnOrAfter *time.Time `xml:",attr"`
  687. SubjectLocality *SubjectLocality
  688. AuthnContext AuthnContext
  689. }
  690. // Element returns an etree.Element representing the object in XML form.
  691. func (a *AuthnStatement) Element() *etree.Element {
  692. el := etree.NewElement("saml:AuthnStatement")
  693. el.CreateAttr("AuthnInstant", a.AuthnInstant.Format(timeFormat))
  694. if a.SessionIndex != "" {
  695. el.CreateAttr("SessionIndex", a.SessionIndex)
  696. }
  697. if a.SubjectLocality != nil {
  698. el.AddChild(a.SubjectLocality.Element())
  699. }
  700. el.AddChild(a.AuthnContext.Element())
  701. return el
  702. }
  703. // MarshalXML implements xml.Marshaler
  704. func (a *AuthnStatement) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  705. type Alias AuthnStatement
  706. aux := &struct {
  707. AuthnInstant RelaxedTime `xml:",attr"`
  708. *Alias
  709. }{
  710. AuthnInstant: RelaxedTime(a.AuthnInstant),
  711. Alias: (*Alias)(a),
  712. }
  713. return e.EncodeElement(aux, start)
  714. }
  715. // UnmarshalXML implements xml.Unmarshaler
  716. func (a *AuthnStatement) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  717. type Alias AuthnStatement
  718. aux := &struct {
  719. AuthnInstant RelaxedTime `xml:",attr"`
  720. *Alias
  721. }{
  722. Alias: (*Alias)(a),
  723. }
  724. if err := d.DecodeElement(&aux, &start); err != nil {
  725. return err
  726. }
  727. a.AuthnInstant = time.Time(aux.AuthnInstant)
  728. return nil
  729. }
  730. // SubjectLocality represents the SAML element SubjectLocality.
  731. //
  732. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.1
  733. type SubjectLocality struct {
  734. Address string `xml:",attr"`
  735. DNSName string `xml:",attr"`
  736. }
  737. // Element returns an etree.Element representing the object in XML form.
  738. func (a *SubjectLocality) Element() *etree.Element {
  739. el := etree.NewElement("saml:SubjectLocality")
  740. if a.Address != "" {
  741. el.CreateAttr("Address", a.Address)
  742. }
  743. if a.DNSName != "" {
  744. el.CreateAttr("DNSName", a.DNSName)
  745. }
  746. return el
  747. }
  748. // AuthnContext represents the SAML element AuthnContext.
  749. //
  750. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2
  751. type AuthnContext struct {
  752. AuthnContextClassRef *AuthnContextClassRef
  753. //AuthnContextDecl *AuthnContextDecl ... TODO
  754. //AuthnContextDeclRef *AuthnContextDeclRef ... TODO
  755. //AuthenticatingAuthorities []AuthenticatingAuthority... TODO
  756. }
  757. // Element returns an etree.Element representing the object in XML form.
  758. func (a *AuthnContext) Element() *etree.Element {
  759. el := etree.NewElement("saml:AuthnContext")
  760. if a.AuthnContextClassRef != nil {
  761. el.AddChild(a.AuthnContextClassRef.Element())
  762. }
  763. return el
  764. }
  765. // AuthnContextClassRef represents the SAML element AuthnContextClassRef.
  766. //
  767. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2
  768. type AuthnContextClassRef struct {
  769. Value string `xml:",chardata"`
  770. }
  771. // Element returns an etree.Element representing the object in XML form.
  772. func (a *AuthnContextClassRef) Element() *etree.Element {
  773. el := etree.NewElement("saml:AuthnContextClassRef")
  774. el.SetText(a.Value)
  775. return el
  776. }
  777. // AttributeStatement represents the SAML element AttributeStatement.
  778. //
  779. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3
  780. type AttributeStatement struct {
  781. Attributes []Attribute `xml:"Attribute"`
  782. }
  783. // Element returns an etree.Element representing the object in XML form.
  784. func (a *AttributeStatement) Element() *etree.Element {
  785. el := etree.NewElement("saml:AttributeStatement")
  786. for _, v := range a.Attributes {
  787. el.AddChild(v.Element())
  788. }
  789. return el
  790. }
  791. // Attribute represents the SAML element Attribute.
  792. //
  793. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3.1
  794. type Attribute struct {
  795. FriendlyName string `xml:",attr"`
  796. Name string `xml:",attr"`
  797. NameFormat string `xml:",attr"`
  798. Values []AttributeValue `xml:"AttributeValue"`
  799. }
  800. // Element returns an etree.Element representing the object in XML form.
  801. func (a *Attribute) Element() *etree.Element {
  802. el := etree.NewElement("saml:Attribute")
  803. if a.FriendlyName != "" {
  804. el.CreateAttr("FriendlyName", a.FriendlyName)
  805. }
  806. if a.Name != "" {
  807. el.CreateAttr("Name", a.Name)
  808. }
  809. if a.NameFormat != "" {
  810. el.CreateAttr("NameFormat", a.NameFormat)
  811. }
  812. for _, v := range a.Values {
  813. el.AddChild(v.Element())
  814. }
  815. return el
  816. }
  817. // AttributeValue represents the SAML element AttributeValue.
  818. //
  819. // See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3.1.1
  820. type AttributeValue struct {
  821. Type string `xml:"http://www.w3.org/2001/XMLSchema-instance type,attr"`
  822. Value string `xml:",chardata"`
  823. NameID *NameID
  824. }
  825. // Element returns an etree.Element representing the object in XML form.
  826. func (a *AttributeValue) Element() *etree.Element {
  827. el := etree.NewElement("saml:AttributeValue")
  828. el.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
  829. el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema")
  830. el.CreateAttr("xsi:type", a.Type)
  831. if a.NameID != nil {
  832. el.AddChild(a.NameID.Element())
  833. }
  834. el.SetText(a.Value)
  835. return el
  836. }