Contains the Concourse pipeline definition for building a line-server container
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.

124 lines
2.4 KiB

  1. package main
  2. import (
  3. "bufio"
  4. "encoding/base64"
  5. "log"
  6. "net/http"
  7. "os"
  8. "strings"
  9. "golang.org/x/crypto/scrypt"
  10. )
  11. const (
  12. authPrefix = "Linx "
  13. scryptSalt = "linx-server"
  14. scryptN = 16384
  15. scryptr = 8
  16. scryptp = 1
  17. scryptKeyLen = 32
  18. )
  19. type AuthOptions struct {
  20. AuthFile string
  21. UnauthMethods []string
  22. }
  23. type auth struct {
  24. successHandler http.Handler
  25. failureHandler http.Handler
  26. authKeys []string
  27. o AuthOptions
  28. }
  29. func checkAuth(authKeys []string, decodedAuth []byte) (result bool, err error) {
  30. checkKey, err := scrypt.Key([]byte(decodedAuth), []byte(scryptSalt), scryptN, scryptr, scryptp, scryptKeyLen)
  31. if err != nil {
  32. return
  33. }
  34. encodedKey := base64.StdEncoding.EncodeToString(checkKey)
  35. for _, v := range authKeys {
  36. if encodedKey == v {
  37. result = true
  38. return
  39. }
  40. }
  41. result = false
  42. return
  43. }
  44. func (a auth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  45. if sliceContains(a.o.UnauthMethods, r.Method) {
  46. // allow unauthenticated methods
  47. a.successHandler.ServeHTTP(w, r)
  48. return
  49. }
  50. authHeader := r.Header.Get("Authorization")
  51. if !strings.HasPrefix(authHeader, authPrefix) {
  52. a.failureHandler.ServeHTTP(w, r)
  53. return
  54. }
  55. decodedAuth, err := base64.StdEncoding.DecodeString(authHeader[len(authPrefix):])
  56. if err != nil {
  57. a.failureHandler.ServeHTTP(w, r)
  58. return
  59. }
  60. result, err := checkAuth(a.authKeys, decodedAuth)
  61. if err != nil || !result {
  62. a.failureHandler.ServeHTTP(w, r)
  63. return
  64. }
  65. a.successHandler.ServeHTTP(w, r)
  66. }
  67. func UploadAuth(o AuthOptions) func(http.Handler) http.Handler {
  68. var authKeys []string
  69. f, err := os.Open(o.AuthFile)
  70. if err != nil {
  71. log.Fatal("Failed to open authfile: ", err)
  72. }
  73. defer f.Close()
  74. scanner := bufio.NewScanner(f)
  75. for scanner.Scan() {
  76. authKeys = append(authKeys, scanner.Text())
  77. }
  78. err = scanner.Err()
  79. if err != nil {
  80. log.Fatal("Scanner error while reading authfile: ", err)
  81. }
  82. fn := func(h http.Handler) http.Handler {
  83. return auth{
  84. successHandler: h,
  85. failureHandler: http.HandlerFunc(badAuthorizationHandler),
  86. authKeys: authKeys,
  87. o: o,
  88. }
  89. }
  90. return fn
  91. }
  92. func badAuthorizationHandler(w http.ResponseWriter, r *http.Request) {
  93. w.WriteHeader(http.StatusUnauthorized)
  94. http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
  95. }
  96. func sliceContains(slice []string, s string) bool {
  97. for _, v := range slice {
  98. if s == v {
  99. return true
  100. }
  101. }
  102. return false
  103. }