Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/services/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ type Identity interface {
// GetOIDCAuthRequest returns OIDC auth request if found
GetOIDCAuthRequest(ctx context.Context, stateToken string) (*types.OIDCAuthRequest, error)

// DeleteOIDCAuthRequest deletes OIDC auth request
DeleteOIDCAuthRequest(ctx context.Context, stateToken string) error

// CreateSAMLConnector creates a new SAML connector.
CreateSAMLConnector(ctx context.Context, connector types.SAMLConnector) (types.SAMLConnector, error)
// UpdateSAMLConnector updates an existing SAML connector
Expand Down
8 changes: 8 additions & 0 deletions lib/services/local/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -1715,6 +1715,14 @@ func (s *IdentityService) GetOIDCAuthRequest(ctx context.Context, stateToken str
return req, nil
}

// DeleteOIDCAuthRequest deletes OIDC auth request
func (s *IdentityService) DeleteOIDCAuthRequest(ctx context.Context, stateToken string) error {
if stateToken == "" {
return trace.BadParameter("missing parameter stateToken")
}
return trace.Wrap(s.Delete(ctx, backend.NewKey(webPrefix, connectorsPrefix, oidcPrefix, requestsPrefix, stateToken)))
}

// UpsertSAMLConnector upserts SAML Connector
func (s *IdentityService) UpsertSAMLConnector(ctx context.Context, connector types.SAMLConnector) (types.SAMLConnector, error) {
if err := services.ValidateSAMLConnector(connector, nil); err != nil {
Expand Down
67 changes: 67 additions & 0 deletions lib/services/local/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1785,3 +1785,70 @@ func TestIdentityService_SSOMFASessionDataCRUD(t *testing.T) {
_, err = identity.GetMFASessionData(ctx, sd.RequestID)
require.True(t, trace.IsNotFound(err))
}

func TestIdentityService_OIDCAuthRequestCRUD(t *testing.T) {
t.Parallel()
ctx := context.Background()
clock := clockwork.NewFakeClock()
identity := newIdentityService(t, clock)

req := types.OIDCAuthRequest{
ConnectorID: "google",
StateToken: "test-state-token",
CSRFToken: "test-csrf-token",
}

// Verify create.
err := identity.CreateOIDCAuthRequest(ctx, req, time.Minute)
require.NoError(t, err)

// Verify read.
got, err := identity.GetOIDCAuthRequest(ctx, req.StateToken)
require.NoError(t, err)
require.Equal(t, req.ConnectorID, got.ConnectorID)
require.Equal(t, req.StateToken, got.StateToken)

// Verify delete.
err = identity.DeleteOIDCAuthRequest(ctx, req.StateToken)
require.NoError(t, err)

// Verify get-after-delete returns NotFound.
_, err = identity.GetOIDCAuthRequest(ctx, req.StateToken)
require.True(t, trace.IsNotFound(err))

// Deleting again should also return NotFound.
err = identity.DeleteOIDCAuthRequest(ctx, req.StateToken)
require.True(t, trace.IsNotFound(err))

// Deleting or getting with an empty state token should be a BadParameter.
err = identity.DeleteOIDCAuthRequest(ctx, "")
require.True(t, trace.IsBadParameter(err))
}

func TestIdentityService_OIDCAuthRequestTTLExpiry(t *testing.T) {
t.Parallel()
ctx := context.Background()
clock := clockwork.NewFakeClock()
identity := newIdentityService(t, clock)

req := types.OIDCAuthRequest{
ConnectorID: "google",
StateToken: "expiring-state-token",
CSRFToken: "test-csrf-token",
}

ttl := time.Minute
err := identity.CreateOIDCAuthRequest(ctx, req, ttl)
require.NoError(t, err)

// Still readable before TTL elapses.
_, err = identity.GetOIDCAuthRequest(ctx, req.StateToken)
require.NoError(t, err)

// Advance the clock past the TTL; the request should expire on its own,
// independent of any explicit delete.
clock.Advance(ttl + time.Second)

_, err = identity.GetOIDCAuthRequest(ctx, req.StateToken)
require.True(t, trace.IsNotFound(err))
}
Loading