-
Notifications
You must be signed in to change notification settings - Fork 50
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 #499 from anandrgitnirman/jwttoken
#312 - Support for Token Generation and Verification
- Loading branch information
Showing
5 changed files
with
145 additions
and
0 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
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,70 @@ | ||
package token | ||
|
||
import ( | ||
"fmt" | ||
"github.com/dgrijalva/jwt-go" | ||
"github.com/singnet/snet-daemon/blockchain" | ||
"github.com/singnet/snet-daemon/config" | ||
"strings" | ||
"time" | ||
) | ||
|
||
type customJWTokenServiceImpl struct { | ||
getGroupId func() string | ||
} | ||
|
||
//This will be used in components as a service to Create and Validate tokens | ||
func NewJWTTokenService(data blockchain.OrganizationMetaData) Service { | ||
return &customJWTokenServiceImpl{ | ||
getGroupId: func() string { | ||
return data.GetGroupIdString() | ||
}, | ||
} | ||
} | ||
|
||
func (service customJWTokenServiceImpl) CreateToken(payLoad PayLoad) (CustomToken, error) { | ||
atClaims := jwt.MapClaims{} | ||
atClaims["payload"] = fmt.Sprintf("%v", payLoad) | ||
atClaims["orgId"] = config.GetString(config.OrganizationId) | ||
atClaims["groupId"] = service.getGroupId() | ||
//set the Expiry of the Token generated | ||
atClaims["exp"] = time.Now().UTC(). | ||
Add(time.Second * time.Duration(config.GetInt(config.TokenExpiryInSeconds))).Unix() | ||
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims) | ||
return jwtToken.SignedString([]byte(config.GetString(config.TokenSecretKey))) | ||
} | ||
|
||
func (service customJWTokenServiceImpl) VerifyToken(receivedToken CustomToken, payLoad PayLoad) (err error) { | ||
tokenString := fmt.Sprintf("%v", receivedToken) | ||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { | ||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { | ||
return nil, fmt.Errorf("unexpected signing method : %v", token.Header["alg"]) | ||
} | ||
return []byte(config.GetString(config.TokenSecretKey)), nil | ||
}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { | ||
if err = service.checkJwtTokenClaims(claims, payLoad); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (service customJWTokenServiceImpl) checkJwtTokenClaims(claims jwt.MapClaims, payload PayLoad) (err error) { | ||
if strings.Compare(fmt.Sprintf("%v", claims["payload"]), fmt.Sprintf("%v", payload)) != 0 { | ||
return fmt.Errorf("payload %v used to generate the Token doesnt match expected values", claims["payload"]) | ||
} | ||
|
||
if strings.Compare(fmt.Sprintf("%v", claims["orgId"]), config.GetString(config.OrganizationId)) != 0 { | ||
return fmt.Errorf("organization %v is not associated with this Daemon", claims["orgId"]) | ||
} | ||
|
||
if strings.Compare(fmt.Sprintf("%v", claims["groupId"]), service.getGroupId()) != 0 { | ||
return fmt.Errorf("groupId %v is not associated with this Daemon", claims["groupId"]) | ||
} | ||
return nil | ||
} |
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,51 @@ | ||
package token | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/singnet/snet-daemon/config" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func Test_customJWTokenClaimsImpl_CreateToken(t *testing.T) { | ||
tokenImpl := &customJWTokenServiceImpl{ | ||
getGroupId: func() string { | ||
return "GroupID" | ||
}, | ||
} | ||
token, err := tokenImpl.CreateToken("any struct") | ||
assert.Nil(t, err) | ||
assert.NotNil(t, token) | ||
err = tokenImpl.VerifyToken(token, "any struct") | ||
config.Vip().Set(config.TokenExpiryInSeconds, 1) | ||
token, err = tokenImpl.CreateToken("any struct") | ||
time.Sleep(time.Second * 5) | ||
assert.Nil(t, err) | ||
err = tokenImpl.VerifyToken(token, "any struct") | ||
assert.Equal(t, "Token is expired", err.Error()) | ||
|
||
} | ||
|
||
func Test_customJWTokenClaimsImpl_checkJwtTokenClaims(t *testing.T) { | ||
tokenImpl := &customJWTokenServiceImpl{ | ||
getGroupId: func() string { | ||
return "GroupID" | ||
}, | ||
} | ||
config.Vip().Set(config.TokenExpiryInSeconds, 50) | ||
token, err := tokenImpl.CreateToken("any struct") | ||
err = tokenImpl.VerifyToken(token, "different struct") | ||
assert.Equal(t, "payload any struct used to generate the Token doesnt match expected values", err.Error()) | ||
config.Vip().Set(config.OrganizationId, "differentOrganization") | ||
err = tokenImpl.VerifyToken(token, "any struct") | ||
assert.Equal(t, "organization ExampleOrganizationId is not associated with this Daemon", err.Error()) | ||
config.Vip().Set(config.OrganizationId, "ExampleOrganizationId") | ||
tokenImpl2 := &customJWTokenServiceImpl{ | ||
getGroupId: func() string { | ||
return "GroupID2" | ||
}, | ||
} | ||
err = tokenImpl2.VerifyToken(token, "any struct") | ||
assert.Equal(t, "groupId GroupID is not associated with this Daemon", 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,10 @@ | ||
package token | ||
|
||
type PayLoad interface{} | ||
type CustomToken interface{} | ||
|
||
// Token.Service interface is an API for creating and verifying tokens | ||
type Service interface { | ||
CreateToken(key PayLoad) (token CustomToken, err error) | ||
VerifyToken(token CustomToken, key PayLoad) (err error) | ||
} |