Files
aperture/mint/mint_test.go
Boris Nagaev a4431801ef multi: replace LSAT with L402
auth: LsatAuthenticator -> L402Authenticator
sed -i 's/LsatAuthenticator/L402Authenticator/g' aperture.go auth/authenticator.go auth/authenticator_test.go

rename package lsat to l402
git mv lsat/ l402
sed 's@aperture/lsat@aperture/l402@g' -i `git grep -l aperture/lsat`
sed -i 's@package lsat@package l402@' `git grep -l 'package lsat'`
sed -i 's@lsat\.@l402.@g' -i `git grep -l 'lsat\.'`
sed 's@l402.Id@lsat.Id@' -i mint/mint_test.go

replace lsat with l402 in the code
sed 's@lsat@l402@' -i mint/mint_test.go
sed 's@Lsat@L402@' -i l402/client_interceptor.go
sed 's@lsatstore@l402store@' -i l402/store_test.go

replace LSAT to L402 in comments
sed '/\/\//s@LSAT@L402@g' -i `git grep -l '//.*LSAT'`

replace LSAT -> L402 in the code, skip when a string starts with it
sed 's@\([^"/]\)LSAT@\1L402@g' -i `git grep -l LSAT`
2024-04-16 19:33:03 -03:00

298 lines
8.2 KiB
Go

package mint
import (
"context"
"crypto/sha256"
"strings"
"testing"
"time"
"github.com/lightninglabs/aperture/l402"
"github.com/stretchr/testify/require"
"gopkg.in/macaroon.v2"
)
var (
testService = l402.Service{
Name: "lightning_loop",
Tier: l402.BaseTier,
}
)
// TestBasicL402 ensures that an L402 can only access the services it's
// authorized to.
func TestBasicL402(t *testing.T) {
t.Parallel()
ctx := context.Background()
mint := New(&Config{
Secrets: newMockSecretStore(),
Challenger: newMockChallenger(),
ServiceLimiter: newMockServiceLimiter(),
Now: time.Now,
})
// Mint a basic L402 which is only able to access the given service.
macaroon, _, err := mint.MintL402(ctx, testService)
if err != nil {
t.Fatalf("unable to mint L402: %v", err)
}
params := VerificationParams{
Macaroon: macaroon,
Preimage: testPreimage,
TargetService: testService.Name,
}
if err := mint.VerifyL402(ctx, &params); err != nil {
t.Fatalf("unable to verify L402: %v", err)
}
// It should not be able to access an unknown service.
unknownParams := params
unknownParams.TargetService = "unknown"
err = mint.VerifyL402(ctx, &unknownParams)
if !strings.Contains(err.Error(), "not authorized") {
t.Fatal("expected L402 to not be authorized")
}
}
// TestAdminL402 ensures that an admin L402 (one without a services caveat) is
// authorized to access any service.
func TestAdminL402(t *testing.T) {
t.Parallel()
ctx := context.Background()
mint := New(&Config{
Secrets: newMockSecretStore(),
Challenger: newMockChallenger(),
ServiceLimiter: newMockServiceLimiter(),
Now: time.Now,
})
// Mint an admin L402 by not including any services.
macaroon, _, err := mint.MintL402(ctx)
if err != nil {
t.Fatalf("unable to mint L402: %v", err)
}
// It should be able to access any service as it doesn't have a services
// caveat.
params := &VerificationParams{
Macaroon: macaroon,
Preimage: testPreimage,
TargetService: testService.Name,
}
if err := mint.VerifyL402(ctx, params); err != nil {
t.Fatalf("unable to verify L402: %v", err)
}
}
// TestRevokedL402 ensures that we can no longer verify a revoked L402.
func TestRevokedL402(t *testing.T) {
t.Parallel()
ctx := context.Background()
mint := New(&Config{
Secrets: newMockSecretStore(),
Challenger: newMockChallenger(),
ServiceLimiter: newMockServiceLimiter(),
Now: time.Now,
})
// Mint an L402 and verify it.
l402, _, err := mint.MintL402(ctx)
if err != nil {
t.Fatalf("unable to mint L402: %v", err)
}
params := &VerificationParams{
Macaroon: l402,
Preimage: testPreimage,
TargetService: testService.Name,
}
if err := mint.VerifyL402(ctx, params); err != nil {
t.Fatalf("unable to verify L402: %v", err)
}
// Proceed to revoke it. We should no longer be able to verify it after.
idHash := sha256.Sum256(l402.Id())
if err := mint.cfg.Secrets.RevokeSecret(ctx, idHash); err != nil {
t.Fatalf("unable to revoke L402: %v", err)
}
if err := mint.VerifyL402(ctx, params); err != ErrSecretNotFound {
t.Fatalf("expected ErrSecretNotFound, got %v", err)
}
}
// TestTamperedL402 ensures that an L402 that has been tampered with by
// modifying its signature results in its verification failing.
func TestTamperedL402(t *testing.T) {
t.Parallel()
ctx := context.Background()
mint := New(&Config{
Secrets: newMockSecretStore(),
Challenger: newMockChallenger(),
ServiceLimiter: newMockServiceLimiter(),
Now: time.Now,
})
// Mint a new L402 and verify it is valid.
mac, _, err := mint.MintL402(ctx, testService)
if err != nil {
t.Fatalf("unable to mint L402: %v", err)
}
params := VerificationParams{
Macaroon: mac,
Preimage: testPreimage,
TargetService: testService.Name,
}
if err := mint.VerifyL402(ctx, &params); err != nil {
t.Fatalf("unable to verify L402: %v", err)
}
// Create a tampered L402 from the valid one.
macBytes, err := mac.MarshalBinary()
if err != nil {
t.Fatalf("unable to serialize macaroon: %v", err)
}
macBytes[len(macBytes)-1] = 0x00
var tampered macaroon.Macaroon
if err := tampered.UnmarshalBinary(macBytes); err != nil {
t.Fatalf("unable to deserialize macaroon: %v", err)
}
// Attempting to verify the tampered L402 should fail.
tamperedParams := params
tamperedParams.Macaroon = &tampered
err = mint.VerifyL402(ctx, &tamperedParams)
if !strings.Contains(err.Error(), "signature mismatch") {
t.Fatal("expected tampered L402 to be invalid")
}
}
// TestDemotedServicesL402 ensures that an L402 which originally was authorized
// to access a service, but was then demoted to no longer be the case, is no
// longer authorized.
func TestDemotedServicesL402(t *testing.T) {
t.Parallel()
ctx := context.Background()
mint := New(&Config{
Secrets: newMockSecretStore(),
Challenger: newMockChallenger(),
ServiceLimiter: newMockServiceLimiter(),
Now: time.Now,
})
unauthorizedService := testService
unauthorizedService.Name = "unauthorized"
// Mint an L402 that is able to access two services, one of which will
// be denied later on.
mac, _, err := mint.MintL402(ctx, testService, unauthorizedService)
if err != nil {
t.Fatalf("unable to mint L402: %v", err)
}
// It should be able to access both services.
authorizedParams := VerificationParams{
Macaroon: mac,
Preimage: testPreimage,
TargetService: testService.Name,
}
if err := mint.VerifyL402(ctx, &authorizedParams); err != nil {
t.Fatalf("unable to verify L402: %v", err)
}
unauthorizedParams := VerificationParams{
Macaroon: mac,
Preimage: testPreimage,
TargetService: unauthorizedService.Name,
}
if err := mint.VerifyL402(ctx, &unauthorizedParams); err != nil {
t.Fatalf("unable to verify L402: %v", err)
}
// Demote the second service by including an additional services caveat
// that only includes the first service.
services, err := l402.NewServicesCaveat(testService)
if err != nil {
t.Fatalf("unable to create services caveat: %v", err)
}
err = l402.AddFirstPartyCaveats(mac, services)
if err != nil {
t.Fatalf("unable to demote L402: %v", err)
}
// It should now only be able to access the first, but not the second.
if err := mint.VerifyL402(ctx, &authorizedParams); err != nil {
t.Fatalf("unable to verify L402: %v", err)
}
err = mint.VerifyL402(ctx, &unauthorizedParams)
if !strings.Contains(err.Error(), "not authorized") {
t.Fatal("expected macaroon to be invalid")
}
}
// TestExpiredServicesL402 asserts the behavior of the Timeout caveat.
func TestExpiredServicesL402(t *testing.T) {
t.Parallel()
initialTime := int64(1000)
mockTime := newMockTime(initialTime)
ctx := context.Background()
mint := New(&Config{
Secrets: newMockSecretStore(),
Challenger: newMockChallenger(),
ServiceLimiter: newMockServiceLimiter(),
Now: mockTime.now,
})
// Mint a new l402 for accessing a test service.
mac, _, err := mint.MintL402(ctx, testService)
require.NoError(t, err)
authorizedParams := VerificationParams{
Macaroon: mac,
Preimage: testPreimage,
TargetService: testService.Name,
}
// It should be able to access the service if no timeout caveat added.
require.NoError(t, mint.VerifyL402(ctx, &authorizedParams))
// Add a timeout caveat that expires in the future.
timeout := l402.NewTimeoutCaveat(testService.Name, 1000, mockTime.now)
require.NoError(t, l402.AddFirstPartyCaveats(mac, timeout))
// Make sure that the L402 is still valid after timeout is added since
// the timeout has not yet been reached.
require.NoError(t, mint.VerifyL402(ctx, &authorizedParams))
// Force time to pass such that the L402 should no longer be valid.
mockTime.setTime(initialTime + 1001)
// Assert that the L402 is no longer valid due to the timeout being
// reached.
err = mint.VerifyL402(ctx, &authorizedParams)
require.Contains(t, err.Error(), "not authorized")
}
type mockTime struct {
time time.Time
}
func newMockTime(initialTime int64) *mockTime {
return &mockTime{
time: time.Unix(initialTime, 0),
}
}
func (mt *mockTime) now() time.Time {
return mt.time
}
func (mt *mockTime) setTime(timestamp int64) {
mt.time = time.Unix(timestamp, 0)
}