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.

provider.go 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package oauth
  2. import (
  3. "bytes"
  4. "fmt"
  5. "math"
  6. "net/http"
  7. "net/url"
  8. "strconv"
  9. "strings"
  10. )
  11. //
  12. // OAuth1 2-legged provider
  13. // Contributed by https://github.com/jacobpgallagher
  14. //
  15. // Provide an buffer reader which implements the Close() interface
  16. type oauthBufferReader struct {
  17. *bytes.Buffer
  18. }
  19. // So that it implements the io.ReadCloser interface
  20. func (m oauthBufferReader) Close() error { return nil }
  21. type ConsumerGetter func(key string, header map[string]string) (*Consumer, error)
  22. // Provider provides methods for a 2-legged Oauth1 provider
  23. type Provider struct {
  24. ConsumerGetter ConsumerGetter
  25. // For mocking
  26. clock clock
  27. }
  28. // NewProvider takes a function to get the consumer secret from a datastore.
  29. // Returns a Provider
  30. func NewProvider(secretGetter ConsumerGetter) *Provider {
  31. provider := &Provider{
  32. secretGetter,
  33. &defaultClock{},
  34. }
  35. return provider
  36. }
  37. // Combine a URL and Request to make the URL absolute
  38. func makeURLAbs(url *url.URL, request *http.Request) {
  39. if !url.IsAbs() {
  40. url.Host = request.Host
  41. if request.TLS != nil || request.Header.Get("X-Forwarded-Proto") == "https" {
  42. url.Scheme = "https"
  43. } else {
  44. url.Scheme = "http"
  45. }
  46. }
  47. }
  48. // IsAuthorized takes an *http.Request and returns a pointer to a string containing the consumer key,
  49. // or nil if not authorized
  50. func (provider *Provider) IsAuthorized(request *http.Request) (*string, error) {
  51. var userParams = map[string]string{}
  52. var err error
  53. // start with the body/query params
  54. if params_temp, err := parseBody(request); err != nil {
  55. return nil, err
  56. } else {
  57. for k, v := range params_temp {
  58. userParams[k] = v[0]
  59. }
  60. }
  61. // if the oauth params are in the Authorization header, grab them, and
  62. // let them override what's in userParams
  63. authHeader := request.Header.Get(HTTP_AUTH_HEADER)
  64. if len(authHeader) > 6 && strings.EqualFold(OAUTH_HEADER, authHeader[0:6]) {
  65. authHeader = authHeader[6:]
  66. params := strings.Split(authHeader, ",")
  67. for _, param := range params {
  68. vals := strings.SplitN(param, "=", 2)
  69. k := strings.Trim(vals[0], " ")
  70. v := strings.Trim(strings.Trim(vals[1], "\""), " ")
  71. if strings.HasPrefix(k, "oauth") {
  72. userParams[k], err = url.QueryUnescape(v)
  73. if err != nil {
  74. return nil, err
  75. }
  76. }
  77. }
  78. }
  79. // pop the request's signature, it's not included in our signature
  80. // calculation
  81. oauthSignature, ok := userParams[SIGNATURE_PARAM]
  82. if !ok {
  83. return nil, fmt.Errorf("no oauth signature")
  84. }
  85. delete(userParams, SIGNATURE_PARAM)
  86. // get the oauth consumer key
  87. consumerKey, ok := userParams[CONSUMER_KEY_PARAM]
  88. if !ok || consumerKey == "" {
  89. return nil, fmt.Errorf("no consumer key")
  90. }
  91. // use it to create a consumer object
  92. consumer, err := provider.ConsumerGetter(consumerKey, userParams)
  93. if err != nil {
  94. return nil, err
  95. }
  96. // Make sure timestamp is no more than 10 digits
  97. timestamp := userParams[TIMESTAMP_PARAM]
  98. if len(timestamp) > 10 {
  99. timestamp = timestamp[0:10]
  100. }
  101. // Check the timestamp
  102. if !consumer.serviceProvider.IgnoreTimestamp {
  103. oauthTimeNumber, err := strconv.Atoi(timestamp)
  104. if err != nil {
  105. return nil, err
  106. }
  107. if math.Abs(float64(int64(oauthTimeNumber)-provider.clock.Seconds())) > 5*60 {
  108. return nil, fmt.Errorf("too much clock skew")
  109. }
  110. }
  111. // Include the query string params in the base string
  112. if consumer.serviceProvider.SignQueryParams {
  113. for k, v := range request.URL.Query() {
  114. userParams[k] = strings.Join(v, "")
  115. }
  116. }
  117. // if our consumer supports bodyhash, check it
  118. if consumer.serviceProvider.BodyHash {
  119. bodyHash, err := calculateBodyHash(request, consumer.signer)
  120. if err != nil {
  121. return nil, err
  122. }
  123. sentHash, ok := userParams[BODY_HASH_PARAM]
  124. if bodyHash == "" && ok {
  125. return nil, fmt.Errorf("body_hash must not be set")
  126. } else if sentHash != bodyHash {
  127. return nil, fmt.Errorf("body_hash mismatch")
  128. }
  129. }
  130. allParams := NewOrderedParams()
  131. for key, value := range userParams {
  132. allParams.Add(key, value)
  133. }
  134. makeURLAbs(request.URL, request)
  135. baseString := consumer.requestString(request.Method, canonicalizeUrl(request.URL), allParams)
  136. err = consumer.signer.Verify(baseString, oauthSignature)
  137. if err != nil {
  138. return nil, err
  139. }
  140. return &consumerKey, nil
  141. }