Skip to content

Commit

Permalink
feat: complete support for this service (#37)
Browse files Browse the repository at this point in the history
* fix: added missing env setup in dockerfile related to JWT secret

* feat: authorize controller operation

* feat: authorization prefix

* feat: update password

* feat: challenge endpoint

* docs: fixed documentation of the specification

* feat: user uuid by username

* docs: added documentation for JWT secret flag

* chore(release): 0.0.22
  • Loading branch information
shoriwe authored Sep 7, 2023
1 parent e2302d5 commit 95d6c54
Show file tree
Hide file tree
Showing 25 changed files with 600 additions and 70 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [0.0.22](https://github.com/hawks-atlanta/authentication-go/compare/v0.0.5...v0.0.22) (2023-09-07)


### Features

* authorization prefix ([f951146](https://github.com/hawks-atlanta/authentication-go/commit/f951146b15219fb42f78235a2badcc64059a083f))
* authorize controller operation ([22845c6](https://github.com/hawks-atlanta/authentication-go/commit/22845c65026f853061f8e1302dd48d670e0af537))
* challenge endpoint ([f4f23c8](https://github.com/hawks-atlanta/authentication-go/commit/f4f23c85a63354860221ff38f42394b71508e362))
* update password ([5b2d77f](https://github.com/hawks-atlanta/authentication-go/commit/5b2d77fb0041731c8819948ddccef0bd33d6ede2))
* user uuid by username ([c81b42f](https://github.com/hawks-atlanta/authentication-go/commit/c81b42f27428b8ab0f25dbcbd88bd6ebb3a3ac86))
* v0.0.10 ([#12](https://github.com/hawks-atlanta/authentication-go/issues/12)) ([96549ef](https://github.com/hawks-atlanta/authentication-go/commit/96549eff4bb24932dec1fca949692bf5efe1395d))
* v0.0.21 ([#35](https://github.com/hawks-atlanta/authentication-go/issues/35)) ([e2302d5](https://github.com/hawks-atlanta/authentication-go/commit/e2302d52080936b1ca6113c87c655c527f79b4b0)), closes [#33](https://github.com/hawks-atlanta/authentication-go/issues/33) [#34](https://github.com/hawks-atlanta/authentication-go/issues/34)
* v0.0.7 ([#8](https://github.com/hawks-atlanta/authentication-go/issues/8)) ([e9a8acd](https://github.com/hawks-atlanta/authentication-go/commit/e9a8acdf6d14be40ed3c05f62b71de28bab8ad83)), closes [#5](https://github.com/hawks-atlanta/authentication-go/issues/5) [#6](https://github.com/hawks-atlanta/authentication-go/issues/6) [#7](https://github.com/hawks-atlanta/authentication-go/issues/7)


### Bug Fixes

* added missing env setup in dockerfile related to JWT secret ([e035eed](https://github.com/hawks-atlanta/authentication-go/commit/e035eed7fc422a842c4547491e7b261f72b3f391))
* fmt ([1653f19](https://github.com/hawks-atlanta/authentication-go/commit/1653f198fcbed059d14a657afe3b553983e5f531))
* removed line ([#15](https://github.com/hawks-atlanta/authentication-go/issues/15)) ([6b3899f](https://github.com/hawks-atlanta/authentication-go/commit/6b3899f5c8a3da1f15c0522b452f5dc5a326a601))
* triggering pipeline ([f1e7475](https://github.com/hawks-atlanta/authentication-go/commit/f1e7475f6d5595c5bcc656136ef6093ff647dcfc))

### 0.0.21 (2023-09-06)


Expand Down
1 change: 1 addition & 0 deletions CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This document describes how to use the service as a CLI tool.

| Variable | Description | Example |
| ----------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| `JWT_SECRET` | Secret used by the JWT engine | `CAPY_FILE` |
| `DATABASE_ENGINE` | Database engine to use. Available are `postgres` and `sqlite` | `postgres` |
| `DATABASE_DSN` | Database connection DSN to use | `host=127.0.0.1 user=sulcud password=sulcud dbname=sulcud port=5432 sslmode=disable` |

Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ USER application
COPY --from=builder /build/ /opt/application
WORKDIR /opt/application/db
WORKDIR /
ENV JWT_SECRET "CAPY_FILE"
ENV DATABASE_ENGINE "sqlite"
ENV DATABASE_DSN "/opt/application/db/database.db?cache=shared&mode=rwc"
ENTRYPOINT ["/opt/application/authentication-go", ":8080"]
31 changes: 31 additions & 0 deletions controller/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package controller

import (
"errors"

"github.com/golang-jwt/jwt/v5"
"github.com/hawks-atlanta/authentication-go/models"
"gorm.io/gorm"
)

func (c *Controller) Authorize(jwtS string) (user models.User, err error) {
tok, err := jwt.Parse(jwtS, c.JWT.KeyFunc)
if err != nil {
err = ErrUnauthorized
return user, err
}
var check models.User
err = check.FromClaims(tok.Claims.(jwt.MapClaims))
if err != nil {
err = ErrUnauthorized
return user, err
}
err = c.DB.
Where("uuid = ?", check.UUID).
First(&user).
Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
err = ErrUnauthorized
}
return user, err
}
60 changes: 60 additions & 0 deletions controller/auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package controller

import (
"testing"

"github.com/hawks-atlanta/authentication-go/database"
"github.com/hawks-atlanta/authentication-go/internal/utils/jwt"
"github.com/hawks-atlanta/authentication-go/internal/utils/random"
"github.com/hawks-atlanta/authentication-go/models"
"github.com/stretchr/testify/assert"
"gorm.io/gorm"
)

func TestController_Authorize(t *testing.T) {
t.Run("Succeed", database.Test(func(t *testing.T, db *gorm.DB) {
assertions := assert.New(t)

c, err := New(WithDB(db), WithSecret(random.Bytes(16)))
assertions.Nil(err)

u := models.RandomUser()
err = c.Register(u)
assertions.Nil(err)

token := c.JWT.New(u.Claims())

user, err := c.Authorize(token)
assertions.Nil(err)

assertions.Equal(u.UUID, user.UUID)
assertions.Equal(u.Username, user.Username)
}))
t.Run("Invalid Token", database.Test(func(t *testing.T, db *gorm.DB) {
assertions := assert.New(t)

c, err := New(WithDB(db), WithSecret(random.Bytes(16)))
assertions.Nil(err)

_, err = c.Authorize("INVALID")
assertions.NotNil(err)
}))
t.Run("Invalid SECRET", database.Test(func(t *testing.T, db *gorm.DB) {
assertions := assert.New(t)

c, err := New(WithDB(db), WithSecret(random.Bytes(16)))
assertions.Nil(err)

_, err = c.Authorize(jwt.New(random.Bytes(16)).New(models.RandomUser().Claims()))
assertions.NotNil(err)
}))
t.Run("Invalid User", database.Test(func(t *testing.T, db *gorm.DB) {
assertions := assert.New(t)

c, err := New(WithDB(db), WithSecret(random.Bytes(16)))
assertions.Nil(err)

_, err = c.Authorize(c.JWT.New(models.RandomUser().Claims()))
assertions.NotNil(err)
}))
}
15 changes: 15 additions & 0 deletions controller/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package controller

import "github.com/hawks-atlanta/authentication-go/models"

type UserRequest struct {
Username string `json:"username"`
}

func (c *Controller) UserByUsername(req *UserRequest) (user models.User, err error) {
err = c.DB.
Where("username = ?", req.Username).
First(&user).
Error
return user, err
}
31 changes: 31 additions & 0 deletions controller/query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package controller

import (
"testing"

"github.com/hawks-atlanta/authentication-go/database"
"github.com/hawks-atlanta/authentication-go/internal/utils/random"
"github.com/hawks-atlanta/authentication-go/models"
"github.com/stretchr/testify/assert"
"gorm.io/gorm"
)

func TestUserByUsername(t *testing.T) {
t.Run("Succeed", database.Test(func(t *testing.T, db *gorm.DB) {
assertions := assert.New(t)

c, err := New(WithDB(db), WithSecret(random.String(16)))
assertions.Nil(err)

u := models.RandomUser()
err = c.Register(u)
assertions.Nil(err)

req := UserRequest{
Username: *u.Username,
}
ou, err := c.UserByUsername(&req)

assertions.Equal(u.UUID, ou.UUID)
}))
}
25 changes: 25 additions & 0 deletions controller/update_password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package controller

import (
"github.com/hawks-atlanta/authentication-go/models"
)

type UpdatePasswordRequest struct {
OldPassword string `json:"oldPassword"`
NewPassword string `json:"newPassword"`
}

func (c *Controller) UpdatePassword(session *models.User, req *UpdatePasswordRequest) (err error) {
if !session.Authenticate(req.OldPassword) {
return ErrUnauthorized
}
update := models.User{
Model: session.Model,
Password: req.NewPassword,
}
err = c.DB.
Where("uuid = ? AND password_hash = ?", session.UUID, session.PasswordHash).
Updates(&update).
Error
return err
}
55 changes: 55 additions & 0 deletions controller/update_password_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package controller

import (
"testing"

"github.com/hawks-atlanta/authentication-go/database"
"github.com/hawks-atlanta/authentication-go/internal/utils/random"
"github.com/hawks-atlanta/authentication-go/models"
"github.com/stretchr/testify/assert"
"gorm.io/gorm"
)

func TestController_UpdatePassword(t *testing.T) {
t.Run("Succeed", database.Test(func(t *testing.T, db *gorm.DB) {
assertions := assert.New(t)

c, err := New(WithDB(db), WithSecret(random.Bytes(16)))
assertions.Nil(err)

u := models.RandomUser()
err = c.Register(u)
assertions.Nil(err)

req := UpdatePasswordRequest{
OldPassword: u.Password,
NewPassword: random.String(16),
}
err = c.UpdatePassword(u, &req)
assertions.Nil(err)

creds := models.User{
Username: u.Username,
Password: req.NewPassword,
}
_, err = c.Login(&creds)
assertions.Nil(err)
}))
t.Run("Invalid Password", database.Test(func(t *testing.T, db *gorm.DB) {
assertions := assert.New(t)

c, err := New(WithDB(db), WithSecret(random.Bytes(16)))
assertions.Nil(err)

u := models.RandomUser()
err = c.Register(u)
assertions.Nil(err)

req := UpdatePasswordRequest{
OldPassword: random.String(16),
NewPassword: random.String(16),
}
err = c.UpdatePassword(u, &req)
assertions.NotNil(err)
}))
}
34 changes: 19 additions & 15 deletions docs/spec.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,18 @@ paths:
$ref: '#/components/schemas/statusResponse'
/challenge:
post:
security:
- bearerAuth: []
tags:
- Authorization
description: Verifies the received token is still valid
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/authorization'
responses:
'200':
description: Account token is still valid
description: Fresh JWT
content:
application/json:
schema:
$ref: '#/components/schemas/account'
$ref: '#/components/schemas/authorization'
'401':
description: Unauthorized
content:
Expand All @@ -105,21 +102,21 @@ paths:

/account/password:
patch:
security:
- bearerAuth: []
tags:
- Account
description: Updates the username password
requestBody:
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/authorization'
- type: object
properties:
currentPassword:
type: string
newPassword:
type: string
type: object
properties:
currentPassword:
type: string
newPassword:
type: string
responses:
'200':
description: Password updated successfully
Expand All @@ -141,6 +138,8 @@ paths:
$ref: '#/components/schemas/statusResponse'
/user/uuid/{username}:
get:
security:
- bearerAuth: []
tags:
- Account
description: Obtain the uuid of an user by its username
Expand Down Expand Up @@ -171,6 +170,11 @@ paths:
$ref: '#/components/schemas/statusResponse'

components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
account:
type: object
Expand Down
2 changes: 1 addition & 1 deletion models/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

type Model struct {
UUID uuid.UUID `json:"uuid" gorm:"primaryKey;"`
UUID uuid.UUID `json:"uuid,omitempty" gorm:"primaryKey;"`
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
DeletedAt *time.Time `json:"-" sql:"index"`
Expand Down
4 changes: 2 additions & 2 deletions models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import (

type User struct {
Model
Username *string `json:"username" gorm:"unique;not null;"`
Password string `json:"password" gorm:"-"`
Username *string `json:"username,omitempty" gorm:"unique;not null;"`
Password string `json:"password,omitempty" gorm:"-"`
PasswordHash []byte `json:"-" gorm:"not null;"`
}

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"git-semver-tags": "^4.1.1",
"standard-version": "^9.5.0"
},
"version": "0.0.21"
"version": "0.0.22"
}
Loading

0 comments on commit 95d6c54

Please sign in to comment.