You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

83 lines
2.4 KiB

  1. package openid
  2. import (
  3. "encoding/xml"
  4. "errors"
  5. "strings"
  6. )
  7. // TODO: As per 11.2 in openid 2 specs, a service may have multiple
  8. // URIs. We don't care for discovery really, but we do care for
  9. // verification though.
  10. type XrdsIdentifier struct {
  11. Type []string `xml:"Type"`
  12. URI string `xml:"URI"`
  13. LocalID string `xml:"LocalID"`
  14. Priority int `xml:"priority,attr"`
  15. }
  16. type Xrd struct {
  17. Service []*XrdsIdentifier `xml:"Service"`
  18. }
  19. type XrdsDocument struct {
  20. XMLName xml.Name `xml:"XRDS"`
  21. Xrd *Xrd `xml:"XRD"`
  22. }
  23. func parseXrds(input []byte) (opEndpoint, opLocalID string, err error) {
  24. xrdsDoc := &XrdsDocument{}
  25. err = xml.Unmarshal(input, xrdsDoc)
  26. if err != nil {
  27. return
  28. }
  29. if xrdsDoc.Xrd == nil {
  30. return "", "", errors.New("XRDS document missing XRD tag")
  31. }
  32. // 7.3.2.2. Extracting Authentication Data
  33. // Once the Relying Party has obtained an XRDS document, it
  34. // MUST first search the document (following the rules
  35. // described in [XRI_Resolution_2.0]) for an OP Identifier
  36. // Element. If none is found, the RP will search for a Claimed
  37. // Identifier Element.
  38. for _, service := range xrdsDoc.Xrd.Service {
  39. // 7.3.2.1.1. OP Identifier Element
  40. // An OP Identifier Element is an <xrd:Service> element with the
  41. // following information:
  42. // An <xrd:Type> tag whose text content is
  43. // "http://specs.openid.net/auth/2.0/server".
  44. // An <xrd:URI> tag whose text content is the OP Endpoint URL
  45. if service.hasType("http://specs.openid.net/auth/2.0/server") {
  46. opEndpoint = strings.TrimSpace(service.URI)
  47. return
  48. }
  49. }
  50. for _, service := range xrdsDoc.Xrd.Service {
  51. // 7.3.2.1.2. Claimed Identifier Element
  52. // A Claimed Identifier Element is an <xrd:Service> element
  53. // with the following information:
  54. // An <xrd:Type> tag whose text content is
  55. // "http://specs.openid.net/auth/2.0/signon".
  56. // An <xrd:URI> tag whose text content is the OP Endpoint
  57. // URL.
  58. // An <xrd:LocalID> tag (optional) whose text content is the
  59. // OP-Local Identifier.
  60. if service.hasType("http://specs.openid.net/auth/2.0/signon") {
  61. opEndpoint = strings.TrimSpace(service.URI)
  62. opLocalID = strings.TrimSpace(service.LocalID)
  63. return
  64. }
  65. }
  66. return "", "", errors.New("Could not find a compatible service")
  67. }
  68. func (xrdsi *XrdsIdentifier) hasType(tpe string) bool {
  69. for _, t := range xrdsi.Type {
  70. if t == tpe {
  71. return true
  72. }
  73. }
  74. return false
  75. }