-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from isd-sgcu/feature/jwt-service
[Feature] Jwt Service
- Loading branch information
Showing
12 changed files
with
330 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,17 @@ | ||
package token | ||
|
||
import "github.com/isd-sgcu/johnjud-auth/src/internal/constant" | ||
import ( | ||
"github.com/golang-jwt/jwt/v4" | ||
"github.com/isd-sgcu/johnjud-auth/src/internal/constant" | ||
) | ||
|
||
type UserCredential struct { | ||
UserId string `json:"user_id"` | ||
Role constant.Role `json:"role"` | ||
} | ||
|
||
type AuthPayload struct { | ||
jwt.RegisteredClaims | ||
UserId string `json:"user_id"` | ||
Role constant.Role `json:"role"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,52 @@ | ||
package jwt | ||
|
||
import ( | ||
"fmt" | ||
_jwt "github.com/golang-jwt/jwt/v4" | ||
"github.com/isd-sgcu/johnjud-auth/src/config" | ||
"github.com/isd-sgcu/johnjud-auth/src/internal/constant" | ||
tokenDto "github.com/isd-sgcu/johnjud-auth/src/internal/domain/dto/token" | ||
"github.com/isd-sgcu/johnjud-auth/src/internal/utils" | ||
"github.com/isd-sgcu/johnjud-auth/src/pkg/strategy" | ||
"github.com/pkg/errors" | ||
"time" | ||
) | ||
|
||
type serviceImpl struct { | ||
config config.Jwt | ||
strategy strategy.JwtStrategy | ||
jwtUtil utils.IJwtUtil | ||
} | ||
|
||
func NewService(config config.Jwt, strategy strategy.JwtStrategy) *serviceImpl { | ||
return &serviceImpl{config: config, strategy: strategy} | ||
func NewService(config config.Jwt, strategy strategy.JwtStrategy, jwtUtil utils.IJwtUtil) *serviceImpl { | ||
return &serviceImpl{config: config, strategy: strategy, jwtUtil: jwtUtil} | ||
} | ||
|
||
func (s *serviceImpl) SignAuth(userId string) (string, error) { | ||
return "", nil | ||
func (s *serviceImpl) SignAuth(userId string, role constant.Role) (string, error) { | ||
payloads := tokenDto.AuthPayload{ | ||
RegisteredClaims: _jwt.RegisteredClaims{ | ||
Issuer: s.config.Issuer, | ||
ExpiresAt: s.jwtUtil.GetNumericDate(time.Now().Add(time.Second * time.Duration(s.config.ExpiresIn))), | ||
IssuedAt: s.jwtUtil.GetNumericDate(time.Now()), | ||
}, | ||
UserId: userId, | ||
Role: role, | ||
} | ||
|
||
token := s.jwtUtil.GenerateJwtToken(_jwt.SigningMethodHS256, payloads) | ||
|
||
tokenStr, err := s.jwtUtil.SignedTokenString(token, s.config.Secret) | ||
if err != nil { | ||
return "", errors.New(fmt.Sprintf("Error while signing the token due to: %s", err.Error())) | ||
} | ||
|
||
return tokenStr, nil | ||
} | ||
|
||
func (s *serviceImpl) VerifyAuth(token string) (*_jwt.Token, error) { | ||
return nil, nil | ||
return s.jwtUtil.ParseToken(token, s.strategy.AuthDecode) | ||
} | ||
|
||
func (s *serviceImpl) GetConfig() *config.Jwt { | ||
return nil | ||
return &s.config | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,149 @@ | ||
package jwt | ||
|
||
import ( | ||
"fmt" | ||
"github.com/go-faker/faker/v4" | ||
"github.com/golang-jwt/jwt/v4" | ||
"github.com/isd-sgcu/johnjud-auth/src/config" | ||
"github.com/isd-sgcu/johnjud-auth/src/pkg/strategy" | ||
"github.com/isd-sgcu/johnjud-auth/src/internal/constant" | ||
tokenDto "github.com/isd-sgcu/johnjud-auth/src/internal/domain/dto/token" | ||
"github.com/isd-sgcu/johnjud-auth/src/mocks/strategy" | ||
"github.com/isd-sgcu/johnjud-auth/src/mocks/utils" | ||
"github.com/pkg/errors" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/mock" | ||
"github.com/stretchr/testify/suite" | ||
"testing" | ||
"time" | ||
) | ||
|
||
type JwtServiceTest struct { | ||
suite.Suite | ||
config config.Jwt | ||
strategy *strategy.JwtStrategy | ||
config config.Jwt | ||
userId string | ||
role constant.Role | ||
numericDate *jwt.NumericDate | ||
payloads tokenDto.AuthPayload | ||
token *jwt.Token | ||
} | ||
|
||
func TestJwtService(t *testing.T) { | ||
suite.Run(t, new(JwtServiceTest)) | ||
} | ||
|
||
func (t *JwtServiceTest) SetupTest() { | ||
config := config.Jwt{ | ||
Secret: "testSecret", | ||
ExpiresIn: 3600, | ||
Issuer: "testIssuer", | ||
} | ||
|
||
userId := faker.UUIDDigit() | ||
role := constant.USER | ||
numericDate := jwt.NewNumericDate(time.Now()) | ||
|
||
payloads := tokenDto.AuthPayload{ | ||
RegisteredClaims: jwt.RegisteredClaims{ | ||
Issuer: t.config.Issuer, | ||
ExpiresAt: numericDate, | ||
IssuedAt: numericDate, | ||
}, | ||
UserId: userId, | ||
Role: role, | ||
} | ||
|
||
token := &jwt.Token{ | ||
Header: map[string]interface{}{ | ||
"typ": "JWT", | ||
"alg": jwt.SigningMethodHS256.Alg(), | ||
}, | ||
Method: jwt.SigningMethodHS256, | ||
Claims: payloads, | ||
} | ||
|
||
t.config = config | ||
t.userId = userId | ||
t.role = role | ||
t.numericDate = numericDate | ||
t.payloads = payloads | ||
t.token = token | ||
} | ||
|
||
func (t *JwtServiceTest) TestSignAuthSuccess() { | ||
expected := "signedTokenStr" | ||
|
||
jwtStrategy := strategy.JwtStrategyMock{} | ||
jwtUtil := utils.JwtUtilMock{} | ||
|
||
jwtUtil.On("GetNumericDate", mock.AnythingOfType("time.Time")).Return(t.numericDate) | ||
jwtUtil.On("GenerateJwtToken", jwt.SigningMethodHS256, t.payloads).Return(t.token) | ||
jwtUtil.On("SignedTokenString", t.token, t.config.Secret).Return(expected, nil) | ||
|
||
jwtSvc := NewService(t.config, &jwtStrategy, &jwtUtil) | ||
actual, err := jwtSvc.SignAuth(t.userId, t.role) | ||
|
||
assert.Nil(t.T(), err) | ||
assert.Equal(t.T(), expected, actual) | ||
} | ||
|
||
func (t *JwtServiceTest) TestSignAuthSignedStringFailed() { | ||
signedTokenError := errors.New("Some Error") | ||
expected := errors.New(fmt.Sprintf("Error while signing the token due to: %s", signedTokenError.Error())) | ||
|
||
jwtStrategy := strategy.JwtStrategyMock{} | ||
jwtUtil := utils.JwtUtilMock{} | ||
|
||
jwtUtil.On("GetNumericDate", mock.AnythingOfType("time.Time")).Return(t.numericDate) | ||
jwtUtil.On("GenerateJwtToken", jwt.SigningMethodHS256, t.payloads).Return(t.token) | ||
jwtUtil.On("SignedTokenString", t.token, t.config.Secret).Return("", signedTokenError) | ||
|
||
jwtSvc := NewService(t.config, &jwtStrategy, &jwtUtil) | ||
actual, err := jwtSvc.SignAuth(t.userId, t.role) | ||
|
||
assert.Equal(t.T(), "", actual) | ||
assert.Equal(t.T(), expected.Error(), err.Error()) | ||
} | ||
|
||
func (t *JwtServiceTest) TestVerifyAuthSuccess() { | ||
tokenStr := "validSignedToken" | ||
expected := t.token | ||
|
||
jwtStrategy := strategy.JwtStrategyMock{} | ||
jwtUtil := utils.JwtUtilMock{} | ||
|
||
jwtUtil.On("ParseToken", tokenStr, mock.AnythingOfType("jwt.Keyfunc")).Return(expected, nil) | ||
|
||
jwtSvc := NewService(t.config, &jwtStrategy, &jwtUtil) | ||
actual, err := jwtSvc.VerifyAuth(tokenStr) | ||
|
||
assert.Nil(t.T(), err) | ||
assert.Equal(t.T(), *expected, *actual) | ||
} | ||
|
||
func (t *JwtServiceTest) TestVerifyAuthFailed() { | ||
tokenStr := "invalidSignedToken" | ||
expected := errors.New("invalid token") | ||
|
||
jwtStrategy := strategy.JwtStrategyMock{} | ||
jwtUtil := utils.JwtUtilMock{} | ||
|
||
jwtUtil.On("ParseToken", tokenStr, mock.AnythingOfType("jwt.Keyfunc")).Return(nil, expected) | ||
|
||
jwtSvc := NewService(t.config, &jwtStrategy, &jwtUtil) | ||
actual, err := jwtSvc.VerifyAuth(tokenStr) | ||
|
||
assert.Nil(t.T(), actual) | ||
assert.Equal(t.T(), expected, err) | ||
} | ||
|
||
func (t *JwtServiceTest) TestGetConfigSuccess() { | ||
expected := &t.config | ||
|
||
jwtStrategy := strategy.JwtStrategyMock{} | ||
jwtUtil := utils.JwtUtilMock{} | ||
|
||
jwtSvc := NewService(t.config, &jwtStrategy, &jwtUtil) | ||
actual := jwtSvc.GetConfig() | ||
|
||
assert.Equal(t.T(), *expected, *actual) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package strategy | ||
|
||
import ( | ||
"fmt" | ||
"github.com/golang-jwt/jwt/v4" | ||
"github.com/pkg/errors" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/suite" | ||
"testing" | ||
) | ||
|
||
type JwtStrategyTest struct { | ||
suite.Suite | ||
secret string | ||
} | ||
|
||
func TestJwtStrategy(t *testing.T) { | ||
suite.Run(t, new(JwtStrategyTest)) | ||
} | ||
|
||
func (t *JwtStrategyTest) SetupTest() { | ||
secret := "testSecret" | ||
|
||
t.secret = secret | ||
} | ||
|
||
func (t *JwtStrategyTest) TestAuthDecodeSuccess() { | ||
token := &jwt.Token{ | ||
Method: jwt.SigningMethodHS256, | ||
} | ||
expected := []byte(t.secret) | ||
|
||
jwtStrategy := NewJwtStrategy(t.secret) | ||
actual, err := jwtStrategy.AuthDecode(token) | ||
|
||
assert.Nil(t.T(), err) | ||
assert.Equal(t.T(), expected, actual) | ||
} | ||
|
||
func (t *JwtStrategyTest) TestAuthDecodeFailed() { | ||
token := &jwt.Token{ | ||
Method: jwt.SigningMethodES256, | ||
Header: map[string]interface{}{ | ||
"typ": "JWT", | ||
"alg": jwt.SigningMethodES256.Alg(), | ||
}, | ||
} | ||
expected := errors.New(fmt.Sprintf("invalid token %v\n", token.Header["alg"])) | ||
|
||
jwtStrategy := NewJwtStrategy(t.secret) | ||
actual, err := jwtStrategy.AuthDecode(token) | ||
|
||
assert.Nil(t.T(), actual) | ||
assert.Equal(t.T(), expected.Error(), err.Error()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package utils | ||
|
||
import ( | ||
"github.com/golang-jwt/jwt/v4" | ||
"time" | ||
) | ||
|
||
type IJwtUtil interface { | ||
GenerateJwtToken(method jwt.SigningMethod, payloads jwt.Claims) *jwt.Token | ||
GetNumericDate(time time.Time) *jwt.NumericDate | ||
SignedTokenString(token *jwt.Token, secret string) (string, error) | ||
ParseToken(tokenStr string, keyFunc jwt.Keyfunc) (*jwt.Token, error) | ||
} | ||
|
||
type jwtUtilImpl struct{} | ||
|
||
func NewJwtUtil() *jwtUtilImpl { | ||
return &jwtUtilImpl{} | ||
} | ||
|
||
func (u *jwtUtilImpl) GenerateJwtToken(method jwt.SigningMethod, payloads jwt.Claims) *jwt.Token { | ||
return jwt.NewWithClaims(method, payloads) | ||
} | ||
|
||
func (u *jwtUtilImpl) GetNumericDate(time time.Time) *jwt.NumericDate { | ||
return jwt.NewNumericDate(time) | ||
} | ||
|
||
func (u *jwtUtilImpl) SignedTokenString(token *jwt.Token, secret string) (string, error) { | ||
return token.SignedString([]byte(secret)) | ||
} | ||
|
||
func (u *jwtUtilImpl) ParseToken(tokenStr string, keyFunc jwt.Keyfunc) (*jwt.Token, error) { | ||
return jwt.Parse(tokenStr, keyFunc) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package strategy | ||
|
||
import ( | ||
"github.com/golang-jwt/jwt/v4" | ||
"github.com/stretchr/testify/mock" | ||
) | ||
|
||
type JwtStrategyMock struct { | ||
mock.Mock | ||
} | ||
|
||
func (m *JwtStrategyMock) AuthDecode(token *jwt.Token) (interface{}, error) { | ||
args := m.Called(token) | ||
if args.Get(0) != nil { | ||
return args.Get(0), nil | ||
} | ||
return nil, args.Error(1) | ||
} |
Oops, something went wrong.