2022-01-07 23:04:58 +00:00
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
2020-12-02 01:18:32 +00:00
// SPDX-License-Identifier: Apache-2.0
package openidconnect
import (
"context"
"net/url"
"testing"
"time"
"github.com/ory/fosite"
"github.com/ory/fosite/handler/openid"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/fake"
2020-12-10 22:47:58 +00:00
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
2020-12-02 01:18:32 +00:00
coretesting "k8s.io/client-go/testing"
2021-12-10 22:22:36 +00:00
clocktesting "k8s.io/utils/clock/testing"
2021-06-15 16:27:30 +00:00
"go.pinniped.dev/internal/oidc/clientregistry"
2021-10-06 22:28:13 +00:00
"go.pinniped.dev/internal/psession"
"go.pinniped.dev/internal/testutil"
2020-12-02 01:18:32 +00:00
)
const namespace = "test-ns"
2020-12-10 22:47:58 +00:00
var fakeNow = time . Date ( 2030 , time . January , 1 , 0 , 0 , 0 , 0 , time . UTC )
var lifetime = time . Minute * 10
var fakeNowPlusLifetimeAsString = metav1 . Time { Time : fakeNow . Add ( lifetime ) } . Format ( time . RFC3339 )
2020-12-02 01:18:32 +00:00
func TestOpenIdConnectStorage ( t * testing . T ) {
secretsGVR := schema . GroupVersionResource {
Group : "" ,
Version : "v1" ,
Resource : "secrets" ,
}
wantActions := [ ] coretesting . Action {
coretesting . NewCreateAction ( secretsGVR , namespace , & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-oidc-pwu5zs7lekbhnln2w4" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "oidc" ,
2020-12-02 01:18:32 +00:00
} ,
2020-12-10 22:47:58 +00:00
Annotations : map [ string ] string {
"storage.pinniped.dev/garbage-collect-after" : fakeNowPlusLifetimeAsString ,
} ,
2020-12-02 01:18:32 +00:00
} ,
Data : map [ string ] [ ] byte {
2022-12-14 00:18:51 +00:00
"pinniped-storage-data" : [ ] byte ( ` { "request": { "id":"abcd-1","requestedAt":"0001-01-01T00:00:00Z","client": { "id":"pinny","redirect_uris":null,"grant_types":null,"response_types":null,"scopes":null,"audience":null,"public":true,"jwks_uri":"where","jwks":null,"token_endpoint_auth_method":"something","request_uris":null,"request_object_signing_alg":"","token_endpoint_auth_signing_alg":""},"scopes":null,"grantedScopes":null,"form": { "key":["val"]},"session": { "fosite": { "id_token_claims":null,"headers":null,"expires_at":null,"username":"snorlax","subject":"panda"},"custom": { "username":"fake-username","providerUID":"fake-provider-uid","providerName":"fake-provider-name","providerType":"fake-provider-type","warnings":null,"oidc": { "upstreamRefreshToken":"fake-upstream-refresh-token","upstreamAccessToken":"","upstreamSubject":"some-subject","upstreamIssuer":"some-issuer"}}},"requestedAudience":null,"grantedAudience":null},"version":"4"} ` ) ,
2020-12-02 01:18:32 +00:00
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/oidc" ,
} ) ,
coretesting . NewGetAction ( secretsGVR , namespace , "pinniped-storage-oidc-pwu5zs7lekbhnln2w4" ) ,
coretesting . NewDeleteAction ( secretsGVR , namespace , "pinniped-storage-oidc-pwu5zs7lekbhnln2w4" ) ,
}
2020-12-10 22:47:58 +00:00
ctx , client , _ , storage := makeTestSubject ( )
2020-12-02 01:18:32 +00:00
request := & fosite . Request {
ID : "abcd-1" ,
RequestedAt : time . Time { } ,
2021-06-15 16:27:30 +00:00
Client : & clientregistry . Client {
DefaultOpenIDConnectClient : fosite . DefaultOpenIDConnectClient {
DefaultClient : & fosite . DefaultClient {
ID : "pinny" ,
Secret : nil ,
RedirectURIs : nil ,
GrantTypes : nil ,
ResponseTypes : nil ,
Scopes : nil ,
Audience : nil ,
Public : true ,
} ,
JSONWebKeysURI : "where" ,
JSONWebKeys : nil ,
TokenEndpointAuthMethod : "something" ,
RequestURIs : nil ,
RequestObjectSigningAlgorithm : "" ,
TokenEndpointAuthSigningAlgorithm : "" ,
2020-12-02 01:18:32 +00:00
} ,
} ,
2021-10-06 22:28:13 +00:00
RequestedScope : nil ,
GrantedScope : nil ,
Form : url . Values { "key" : [ ] string { "val" } } ,
Session : testutil . NewFakePinnipedSession ( ) ,
2020-12-02 01:18:32 +00:00
RequestedAudience : nil ,
GrantedAudience : nil ,
}
err := storage . CreateOpenIDConnectSession ( ctx , "fancy-code.fancy-signature" , request )
require . NoError ( t , err )
newRequest , err := storage . GetOpenIDConnectSession ( ctx , "fancy-code.fancy-signature" , nil )
require . NoError ( t , err )
require . Equal ( t , request , newRequest )
2022-08-24 21:45:55 +00:00
err = storage . DeleteOpenIDConnectSession ( ctx , "fancy-code.fancy-signature" ) //nolint:staticcheck // we know this is deprecated and never called. our GC controller cleans these up.
2020-12-02 01:18:32 +00:00
require . NoError ( t , err )
2021-10-06 22:28:13 +00:00
testutil . LogActualJSONFromCreateAction ( t , client , 0 ) // makes it easier to update expected values when needed
2020-12-02 01:18:32 +00:00
require . Equal ( t , wantActions , client . Actions ( ) )
}
func TestGetNotFound ( t * testing . T ) {
2020-12-10 22:47:58 +00:00
ctx , _ , _ , storage := makeTestSubject ( )
2020-12-02 01:18:32 +00:00
_ , notFoundErr := storage . GetOpenIDConnectSession ( ctx , "authcode.non-existent-signature" , nil )
require . EqualError ( t , notFoundErr , "not_found" )
require . True ( t , errors . Is ( notFoundErr , fosite . ErrNotFound ) )
}
func TestWrongVersion ( t * testing . T ) {
2020-12-10 22:47:58 +00:00
ctx , _ , secrets , storage := makeTestSubject ( )
2020-12-02 01:18:32 +00:00
secret := & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-oidc-pwu5zs7lekbhnln2w4" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "oidc" ,
2020-12-02 01:18:32 +00:00
} ,
} ,
Data : map [ string ] [ ] byte {
2021-10-06 22:28:13 +00:00
"pinniped-storage-data" : [ ] byte ( ` { "request": { "id":"abcd-1"},"version":"not-the-right-version"} ` ) ,
2020-12-02 01:18:32 +00:00
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/oidc" ,
}
_ , err := secrets . Create ( ctx , secret , metav1 . CreateOptions { } )
require . NoError ( t , err )
_ , err = storage . GetOpenIDConnectSession ( ctx , "fancy-code.fancy-signature" , nil )
2022-12-14 00:18:51 +00:00
require . EqualError ( t , err , "oidc request data has wrong version: oidc session for fancy-signature has version not-the-right-version instead of 4" )
2020-12-02 01:18:32 +00:00
}
func TestNilSessionRequest ( t * testing . T ) {
2020-12-10 22:47:58 +00:00
ctx , _ , secrets , storage := makeTestSubject ( )
2020-12-02 01:18:32 +00:00
secret := & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
Name : "pinniped-storage-oidc-pwu5zs7lekbhnln2w4" ,
ResourceVersion : "" ,
Labels : map [ string ] string {
2020-12-04 22:39:11 +00:00
"storage.pinniped.dev/type" : "oidc" ,
2020-12-02 01:18:32 +00:00
} ,
} ,
Data : map [ string ] [ ] byte {
2022-12-14 00:18:51 +00:00
"pinniped-storage-data" : [ ] byte ( ` { "nonsense-key": "nonsense-value","version":"4"} ` ) ,
2020-12-02 01:18:32 +00:00
"pinniped-storage-version" : [ ] byte ( "1" ) ,
} ,
Type : "storage.pinniped.dev/oidc" ,
}
_ , err := secrets . Create ( ctx , secret , metav1 . CreateOptions { } )
require . NoError ( t , err )
_ , err = storage . GetOpenIDConnectSession ( ctx , "fancy-code.fancy-signature" , nil )
require . EqualError ( t , err , "malformed oidc session for fancy-signature: oidc request data must be present" )
}
func TestCreateWithNilRequester ( t * testing . T ) {
2020-12-10 22:47:58 +00:00
ctx , _ , _ , storage := makeTestSubject ( )
2020-12-02 01:18:32 +00:00
err := storage . CreateOpenIDConnectSession ( ctx , "authcode.signature-doesnt-matter" , nil )
require . EqualError ( t , err , "requester must be of type fosite.Request" )
}
func TestCreateWithWrongRequesterDataTypes ( t * testing . T ) {
2020-12-10 22:47:58 +00:00
ctx , _ , _ , storage := makeTestSubject ( )
2020-12-02 01:18:32 +00:00
request := & fosite . Request {
Session : nil ,
2021-06-15 16:27:30 +00:00
Client : & clientregistry . Client { } ,
2020-12-02 01:18:32 +00:00
}
err := storage . CreateOpenIDConnectSession ( ctx , "authcode.signature-doesnt-matter" , request )
2021-10-06 22:28:13 +00:00
require . EqualError ( t , err , "requester's session must be of type PinnipedSession" )
2020-12-02 01:18:32 +00:00
request = & fosite . Request {
2021-10-06 22:28:13 +00:00
Session : & psession . PinnipedSession { } ,
2020-12-02 01:18:32 +00:00
Client : nil ,
}
err = storage . CreateOpenIDConnectSession ( ctx , "authcode.signature-doesnt-matter" , request )
2021-06-15 16:27:30 +00:00
require . EqualError ( t , err , "requester's client must be of type clientregistry.Client" )
2020-12-02 01:18:32 +00:00
}
func TestAuthcodeHasNoDot ( t * testing . T ) {
2020-12-10 22:47:58 +00:00
ctx , _ , _ , storage := makeTestSubject ( )
2020-12-02 01:18:32 +00:00
err := storage . CreateOpenIDConnectSession ( ctx , "all-one-part" , nil )
require . EqualError ( t , err , "malformed authorization code" )
}
2020-12-10 22:47:58 +00:00
func makeTestSubject ( ) ( context . Context , * fake . Clientset , corev1client . SecretInterface , openid . OpenIDConnectRequestStorage ) {
client := fake . NewSimpleClientset ( )
secrets := client . CoreV1 ( ) . Secrets ( namespace )
2021-12-10 22:22:36 +00:00
return context . Background ( ) , client , secrets , New ( secrets , clocktesting . NewFakeClock ( fakeNow ) . Now , lifetime )
2020-12-10 22:47:58 +00:00
}