Skip to content

Commit

Permalink
Return error not *ErrUmbrella + add a sample app (#3)
Browse files Browse the repository at this point in the history
* Add example application
  • Loading branch information
mikogs authored Jan 1, 2025
1 parent 5f1445b commit 9f1216c
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 86 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/cmd/example1/example1
23 changes: 23 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.DEFAULT_GOAL := help

.PHONY: help test

test: ## Runs tests
go test

run-example1: clean ## Runs sample app
@echo "* Creating docker container with PostgreSQL"
docker run --name umbrella-example1 -d -e POSTGRES_PASSWORD=upass -e POSTGRES_USER=uuser -e POSTGRES_DB=udb -p 54321:5432 postgres:13
@echo "* Sleeping for 10 seconds to give database time to initialize..."
@sleep 10
@echo "* Building and starting application..."
cd cmd/example1 && go build .
cd cmd/example1 && ./example1
@echo "* Removing previously created docker container..."


clean: ## Removes all created dockers
docker rm -f umbrella-example1

help: ## Displays this help
@awk 'BEGIN {FS = ":.*##"; printf "$(MAKEFILE_NAME)\n\nUsage:\n make \033[1;36m<target>\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[1;36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
59 changes: 20 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,26 @@ Package umbrella provides a simple authentication mechanism for an HTTP endpoint
5. [Motivation](#motivation)

## Sample code
The following code snippet shows how the module can be used.

```go
// database connection
dbConn, _ = sql.Open("postgres", "host=localhost user=myuser password=mypass port=5432 dbname=mydb sslmode=disable")

// umbrella controller
u := NewUmbrella(dbConn, "tblprefix_", &JWTConfig{
Key: "SomeSecretKey--.",
Issuer: "SomeIssuer",
ExpirationMinutes: 15,
}, nil)

// create db tables
_ := u.CreateDBTables()

// http server
// uri with registration, activation, login (returns auth token), logout endpoint
http.Handle("/umbrella/", u.GetHTTPHandler("/umbrella/"))
// restricted stuff that requires signing in (a token in http header)
http.Handle("/restricted_stuff/", u.GetHTTPHandlerWrapper(
getRestrictedStuffHTTPHandler(),
umbrella.HandlerConfig{},
))
http.ListenAndServe(":8001", nil)

// wrap http handler with a check for logged user
func getRestrictedStuffHTTPHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userID := umbrella.GetUserIDFromRequest(r)
if userID != 0 {
w.WriteHeader(http.StatusOK)
w.Write([]byte("RestrictedAreaContent"))
} else {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("NoAccess"))
}
})
}
A working application can be found in the `cmd/example1`. Type `make run-example1` to start an HTTP server and check the endpoints as shown below. jq is used to parse out the token from JSON output, however, it can be done manually as well.

```bash
# run the application
% make run-example1
# ...some output...

# sign in to get a token
% UMB_TOKEN=$(curl -s -X POST -d "[email protected]&password=admin" http://localhost:8001/umbrella/login | jq -r '.data.token')

# call restricted endpoint without the token
% curl http://localhost:8001/secret_stuff/
YouHaveToBeLoggedIn

# call it again with token
% curl -H "Authorization: Bearer $UMB_TOKEN" http://localhost:8001/secret_stuff/
SecretStuffOnlyForAdmin%

# remove temporary postgresql docker
make clean
```

## Database connection
Expand Down
72 changes: 72 additions & 0 deletions cmd/example1/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package main

import (
"database/sql"
"log"
"net/http"

"github.com/go-phings/umbrella"
_ "github.com/lib/pq"
)

const dbDSN = "host=localhost user=uuser password=upass port=54321 dbname=udb sslmode=disable"
const tblPrefix = "p_"

func main() {
db, err := sql.Open("postgres", dbDSN)
if err != nil {
log.Fatal("Error connecting to db")
}

// create umbrella controller
u := *umbrella.NewUmbrella(db, tblPrefix, &umbrella.JWTConfig{
Key: "someSecretKey",
Issuer: "someIssuer",
ExpirationMinutes: 15,
}, &umbrella.UmbrellaConfig{
TagName: "ui",
})

// create database tables
err = u.CreateDBTables()
if err != nil {
log.Fatalf("error creating database tables: %s", err.Error())
}

// create admin user
key, err := u.CreateUser("[email protected]", "admin", map[string]string{
"Name": "admin",
})
if err != nil {
log.Fatalf("error with creating admin: %s", err.Error())
}
err = u.ConfirmEmail(key)
if err != nil {
log.Fatalf("error with confirming admin email: %s", err.Error())
}

// /umbrella/{login,logout,register,confirm}
http.Handle("/umbrella/", u.GetHTTPHandler("/umbrella/"))

// secret stuff
http.Handle("/secret_stuff/", u.GetHTTPHandlerWrapper(secretStuff(), umbrella.HandlerConfig{}))

log.Fatal(http.ListenAndServe(":8001", nil))
}

func secretStuff() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
userID := umbrella.GetUserIDFromRequest(r)
switch userID {
case 1:
w.WriteHeader(http.StatusOK)
w.Write([]byte("SecretStuffOnlyForAdmin"))
case 0:
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("YouHaveToBeLoggedIn"))
default:
w.WriteHeader(http.StatusOK)
w.Write([]byte("SecretStuffForOtherUser"))
}
})
}
4 changes: 2 additions & 2 deletions err.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ type ErrUmbrella struct {
Err error
}

func (e *ErrUmbrella) Error() string {
func (e ErrUmbrella) Error() string {
return e.Err.Error()
}

func (e *ErrUmbrella) Unwrap() error {
func (e ErrUmbrella) Unwrap() error {
return e.Err
}
Loading

0 comments on commit 9f1216c

Please sign in to comment.