Skip to content

Commit

Permalink
fixed roles and attributes for authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
rjtch committed Sep 21, 2024
1 parent bae798b commit d67d9c6
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 58 deletions.
44 changes: 22 additions & 22 deletions cmd/book-api/internal/handlers/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,47 +31,47 @@ func API(build string, shutdown chan os.Signal, log *log.Logger, db *sqlx.DB, au
authenticator: authenticator,
}

app.Handle("GET", "/v1/users/all", u.List, mid.Authentication(authenticator))
app.Handle("POST", "/v1/users/create", u.Create, mid.Authentication(authenticator))
app.Handle("GET", "/v1/users/:id", u.Retrieve, mid.Authentication(authenticator))
app.Handle("PUT", "/v1/users/:id/update", u.Update, mid.Authentication(authenticator))
app.Handle("DELETE", "/v1/users/:id/delete", u.Delete, mid.Authentication(authenticator))
app.Handle("GET", "/v1/users/all", u.List, mid.Authentication(authenticator, auth.RoleAdmin))
app.Handle("POST", "/v1/users/create", u.Create, mid.Authentication(authenticator, auth.RoleAdmin))
app.Handle("GET", "/v1/users/:id", u.Retrieve, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("PUT", "/v1/users/:id/update", u.Update, mid.Authentication(authenticator, auth.RoleAdmin))
app.Handle("DELETE", "/v1/users/:id/delete", u.Delete, mid.Authentication(authenticator, auth.RoleAdmin))

// This routes are not authenticated
app.Handle("POST", "/v1/users/token", u.TokenAuthenticator)
// app.Handle("POST", "/v1/users/token", u.TokenAuthenticator, auth.RoleUser)
app.Handle("GET", "/v1/users/refresh-token", u.RefreshToken)
app.Handle("POST", "/v1/users/:user_id/logout", u.Logout)

// Register books endpoints.
bk := Book{
db: db,
}
app.Handle("GET", "/v1/books/all", bk.List, mid.Authentication(authenticator))
app.Handle("GET", "/v1/books/title", bk.RetrieveByTitle, mid.Authentication(authenticator))
app.Handle("POST", "/v1/books/create", bk.Create, mid.Authentication(authenticator))
app.Handle("GET", "/v1/books/:id", bk.Retrieve, mid.Authentication(authenticator))
app.Handle("PUT", "/v1/books/:id/update", bk.Update, mid.Authentication(authenticator))
app.Handle("DELETE", "/v1/books/:id/delete", bk.Delete, mid.Authentication(authenticator))
app.Handle("GET", "/v1/books/all", bk.List, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("GET", "/v1/books/title", bk.RetrieveByTitle, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("POST", "/v1/books/create", bk.Create, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("GET", "/v1/books/:id", bk.Retrieve, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("PUT", "/v1/books/:id/update", bk.Update, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("DELETE", "/v1/books/:id/delete", bk.Delete, mid.Authentication(authenticator, auth.RoleUser))

// Register book-category endpoints.
ct := BookCategory{
db: db,
}
app.Handle("GET", "/v1/categories/all", ct.List, mid.Authentication(authenticator))
app.Handle("POST", "/v1/categories/create", ct.Create, mid.Authentication(authenticator))
app.Handle("PUT", "/v1/categories/:id/update", ct.Update, mid.Authentication(authenticator))
app.Handle("DELETE", "/v1/categories/:id/delete", ct.Delete, mid.Authentication(authenticator))
app.Handle("GET", "/v1/categories/:id", ct.Retreive, mid.Authentication(authenticator))
app.Handle("GET", "/v1/categories/all", ct.List, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("POST", "/v1/categories/create", ct.Create, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("PUT", "/v1/categories/:id/update", ct.Update, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("DELETE", "/v1/categories/:id/delete", ct.Delete, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("GET", "/v1/categories/:id", ct.Retreive, mid.Authentication(authenticator, auth.RoleUser))

// Register loans endpoints.
l := Loan{
db: db,
}
app.Handle("GET", "/v1/loans/:user_id/all", l.List, mid.Authentication(authenticator))
app.Handle("POST", "/v1/loans/:user_id/init", l.Create, mid.Authentication(authenticator))
app.Handle("PUT", "/v1/loans/:user_id/update/:id", l.Update, mid.Authentication(authenticator))
app.Handle("DELETE", "/v1/loans/:user_id/delete/:id", l.Delete, mid.Authentication(authenticator))
app.Handle("GET", "/v1/loans/:user_id/retrieve/:id", l.Retrieve, mid.Authentication(authenticator))
app.Handle("GET", "/v1/loans/:user_id/all", l.List, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("POST", "/v1/loans/:user_id/init", l.Create, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("PUT", "/v1/loans/:user_id/update/:id", l.Update, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("DELETE", "/v1/loans/:user_id/delete/:id", l.Delete, mid.Authentication(authenticator, auth.RoleUser))
app.Handle("GET", "/v1/loans/:user_id/retrieve/:id", l.Retrieve, mid.Authentication(authenticator, auth.RoleUser))

return app
}
17 changes: 0 additions & 17 deletions cmd/book-api/internal/handlers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package handlers

import (
"context"
"github.com/book-library/internal/mid"
"github.com/golang-jwt/jwt/v5"
"net/http"
"slices"
"time"

"github.com/book-library/internal/platform/auth"
Expand Down Expand Up @@ -37,20 +34,6 @@ func (u *User) List(ctx context.Context, w http.ResponseWriter, r *http.Request,
ctx, span := trace.StartSpan(ctx, "handlers.users.List")
defer span.End()

//TODO fixed role
claims, ok := ctx.Value(auth.Key).(*jwt.Token)
if !ok {
return errors.New("claims missing from context")
}

roles := mid.ParseRealmRoles(claims.Claims.(jwt.MapClaims))
if len(roles) == 0 {
return errors.New("Not roles related to the this user")
}
if !slices.Contains(roles, "Admin") {
return errors.New("You don't have the wright to see the required resources.")
}

usr, err := users.List(ctx, u.Db)
if err != nil {
return err
Expand Down
10 changes: 8 additions & 2 deletions cmd/book-api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,10 @@ func run() error {

defer func() {
logger.Printf("main : Database Stopping : %s", db.Host)
dbank.Close()
err := dbank.Close()
if err != nil {
return
}
}()

// =========================================================================
Expand All @@ -191,7 +194,10 @@ func run() error {

defer func() {
logger.Printf("main : Tracing Stopping : %s", zipkinServer.LocalEndpoint)
reporter.Close()
err := reporter.Close()
if err != nil {
return
}
}()

// =========================================================================
Expand Down
6 changes: 3 additions & 3 deletions cmd/book-api/oidc/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
"shutdownTimeout": "5s"
},
"db": {
"user": "postgres",
"password": "postgres",
"user": "book",
"password": "postgres-password",
"host": "0.0.0.0",
"name": "postgres",
"name": "book",
"disabledTls": "false"
},
"auth": {
Expand Down
24 changes: 16 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ networks:
shared-network:
driver: bridge

volumes:
data:
media:
pgdata:
redisdata:

services:

# This sidecar allows for the viewing of traces.
Expand Down Expand Up @@ -76,20 +82,22 @@ services:
# # This starts a local PostgreSQL DB.
postgres:
image: docker.io/library/postgres:16
restart: always
restart: unless-stopped
platform: linux/amd64
shm_size: 128mb
user: postgres
environment:
POSTGRES_USER: book
POSTGRES_PASSWORD: postgres-password
POSTGRES_DB: book
POSTGRES_HOST_AUTH_METHOD: trust
healthcheck:
test: pg_isready -U book -d book
interval: 10s
timeout: 5s
retries: 5
network_mode: host
# POSTGRES_HOST_AUTH_METHOD: trust
# healthcheck:
# test: pg_isready -U book -d book
# interval: 10s
# timeout: 5s
# retries: 5
# network_mode: host
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
18 changes: 15 additions & 3 deletions internal/mid/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/base64"
"log"
"net/http"
"slices"
"strings"

"github.com/book-library/internal/platform/auth"
Expand All @@ -32,7 +33,7 @@ var ErrForbidden = web.NewRequestError(

// Authentication validates a jwt and the csrf cookie from the Authorization header
// TODO extend this methode with role.
func Authentication(authenticator *auth.OAuthenticator) web.Middleware {
func Authentication(authenticator *auth.OAuthenticator, role string) web.Middleware {

//actual middleware to be execute
f := func(after web.Handler) web.Handler {
Expand All @@ -48,7 +49,7 @@ func Authentication(authenticator *auth.OAuthenticator) web.Middleware {
return errors.New("expected authorization header format: bearer <token>")
}

err, token := extractClaims(w, r, ctx, authenticator)
err, token := extractClaims(w, r, ctx, authenticator, role)
if err != nil {
return errors.New(" authorization header token bearer not valid")
}
Expand All @@ -63,7 +64,7 @@ func Authentication(authenticator *auth.OAuthenticator) web.Middleware {
return f
}

func extractClaims(w http.ResponseWriter, request *http.Request, ctx context.Context, oauth *auth.OAuthenticator) (error, *jwt.Token) {
func extractClaims(w http.ResponseWriter, request *http.Request, ctx context.Context, oauth *auth.OAuthenticator, role string) (error, *jwt.Token) {
stringToken := request.Header.Get(authorization)
secretKey, err := parseRSAPublicKey(oauth.PublicKeyRS256)
if err != nil {
Expand All @@ -89,6 +90,17 @@ func extractClaims(w http.ResponseWriter, request *http.Request, ctx context.Con
return secretKey, nil
})

claims, ok := ctx.Value(auth.Key).(*jwt.Token)
if !ok {
return errors.New("claims missing from context"), nil
}
roles := ParseRealmRoles(claims.Claims.(jwt.MapClaims))
if len(roles) == 0 {
return errors.New("Not roles related to the this user"), nil
}
if !slices.Contains(roles, role) {
return errors.New("You don't have the wright to see the required resources."), nil
}
if errors.Is(err, jwt.ErrSignatureInvalid) {
return errors.New(err.Error()), nil
}
Expand Down
4 changes: 2 additions & 2 deletions internal/platform/auth/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const (
)

type Role struct {
RoleAdmin []string
RoleUser []string
RoleAdmin string
RoleUser string
}

// ctxKey represents the type of value for the context key.
Expand Down
2 changes: 1 addition & 1 deletion internal/users/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func List(ctx context.Context, db *sqlx.DB) ([]User, error) {
const q = `SELECT * FROM users`

if err := db.SelectContext(ctx, &users, q); err != nil {
return nil, errors.Wrap(err, "selecting users")
return nil, errors.Wrap(err, "error when selecting users")
}

return users, nil
Expand Down

0 comments on commit d67d9c6

Please sign in to comment.