2014-12-17 06:58:39 +00:00
package token
import (
"crypto"
2023-10-08 22:02:45 +00:00
"crypto/ecdsa"
"crypto/elliptic"
2014-12-17 06:58:39 +00:00
"crypto/rand"
"crypto/x509"
2023-10-08 22:02:45 +00:00
"crypto/x509/pkix"
2014-12-17 06:58:39 +00:00
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
2023-10-08 22:02:45 +00:00
"math/big"
"net"
2014-12-17 06:58:39 +00:00
"net/http"
"os"
"testing"
"time"
2020-08-24 11:18:39 +00:00
"github.com/distribution/distribution/v3/registry/auth"
2023-10-08 22:02:45 +00:00
"github.com/go-jose/go-jose/v3"
"github.com/go-jose/go-jose/v3/jwt"
2014-12-17 06:58:39 +00:00
)
2023-10-08 22:02:45 +00:00
func makeRootKeys ( numKeys int ) ( [ ] * ecdsa . PrivateKey , error ) {
rootKeys := make ( [ ] * ecdsa . PrivateKey , 0 , numKeys )
2014-12-17 06:58:39 +00:00
for i := 0 ; i < numKeys ; i ++ {
2023-10-08 22:02:45 +00:00
pk , err := ecdsa . GenerateKey ( elliptic . P256 ( ) , rand . Reader )
2014-12-17 06:58:39 +00:00
if err != nil {
return nil , err
}
2023-10-08 22:02:45 +00:00
rootKeys = append ( rootKeys , pk )
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
return rootKeys , nil
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
func makeRootCerts ( rootKeys [ ] * ecdsa . PrivateKey ) ( [ ] * x509 . Certificate , error ) {
rootCerts := make ( [ ] * x509 . Certificate , 0 , len ( rootKeys ) )
for _ , rootKey := range rootKeys {
cert , err := generateCACert ( rootKey , rootKey )
if err != nil {
return nil , err
}
rootCerts = append ( rootCerts , cert )
}
return rootCerts , nil
}
func makeSigningKeyWithChain ( rootKey * ecdsa . PrivateKey , depth int ) ( * jose . JSONWebKey , error ) {
2014-12-17 06:58:39 +00:00
if depth == 0 {
// Don't need to build a chain.
2023-10-08 22:02:45 +00:00
return & jose . JSONWebKey {
Key : rootKey ,
KeyID : rootKey . X . String ( ) ,
Algorithm : string ( jose . ES256 ) ,
} , nil
2014-12-17 06:58:39 +00:00
}
var (
2023-10-08 22:02:45 +00:00
certs = make ( [ ] * x509 . Certificate , depth )
2014-12-17 06:58:39 +00:00
parentKey = rootKey
2023-10-08 22:02:45 +00:00
pk * ecdsa . PrivateKey
cert * x509 . Certificate
err error
2014-12-17 06:58:39 +00:00
)
for depth > 0 {
2023-10-08 22:02:45 +00:00
if pk , err = ecdsa . GenerateKey ( elliptic . P256 ( ) , rand . Reader ) ; err != nil {
2014-12-17 06:58:39 +00:00
return nil , err
}
2023-10-08 22:02:45 +00:00
if cert , err = generateCACert ( parentKey , pk ) ; err != nil {
2014-12-17 06:58:39 +00:00
return nil , err
}
depth --
2023-10-08 22:02:45 +00:00
certs [ depth ] = cert
parentKey = pk
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
return & jose . JSONWebKey {
Key : parentKey ,
KeyID : rootKey . X . String ( ) ,
Algorithm : string ( jose . ES256 ) ,
Certificates : certs ,
} , nil
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
func makeTestToken ( jwk * jose . JSONWebKey , issuer , audience string , access [ ] * ResourceActions , now time . Time , exp time . Time ) ( * Token , error ) {
signingKey := jose . SigningKey {
Algorithm : jose . ES256 ,
Key : jwk ,
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
signerOpts := jose . SignerOptions {
EmbedJWK : true ,
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
signerOpts . WithType ( "JWT" )
2014-12-17 06:58:39 +00:00
2023-10-08 22:02:45 +00:00
signer , err := jose . NewSigner ( signingKey , & signerOpts )
2014-12-17 06:58:39 +00:00
if err != nil {
2023-10-08 22:02:45 +00:00
return nil , fmt . Errorf ( "unable to create a signer: %s" , err )
2014-12-17 06:58:39 +00:00
}
randomBytes := make ( [ ] byte , 15 )
if _ , err = rand . Read ( randomBytes ) ; err != nil {
return nil , fmt . Errorf ( "unable to read random bytes for jwt id: %s" , err )
}
claimSet := & ClaimSet {
Issuer : issuer ,
Subject : "foo" ,
2022-09-27 13:34:26 +00:00
Audience : [ ] string { audience } ,
2016-04-28 03:54:36 +00:00
Expiration : exp . Unix ( ) ,
2014-12-17 06:58:39 +00:00
NotBefore : now . Unix ( ) ,
IssuedAt : now . Unix ( ) ,
JWTID : base64 . URLEncoding . EncodeToString ( randomBytes ) ,
Access : access ,
}
2023-10-08 22:02:45 +00:00
tokenString , err := jwt . Signed ( signer ) . Claims ( claimSet ) . CompactSerialize ( )
if err != nil {
return nil , fmt . Errorf ( "unable to build token string: %v" , err )
}
return NewToken ( tokenString )
}
// NOTE(milosgajdos): certTemplateInfo type as well
// as some of the functions in this file have been
// adopted from https://github.com/docker/libtrust
// and modiified to fit the purpose of the token package.
type certTemplateInfo struct {
commonName string
domains [ ] string
ipAddresses [ ] net . IP
isCA bool
clientAuth bool
serverAuth bool
}
func generateCertTemplate ( info * certTemplateInfo ) * x509 . Certificate {
// Generate a certificate template which is valid from the past week to
// 10 years from now. The usage of the certificate depends on the
// specified fields in the given certTempInfo object.
var (
keyUsage x509 . KeyUsage
extKeyUsage [ ] x509 . ExtKeyUsage
)
2014-12-17 06:58:39 +00:00
2023-10-08 22:02:45 +00:00
if info . isCA {
keyUsage = x509 . KeyUsageCertSign
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
if info . clientAuth {
extKeyUsage = append ( extKeyUsage , x509 . ExtKeyUsageClientAuth )
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
if info . serverAuth {
extKeyUsage = append ( extKeyUsage , x509 . ExtKeyUsageServerAuth )
}
2014-12-17 06:58:39 +00:00
2023-10-08 22:02:45 +00:00
return & x509 . Certificate {
SerialNumber : big . NewInt ( 0 ) ,
Subject : pkix . Name {
CommonName : info . commonName ,
} ,
NotBefore : time . Now ( ) . Add ( - time . Hour * 24 * 7 ) ,
NotAfter : time . Now ( ) . Add ( time . Hour * 24 * 365 * 10 ) ,
DNSNames : info . domains ,
IPAddresses : info . ipAddresses ,
IsCA : info . isCA ,
KeyUsage : keyUsage ,
ExtKeyUsage : extKeyUsage ,
BasicConstraintsValid : info . isCA ,
2014-12-17 06:58:39 +00:00
}
2023-10-08 22:02:45 +00:00
}
2014-12-17 06:58:39 +00:00
2023-10-08 22:02:45 +00:00
func generateCert ( priv crypto . PrivateKey , pub crypto . PublicKey , subInfo , issInfo * certTemplateInfo ) ( * x509 . Certificate , error ) {
pubCertTemplate := generateCertTemplate ( subInfo )
privCertTemplate := generateCertTemplate ( issInfo )
2014-12-17 06:58:39 +00:00
2023-10-08 22:02:45 +00:00
certDER , err := x509 . CreateCertificate (
rand . Reader , pubCertTemplate , privCertTemplate ,
pub , priv ,
)
if err != nil {
return nil , fmt . Errorf ( "failed to create certificate: %s" , err )
}
cert , err := x509 . ParseCertificate ( certDER )
if err != nil {
return nil , fmt . Errorf ( "failed to parse certificate: %s" , err )
}
return cert , nil
}
// generateCACert creates a certificate which can be used as a trusted
// certificate authority.
func generateCACert ( signer * ecdsa . PrivateKey , trustedKey * ecdsa . PrivateKey ) ( * x509 . Certificate , error ) {
subjectInfo := & certTemplateInfo {
commonName : trustedKey . X . String ( ) ,
isCA : true ,
}
issuerInfo := & certTemplateInfo {
commonName : signer . X . String ( ) ,
}
return generateCert ( signer , trustedKey . Public ( ) , subjectInfo , issuerInfo )
2014-12-17 06:58:39 +00:00
}
// This test makes 4 tokens with a varying number of intermediate
// certificates ranging from no intermediate chain to a length of 3
// intermediates.
func TestTokenVerify ( t * testing . T ) {
var (
numTokens = 4
issuer = "test-issuer"
audience = "test-audience"
access = [ ] * ResourceActions {
{
Type : "repository" ,
Name : "foo/bar" ,
Actions : [ ] string { "pull" , "push" } ,
} ,
}
)
rootKeys , err := makeRootKeys ( numTokens )
if err != nil {
t . Fatal ( err )
}
rootCerts , err := makeRootCerts ( rootKeys )
if err != nil {
t . Fatal ( err )
}
rootPool := x509 . NewCertPool ( )
for _ , rootCert := range rootCerts {
rootPool . AddCert ( rootCert )
}
tokens := make ( [ ] * Token , 0 , numTokens )
2023-10-08 22:02:45 +00:00
trustedKeys := map [ string ] crypto . PublicKey { }
2014-12-17 06:58:39 +00:00
for i := 0 ; i < numTokens ; i ++ {
2023-10-08 22:02:45 +00:00
jwk , err := makeSigningKeyWithChain ( rootKeys [ i ] , i )
if err != nil {
t . Fatal ( err )
}
// add to trusted keys
trustedKeys [ jwk . KeyID ] = jwk . Public ( )
token , err := makeTestToken ( jwk , issuer , audience , access , time . Now ( ) , time . Now ( ) . Add ( 5 * time . Minute ) )
2014-12-17 06:58:39 +00:00
if err != nil {
t . Fatal ( err )
}
tokens = append ( tokens , token )
}
verifyOps := VerifyOptions {
2015-01-06 02:21:03 +00:00
TrustedIssuers : [ ] string { issuer } ,
AcceptedAudiences : [ ] string { audience } ,
2014-12-17 06:58:39 +00:00
Roots : rootPool ,
TrustedKeys : trustedKeys ,
}
for _ , token := range tokens {
2023-10-08 22:02:45 +00:00
if _ , err := token . Verify ( verifyOps ) ; err != nil {
2014-12-17 06:58:39 +00:00
t . Fatal ( err )
}
}
}
2016-04-28 03:54:36 +00:00
// This tests that we don't fail tokens with nbf within
// the defined leeway in seconds
func TestLeeway ( t * testing . T ) {
var (
issuer = "test-issuer"
audience = "test-audience"
access = [ ] * ResourceActions {
{
Type : "repository" ,
Name : "foo/bar" ,
Actions : [ ] string { "pull" , "push" } ,
} ,
}
)
rootKeys , err := makeRootKeys ( 1 )
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
jwk , err := makeSigningKeyWithChain ( rootKeys [ 0 ] , 0 )
if err != nil {
t . Fatal ( err )
}
trustedKeys := map [ string ] crypto . PublicKey {
jwk . KeyID : jwk . Public ( ) ,
}
2016-04-28 03:54:36 +00:00
verifyOps := VerifyOptions {
TrustedIssuers : [ ] string { issuer } ,
AcceptedAudiences : [ ] string { audience } ,
Roots : nil ,
TrustedKeys : trustedKeys ,
}
// nbf verification should pass within leeway
futureNow := time . Now ( ) . Add ( time . Duration ( 5 ) * time . Second )
2023-10-08 22:02:45 +00:00
token , err := makeTestToken ( jwk , issuer , audience , access , futureNow , futureNow . Add ( 5 * time . Minute ) )
2016-04-28 03:54:36 +00:00
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
if _ , err := token . Verify ( verifyOps ) ; err != nil {
2016-04-28 03:54:36 +00:00
t . Fatal ( err )
}
// nbf verification should fail with a skew larger than leeway
futureNow = time . Now ( ) . Add ( time . Duration ( 61 ) * time . Second )
2023-10-08 22:02:45 +00:00
token , err = makeTestToken ( jwk , issuer , audience , access , futureNow , futureNow . Add ( 5 * time . Minute ) )
2016-04-28 03:54:36 +00:00
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
if _ , err = token . Verify ( verifyOps ) ; err == nil {
2016-04-28 03:54:36 +00:00
t . Fatal ( "Verification should fail for token with nbf in the future outside leeway" )
}
// exp verification should pass within leeway
2023-10-08 22:02:45 +00:00
token , err = makeTestToken ( jwk , issuer , audience , access , time . Now ( ) , time . Now ( ) . Add ( - 59 * time . Second ) )
2016-04-28 03:54:36 +00:00
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
if _ , err = token . Verify ( verifyOps ) ; err != nil {
2016-04-28 03:54:36 +00:00
t . Fatal ( err )
}
// exp verification should fail with a skew larger than leeway
2023-10-08 22:02:45 +00:00
token , err = makeTestToken ( jwk , issuer , audience , access , time . Now ( ) , time . Now ( ) . Add ( - 60 * time . Second ) )
2016-04-28 03:54:36 +00:00
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
if _ , err = token . Verify ( verifyOps ) ; err == nil {
2016-04-28 03:54:36 +00:00
t . Fatal ( "Verification should fail for token with exp in the future outside leeway" )
}
}
2023-10-08 22:02:45 +00:00
func writeTempRootCerts ( rootKeys [ ] * ecdsa . PrivateKey ) ( filename string , err error ) {
2014-12-17 06:58:39 +00:00
rootCerts , err := makeRootCerts ( rootKeys )
if err != nil {
return "" , err
}
2022-11-02 21:55:22 +00:00
tempFile , err := os . CreateTemp ( "" , "rootCertBundle" )
2014-12-17 06:58:39 +00:00
if err != nil {
return "" , err
}
defer tempFile . Close ( )
for _ , cert := range rootCerts {
if err = pem . Encode ( tempFile , & pem . Block {
Type : "CERTIFICATE" ,
Bytes : cert . Raw ,
} ) ; err != nil {
os . Remove ( tempFile . Name ( ) )
return "" , err
}
}
return tempFile . Name ( ) , nil
}
2023-10-08 22:02:45 +00:00
func writeTempJWKS ( rootKeys [ ] * ecdsa . PrivateKey ) ( filename string , err error ) {
keys := make ( [ ] jose . JSONWebKey , len ( rootKeys ) )
for i := range rootKeys {
jwk , err := makeSigningKeyWithChain ( rootKeys [ i ] , i )
if err != nil {
return "" , err
}
keys [ i ] = * jwk
}
jwks := jose . JSONWebKeySet {
Keys : keys ,
}
tempFile , err := os . CreateTemp ( "" , "jwksBundle" )
if err != nil {
return "" , err
}
defer tempFile . Close ( )
if err := json . NewEncoder ( tempFile ) . Encode ( jwks ) ; err != nil {
return "" , err
}
return tempFile . Name ( ) , nil
}
2014-12-17 06:58:39 +00:00
// TestAccessController tests complete integration of the token auth package.
// It starts by mocking the options for a token auth accessController which
// it creates. It then tries a few mock requests:
2022-11-02 21:05:45 +00:00
// - don't supply a token; should error with challenge
// - supply an invalid token; should error with challenge
// - supply a token with insufficient access; should error with challenge
// - supply a valid token; should not error
2014-12-17 06:58:39 +00:00
func TestAccessController ( t * testing . T ) {
// Make 2 keys; only the first is to be a trusted root key.
rootKeys , err := makeRootKeys ( 2 )
if err != nil {
t . Fatal ( err )
}
rootCertBundleFilename , err := writeTempRootCerts ( rootKeys [ : 1 ] )
if err != nil {
t . Fatal ( err )
}
defer os . Remove ( rootCertBundleFilename )
2023-10-08 22:02:45 +00:00
jwksFilename , err := writeTempJWKS ( rootKeys )
if err != nil {
t . Fatal ( err )
}
2014-12-17 06:58:39 +00:00
realm := "https://auth.example.com/token/"
issuer := "test-issuer.example.com"
service := "test-service.example.com"
options := map [ string ] interface { } {
"realm" : realm ,
"issuer" : issuer ,
"service" : service ,
2015-02-20 00:46:24 +00:00
"rootcertbundle" : rootCertBundleFilename ,
2018-09-21 01:54:57 +00:00
"autoredirect" : false ,
2023-10-08 22:02:45 +00:00
"jwks" : jwksFilename ,
2014-12-17 06:58:39 +00:00
}
accessController , err := newAccessController ( options )
if err != nil {
t . Fatal ( err )
}
// 1. Make a mock http.Request with no token.
2022-11-02 22:31:23 +00:00
req , err := http . NewRequest ( http . MethodGet , "http://example.com/foo" , nil )
2014-12-17 06:58:39 +00:00
if err != nil {
t . Fatal ( err )
}
testAccess := auth . Access {
Resource : auth . Resource {
Type : "foo" ,
Name : "bar" ,
} ,
Action : "baz" ,
}
2023-10-24 18:08:04 +00:00
authCtx , err := accessController . Authorized ( req , testAccess )
2014-12-17 06:58:39 +00:00
challenge , ok := err . ( auth . Challenge )
if ! ok {
t . Fatal ( "accessController did not return a challenge" )
}
if challenge . Error ( ) != ErrTokenRequired . Error ( ) {
t . Fatalf ( "accessControler did not get expected error - got %s - expected %s" , challenge , ErrTokenRequired )
}
2015-02-04 01:59:24 +00:00
if authCtx != nil {
t . Fatalf ( "expected nil auth context but got %s" , authCtx )
}
2014-12-17 06:58:39 +00:00
// 2. Supply an invalid token.
2023-10-08 22:02:45 +00:00
invalidJwk , err := makeSigningKeyWithChain ( rootKeys [ 1 ] , 1 )
if err != nil {
t . Fatal ( err )
}
2014-12-17 06:58:39 +00:00
token , err := makeTestToken (
2023-10-08 22:02:45 +00:00
invalidJwk , issuer , service ,
2014-12-17 06:58:39 +00:00
[ ] * ResourceActions { {
Type : testAccess . Type ,
Name : testAccess . Name ,
Actions : [ ] string { testAccess . Action } ,
} } ,
2023-10-08 22:02:45 +00:00
time . Now ( ) , time . Now ( ) . Add ( 5 * time . Minute ) , // Everything is valid except the key which signed it.
2014-12-17 06:58:39 +00:00
)
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
req . Header . Set ( "Authorization" , fmt . Sprintf ( "Bearer %s" , token . Raw ) )
2014-12-17 06:58:39 +00:00
2023-10-24 18:08:04 +00:00
authCtx , err = accessController . Authorized ( req , testAccess )
2014-12-17 06:58:39 +00:00
challenge , ok = err . ( auth . Challenge )
if ! ok {
t . Fatal ( "accessController did not return a challenge" )
}
if challenge . Error ( ) != ErrInvalidToken . Error ( ) {
t . Fatalf ( "accessControler did not get expected error - got %s - expected %s" , challenge , ErrTokenRequired )
}
2015-02-04 01:59:24 +00:00
if authCtx != nil {
t . Fatalf ( "expected nil auth context but got %s" , authCtx )
}
2023-10-08 22:02:45 +00:00
// create a valid jwk
jwk , err := makeSigningKeyWithChain ( rootKeys [ 0 ] , 1 )
if err != nil {
t . Fatal ( err )
}
2014-12-17 06:58:39 +00:00
// 3. Supply a token with insufficient access.
token , err = makeTestToken (
2023-10-08 22:02:45 +00:00
jwk , issuer , service ,
2014-12-17 06:58:39 +00:00
[ ] * ResourceActions { } , // No access specified.
2023-10-08 22:02:45 +00:00
time . Now ( ) , time . Now ( ) . Add ( 5 * time . Minute ) ,
2014-12-17 06:58:39 +00:00
)
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
req . Header . Set ( "Authorization" , fmt . Sprintf ( "Bearer %s" , token . Raw ) )
2014-12-17 06:58:39 +00:00
2023-10-24 18:08:04 +00:00
authCtx , err = accessController . Authorized ( req , testAccess )
2014-12-17 06:58:39 +00:00
challenge , ok = err . ( auth . Challenge )
if ! ok {
t . Fatal ( "accessController did not return a challenge" )
}
if challenge . Error ( ) != ErrInsufficientScope . Error ( ) {
t . Fatalf ( "accessControler did not get expected error - got %s - expected %s" , challenge , ErrInsufficientScope )
}
2015-02-04 01:59:24 +00:00
if authCtx != nil {
t . Fatalf ( "expected nil auth context but got %s" , authCtx )
}
2014-12-17 06:58:39 +00:00
// 4. Supply the token we need, or deserve, or whatever.
token , err = makeTestToken (
2023-10-08 22:02:45 +00:00
jwk , issuer , service ,
2014-12-17 06:58:39 +00:00
[ ] * ResourceActions { {
Type : testAccess . Type ,
Name : testAccess . Name ,
Actions : [ ] string { testAccess . Action } ,
} } ,
2023-10-08 22:02:45 +00:00
time . Now ( ) , time . Now ( ) . Add ( 5 * time . Minute ) ,
2014-12-17 06:58:39 +00:00
)
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
req . Header . Set ( "Authorization" , fmt . Sprintf ( "Bearer %s" , token . Raw ) )
2014-12-17 06:58:39 +00:00
2023-10-24 18:08:04 +00:00
authCtx , err = accessController . Authorized ( req , testAccess )
2015-02-04 01:59:24 +00:00
if err != nil {
2014-12-17 06:58:39 +00:00
t . Fatalf ( "accessController returned unexpected error: %s" , err )
}
2015-02-04 01:59:24 +00:00
2016-01-29 01:02:09 +00:00
userInfo , ok := authCtx . Value ( auth . UserKey ) . ( auth . UserInfo )
2015-02-04 01:59:24 +00:00
if ! ok {
t . Fatal ( "token accessController did not set auth.user context" )
}
if userInfo . Name != "foo" {
t . Fatalf ( "expected user name %q, got %q" , "foo" , userInfo . Name )
}
2017-01-07 00:08:32 +00:00
// 5. Supply a token with full admin rights, which is represented as "*".
token , err = makeTestToken (
2023-10-08 22:02:45 +00:00
jwk , issuer , service ,
2017-01-07 00:08:32 +00:00
[ ] * ResourceActions { {
Type : testAccess . Type ,
Name : testAccess . Name ,
Actions : [ ] string { "*" } ,
} } ,
2023-10-08 22:02:45 +00:00
time . Now ( ) , time . Now ( ) . Add ( 5 * time . Minute ) ,
2017-01-07 00:08:32 +00:00
)
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
req . Header . Set ( "Authorization" , fmt . Sprintf ( "Bearer %s" , token . Raw ) )
2017-01-07 00:08:32 +00:00
2023-10-24 18:08:04 +00:00
_ , err = accessController . Authorized ( req , testAccess )
2017-01-07 00:08:32 +00:00
if err != nil {
t . Fatalf ( "accessController returned unexpected error: %s" , err )
}
2014-12-17 06:58:39 +00:00
}
2016-08-31 17:00:12 +00:00
// This tests that newAccessController can handle PEM blocks in the certificate
// file other than certificates, for example a private key.
func TestNewAccessControllerPemBlock ( t * testing . T ) {
rootKeys , err := makeRootKeys ( 2 )
if err != nil {
t . Fatal ( err )
}
rootCertBundleFilename , err := writeTempRootCerts ( rootKeys )
if err != nil {
t . Fatal ( err )
}
defer os . Remove ( rootCertBundleFilename )
// Add something other than a certificate to the rootcertbundle
2022-11-02 21:05:45 +00:00
file , err := os . OpenFile ( rootCertBundleFilename , os . O_WRONLY | os . O_APPEND , 0 o666 )
2016-08-31 17:00:12 +00:00
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
bytes , err := x509 . MarshalECPrivateKey ( rootKeys [ 0 ] )
2016-08-31 17:00:12 +00:00
if err != nil {
t . Fatal ( err )
}
2023-10-08 22:02:45 +00:00
_ , err = file . Write ( bytes )
2016-08-31 17:00:12 +00:00
if err != nil {
t . Fatal ( err )
}
err = file . Close ( )
if err != nil {
t . Fatal ( err )
}
realm := "https://auth.example.com/token/"
issuer := "test-issuer.example.com"
service := "test-service.example.com"
options := map [ string ] interface { } {
"realm" : realm ,
"issuer" : issuer ,
"service" : service ,
"rootcertbundle" : rootCertBundleFilename ,
2018-09-21 01:54:57 +00:00
"autoredirect" : false ,
2016-08-31 17:00:12 +00:00
}
ac , err := newAccessController ( options )
if err != nil {
t . Fatal ( err )
}
2023-05-09 11:19:48 +00:00
if len ( ac . ( * accessController ) . rootCerts . Subjects ( ) ) != 2 { //nolint:staticcheck // FIXME(thaJeztah): ignore SA1019: ac.(*accessController).rootCerts.Subjects has been deprecated since Go 1.18: if s was returned by SystemCertPool, Subjects will not include the system roots. (staticcheck)
2016-08-31 17:00:12 +00:00
t . Fatal ( "accessController has the wrong number of certificates" )
}
}