Skip to content

Commit

Permalink
Setup basic http authentication via /secure/ handler
Browse files Browse the repository at this point in the history
  • Loading branch information
peteretelej committed Jul 18, 2016
1 parent ac9b952 commit b8c2918
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
index.html
releases

secure/
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ Option 2. Install via `go get`. (Requires Golang)
go get github.com/peteretelej/dserve
```



### Usage

Run `dserve` command while in the directory to serve. Serves the current working directory on ":9011", accessible on browsers e.g via http://localhost:9011
Expand Down Expand Up @@ -66,4 +64,13 @@ func main() {
dserve.Serve(".",":80")
}
```
## Secure directory
The secure directory (served at secure) uses `http basic authentication`. Files are served from the `secure/static` directory onto `/secure/`

Files:
- secure/securepass.json.sample - a sample username and password
- secure/securepass.json - your username and password ( create this file )

Note:
- Though the `secure/securepass.json` password is not served/ visible, it is stored in plaintext
- Dserve does not need to be restart to pick new credenctions
87 changes: 87 additions & 0 deletions dserve/basichttpauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package dserve

import (
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
)

// AuthCreds defines the http basic authentication credentials for /secure
// Note: Though the password is not served, it is stored in plaintext
type AuthCreds struct {
invalid string
Username string `json:"username"`
Password string `json:"password"`
}

var securedir string

// authInit initializes the secure directory
func authInit() {
// files served on /secure (secure/static)
securedir = basedir + "/secure/static"
if _, err := os.Stat(securedir); err != nil {
err := os.MkdirAll(securedir, 0700)

This comment has been minimized.

Copy link
@peteretelej

peteretelej Jul 19, 2016

Author Owner

create secure/static directory (and parent secure, if necessary) for files served on /secure/

if err != nil {
log.Fatal(err.Error())
}
}
// get creds
err := func() error {
// Read the securepass.json creds
_, err := getCreds()
return err
}()
if err != nil {
// create sample securepass.json example
sample := &AuthCreds{Username: "example", Password: "pass123"}
d, err := json.MarshalIndent(sample, "", " ")
if err != nil {
log.Fatal(err.Error())
}
err = ioutil.WriteFile(basedir+"/secure/securepass.json.sample", d, 0644)
}
}

// validBasicAuth checks the authentication credentials to access /secure files
func validBasicAuth(r *http.Request) bool {
creds, err := getCreds()
if err != nil {
return false
}
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
if len(s) != 2 {
return false
}
b, err := base64.StdEncoding.DecodeString(s[1])

This comment has been minimized.

Copy link
@peteretelej

peteretelej Jul 19, 2016

Author Owner

unencrypt basic auth (base64)

if err != nil {
return false
}
pair := strings.SplitN(string(b), ":", 2)
if len(pair) != 2 {
return false
}
return pair[0] == creds.Username && pair[1] == creds.Password
}

// getCreds gets the current http basic credentials
func getCreds() (*AuthCreds, error) {
creds := &AuthCreds{}
sp, err := ioutil.ReadFile(basedir + "/secure/securepass.json")
if err != nil {
return creds, err
}
err = json.Unmarshal(sp, &creds)
if err != nil {
return creds, err
}
if creds.Username == "" && creds.Password == "" {
return creds, errors.New("No username and password in securepass.json.")
}
return creds, nil
}
14 changes: 0 additions & 14 deletions dserve/defaultpage.go

This file was deleted.

38 changes: 23 additions & 15 deletions dserve/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,32 @@ package dserve launches a fileserver on that serves a specified directory on a s
package dserve

import (
"errors"
"io/ioutil"
"log"
"net/http"
"os"
"path"
)

var basedir string

// Serve create a webserver that serves all files in a given folder(path) on a
// given listenAddress (e.g ":80") or on failure checks ":9012"-":9016"
func Serve(folder, listenAddr string) error {
func Serve(folder, listenAddr string) {
if _, err := os.Stat(folder); err != nil {
err := os.Mkdir(folder, 0700)

This comment has been minimized.

Copy link
@peteretelej

peteretelej Jul 19, 2016

Author Owner

creates folder (-d) to serve as http root directory if it does not exist

if err != nil {
return err
log.Fatal(err.Error())
}
}
if _, err := os.Stat(path.Join(folder, "index.html")); err != nil {
indexhtml := []byte(indexHtml)
err = ioutil.WriteFile(path.Join(folder, "index.html"), indexhtml, 0644)
if err != nil {
return errors.New("Could not find index.html in folder, " +
"and unable to write file: " + err.Error())
}
}
log.Println("Starting dserve on directory '" + folder + "'")
basedir = folder

// initialize secure files directory
authInit()

log.Println("Starting dserve on directory '" + folder + "'. Add an index.html to the folder.")
http.Handle("/", http.FileServer(http.Dir(folder)))

http.HandleFunc("/secure/", handleSecure)

lAs := []string{listenAddr, ":9012", ":9013", ":9014", ":9015", ":9016"}

for _, val := range lAs {

This comment has been minimized.

Copy link
@peteretelej

peteretelej Jul 19, 2016

Author Owner

Checks for an open port to serve on, starting with the listenAddr specified (defaults to 9011) and 9012, 9013, 9014, 9015 and 9016

Expand All @@ -41,6 +39,16 @@ func Serve(folder, listenAddr string) error {
log.Printf("Error listening on %s. trying next port..\n", val)
}
}
}

return nil
func handleSecure(w http.ResponseWriter, r *http.Request) {
if validBasicAuth(r) {
fs := http.FileServer(http.Dir(basedir + "/secure/static"))
h := http.StripPrefix("/secure/", fs)
h.ServeHTTP(w, r)
return
}
w.Header().Set("WWW-Authenticate", `Basic realm="Dserve secure/ Basic Authentication"`)

This comment has been minimized.

Copy link
@peteretelej

peteretelej Jul 19, 2016

Author Owner

http basic auth header

w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("401 Unauthorized\n"))
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func main() {
listenAddr = c.String("l")
}
// Launching dserve on the current working directory
log.Fatal(dserve.Serve(dir, listenAddr))
dserve.Serve(dir, listenAddr)
}

app.Run(os.Args)
Expand Down

0 comments on commit b8c2918

Please sign in to comment.