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.

111 lines
2.1 KiB

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