-
Notifications
You must be signed in to change notification settings - Fork 99
Add License Validation Mechanism using JWT and JWKS #4799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This commit introduces a robust license validation system using JSON Web Tokens (JWT) and JSON Web Key Sets (JWKS). The implementation provides cryptographic verification of license tokens using public key cryptography, specifically supporting both RSA and ECDSA algorithms. The license validation system is built on two modern standards: 1. JWT (JSON Web Tokens) for the license token format 2. JWKS (JSON Web Key Sets) for public key distribution License tokens are cryptographically signed JWTs that contain claims about the license, such as: - Features enabled - Usage limitations - Expiration dates - License metadata Linear: https://linear.app/expanso/issue/ENG-512/license-inspection-and-tooling
WalkthroughThis pull request introduces a comprehensive license validation system for JWT tokens using JSON Web Key Sets (JWKS). The changes include updating Go module dependencies, implementing a new Changes
Sequence DiagramsequenceDiagram
participant Client
participant LicenseValidator
participant JWKS
participant JWT
Client->>LicenseValidator: Initialize with JWKS
LicenseValidator->>JWKS: Load Key Set
Client->>LicenseValidator: Validate Token
LicenseValidator->>JWT: Parse and Verify
LicenseValidator->>LicenseValidator: Check Additional Constraints
LicenseValidator-->>Client: Return Validated Claims
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🔭 Outside diff range comments (2)
go.mod (2)
Line range hint
3-3
: Fix invalid Go version.
go 1.23
specified in thego.mod
file is invalid as Go 1.23 hasn't been released yet. The latest stable version is Go 1.22.-go 1.23 +go 1.22
Line range hint
18-18
: Remove old JWT library to prevent conflicts.Both v3 and v5 of the JWT library are present which could lead to dependency conflicts and confusion. Since you're implementing new JWT functionality, standardize on v5.
- github.com/golang-jwt/jwt v3.2.2+incompatible
Also applies to: 25-25
🧹 Nitpick comments (7)
pkg/lib/license/license_validator.go (5)
43-62
: Simplify JWKS validation inNewLicenseValidatorFromJSON
The manual parsing and validation of the JWKS JSON may be redundant since
keyfunc.NewJWKSetJSON
already handles parsing and structure validation of the JWKS. Consider removing the explicit JSON unmarshalling and checks to simplify the code.Apply this diff to streamline the function:
func NewLicenseValidatorFromJSON(jwksJSON json.RawMessage) (*LicenseValidator, error) { - if len(jwksJSON) == 0 { - return nil, fmt.Errorf("empty JWKS JSON") - } - - // Parse the JSON first to validate structure - var jwks struct { - Keys []interface{} `json:"keys"` - } - if err := json.Unmarshal(jwksJSON, &jwks); err != nil { - return nil, fmt.Errorf("invalid JWKS JSON: %w", err) - } - - // Check if keys array exists and is not empty - if jwks.Keys == nil { - return nil, fmt.Errorf("missing 'keys' array in JWKS") - } - if len(jwks.Keys) == 0 { - return nil, fmt.Errorf("empty 'keys' array in JWKS") - } // Create the JWKS key function keyFunc, err := keyfunc.NewJWKSetJSON(jwksJSON) if err != nil { return nil, fmt.Errorf("failed to create JWKS key function: %w", err) } return &LicenseValidator{ keyFunc: keyFunc.Keyfunc, }, nil }
81-83
: Enhance error handling for token parsingCurrently, when token parsing fails, the error message is wrapped with "failed to parse token" using
%w
. To provide clearer error messages without exposing sensitive information, consider using%v
or adding more context to the error.Apply this diff to adjust the error reporting:
if err != nil { - return nil, fmt.Errorf("failed to parse token: %w", err) + return nil, fmt.Errorf("failed to parse token: %v", err) }
85-87
: Remove redundant token validity checkThe
jwt.ParseWithClaims
function already validates the token and returns an error if the token is invalid. Checkingif !token.Valid
immediately after parsing is redundant. Consider removing this check to simplify the code.Apply this diff to eliminate the redundant code:
if err != nil { return nil, fmt.Errorf("failed to parse token: %v", err) } - - if !token.Valid { - return nil, fmt.Errorf("invalid token") - }
97-113
: Utilize built-in claims validationThe
jwt.RegisteredClaims
type provides aValid()
method that performs standard validation of registered claims likeExpiresAt
andNotBefore
. Replace the manual checks with this method to ensure consistent and thorough validation.Apply this diff to use the built-in validation:
func (v *LicenseValidator) validateAdditionalConstraints(claims *LicenseClaims) error { - now := time.Now() - - // Check if token is expired - if claims.ExpiresAt != nil && claims.ExpiresAt.Before(now) { - return fmt.Errorf("license has expired") - } - - // Check if token is not yet valid - if claims.NotBefore != nil && claims.NotBefore.After(now) { - return fmt.Errorf("license is not yet valid") - } + if err := claims.RegisteredClaims.Valid(); err != nil { + return fmt.Errorf("token validation error: %v", err) + } // Add any other custom validation logic here return nil }
9-10
: Consider implementing JWKS refresh for key rotationIf the public keys in the JWKS might change over time due to key rotation, consider implementing a mechanism to refresh the JWKS periodically. The
keyfunc
package supports fetching JWKS from a URL with auto-refresh capabilities.This enhancement improves security by ensuring that the validator uses the most recent set of keys.
pkg/lib/license/license_validator_test.go (1)
96-157
: Expand test coverage for token validationCurrently, the
TestValidateToken
function does not include tests for expired or not-yet-valid tokens. Adding these test cases will ensure that thevalidateAdditionalConstraints
method correctly handles tokens outside their valid time window.Would you like assistance in adding these test cases?
🧰 Tools
🪛 Gitleaks (8.21.2)
130-130: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
136-136: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
cspell.yaml (1)
36-36
: Re-evaluate the need to ignore the test file in spell checkingAdding
pkg/lib/license/license_validator_test.go
toignorePaths
excludes it from spell checking, which might allow typos to slip through. Consider removing this entry and instead add any necessary words to the custom dictionary or address specific spelling errors within the test file.This approach maintains code quality by ensuring all files are checked for spelling errors.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
go.sum
is excluded by!**/*.sum
go.work.sum
is excluded by!**/*.sum
📒 Files selected for processing (4)
cspell.yaml
(1 hunks)go.mod
(3 hunks)pkg/lib/license/license_validator.go
(1 hunks)pkg/lib/license/license_validator_test.go
(1 hunks)
🧰 Additional context used
🪛 Gitleaks (8.21.2)
pkg/lib/license/license_validator_test.go
34-34: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
35-35: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
130-130: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
136-136: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
🔇 Additional comments (3)
pkg/lib/license/license_validator.go (1)
22-30
: Ensure required claims are properly validatedAll custom claims in
LicenseClaims
are tagged withomitempty
, which means they are optional during JSON unmarshalling. If certain claims are mandatory for license validation, remove theomitempty
tag to enforce their presence.Please verify which claims are required and adjust the struct tags accordingly.
pkg/lib/license/license_validator_test.go (1)
211-212
: Verify the accuracy of the expiration timestamp in test claimsThe test asserts that
claims.ExpiresAt.Unix()
equals10376240107
, which corresponds to a date approximately in the year 3300. Confirm that this timestamp is intentional and that it aligns with the expected behavior of the license expiration.Adjust the timestamp if a more realistic expiration time is intended.
Also applies to: 225-226
go.mod (1)
8-8
: Good choice of JWT/JWKS libraries.The selected libraries for JWT (
github.com/golang-jwt/jwt/v5
) and JWKS (github.com/MicahParks/keyfunc/v3
and its dependencygithub.com/MicahParks/jwkset
) are well-maintained, popular choices that provide the necessary functionality for secure license validation.Let's verify the latest versions and security advisories for these dependencies:
Also applies to: 25-25, 92-92
✅ Verification successful
Verified: JWT/JWKS libraries are secure and well-maintained
The project uses the latest versions (jwt v5.x.x, keyfunc v3.3.5) of both libraries, which are actively maintained with recent updates (Nov 2024 and Sept 2024 respectively) and have no known security vulnerabilities.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check for security advisories in the JWT and JWKS libraries gh api graphql -f query=' { securityVulnerabilities(first: 5, ecosystem: GO, package: "github.com/golang-jwt/jwt") { nodes { advisory { summary severity publishedAt } vulnerableVersionRange firstPatchedVersion { identifier } } } } ' gh api graphql -f query=' { securityVulnerabilities(first: 5, ecosystem: GO, package: "github.com/MicahParks/keyfunc") { nodes { advisory { summary severity publishedAt } vulnerableVersionRange firstPatchedVersion { identifier } } } } 'Length of output: 720
Script:
#!/bin/bash # Check latest versions and activity for JWT libraries curl -s "https://pkg.go.dev/github.com/golang-jwt/jwt/v5?tab=versions" | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' curl -s "https://pkg.go.dev/github.com/MicahParks/keyfunc/v3?tab=versions" | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' # Check recent activity gh api repos/golang-jwt/jwt/commits?per_page=1 gh api repos/MicahParks/keyfunc/commits?per_page=1 # Check popularity curl -s "https://pkg.go.dev/github.com/golang-jwt/jwt/v5" | grep -o "[0-9]\+[KM]\? imports" curl -s "https://pkg.go.dev/github.com/MicahParks/keyfunc/v3" | grep -o "[0-9]\+[KM]\? imports"Length of output: 10794
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
- Add more tests to cover them - Add README to cover tokens generation for tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
pkg/lib/license/license_validator_test.go (1)
260-264
: Consider using a cross-platform approach to test invalid file permissionsThe test case uses the hardcoded file path
/root/test.json
, which may not behave consistently across different operating systems or environments. On non-Unix systems or when tests are run with elevated permissions, this path might exist or be accessible, causing the test to produce unreliable results.Consider creating a temporary file and programmatically setting its permissions to an inaccessible state using
os.Chmod
. This approach ensures the test reliably simulates the scenario of invalid file permissions across all environments.Example:
import ( "io/ioutil" "os" ) // In your test function file, err := ioutil.TempFile("", "test.json") require.NoError(t, err) defer os.Remove(file.Name()) // Set file permissions to 000 to simulate invalid permissions err = os.Chmod(file.Name(), 0000) require.NoError(t, err) validator, err := NewLicenseValidatorFromFile(file.Name()) // Continue with your assertionspkg/lib/license/README.md (3)
1-1
: Remove trailing colons from headingsThe headings on lines 1 and 21 have trailing colons, which is against Markdown style guidelines. Removing the colons will improve the readability and adhere to standard Markdown practices.
Apply this diff:
-## How to verify a license: +## How to verify a license ... -## How to generate JWKS and JWT tokens for tests: +## How to generate JWKS and JWT tokens for testsAlso applies to: 21-21
🧰 Tools
🪛 Markdownlint (0.37.0)
1-1: Punctuation: ':'
Trailing punctuation in heading(MD026, no-trailing-punctuation)
1-1: null
First line in a file should be a top-level heading(MD041, first-line-heading, first-line-h1)
1-1
: Add a top-level heading at the beginning of the fileMarkdown linting suggests that the first line should be a top-level heading (
#
). Adding a main heading will provide a clear title for the README and improve navigation.Example:
+# License Validation Guide + ## How to verify a license🧰 Tools
🪛 Markdownlint (0.37.0)
1-1: Punctuation: ':'
Trailing punctuation in heading(MD026, no-trailing-punctuation)
1-1: null
First line in a file should be a top-level heading(MD041, first-line-heading, first-line-h1)
32-36
: Align the comment with the codeThe comment states "Generate four RSA key pairs," but the code only generates one key pair (
rsa_key_1
). To avoid confusion, either update the comment to reflect the actual code or modify the code to generate four key pairs as indicated.Option 1: Update the comment:
- # Generate four RSA key pairs + # Generate an RSA key pairOption 2: Update the code to generate four key pairs (if intended):
# Generate four RSA key pairs rsa_keys = [] for i in range(4): rsa_key = jwk.JWK.generate(kty='RSA', size=2048, alg='RS256', use='sig', kid=f'{key_name}_{i+1}') rsa_keys.append(rsa_key) # Save keys and tokens as neededpkg/lib/license/license_validator.go (1)
110-140
: Define constants for expected values to enhance maintainabilityHardcoding expected values like the license version
"v1"
and issuer"https://expanso.io/"
can introduce risks of typos and make future updates more cumbersome. Consider defining these values as constants to improve code maintainability and readability.Example:
const ( ExpectedLicenseVersion = "v1" ExpectedIssuer = "https://expanso.io/" ) // Then use: if claims.LicenseVersion == ExpectedLicenseVersion { // ... if claims.Issuer != ExpectedIssuer { return fmt.Errorf("invalid issuer: expected '%s', got '%s'", ExpectedIssuer, claims.Issuer) } } else { return fmt.Errorf("unsupported license version: %s", claims.LicenseVersion) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
pkg/lib/license/README.md
(1 hunks)pkg/lib/license/license_validator.go
(1 hunks)pkg/lib/license/license_validator_test.go
(1 hunks)
🧰 Additional context used
📓 Learnings (1)
pkg/lib/license/license_validator_test.go (1)
Learnt from: jamlo
PR: bacalhau-project/bacalhau#4799
File: pkg/lib/license/license_validator_test.go:34-35
Timestamp: 2025-01-07T05:49:03.470Z
Learning: In the context of testing JWT functionality, it is acceptable and preferred to use hardcoded JWT tokens with test data for better clarity and maintainability, even if static analysis tools flag them as potential security issues.
🪛 Markdownlint (0.37.0)
pkg/lib/license/README.md
1-1: Punctuation: ':'
Trailing punctuation in heading
(MD026, no-trailing-punctuation)
21-21: Punctuation: ':'
Trailing punctuation in heading
(MD026, no-trailing-punctuation)
1-1: null
First line in a file should be a top-level heading
(MD041, first-line-heading, first-line-h1)
🪛 Gitleaks (8.21.2)
pkg/lib/license/license_validator_test.go
111-111: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
112-112: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
113-113: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
117-117: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
118-118: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
120-120: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
121-121: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
122-122: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
123-123: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
124-124: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
219-219: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
225-225: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: testcontainers-suite / tests
🔇 Additional comments (2)
pkg/lib/license/license_validator.go (2)
18-29
: Well-structuredLicenseClaims
with agreed-upon fieldsThe
LicenseClaims
struct is well-defined and incorporates theCapabilities
field as amap[string]string
, aligning with the design decisions discussed in previous reviews. The removal ofFeatures
andLimitations
in favor ofCapabilities
enhances flexibility and adheres to the agreed-upon approach.
96-143
: Comprehensive validation invalidateAdditionalConstraints
The
validateAdditionalConstraints
function provides thorough validation of the license claims, including checks for token expiration, not-before constraints, required fields, and issuer verification. The error messages are clear and informative, aiding in debugging and ensuring that invalid tokens are properly rejected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
pkg/lib/license/license_validator_test.go (4)
112-127
: Consider using constants for common test values.While the JWT tokens are well organized, there are repeated values like "customer_1", "license_1", etc. Consider extracting these as constants for better maintainability.
+const ( + testCustomerID1 = "customer_1" + testLicenseID1 = "license_1" + testIssuer = "https://expanso.io/" + testProduct = "Bacalhau" +)🧰 Tools
🪛 Gitleaks (8.21.2)
113-113: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
114-114: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
115-115: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
119-119: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
120-120: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
122-122: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
123-123: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
124-124: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
125-125: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
126-126: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
250-280
: Add positive test case for file-based validator.The test only covers error cases. Consider adding a positive test case with a temporary file containing valid JWKS data.
func TestNewLicenseValidatorFromFile(t *testing.T) { + // Create a temporary file with valid JWKS + tmpFile, err := os.CreateTemp("", "jwks_*.json") + require.NoError(t, err) + defer os.Remove(tmpFile.Name()) + + _, err = tmpFile.Write(testJWKS) + require.NoError(t, err) + require.NoError(t, tmpFile.Close()) + tests := []struct { name string filename string wantErr bool }{ + { + name: "Valid JWKS file", + filename: tmpFile.Name(), + wantErr: false, + }, {
339-347
: Consider adding more time-based test cases.While the test verifies expired tokens, consider adding cases for:
- Tokens that are not yet valid (before NBF)
- Tokens that are about to expire
- Tokens with invalid time formats
1-424
: Consider adding test coverage for edge cases.While the test coverage is comprehensive, consider adding tests for:
- Very large tokens that might exceed size limits
- Tokens with unsupported algorithms
- Tokens with invalid claim types (e.g., numbers instead of strings)
- Concurrent validation of multiple tokens
🧰 Tools
🪛 Gitleaks (8.21.2)
113-113: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
114-114: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
115-115: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
119-119: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
120-120: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
122-122: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
123-123: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
124-124: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
125-125: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
126-126: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
221-221: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
227-227: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
pkg/lib/license/license_validator_test.go
(1 hunks)
🧰 Additional context used
📓 Learnings (1)
pkg/lib/license/license_validator_test.go (1)
Learnt from: jamlo
PR: bacalhau-project/bacalhau#4799
File: pkg/lib/license/license_validator_test.go:34-35
Timestamp: 2025-01-07T05:49:03.470Z
Learning: In the context of testing JWT functionality, it is acceptable and preferred to use hardcoded JWT tokens with test data for better clarity and maintainability, even if static analysis tools flag them as potential security issues.
🪛 Gitleaks (8.21.2)
pkg/lib/license/license_validator_test.go
113-113: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
114-114: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
115-115: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
119-119: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
120-120: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
122-122: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
123-123: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
124-124: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
125-125: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
126-126: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
221-221: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
227-227: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: testcontainers-suite / tests
🔇 Additional comments (7)
pkg/lib/license/license_validator_test.go (7)
11-12
: LGTM! Good practice adding spell check disable comment.The comment clearly explains why spell checking is disabled for this file.
13-40
: LGTM! Well-structured JWKS test data.The test JWKS is comprehensive and includes multiple RSA keys for different test scenarios.
42-109
: LGTM! Comprehensive test JWKS for invalid scenarios.The test JWKS for invalid tokens covers various error cases with descriptive key IDs.
129-185
: LGTM! Well-structured table-driven tests for JWKS validation.The test cases comprehensively cover various scenarios including:
- Valid JWKS
- Invalid JSON format
- Empty JSON
- Empty and null keys array
187-248
: LGTM! Comprehensive token validation test cases.The test cases cover essential scenarios:
- Valid RSA tokens
- Empty tokens
- Invalid format
- Unknown key ID
- Invalid signatures
🧰 Tools
🪛 Gitleaks (8.21.2)
221-221: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
227-227: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.
(jwt)
282-337
: LGTM! Thorough validation of token claims.The test comprehensively verifies all claim fields including:
- Standard JWT claims (iss, sub, exp, nbf)
- Custom license claims (product, license_id, license_type, etc.)
- Capabilities and metadata
349-424
: LGTM! Comprehensive validation of token constraints.The test thoroughly covers validation of:
- License version
- Product name
- Required fields (license_id, license_type, customer_id)
- Issuer validation
- Subject and JTI requirements
Add License Validation using JWT and JWKS
This PR introduces a robust license validation system using JSON Web Tokens (JWT) and JSON Web Key Sets (JWKS). The implementation provides cryptographic verification of license tokens using public key cryptography, specifically supporting both RSA and ECDSA algorithms.
Overview
The license validation system is built on two modern standards:
License tokens are cryptographically signed JWTs that contain claims about the license, such as:
Example License Data:
The validation system uses JWKS to maintain a set of trusted public keys that can verify these license tokens. Each key in the JWKS has a unique key ID (kid), allowing for key rotation and multiple signing authorities.
Implementation Details
github.com/golang-jwt/jwt/v5
for JWT handlinggithub.com/MicahParks/keyfunc/v3
for JWKS processingExample usage:
Future Extensibility
While the current implementation embeds the JWKS in the binary, the system is designed to be easily extended to fetch JWKS from a well-known URL endpoint. This follows the standard practice used in OAuth2 and OpenID Connect where JWKs are typically available at
/.well-known/jwks.json
.This future enhancement would enable:
Security Considerations
Summary by CodeRabbit
Release Notes
New Features
Dependencies
Documentation
Tests