api_key.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package v1
  2. import (
  3. "crypto/rand"
  4. "crypto/sha512"
  5. "encoding/hex"
  6. "fmt"
  7. "net/http"
  8. "strings"
  9. "github.com/crowdsecurity/crowdsec/pkg/database"
  10. "github.com/gin-gonic/gin"
  11. log "github.com/sirupsen/logrus"
  12. )
  13. var (
  14. APIKeyHeader = "X-Api-Key"
  15. )
  16. type APIKey struct {
  17. HeaderName string
  18. DbClient *database.Client
  19. }
  20. func GenerateAPIKey(n int) (string, error) {
  21. bytes := make([]byte, n)
  22. if _, err := rand.Read(bytes); err != nil {
  23. return "", err
  24. }
  25. return hex.EncodeToString(bytes), nil
  26. }
  27. func NewAPIKey(dbClient *database.Client) *APIKey {
  28. return &APIKey{
  29. HeaderName: APIKeyHeader,
  30. DbClient: dbClient,
  31. }
  32. }
  33. func HashSHA512(str string) string {
  34. hashedKey := sha512.New()
  35. hashedKey.Write([]byte(str))
  36. hashStr := fmt.Sprintf("%x", hashedKey.Sum(nil))
  37. return hashStr
  38. }
  39. func (a *APIKey) MiddlewareFunc() gin.HandlerFunc {
  40. return func(c *gin.Context) {
  41. val, ok := c.Request.Header[APIKeyHeader]
  42. if !ok {
  43. c.JSON(http.StatusForbidden, gin.H{"message": "access forbidden"})
  44. c.Abort()
  45. return
  46. }
  47. hashStr := HashSHA512(val[0])
  48. bouncer, err := a.DbClient.SelectBouncer(hashStr)
  49. if err != nil {
  50. log.Errorf("auth api key error: %s", err)
  51. c.JSON(http.StatusForbidden, gin.H{"message": "access forbidden"})
  52. c.Abort()
  53. return
  54. }
  55. if bouncer == nil {
  56. c.JSON(http.StatusForbidden, gin.H{"message": "access forbidden"})
  57. c.Abort()
  58. return
  59. }
  60. c.Set("BOUNCER_NAME", bouncer.Name)
  61. if bouncer.IPAddress == "" {
  62. err = a.DbClient.UpdateBouncerIP(c.ClientIP(), bouncer.ID)
  63. if err != nil {
  64. log.Errorf("Failed to update ip address for '%s': %s\n", bouncer.Name, err)
  65. c.JSON(http.StatusForbidden, gin.H{"message": "access forbidden"})
  66. c.Abort()
  67. return
  68. }
  69. }
  70. if bouncer.IPAddress != c.ClientIP() && bouncer.IPAddress != "" {
  71. log.Warningf("new IP address detected for bouncer '%s': %s (old: %s)", bouncer.Name, c.ClientIP(), bouncer.IPAddress)
  72. err = a.DbClient.UpdateBouncerIP(c.ClientIP(), bouncer.ID)
  73. if err != nil {
  74. log.Errorf("Failed to update ip address for '%s': %s\n", bouncer.Name, err)
  75. c.JSON(http.StatusForbidden, gin.H{"message": "access forbidden"})
  76. c.Abort()
  77. return
  78. }
  79. }
  80. useragent := strings.Split(c.Request.UserAgent(), "/")
  81. if len(useragent) != 2 {
  82. log.Warningf("bad user agent '%s' from '%s'", c.Request.UserAgent(), c.ClientIP())
  83. useragent = []string{c.Request.UserAgent(), "N/A"}
  84. }
  85. if bouncer.Version != useragent[1] || bouncer.Type != useragent[0] {
  86. if err := a.DbClient.UpdateBouncerTypeAndVersion(useragent[0], useragent[1], bouncer.ID); err != nil {
  87. log.Errorf("failed to update bouncer version and type from '%s' (%s): %s", c.Request.UserAgent(), c.ClientIP(), err)
  88. c.JSON(http.StatusForbidden, gin.H{"message": "bad user agent"})
  89. c.Abort()
  90. return
  91. }
  92. }
  93. c.Next()
  94. }
  95. }