-
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.
- Loading branch information
Showing
6 changed files
with
143 additions
and
45 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
.env | ||
./listener/tmp/* | ||
./listener/bin/* | ||
jwt | ||
private.pem | ||
public.pem |
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,52 @@ | ||
package jwt | ||
|
||
import ( | ||
"os" | ||
"time" | ||
|
||
"github.com/dappnode/validator-monitoring/listener/internal/logger" | ||
"github.com/golang-jwt/jwt/v5" | ||
) | ||
|
||
func GenerateJWT(kid, privateKeyPath, subject, expiration string) (string, error) { | ||
logger.Info("Starting JWT generation") | ||
|
||
privateKeyData, err := os.ReadFile(privateKeyPath) | ||
if err != nil { | ||
logger.Error("Failed to read private key file: " + err.Error()) | ||
return "", err | ||
} | ||
privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(privateKeyData) | ||
if err != nil { | ||
logger.Error("Failed to parse private key: " + err.Error()) | ||
return "", err | ||
} | ||
|
||
claims := jwt.MapClaims{} | ||
if subject != "" { | ||
claims["sub"] = subject | ||
logger.Info("Subject claim set: " + subject) | ||
} | ||
if expiration != "" { | ||
duration, err := time.ParseDuration(expiration) | ||
if err != nil { | ||
logger.Error("Failed to parse expiration duration: " + err.Error()) | ||
return "", err | ||
} | ||
claims["exp"] = time.Now().Add(duration).Unix() | ||
logger.Info("Expiration claim set: " + expiration) | ||
} | ||
|
||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) | ||
token.Header["kid"] = kid | ||
logger.Info("JWT claims prepared") | ||
|
||
tokenString, err := token.SignedString(privateKey) | ||
if err != nil { | ||
logger.Error("Failed to sign token: " + err.Error()) | ||
return "", err | ||
} | ||
logger.Info("JWT generated and signed successfully") | ||
|
||
return tokenString, 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,77 @@ | ||
package jwt | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/golang-jwt/jwt/v5" | ||
) | ||
|
||
const testPublicKey string = `-----BEGIN PUBLIC KEY----- | ||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVyO2yhG8kGX14//pdCc | ||
XHEXIGB6qNAuVpiX7go8ZMC7dcSUXizQSxE4ffqegHnNiemyNbHOFAbhFaxszkP7 | ||
VOdbYdMe1IoFQ3yGGTfpAZtLWinq/CMwI9CSziSKgif3Rsvbj/xhDfQqfamLqmUJ | ||
Mk8gRdeMp7SiwDHrwVnwUdAgwKioEiTGU2y+C6EHdJeX0I6eFkLvGjbYFt35y0du | ||
wSp0ZYsB+P8glqGQvBOMtvWzoQQ8skuJ8yVBtR+GvU7hPXYBknL4jSLBOzJhHeEW | ||
srsGhn9V5Lo775y7n/ZBJFU0tVn/2zi//HKAVCTfG3J7IHAZqnhEivoM3jaFkzHh | ||
TQIDAQAB | ||
-----END PUBLIC KEY-----` | ||
|
||
// Test RSA Private Key (usually generated and safely stored; this is for testing only!) | ||
const testPrivateKeyPath = "../../test/data/private.pem" | ||
|
||
// TestGenerateJWT tests the GenerateJWT function. From an example private key in | ||
// ../../test/data/private.pem, it generates a JWT token with the kid "testKid". | ||
func TestGenerateJWT(t *testing.T) { | ||
kid := "testKid" | ||
subject := "testSubject" | ||
expiration := "1h" | ||
|
||
tokenString, err := GenerateJWT(kid, testPrivateKeyPath, subject, expiration) | ||
if err != nil { | ||
t.Fatalf("Generating JWT should not produce an error: %v", err) | ||
} | ||
|
||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { | ||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { | ||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) | ||
} | ||
|
||
kid, ok := token.Header["kid"].(string) | ||
if !ok { | ||
return nil, fmt.Errorf("kid not found in token header, generate a new token with a 'kid'") | ||
} | ||
|
||
if kid != "testKid" { | ||
return nil, fmt.Errorf("expected kid to be 'testKid', got %v", kid) | ||
} | ||
|
||
return jwt.ParseRSAPublicKeyFromPEM([]byte(testPublicKey)) | ||
}) | ||
|
||
if err != nil { | ||
t.Fatalf("The token should be valid: %v", err) | ||
} | ||
|
||
if !token.Valid { | ||
t.Fatalf("The token should be successfully validated") | ||
} | ||
|
||
claims, ok := token.Claims.(jwt.MapClaims) | ||
if !ok { | ||
t.Fatalf("Claims should be of type MapClaims") | ||
} | ||
|
||
if claims["sub"] != subject { | ||
t.Fatalf("Expected subject to be %v, got %v", subject, claims["sub"]) | ||
} | ||
|
||
if exp, ok := claims["exp"].(float64); ok { | ||
if time.Now().Add(50*time.Minute).Unix() >= int64(exp) { | ||
t.Fatalf("Expiration should be correct") | ||
} | ||
} else { | ||
t.Fatalf("Expiration claim missing or not a float64") | ||
} | ||
} |
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