2021-04-13 16:42:25 -07:00
// Copyright (c) HashiCorp, Inc.
2021-04-08 20:54:32 -04:00
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2021-04-08 20:54:32 -04:00
package authmethods_test
import (
"context"
"crypto/x509"
"fmt"
"net/http"
"net/http/httptest"
2021-04-29 14:47:13 -07:00
"net/url"
2021-04-08 20:54:32 -04:00
"regexp"
2021-04-13 16:42:25 -07:00
"sort"
2021-04-08 20:54:32 -04:00
"testing"
"time"
"github.com/google/go-cmp/cmp"
2023-10-31 13:44:17 +00:00
"github.com/google/go-cmp/cmp/cmpopts"
2022-10-28 15:52:06 -04:00
"github.com/hashicorp/boundary/globals"
2021-10-19 17:21:41 -04:00
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
2023-12-21 14:58:21 -05:00
am "github.com/hashicorp/boundary/internal/auth"
2023-03-15 11:40:40 -04:00
"github.com/hashicorp/boundary/internal/auth/ldap"
2021-04-08 20:54:32 -04:00
"github.com/hashicorp/boundary/internal/auth/oidc"
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/authtoken"
2022-05-09 12:45:10 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/auth"
"github.com/hashicorp/boundary/internal/daemon/controller/common"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/authmethods"
2021-04-08 20:54:32 -04:00
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
2021-05-04 19:57:35 -05:00
"github.com/hashicorp/boundary/internal/requests"
2022-06-20 18:20:17 -07:00
"github.com/hashicorp/boundary/internal/server"
2021-04-08 20:54:32 -04:00
"github.com/hashicorp/boundary/internal/types/scope"
2021-08-26 10:44:41 -04:00
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authmethods"
scopepb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
2021-04-08 20:54:32 -04:00
capoidc "github.com/hashicorp/cap/oidc"
2022-03-16 17:04:07 -04:00
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
2021-04-08 20:54:32 -04:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/genproto/protobuf/field_mask"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
type setup struct {
ctx context . Context
2021-09-30 09:17:27 -04:00
conn * db . DB
2021-04-08 20:54:32 -04:00
rw * db . Db
rootWrapper wrapping . Wrapper
kmsCache * kms . Kms
iamRepo * iam . Repository
iamRepoFn common . IamRepoFactory
oidcRepoFn common . OidcAuthRepoFactory
2023-03-15 11:40:40 -04:00
ldapRepoFn common . LdapAuthRepoFactory
2021-04-08 20:54:32 -04:00
pwRepoFn common . PasswordAuthRepoFactory
atRepoFn common . AuthTokenRepoFactory
2023-12-21 14:58:21 -05:00
authMethodRepoFn common . AuthMethodRepoFactory
maxPageSize int
2021-04-08 20:54:32 -04:00
org * iam . Scope
proj * iam . Scope
databaseWrapper wrapping . Wrapper
authMethodService authmethods . Service
testProvider * capoidc . TestProvider
testProviderAlg capoidc . Alg
testProviderCaCert [] * x509 . Certificate
testController * httptest . Server
authMethod * oidc . AuthMethod
testProviderAllowedRedirect string
}
func getSetup ( t * testing . T ) setup {
t . Helper ()
2021-07-29 18:52:56 -06:00
ctx := context . TODO ()
2021-04-08 20:54:32 -04:00
require := require . New ( t )
var ret setup
var err error
ret . ctx = context . Background ()
ret . conn , _ = db . TestSetup ( t , "postgres" )
ret . rw = db . New ( ret . conn )
ret . rootWrapper = db . TestWrapper ( t )
ret . kmsCache = kms . TestKms ( t , ret . conn , ret . rootWrapper )
ret . iamRepo = iam . TestRepo ( t , ret . conn , ret . rootWrapper )
ret . iamRepoFn = func () ( * iam . Repository , error ) {
return ret . iamRepo , nil
}
ret . oidcRepoFn = func () ( * oidc . Repository , error ) {
2021-07-29 18:52:56 -06:00
return oidc . NewRepository ( ctx , ret . rw , ret . rw , ret . kmsCache )
2021-04-08 20:54:32 -04:00
}
2023-03-15 11:40:40 -04:00
ret . ldapRepoFn = func () ( * ldap . Repository , error ) {
return ldap . NewRepository ( ctx , ret . rw , ret . rw , ret . kmsCache )
}
2021-04-08 20:54:32 -04:00
ret . pwRepoFn = func () ( * password . Repository , error ) {
2023-06-06 17:09:08 -04:00
return password . NewRepository ( ctx , ret . rw , ret . rw , ret . kmsCache )
2021-04-08 20:54:32 -04:00
}
ret . atRepoFn = func () ( * authtoken . Repository , error ) {
2023-06-06 17:09:08 -04:00
return authtoken . NewRepository ( ctx , ret . rw , ret . rw , ret . kmsCache )
2021-04-08 20:54:32 -04:00
}
2023-12-21 14:58:21 -05:00
ret . authMethodRepoFn = func () ( * am . AuthMethodRepository , error ) {
return am . NewAuthMethodRepository ( ctx , ret . rw , ret . rw , ret . kmsCache )
}
ret . maxPageSize = 1000
2021-04-08 20:54:32 -04:00
ret . org , ret . proj = iam . TestScopes ( t , ret . iamRepo )
ret . databaseWrapper , err = ret . kmsCache . GetWrapper ( ret . ctx , ret . org . PublicId , kms . KeyPurposeDatabase )
require . NoError ( err )
2023-12-21 14:58:21 -05:00
ret . authMethodService , err = authmethods . NewService (
ret . ctx ,
ret . kmsCache ,
ret . pwRepoFn ,
ret . oidcRepoFn ,
ret . iamRepoFn ,
ret . atRepoFn ,
ret . ldapRepoFn ,
ret . authMethodRepoFn ,
uint ( ret . maxPageSize ),
)
2021-04-08 20:54:32 -04:00
require . NoError ( err )
ret . testProvider = capoidc . StartTestProvider ( t )
_ , _ , ret . testProviderAlg , _ = ret . testProvider . SigningKeys ()
2021-07-29 18:52:56 -06:00
ret . testProviderCaCert , err = oidc . ParseCertificates ( ctx , ret . testProvider . CACert ())
2021-04-08 20:54:32 -04:00
require . NoError ( err )
ret . testController = httptest . NewTLSServer ( http . HandlerFunc ( func ( w http . ResponseWriter , req * http . Request ) {
w . WriteHeader ( 200 )
}))
t . Cleanup ( ret . testController . Close )
ret . authMethod = oidc . TestAuthMethod (
t , ret . conn , ret . databaseWrapper , ret . org . PublicId , oidc . ActivePublicState ,
"test-rp" , "fido" ,
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , ret . testProvider . Addr ())[ 0 ]),
oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , ret . testController . URL )[ 0 ]),
oidc . WithSigningAlgs ( oidc . Alg ( ret . testProviderAlg )),
oidc . WithCertificates ( ret . testProviderCaCert ... ),
2023-11-21 11:30:02 -05:00
oidc . WithPrompts ( oidc . Consent ),
2021-04-08 20:54:32 -04:00
)
2021-05-02 15:25:29 -04:00
ret . testProviderAllowedRedirect = fmt . Sprintf ( oidc . CallbackEndpoint , ret . testController . URL )
2021-04-08 20:54:32 -04:00
ret . testProvider . SetAllowedRedirectURIs ([] string { ret . testProviderAllowedRedirect })
r , err := ret . oidcRepoFn ()
require . NoError ( err )
// update the test's auth method, now that we've added a new callback
ret . authMethod , err = r . LookupAuthMethod ( ret . ctx , ret . authMethod . PublicId )
require . NoError ( err )
require . NotNil ( ret . authMethod )
return ret
}
2021-04-13 16:42:25 -07:00
func TestList_FilterNonPublic ( t * testing . T ) {
2021-07-29 18:52:56 -06:00
ctx := context . TODO ()
2021-04-13 16:42:25 -07:00
conn , _ := db . TestSetup ( t , "postgres" )
rw := db . New ( conn )
wrapper := db . TestWrapper ( t )
kmsCache := kms . TestKms ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iam . TestRepo ( t , conn , wrapper ), nil
}
oidcRepoFn := func () ( * oidc . Repository , error ) {
2021-07-29 18:52:56 -06:00
return oidc . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-13 16:42:25 -07:00
}
2023-03-15 11:40:40 -04:00
ldapRepoFn := func () ( * ldap . Repository , error ) {
return ldap . NewRepository ( ctx , rw , rw , kmsCache )
}
2021-04-13 16:42:25 -07:00
pwRepoFn := func () ( * password . Repository , error ) {
2023-06-06 17:09:08 -04:00
return password . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-13 16:42:25 -07:00
}
atRepoFn := func () ( * authtoken . Repository , error ) {
2023-06-06 17:09:08 -04:00
return authtoken . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-13 16:42:25 -07:00
}
2022-06-20 18:20:17 -07:00
serversRepoFn := func () ( * server . Repository , error ) {
2023-06-06 17:09:08 -04:00
return server . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-13 16:42:25 -07:00
}
2023-12-21 14:58:21 -05:00
authMethodRepoFn := func () ( * am . AuthMethodRepository , error ) {
return am . NewAuthMethodRepository ( ctx , rw , rw , kmsCache )
}
2021-05-04 19:57:35 -05:00
2021-04-13 16:42:25 -07:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
o , _ := iam . TestScopes ( t , iamRepo )
2023-06-06 17:09:08 -04:00
databaseWrapper , err := kmsCache . GetWrapper ( ctx , o . GetPublicId (), kms . KeyPurposeDatabase )
2021-04-13 16:42:25 -07:00
require . NoError ( t , err )
// 1 Public
i := 0
oidcam := oidc . TestAuthMethod ( t , conn , databaseWrapper , o . GetPublicId (), oidc . ActivePublicState , "alice_rp" , "secret" , oidc . WithDescription ( fmt . Sprintf ( "%d" , i )),
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , fmt . Sprintf ( "https://alice%d.com" , i ))[ 0 ]), oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://api.com" )[ 0 ]), oidc . WithSigningAlgs ( oidc . EdDSA ))
i ++
iam . TestSetPrimaryAuthMethod ( t , iamRepo , o , oidcam . GetPublicId ())
// 4 private
for ; i < 4 ; i ++ {
_ = oidc . TestAuthMethod ( t , conn , databaseWrapper , o . GetPublicId (), oidc . ActivePrivateState , "alice_rp" , "secret" , oidc . WithDescription ( fmt . Sprintf ( "%d" , i )),
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , fmt . Sprintf ( "https://alice%d.com" , i ))[ 0 ]), oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://api.com" )[ 0 ]), oidc . WithSigningAlgs ( oidc . EdDSA ))
}
// 5 inactive
for ; i < 10 ; i ++ {
_ = oidc . TestAuthMethod ( t , conn , databaseWrapper , o . GetPublicId (), oidc . InactiveState , "alice_rp" , "secret" , oidc . WithDescription ( fmt . Sprintf ( "%d" , i )),
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , fmt . Sprintf ( "https://alice%d.com" , i ))[ 0 ]), oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://api.com" )[ 0 ]))
}
2023-12-21 14:58:21 -05:00
s , err := authmethods . NewService ( ctx , kmsCache , pwRepoFn , oidcRepoFn , iamRepoFn , atRepoFn , ldapRepoFn , authMethodRepoFn , 1000 )
2021-04-13 16:42:25 -07:00
require . NoError ( t , err , "Couldn't create new auth_method service." )
req := & pbs . ListAuthMethodsRequest {
ScopeId : o . GetPublicId (),
Filter : `"/item/type"=="oidc"` , // We are concerned about OIDC auth methods being filtered by authn state
}
cases := [] struct {
name string
reqCtx context . Context
respCount int
}{
{
name : "unauthenticated" ,
2022-10-28 15:52:06 -04:00
reqCtx : auth . DisabledAuthTestContext ( iamRepoFn , o . GetPublicId (), auth . WithUserId ( globals . AnonymousUserId )),
2021-04-13 16:42:25 -07:00
respCount : 1 ,
},
{
name : "authenticated" ,
reqCtx : func () context . Context {
at := authtoken . TestAuthToken ( t , conn , kmsCache , o . GetPublicId ())
2021-05-04 19:57:35 -05:00
return auth . NewVerifierContext ( requests . NewRequestContext ( context . Background ()),
2021-04-13 16:42:25 -07:00
iamRepoFn ,
2021-06-22 22:26:26 -04:00
atRepoFn ,
2021-04-13 16:42:25 -07:00
serversRepoFn ,
kmsCache ,
2021-10-19 17:21:41 -04:00
& authpb . RequestInfo {
2021-04-13 16:42:25 -07:00
Token : at . GetToken (),
2021-10-19 17:21:41 -04:00
TokenFormat : uint32 ( auth . AuthTokenTypeBearer ),
2021-04-13 16:42:25 -07:00
PublicId : at . GetPublicId (),
})
}(),
respCount : 10 ,
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
got , err := s . ListAuthMethods ( tc . reqCtx , req )
assert . NoError ( t , err )
require . NotNil ( t , got )
require . Len ( t , got . GetItems (), tc . respCount )
gotSorted := got . GetItems ()
sort . Slice ( gotSorted , func ( i , j int ) bool {
return gotSorted [ i ]. GetDescription (). GetValue () < gotSorted [ j ]. GetDescription (). GetValue ()
})
for i := 0 ; i < tc . respCount ; i ++ {
assert . Equal ( t , fmt . Sprintf ( "%d" , i ), gotSorted [ i ]. GetDescription (). GetValue (), "Auth method with description '%d' missing" , i )
}
})
}
}
2021-04-08 20:54:32 -04:00
func TestUpdate_OIDC ( t * testing . T ) {
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2021-04-08 20:54:32 -04:00
conn , _ := db . TestSetup ( t , "postgres" )
rw := db . New ( conn )
wrapper := db . TestWrapper ( t )
kms := kms . TestKms ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iam . TestRepo ( t , conn , wrapper ), nil
}
oidcRepoFn := func () ( * oidc . Repository , error ) {
2021-07-29 18:52:56 -06:00
return oidc . NewRepository ( ctx , rw , rw , kms )
2021-04-08 20:54:32 -04:00
}
2023-03-15 11:40:40 -04:00
ldapRepoFn := func () ( * ldap . Repository , error ) {
return ldap . NewRepository ( ctx , rw , rw , kms )
}
2021-04-08 20:54:32 -04:00
pwRepoFn := func () ( * password . Repository , error ) {
2023-06-06 17:09:08 -04:00
return password . NewRepository ( ctx , rw , rw , kms )
2021-04-08 20:54:32 -04:00
}
atRepoFn := func () ( * authtoken . Repository , error ) {
2023-06-06 17:09:08 -04:00
return authtoken . NewRepository ( ctx , rw , rw , kms )
2021-04-08 20:54:32 -04:00
}
2023-12-21 14:58:21 -05:00
authMethodRepoFn := func () ( * am . AuthMethodRepository , error ) {
return am . NewAuthMethodRepository ( ctx , rw , rw , kms )
}
2021-04-08 20:54:32 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
o , _ := iam . TestScopes ( t , iamRepo )
2023-12-21 14:58:21 -05:00
tested , err := authmethods . NewService ( ctx , kms , pwRepoFn , oidcRepoFn , iamRepoFn , atRepoFn , ldapRepoFn , authMethodRepoFn , 1000 )
2021-04-08 20:54:32 -04:00
require . NoError ( t , err , "Error when getting new auth_method service." )
defaultScopeInfo := & scopepb . ScopeInfo { Id : o . GetPublicId (), Type : o . GetType (), ParentScopeId : scope . Global . String ()}
tp := capoidc . StartTestProvider ( t )
tpClientId := "alice-rp"
tpClientSecret := "her-dog's-name"
tp . SetClientCreds ( tpClientId , tpClientSecret )
_ , _ , tpAlg , _ := tp . SigningKeys ()
2023-11-21 11:30:02 -05:00
tpPrompt := capoidc . None
2021-04-08 20:54:32 -04:00
2022-04-08 11:40:59 -04:00
defaultAttributes := & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
Issuer : wrapperspb . String ( tp . Addr ()),
ClientId : wrapperspb . String ( "someclientid" ),
ClientSecret : wrapperspb . String ( "secret" ),
ApiUrlPrefix : wrapperspb . String ( "https://example.com" ),
IdpCaCerts : [] string { tp . CACert ()},
SigningAlgorithms : [] string { string ( tpAlg )},
2023-11-21 11:30:02 -05:00
Prompts : [] string { string ( tpPrompt )},
2022-04-08 11:40:59 -04:00
},
2021-04-08 20:54:32 -04:00
}
2022-04-08 11:40:59 -04:00
defaultReadAttributes := & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
Issuer : wrapperspb . String ( tp . Addr ()),
ClientId : wrapperspb . String ( "someclientid" ),
ClientSecretHmac : "<hmac>" ,
State : string ( oidc . ActivePrivateState ),
ApiUrlPrefix : wrapperspb . String ( "https://example.com" ),
CallbackUrl : "https://example.com/v1/auth-methods/oidc:authenticate:callback" ,
IdpCaCerts : [] string { tp . CACert ()},
SigningAlgorithms : [] string { string ( tpAlg )},
2023-11-21 11:30:02 -05:00
Prompts : [] string { string ( tpPrompt )},
2022-04-08 11:40:59 -04:00
},
2021-04-08 20:54:32 -04:00
}
freshAuthMethod := func ( t * testing . T ) ( * pb . AuthMethod , func ()) {
ctx := auth . DisabledAuthTestContext ( iamRepoFn , o . GetPublicId ())
am , err := tested . CreateAuthMethod ( ctx , & pbs . CreateAuthMethodRequest { Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : wrapperspb . String ( "default" ),
Description : wrapperspb . String ( "default" ),
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : defaultAttributes ,
2021-04-08 20:54:32 -04:00
}})
require . NoError ( t , err )
csr , err := tested . ChangeState ( ctx , & pbs . ChangeStateRequest {
Id : am . GetItem (). GetId (),
Version : am . GetItem (). GetVersion (),
2022-04-08 11:40:59 -04:00
Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "active-private" ,
},
2021-04-08 20:54:32 -04:00
},
})
require . NoError ( t , err )
clean := func () {
_ , err := tested . DeleteAuthMethod ( auth . DisabledAuthTestContext ( iamRepoFn , o . GetPublicId ()),
& pbs . DeleteAuthMethodRequest { Id : am . GetItem (). GetId ()})
require . NoError ( t , err )
}
return csr . GetItem (), clean
}
cases := [] struct {
name string
req * pbs . UpdateAuthMethodRequest
res * pbs . UpdateAuthMethodResponse
err error
wantErr bool
}{
{
name : "Update an Existing AuthMethod" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" , "description" },
},
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2021-04-08 20:54:32 -04:00
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : defaultReadAttributes ,
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Multiple Paths in single string" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name,description,type" },
},
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2021-04-08 20:54:32 -04:00
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : defaultReadAttributes ,
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Update Issuer" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.issuer" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . Issuer = wrapperspb . String ( "http://localhost:72759/somepath/.well-known/openid-configuration" )
f . DisableDiscoveredConfigValidation = true
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-08 20:54:32 -04:00
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . Issuer = wrapperspb . String ( "http://localhost:72759/somepath/" )
f . DisableDiscoveredConfigValidation = true
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
2021-06-05 13:17:46 -04:00
{
name : "invalid-issuer-port" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.issuer" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . Issuer = wrapperspb . String ( "http://localhost:7dddd" )
f . DisableDiscoveredConfigValidation = true
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-06-05 13:17:46 -04:00
},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
2021-04-08 20:54:32 -04:00
{
name : "No Update Mask" ,
req : & pbs . UpdateAuthMethodRequest {
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "updated name" },
Description : & wrapperspb . StringValue { Value : "updated desc" },
},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "No Paths in Mask" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask { Paths : [] string {}},
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "updated name" },
Description : & wrapperspb . StringValue { Value : "updated desc" },
},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
2024-02-16 08:30:16 -05:00
name : "Only non-existent paths in Mask" ,
2021-04-08 20:54:32 -04:00
req : & pbs . UpdateAuthMethodRequest {
2024-02-16 08:30:16 -05:00
UpdateMask : & field_mask . FieldMask { Paths : [] string { "nonexistent_field" }},
2021-04-08 20:54:32 -04:00
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "updated name" },
Description : & wrapperspb . StringValue { Value : "updated desc" },
},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Cant change type" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask { Paths : [] string { "name" , "type" }},
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "updated name" },
2023-11-02 16:03:47 -04:00
Type : password . Subtype . String (),
2021-04-08 20:54:32 -04:00
},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Cant change is primary" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask { Paths : [] string { "is_primary" }},
Item : & pb . AuthMethod {
IsPrimary : true ,
},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Unset Name" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" },
},
Item : & pb . AuthMethod {
Description : & wrapperspb . StringValue { Value : "ignored" },
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
ScopeId : o . GetPublicId (),
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : defaultReadAttributes ,
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Unset Description" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "description" },
},
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "ignored" },
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : defaultReadAttributes ,
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Update Only Name" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "name" },
},
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "updated" },
Description : & wrapperspb . StringValue { Value : "ignored" },
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "updated" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : defaultReadAttributes ,
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Update Only Description" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "description" },
},
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "ignored" },
Description : & wrapperspb . StringValue { Value : "notignored" },
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "notignored" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : defaultReadAttributes ,
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Update a Non Existing AuthMethod" ,
req : & pbs . UpdateAuthMethodRequest {
2023-03-10 15:06:39 -05:00
Id : globals . PasswordAuthMethodPrefix + "_DoesntExis" ,
2021-04-08 20:54:32 -04:00
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "description" },
},
Item : & pb . AuthMethod {
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "desc" },
},
},
err : handlers . ApiErrorWithCode ( codes . NotFound ),
},
{
name : "Cant change Id" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "id" },
},
Item : & pb . AuthMethod {
2023-03-10 15:06:39 -05:00
Id : globals . PasswordAuthMethodPrefix + "_somethinge" ,
2021-04-08 20:54:32 -04:00
Name : & wrapperspb . StringValue { Value : "new" },
Description : & wrapperspb . StringValue { Value : "new desc" },
},
},
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Cant specify Created Time" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "created_time" },
},
Item : & pb . AuthMethod {
CreatedTime : timestamppb . Now (),
},
},
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Cant specify Updated Time" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "updated_time" },
},
Item : & pb . AuthMethod {
UpdatedTime : timestamppb . Now (),
},
},
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Cant specify Type" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "type" },
},
Item : & pb . AuthMethod {
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2021-04-08 20:54:32 -04:00
},
},
res : nil ,
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Unset Client Id" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.client_id" },
},
Item : & pb . AuthMethod {},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Unset Client Secret" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.client_secret" },
},
Item : & pb . AuthMethod {},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Unset Signing Algorithms" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.signing_algorithms" },
},
Item : & pb . AuthMethod {},
},
wantErr : true ,
},
{
name : "Set Max Age to zero" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.max_age" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
MaxAge : wrapperspb . UInt32 ( 0 ),
2021-04-08 20:54:32 -04:00
},
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . MaxAge = wrapperspb . UInt32 ( 0 )
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Change Max Age" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.max_age" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
MaxAge : wrapperspb . UInt32 ( 4 ),
2021-04-08 20:54:32 -04:00
},
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . MaxAge = wrapperspb . UInt32 ( 4 )
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Change Client Id" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.client_id" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
ClientId : wrapperspb . String ( "new id" ),
2021-04-08 20:54:32 -04:00
},
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . ClientId = wrapperspb . String ( "new id" )
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Unset Api Url Prefix" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.api_url_prefix" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
ApiUrlPrefix : nil , // Not strictly necessary to populate this, since it is the zero value, but be explicit
},
},
2021-04-08 20:54:32 -04:00
},
},
wantErr : true ,
},
{
name : "Change Api Url Prefix" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.api_url_prefix" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
ApiUrlPrefix : wrapperspb . String ( "https://callback.prefix:9281/path" ),
},
2021-04-08 20:54:32 -04:00
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . ApiUrlPrefix = wrapperspb . String ( "https://callback.prefix:9281/path" )
f . CallbackUrl = "https://callback.prefix:9281/path/v1/auth-methods/oidc:authenticate:callback"
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Change Allowed Audiences" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.allowed_audiences" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
AllowedAudiences : [] string { "bar" , "foo" },
2021-04-08 20:54:32 -04:00
},
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . AllowedAudiences = [] string { "bar" , "foo" }
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
2021-04-28 06:53:13 -04:00
{
name : "Change Claims Scopes" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.claims_scopes" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
ClaimsScopes : [] string { "email" , "profile" },
2021-04-28 06:53:13 -04:00
},
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . ClaimsScopes = [] string { "email" , "profile" }
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-28 06:53:13 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
2021-05-04 08:41:04 -04:00
{
name : "Change Account Claim Maps" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.account_claim_maps" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
AccountClaimMaps : [] string { "display_name=name" },
2021-05-04 08:41:04 -04:00
},
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . AccountClaimMaps = [] string { "display_name=name" }
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-05-04 08:41:04 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
{
name : "Attempt to Change Account Claim Maps for sub" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.account_claim_maps" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
AccountClaimMaps : [] string { "oid=sub" },
2021-05-04 08:41:04 -04:00
},
},
},
},
wantErr : true ,
},
2021-04-08 20:54:32 -04:00
{
name : "Unset Issuer Is Incomplete" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.issuer" },
},
Item : & pb . AuthMethod {},
},
wantErr : true ,
},
{
name : "Unsupported Signing Algorithms" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.signing_algorithms" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
SigningAlgorithms : [] string { string ( oidc . EdDSA )},
},
2021-04-08 20:54:32 -04:00
},
},
},
wantErr : true ,
},
{
name : "Forced Unsupported Signing Algorithms" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.signing_algorithms" },
},
Item : & pb . AuthMethod {
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
DisableDiscoveredConfigValidation : true ,
SigningAlgorithms : [] string { string ( oidc . EdDSA )},
},
2021-04-08 20:54:32 -04:00
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . SigningAlgorithms = [] string { string ( oidc . EdDSA )}
f . DisableDiscoveredConfigValidation = true
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
2021-04-08 20:54:32 -04:00
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
2023-11-21 11:30:02 -05:00
{
name : "Unsupported Prompts" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.prompts" },
},
Item : & pb . AuthMethod {
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
Prompts : [] string { string ( "invalid" )},
},
},
},
},
err : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "Update Prompt With Valid Values" ,
req : & pbs . UpdateAuthMethodRequest {
UpdateMask : & field_mask . FieldMask {
Paths : [] string { "attributes.prompts" },
},
Item : & pb . AuthMethod {
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
Prompts : [] string { string ( oidc . Consent ), string ( oidc . SelectAccount )},
},
},
},
},
res : & pbs . UpdateAuthMethodResponse {
Item : & pb . AuthMethod {
ScopeId : o . GetPublicId (),
Name : & wrapperspb . StringValue { Value : "default" },
Description : & wrapperspb . StringValue { Value : "default" },
Type : oidc . Subtype . String (),
Attrs : func () * pb . AuthMethod_OidcAuthMethodsAttributes {
f := proto . Clone ( defaultReadAttributes . OidcAuthMethodsAttributes ).( * pb . OidcAuthMethodAttributes )
f . Prompts = [] string { string ( oidc . Consent ), string ( oidc . SelectAccount )}
return & pb . AuthMethod_OidcAuthMethodsAttributes { OidcAuthMethodsAttributes : f }
}(),
Scope : defaultScopeInfo ,
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
},
},
},
2021-04-08 20:54:32 -04:00
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
am , cleanup := freshAuthMethod ( t )
defer cleanup ()
tc . req . Item . Version = am . GetVersion ()
if tc . req . GetId () == "" {
tc . req . Id = am . GetId ()
}
if tc . res != nil && tc . res . Item != nil {
tc . res . Item . Id = am . GetId ()
tc . res . Item . CreatedTime = am . GetCreatedTime ()
}
got , gErr := tested . UpdateAuthMethod ( auth . DisabledAuthTestContext ( iamRepoFn , o . GetPublicId ()), tc . req )
// TODO: When handlers move to domain errors remove wantErr and rely errors.Match here.
if tc . err != nil || tc . wantErr {
require . Error ( gErr )
if tc . err != nil {
assert . True ( errors . Is ( gErr , tc . err ), "UpdateAuthMethod(%+v) got error %v, wanted %v" , tc . req , gErr , tc . err )
}
return
}
require . NoError ( gErr )
if tc . res == nil {
require . Nil ( got )
}
2023-10-31 13:44:17 +00:00
cmpOptions := [] cmp . Option {
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
cmpopts . SortSlices ( func ( a , b protocmp . Message ) bool {
return a . String () < b . String ()
}),
}
2021-04-08 20:54:32 -04:00
if got != nil {
assert . NotNilf ( tc . res , "Expected UpdateAuthMethod response to be nil, but was %v" , got )
gotUpdateTime := got . GetItem (). GetUpdatedTime (). AsTime ()
created := am . GetCreatedTime (). AsTime ()
// Verify it is a auth_method updated after it was created
assert . True ( gotUpdateTime . After ( created ), "Updated auth_method should have been updated after it's creation. Was updated %v, which is after %v" , gotUpdateTime , created )
2022-04-08 11:40:59 -04:00
// Ignore all values which are hard to compare against.
cmpOptions = append (
cmpOptions ,
protocmp . IgnoreFields ( & pb . AuthMethod {}, "updated_time" ),
protocmp . IgnoreFields ( & pb . OidcAuthMethodAttributes {}, "client_secret_hmac" , "callback_url" ),
)
assert . NotEqual ( "secret" , got . Item . GetOidcAuthMethodsAttributes (). GetClientSecretHmac ())
if got . Item . GetOidcAuthMethodsAttributes (). CallbackUrl != "" {
exp := tc . res . Item . GetOidcAuthMethodsAttributes (). GetCallbackUrl ()
gVal := got . Item . GetOidcAuthMethodsAttributes (). GetCallbackUrl ()
2021-04-08 20:54:32 -04:00
matches , err := regexp . MatchString ( exp , gVal )
require . NoError ( err )
assert . True ( matches , "%q doesn't match %q" , gVal , exp )
}
assert . EqualValues ( 3 , got . Item . Version )
tc . res . Item . Version = 3
2022-04-08 11:40:59 -04:00
2021-04-08 20:54:32 -04:00
}
2022-04-08 11:40:59 -04:00
assert . Empty ( cmp . Diff ( got , tc . res , cmpOptions ... ), "UpdateAuthMethod(%q) got response %q, wanted %q" , tc . req , got , tc . res )
2021-04-08 20:54:32 -04:00
})
}
}
func TestUpdate_OIDCDryRun ( t * testing . T ) {
2021-07-29 18:52:56 -06:00
ctx := context . TODO ()
2021-04-08 20:54:32 -04:00
conn , _ := db . TestSetup ( t , "postgres" )
rw := db . New ( conn )
wrapper := db . TestWrapper ( t )
kmsCache := kms . TestKms ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iam . TestRepo ( t , conn , wrapper ), nil
}
oidcRepoFn := func () ( * oidc . Repository , error ) {
2021-07-29 18:52:56 -06:00
return oidc . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-08 20:54:32 -04:00
}
2023-03-15 11:40:40 -04:00
ldapRepoFn := func () ( * ldap . Repository , error ) {
return ldap . NewRepository ( ctx , rw , rw , kmsCache )
}
2021-04-08 20:54:32 -04:00
pwRepoFn := func () ( * password . Repository , error ) {
2023-06-06 17:09:08 -04:00
return password . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-08 20:54:32 -04:00
}
atRepoFn := func () ( * authtoken . Repository , error ) {
2023-06-06 17:09:08 -04:00
return authtoken . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-08 20:54:32 -04:00
}
2023-12-21 14:58:21 -05:00
authMethodRepoFn := func () ( * am . AuthMethodRepository , error ) {
return am . NewAuthMethodRepository ( ctx , rw , rw , kmsCache )
}
2021-04-08 20:54:32 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
o , _ := iam . TestScopes ( t , iamRepo )
tp := capoidc . StartTestProvider ( t )
tpClientId := "alice-rp"
tpClientSecret := "her-dog's-name"
tp . SetClientCreds ( tpClientId , tpClientSecret )
_ , _ , tpAlg , _ := tp . SigningKeys ()
2021-07-29 18:52:56 -06:00
tpCert , err := oidc . ParseCertificates ( ctx , tp . CACert ())
2021-04-08 20:54:32 -04:00
require . NoError ( t , err )
databaseWrapper , err := kmsCache . GetWrapper ( context . Background (), o . PublicId , kms . KeyPurposeDatabase )
require . NoError ( t , err )
am := oidc . TestAuthMethod ( t ,
conn , databaseWrapper ,
o . PublicId ,
oidc . ActivePrivateState ,
tpClientId , oidc . ClientSecret ( tpClientSecret ),
oidc . WithName ( "default" ),
oidc . WithDescription ( "default" ),
oidc . WithCertificates ( tpCert [ 0 ]),
oidc . WithSigningAlgs ( oidc . Alg ( tpAlg )),
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , tp . Addr ())[ 0 ]),
oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "http://localhost/" )[ 0 ]),
)
wireAuthMethod := & pb . AuthMethod {
Id : am . GetPublicId (),
ScopeId : am . GetScopeId (),
Scope : & scopepb . ScopeInfo { Id : o . GetPublicId (), Type : o . GetType (), ParentScopeId : scope . Global . String ()},
Name : wrapperspb . String ( am . GetName ()),
Description : wrapperspb . String ( am . GetDescription ()),
CreatedTime : am . GetCreateTime (). GetTimestamp (),
UpdatedTime : am . GetUpdateTime (). GetTimestamp (),
Version : am . GetVersion (),
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2021-04-08 20:54:32 -04:00
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
ApiUrlPrefix : wrapperspb . String ( am . GetApiUrl ()),
CallbackUrl : fmt . Sprintf ( "%s/v1/auth-methods/oidc:authenticate:callback" , am . GetApiUrl ()),
ClientId : wrapperspb . String ( am . GetClientId ()),
ClientSecretHmac : am . GetClientSecretHmac (),
Issuer : wrapperspb . String ( am . GetIssuer ()),
State : am . GetOperationalState (),
IdpCaCerts : [] string { tp . CACert ()},
SigningAlgorithms : [] string { string ( tpAlg )},
},
},
2021-04-08 20:54:32 -04:00
}
2023-12-21 14:58:21 -05:00
tested , err := authmethods . NewService ( ctx , kmsCache , pwRepoFn , oidcRepoFn , iamRepoFn , atRepoFn , ldapRepoFn , authMethodRepoFn , 1000 )
2021-04-08 20:54:32 -04:00
require . NoError ( t , err , "Error when getting new auth_method service." )
cases := [] struct {
name string
id string
mask [] string
item * pb . AuthMethod
want * pb . AuthMethod
err error
wantErr bool
}{
{
name : "Update an Existing AuthMethod" ,
id : am . GetPublicId (),
mask : [] string { "name" , "description" , "attributes.dry_run" },
item : & pb . AuthMethod {
Name : wrapperspb . String ( "updated" ),
Description : wrapperspb . String ( "updated" ),
Version : am . GetVersion (),
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
DryRun : true ,
},
},
2021-04-08 20:54:32 -04:00
},
want : func () * pb . AuthMethod {
c := proto . Clone ( wireAuthMethod ).( * pb . AuthMethod )
c . Name = wrapperspb . String ( "updated" )
c . Description = wrapperspb . String ( "updated" )
2022-04-08 11:40:59 -04:00
c . GetOidcAuthMethodsAttributes (). DryRun = true
2021-04-08 20:54:32 -04:00
return c
}(),
},
{
name : "Update To Make Not Complete" ,
id : am . GetPublicId (),
mask : [] string { "attributes.issuer" },
item : & pb . AuthMethod {
Version : am . GetVersion (),
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
DryRun : true ,
},
},
2021-04-08 20:54:32 -04:00
},
wantErr : true ,
},
{
name : "Update To Make Not Validated" ,
id : am . GetPublicId (),
mask : [] string { "attributes.signing_algorithms" },
item : & pb . AuthMethod {
Version : am . GetVersion (),
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
DryRun : true ,
SigningAlgorithms : [] string { string ( oidc . RS512 )},
},
},
2021-04-08 20:54:32 -04:00
},
wantErr : true ,
},
{
name : "Update dry run with force" ,
id : am . GetPublicId (),
mask : [] string { "name" },
item : & pb . AuthMethod {
Version : am . GetVersion (),
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
DryRun : true ,
DisableDiscoveredConfigValidation : true ,
},
},
2021-04-08 20:54:32 -04:00
},
wantErr : true ,
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
dryUpdated , err := tested . UpdateAuthMethod ( auth . DisabledAuthTestContext ( iamRepoFn , o . GetPublicId ()),
& pbs . UpdateAuthMethodRequest {
Id : tc . id ,
Item : tc . item ,
UpdateMask : & field_mask . FieldMask { Paths : tc . mask },
})
// TODO: When handlers move to domain errors remove wantErr and rely errors.Match here.
if tc . err != nil || tc . wantErr {
require . Error ( t , err )
if tc . err != nil {
assert . True ( t , errors . Is ( err , tc . err ))
}
return
}
require . NoError ( t , err )
2023-10-31 13:44:17 +00:00
assert . Empty ( t , cmp . Diff (
dryUpdated . GetItem (),
tc . want ,
protocmp . Transform (),
protocmp . SortRepeatedFields ( dryUpdated ),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
cmpopts . SortSlices ( func ( a , b protocmp . Message ) bool {
return a . String () < b . String ()
}),
))
2021-04-08 20:54:32 -04:00
got , err := tested . GetAuthMethod ( auth . DisabledAuthTestContext ( iamRepoFn , o . GetPublicId ()), & pbs . GetAuthMethodRequest { Id : tc . id })
require . NoError ( t , err )
2023-10-31 13:44:17 +00:00
assert . Empty ( t , cmp . Diff (
got . GetItem (),
wireAuthMethod ,
protocmp . Transform (),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
cmpopts . SortSlices ( func ( a , b protocmp . Message ) bool {
return a . String () < b . String ()
}),
))
2021-04-08 20:54:32 -04:00
})
}
}
func TestChangeState_OIDC ( t * testing . T ) {
2021-07-29 18:52:56 -06:00
ctx := context . TODO ()
2021-04-08 20:54:32 -04:00
conn , _ := db . TestSetup ( t , "postgres" )
rw := db . New ( conn )
wrapper := db . TestWrapper ( t )
kmsCache := kms . TestKms ( t , conn , wrapper )
iamRepoFn := func () ( * iam . Repository , error ) {
return iam . TestRepo ( t , conn , wrapper ), nil
}
oidcRepoFn := func () ( * oidc . Repository , error ) {
2021-07-29 18:52:56 -06:00
return oidc . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-08 20:54:32 -04:00
}
2023-03-15 11:40:40 -04:00
ldapRepoFn := func () ( * ldap . Repository , error ) {
return ldap . NewRepository ( ctx , rw , rw , kmsCache )
}
2021-04-08 20:54:32 -04:00
pwRepoFn := func () ( * password . Repository , error ) {
2023-06-06 17:09:08 -04:00
return password . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-08 20:54:32 -04:00
}
atRepoFn := func () ( * authtoken . Repository , error ) {
2023-06-06 17:09:08 -04:00
return authtoken . NewRepository ( ctx , rw , rw , kmsCache )
2021-04-08 20:54:32 -04:00
}
2023-12-21 14:58:21 -05:00
authMethodRepoFn := func () ( * am . AuthMethodRepository , error ) {
return am . NewAuthMethodRepository ( ctx , rw , rw , kmsCache )
}
2021-04-08 20:54:32 -04:00
iamRepo := iam . TestRepo ( t , conn , wrapper )
o , _ := iam . TestScopes ( t , iamRepo )
pwam := password . TestAuthMethods ( t , conn , o . GetPublicId (), 1 )[ 0 ]
databaseWrapper , err := kmsCache . GetWrapper ( context . Background (), o . PublicId , kms . KeyPurposeDatabase )
require . NoError ( t , err )
tp := capoidc . StartTestProvider ( t )
tpClientId := "alice-rp"
tpClientSecret := "her-dog's-name"
tp . SetClientCreds ( tpClientId , tpClientSecret )
_ , _ , tpAlg , _ := tp . SigningKeys ()
2021-07-29 18:52:56 -06:00
tpCert , err := oidc . ParseCertificates ( ctx , tp . CACert ())
2021-04-08 20:54:32 -04:00
require . NoError ( t , err )
incompleteAm := oidc . TestAuthMethod ( t , conn , databaseWrapper , o . PublicId , "inactive" , "client id" , "secret" ,
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , "https://alice.com" )[ 0 ]), oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://api.com" )[ 0 ]))
oidcam := oidc . TestAuthMethod ( t , conn , databaseWrapper , o . PublicId , "inactive" , tpClientId , oidc . ClientSecret ( tpClientSecret ),
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , tp . Addr ())[ 0 ]), oidc . WithSigningAlgs ( oidc . Alg ( tpAlg )), oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://example.callback:58" )[ 0 ]), oidc . WithCertificates ( tpCert ... ))
mismatchedAM := oidc . TestAuthMethod ( t , conn , databaseWrapper , o . PublicId , "inactive" , "different_client_id" , oidc . ClientSecret ( tpClientSecret ),
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , tp . Addr ())[ 0 ]), oidc . WithSigningAlgs ( oidc . EdDSA ), oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://example.callback:58" )[ 0 ]), oidc . WithCertificates ( tpCert ... ))
2023-12-21 14:58:21 -05:00
s , err := authmethods . NewService ( ctx , kmsCache , pwRepoFn , oidcRepoFn , iamRepoFn , atRepoFn , ldapRepoFn , authMethodRepoFn , 1000 )
2021-04-08 20:54:32 -04:00
require . NoError ( t , err , "Error when getting new auth_method service." )
wantTemplate := & pb . AuthMethod {
Id : oidcam . GetPublicId (),
ScopeId : oidcam . GetScopeId (),
CreatedTime : oidcam . CreateTime . GetTimestamp (),
UpdatedTime : oidcam . UpdateTime . GetTimestamp (),
2023-11-02 16:03:47 -04:00
Type : oidc . Subtype . String (),
2022-04-08 11:40:59 -04:00
Attrs : & pb . AuthMethod_OidcAuthMethodsAttributes {
OidcAuthMethodsAttributes : & pb . OidcAuthMethodAttributes {
Issuer : wrapperspb . String ( oidcam . GetIssuer ()),
ClientId : wrapperspb . String ( tpClientId ),
ClientSecretHmac : "<hmac>" ,
State : string ( oidc . InactiveState ),
CallbackUrl : "https://example.callback:58/v1/auth-methods/oidc:authenticate:callback" ,
ApiUrlPrefix : wrapperspb . String ( "https://example.callback:58" ),
SigningAlgorithms : [] string { string ( tpAlg )},
IdpCaCerts : [] string { tp . CACert ()},
},
},
2021-04-08 20:54:32 -04:00
Version : 1 ,
Scope : & scopepb . ScopeInfo {
Id : o . GetPublicId (),
Type : o . GetType (),
ParentScopeId : scope . Global . String (),
},
AuthorizedActions : oidcAuthorizedActions ,
AuthorizedCollectionActions : authorizedCollectionActions ,
}
// These test cases must be run in this order since these tests rely on the correct versions being provided
cases := [] struct {
name string
req * pbs . ChangeStateRequest
res * pbs . ChangeStateResponse
err bool
}{
{
name : "Password Auth Method" ,
2022-04-08 11:40:59 -04:00
req : & pbs . ChangeStateRequest {
Id : pwam . GetPublicId (),
Version : pwam . GetVersion (),
Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "inactive" ,
},
},
},
err : true ,
2021-04-08 20:54:32 -04:00
},
{
name : "No Version Specified" ,
2022-04-08 11:40:59 -04:00
req : & pbs . ChangeStateRequest {
Id : oidcam . GetPublicId (),
Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "inactive" ,
},
},
},
err : true ,
2021-04-08 20:54:32 -04:00
},
{
name : "Keep Inactive" ,
2022-04-08 11:40:59 -04:00
req : & pbs . ChangeStateRequest {
Id : oidcam . GetPublicId (),
Version : oidcam . GetVersion (),
Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "inactive" ,
},
},
},
2021-04-08 20:54:32 -04:00
res : & pbs . ChangeStateResponse { Item : func () * pb . AuthMethod {
am := proto . Clone ( wantTemplate ).( * pb . AuthMethod )
return am
}()},
},
{
name : "Make Incomplete Private" ,
2022-04-08 11:40:59 -04:00
req : & pbs . ChangeStateRequest {
Id : incompleteAm . GetPublicId (),
Version : oidcam . GetVersion (),
Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "active-private" ,
},
},
},
err : true ,
2021-04-08 20:54:32 -04:00
},
{
name : "Make Incomplete Public" ,
2022-04-08 11:40:59 -04:00
req : & pbs . ChangeStateRequest {
Id : incompleteAm . GetPublicId (),
Version : oidcam . GetVersion (),
Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "active-public" ,
},
},
},
err : true ,
2021-04-08 20:54:32 -04:00
},
{
name : "Mismatched To Public" ,
req : & pbs . ChangeStateRequest {
2022-04-08 11:40:59 -04:00
Id : mismatchedAM . GetPublicId (),
Version : mismatchedAM . GetVersion (),
Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "active-public" ,
},
},
2021-04-08 20:54:32 -04:00
},
err : true ,
},
{
name : "Force Mismatched To Public" ,
req : & pbs . ChangeStateRequest {
Id : mismatchedAM . GetPublicId (),
Version : mismatchedAM . GetVersion (),
2022-04-08 11:40:59 -04:00
Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "active-public" ,
DisableDiscoveredConfigValidation : true ,
},
},
2021-04-08 20:54:32 -04:00
},
res : & pbs . ChangeStateResponse { Item : func () * pb . AuthMethod {
am := proto . Clone ( wantTemplate ).( * pb . AuthMethod )
am . Id = mismatchedAM . PublicId
2022-04-08 11:40:59 -04:00
am . GetOidcAuthMethodsAttributes (). DisableDiscoveredConfigValidation = true
am . GetOidcAuthMethodsAttributes (). State = "active-public"
am . GetOidcAuthMethodsAttributes (). ClientId = wrapperspb . String ( mismatchedAM . ClientId )
am . GetOidcAuthMethodsAttributes (). SigningAlgorithms = [] string { string ( oidc . EdDSA )}
2021-04-08 20:54:32 -04:00
am . CreatedTime = mismatchedAM . CreateTime . GetTimestamp ()
am . Version = 2
return am
}()},
},
{
name : "Make Complete Private" ,
2022-04-11 14:50:29 -04:00
req : & pbs . ChangeStateRequest {
Id : oidcam . GetPublicId (), Version : oidcam . GetVersion (), Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "active-private" ,
},
2022-04-08 11:40:59 -04:00
},
},
2021-04-08 20:54:32 -04:00
res : & pbs . ChangeStateResponse { Item : func () * pb . AuthMethod {
am := proto . Clone ( wantTemplate ).( * pb . AuthMethod )
2022-04-08 11:40:59 -04:00
am . GetOidcAuthMethodsAttributes (). State = "active-private"
2021-04-08 20:54:32 -04:00
am . Version = 2
return am
}()},
},
{
name : "Make Complete Public" ,
2022-04-11 14:50:29 -04:00
req : & pbs . ChangeStateRequest {
Id : oidcam . GetPublicId (), Version : 2 , Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "active-public" ,
},
2022-04-08 11:40:59 -04:00
},
},
2021-04-08 20:54:32 -04:00
res : & pbs . ChangeStateResponse { Item : func () * pb . AuthMethod {
am := proto . Clone ( wantTemplate ).( * pb . AuthMethod )
2022-04-08 11:40:59 -04:00
am . GetOidcAuthMethodsAttributes (). State = "active-public"
2021-04-08 20:54:32 -04:00
am . Version = 3
return am
}()},
},
{
name : "Make Complete Inactive" ,
2022-04-11 14:50:29 -04:00
req : & pbs . ChangeStateRequest {
Id : oidcam . GetPublicId (), Version : 3 , Attrs : & pbs . ChangeStateRequest_OidcChangeStateAttributes {
OidcChangeStateAttributes : & pbs . OidcChangeStateAttributes {
State : "inactive" ,
},
2022-04-08 11:40:59 -04:00
},
},
2021-04-08 20:54:32 -04:00
res : & pbs . ChangeStateResponse { Item : func () * pb . AuthMethod {
am := proto . Clone ( wantTemplate ).( * pb . AuthMethod )
2022-04-08 11:40:59 -04:00
am . GetOidcAuthMethodsAttributes (). State = "inactive"
2021-04-08 20:54:32 -04:00
am . Version = 4
return am
}()},
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
got , gErr := s . ChangeState ( auth . DisabledAuthTestContext ( iamRepoFn , o . GetPublicId ()), tc . req )
if tc . err {
require . Error ( gErr )
return
}
require . NoError ( gErr )
2022-04-08 11:40:59 -04:00
if got . Item . GetOidcAuthMethodsAttributes (). CallbackUrl != "" {
exp := tc . res . Item . GetOidcAuthMethodsAttributes (). CallbackUrl
gVal := got . Item . GetOidcAuthMethodsAttributes (). CallbackUrl
2021-04-08 20:54:32 -04:00
matches , err := regexp . MatchString ( exp , gVal )
require . NoError ( err )
assert . True ( matches , "%q doesn't match %q" , gVal , exp )
}
got . Item . UpdatedTime , tc . res . Item . UpdatedTime = nil , nil
2022-04-08 11:40:59 -04:00
assert . Empty (
2023-10-31 13:44:17 +00:00
cmp . Diff (
got ,
tc . res ,
protocmp . Transform (),
protocmp . IgnoreFields ( & pb . OidcAuthMethodAttributes {}, "client_secret_hmac" , "callback_url" ),
cmpopts . SortSlices ( func ( a , b string ) bool {
return a < b
}),
cmpopts . SortSlices ( func ( a , b protocmp . Message ) bool {
return a . String () < b . String ()
}),
),
2022-04-08 11:40:59 -04:00
"ChangeState() got response %q, wanted %q" , got , tc . res ,
)
2021-04-08 20:54:32 -04:00
})
}
}
func TestAuthenticate_OIDC_Start ( t * testing . T ) {
s := getSetup ( t )
cases := [] struct {
2024-08-30 16:33:18 +01:00
name string
request * pbs . AuthenticateRequest
beforeTest func ( t * testing . T )
wantErr error
2021-04-08 20:54:32 -04:00
}{
{
name : "no command" ,
request : & pbs . AuthenticateRequest {
AuthMethodId : s . authMethod . GetPublicId (),
},
wantErr : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "bad command" ,
request : & pbs . AuthenticateRequest {
Command : "bad" ,
AuthMethodId : s . authMethod . GetPublicId (),
},
wantErr : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "no auth method id" ,
request : & pbs . AuthenticateRequest {
Command : "start" ,
},
wantErr : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "good request, no attributes" ,
request : & pbs . AuthenticateRequest {
Command : "start" ,
AuthMethodId : s . authMethod . GetPublicId (),
},
},
2024-08-30 16:33:18 +01:00
{
name : "auth method does not exist" ,
request : & pbs . AuthenticateRequest {
Command : "start" ,
AuthMethodId : "amoidc_1234" ,
Attrs : & pbs . AuthenticateRequest_OidcStartAttributes {
OidcStartAttributes : & pbs . OidcStartAttributes {
RoundtripPayload : func () * structpb . Struct {
ret , err := structpb . NewStruct ( map [ string ] any {
"foo" : "bar" ,
"baz" : true ,
})
require . NoError ( t , err )
return ret
}(),
},
},
},
wantErr : handlers . ApiErrorWithCode ( codes . NotFound ),
},
{
name : "auth method is inactive" ,
beforeTest : func ( t * testing . T ) {
r , err := s . oidcRepoFn ()
require . NoError ( t , err )
_ , err = r . MakeInactive ( s . ctx , s . authMethod . GetPublicId (), 2 )
require . NoError ( t , err )
t . Cleanup ( func () {
_ , err = r . MakePublic ( s . ctx , s . authMethod . GetPublicId (), 3 )
require . NoError ( t , err )
})
},
request : & pbs . AuthenticateRequest {
Command : "start" ,
AuthMethodId : s . authMethod . GetPublicId (),
Attrs : & pbs . AuthenticateRequest_OidcStartAttributes {
OidcStartAttributes : & pbs . OidcStartAttributes {
RoundtripPayload : func () * structpb . Struct {
ret , err := structpb . NewStruct ( map [ string ] any {
"foo" : "bar" ,
"baz" : true ,
})
require . NoError ( t , err )
return ret
}(),
},
},
},
wantErr : handlers . ApiErrorWithCode ( codes . FailedPrecondition ),
},
2021-04-08 20:54:32 -04:00
// NOTE: We can't really test bad roundtrip payload attributes because
// any type structpb lets us use in creation will be valid for JSON, and
// attempting to force with e.g. json.RawMessage causes structpb to
// error. This is okay; in the real world anything coming in would
// _have_ to be valid JSON because it came in on the JSON API
// successfully!
//
// The below test is really testing that it doesn't error; it won't be
// until a test all the way through the token step that we can verify
// the underlying functionality, at least without some very onerous
// decryption steps. Not worth it; just validate once we perform all
// steps!
{
name : "roundtrip payload attributes" ,
request : & pbs . AuthenticateRequest {
Command : "start" ,
AuthMethodId : s . authMethod . GetPublicId (),
2022-04-11 14:50:29 -04:00
Attrs : & pbs . AuthenticateRequest_OidcStartAttributes {
OidcStartAttributes : & pbs . OidcStartAttributes {
RoundtripPayload : func () * structpb . Struct {
2022-10-25 18:29:38 -05:00
ret , err := structpb . NewStruct ( map [ string ] any {
2022-04-11 14:50:29 -04:00
"foo" : "bar" ,
"baz" : true ,
})
require . NoError ( t , err )
return ret
}(),
},
},
2021-04-08 20:54:32 -04:00
},
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
2024-08-30 16:33:18 +01:00
if tc . beforeTest != nil {
tc . beforeTest ( t )
}
2021-04-08 20:54:32 -04:00
assert , require := assert . New ( t ), require . New ( t )
got , err := s . authMethodService . Authenticate ( auth . DisabledAuthTestContext ( s . iamRepoFn , s . org . GetPublicId ()), tc . request )
if tc . wantErr != nil {
assert . Error ( err )
assert . Truef ( errors . Is ( err , tc . wantErr ), "Got %#v, wanted %#v" , err , tc . wantErr )
return
}
require . NoError ( err )
require . Equal ( got . GetCommand (), "start" )
// We can't really compare directly as a lot of the values contain
// random data, so just verify existence
2022-04-11 14:50:29 -04:00
got . GetAuthTokenResponse ()
require . NotNil ( got . GetOidcAuthMethodAuthenticateStartResponse ())
require . NotEmpty ( got . GetOidcAuthMethodAuthenticateStartResponse (). GetAuthUrl ())
require . NotEmpty ( got . GetOidcAuthMethodAuthenticateStartResponse (). GetTokenId ())
2021-04-08 20:54:32 -04:00
})
}
}
func TestAuthenticate_OIDC_Token ( t * testing . T ) {
2023-06-06 17:09:08 -04:00
ctx := context . Background ()
2021-04-08 20:54:32 -04:00
s := getSetup ( t )
2023-06-06 17:09:08 -04:00
testAtRepo , err := authtoken . NewRepository ( ctx , s . rw , s . rw , s . kmsCache )
2021-04-08 20:54:32 -04:00
require . NoError ( t , err )
// a reusable test authmethod for the unit tests
testAuthMethod := oidc . TestAuthMethod ( t , s . conn , s . databaseWrapper , s . org . PublicId , oidc . ActivePublicState ,
"alice-rp" , "fido" ,
oidc . WithIssuer ( oidc . TestConvertToUrls ( t , "https://alice.com" )[ 0 ]),
oidc . WithSigningAlgs ( oidc . Alg ( oidc . RS256 )),
oidc . WithApiUrl ( oidc . TestConvertToUrls ( t , "https://alice.com/callback" )[ 0 ]))
testAcct := oidc . TestAccount ( t , s . conn , testAuthMethod , "alice" )
testUser := iam . TestUser ( t , s . iamRepo , s . org . PublicId , iam . WithAccountIds ( testAcct . PublicId ))
cases := [] struct {
name string
request * pbs . AuthenticateRequest
wantErr error
wantErrMatch * errors . Template
}{
{
name : "no command" ,
request : & pbs . AuthenticateRequest {
AuthMethodId : s . authMethod . GetPublicId (),
},
wantErr : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "bad command" ,
request : & pbs . AuthenticateRequest {
Command : "bad" ,
AuthMethodId : s . authMethod . GetPublicId (),
},
wantErr : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "no auth method id" ,
request : & pbs . AuthenticateRequest {
Command : "token" ,
},
wantErr : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
},
{
name : "no attributes" ,
request : & pbs . AuthenticateRequest {
Command : "token" ,
AuthMethodId : s . authMethod . GetPublicId (),
},
2024-06-06 15:59:43 +02:00
wantErr : handlers . ApiErrorWithCode ( codes . InvalidArgument ),
2021-04-08 20:54:32 -04:00
},
{
name : "success" ,
request : & pbs . AuthenticateRequest {
Command : "token" ,
AuthMethodId : s . authMethod . GetPublicId (),
2022-04-11 14:50:29 -04:00
Attrs : & pbs . AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest {
OidcAuthMethodAuthenticateTokenRequest : & pb . OidcAuthMethodAuthenticateTokenRequest {
TokenId : func () string {
2023-06-06 17:09:08 -04:00
tokenPublicId , err := authtoken . NewAuthTokenId ( ctx )
2021-04-08 20:54:32 -04:00
require . NoError ( t , err )
oidc . TestPendingToken ( t , testAtRepo , testUser , testAcct , tokenPublicId )
2021-04-12 17:17:28 -04:00
return oidc . TestTokenRequestId ( t , s . authMethod , s . kmsCache , 200 * time . Second , tokenPublicId )
2021-04-08 20:54:32 -04:00
}(),
2022-04-11 14:50:29 -04:00
},
},
2021-04-08 20:54:32 -04:00
},
},
{
name : "expired" ,
request : & pbs . AuthenticateRequest {
Command : "token" ,
AuthMethodId : s . authMethod . GetPublicId (),
2022-04-11 14:50:29 -04:00
Attrs : & pbs . AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest {
OidcAuthMethodAuthenticateTokenRequest : & pb . OidcAuthMethodAuthenticateTokenRequest {
TokenId : func () string {
2023-06-06 17:09:08 -04:00
tokenPublicId , err := authtoken . NewAuthTokenId ( ctx )
2021-04-08 20:54:32 -04:00
require . NoError ( t , err )
oidc . TestPendingToken ( t , testAtRepo , testUser , testAcct , tokenPublicId )
2021-04-12 17:17:28 -04:00
return oidc . TestTokenRequestId ( t , s . authMethod , s . kmsCache , - 20 * time . Second , tokenPublicId )
2021-04-08 20:54:32 -04:00
}(),
2022-04-11 14:50:29 -04:00
},
},
2021-04-08 20:54:32 -04:00
},
2024-06-06 15:59:43 +02:00
wantErr : handlers . ApiErrorWithCode ( codes . PermissionDenied ),
2021-04-08 20:54:32 -04:00
},
{
name : "invalid-token-id-not-encoded-encrypted-proto" ,
request : & pbs . AuthenticateRequest {
Command : "token" ,
AuthMethodId : s . authMethod . GetPublicId (),
2022-04-11 14:50:29 -04:00
Attrs : & pbs . AuthenticateRequest_OidcAuthMethodAuthenticateTokenRequest {
OidcAuthMethodAuthenticateTokenRequest : & pb . OidcAuthMethodAuthenticateTokenRequest {
TokenId : "bad-token-id" ,
},
},
2021-04-08 20:54:32 -04:00
},
2024-06-06 15:59:43 +02:00
wantErr : handlers . ApiErrorWithCode ( codes . Internal ),
2021-04-08 20:54:32 -04:00
},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
assert , require := assert . New ( t ), require . New ( t )
got , err := s . authMethodService . Authenticate ( auth . DisabledAuthTestContext ( s . iamRepoFn , s . org . GetPublicId ()), tc . request )
if tc . wantErr != nil {
require . Error ( err )
assert . Truef ( errors . Is ( err , tc . wantErr ), "Got %#v, wanted %#v" , err , tc . wantErr )
return
}
if tc . wantErrMatch != nil {
require . Error ( err )
assert . Truef ( errors . Match ( tc . wantErrMatch , err ), "Got %#v, wanted %#v" , err , tc . wantErrMatch . Code )
return
}
require . NoError ( err )
require . Equal ( got . GetCommand (), "token" )
2022-04-11 14:50:29 -04:00
require . NotNil ( got . GetAuthTokenResponse ())
require . NotEmpty ( got . GetAuthTokenResponse (). GetToken ())
2021-04-08 20:54:32 -04:00
})
}
}
2021-04-29 14:47:13 -07:00
func TestAuthenticate_OIDC_Callback_ErrorRedirect ( t * testing . T ) {
s := getSetup ( t )
directErrorCases := [] struct {
name string
req * pbs . AuthenticateRequest
}{
{
name : "No Code Or Error" ,
req : & pbs . AuthenticateRequest {
AuthMethodId : s . authMethod . GetPublicId (),
Command : "callback" ,
2022-04-11 14:50:29 -04:00
Attrs : & pbs . AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest {
OidcAuthMethodAuthenticateCallbackRequest : & pb . OidcAuthMethodAuthenticateCallbackRequest {
2021-04-29 14:47:13 -07:00
State : "anything" ,
2022-04-11 14:50:29 -04:00
},
},
2021-04-29 14:47:13 -07:00
},
},
{
name : "No Auth Method Id" ,
req : & pbs . AuthenticateRequest {
Command : "callback" ,
2022-04-11 14:50:29 -04:00
Attrs : & pbs . AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest {
OidcAuthMethodAuthenticateCallbackRequest : & pb . OidcAuthMethodAuthenticateCallbackRequest {
2021-04-29 14:47:13 -07:00
Code : "anythingworks" ,
State : "anything" ,
2022-04-11 14:50:29 -04:00
},
},
2021-04-29 14:47:13 -07:00
},
},
{
name : "No State" ,
req : & pbs . AuthenticateRequest {
AuthMethodId : s . authMethod . GetPublicId (),
Command : "callback" ,
2022-04-11 14:50:29 -04:00
Attrs : & pbs . AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest {
OidcAuthMethodAuthenticateCallbackRequest : & pb . OidcAuthMethodAuthenticateCallbackRequest {
2021-04-29 14:47:13 -07:00
Code : "anythingworks" ,
2022-04-11 14:50:29 -04:00
},
},
2021-04-29 14:47:13 -07:00
},
},
}
for _ , tc := range directErrorCases {
t . Run ( tc . name , func ( t * testing . T ) {
_ , err := s . authMethodService . Authenticate ( auth . DisabledAuthTestContext ( s . iamRepoFn , s . org . GetPublicId ()), tc . req )
require . Error ( t , err )
})
}
redirectUrlErrorCases := [] struct {
name string
attrs * pb . OidcAuthMethodAuthenticateCallbackRequest
errorSubStr string
}{
{
name : "Cant decrypt state" ,
attrs : & pb . OidcAuthMethodAuthenticateCallbackRequest {
Code : "anythingworkshere" ,
State : "cant decrypt this!" ,
},
errorSubStr : url . QueryEscape ( "unable to decode message" ),
},
{
name : "OIDC Error" ,
attrs : & pb . OidcAuthMethodAuthenticateCallbackRequest {
State : "foo" ,
Error : "some_error" ,
ErrorDescription : "error description" ,
},
errorSubStr : url . QueryEscape ( "error description" ),
},
}
for _ , tc := range redirectUrlErrorCases {
t . Run ( tc . name , func ( t * testing . T ) {
got , err := s . authMethodService . Authenticate ( auth . DisabledAuthTestContext ( s . iamRepoFn , s . org . GetPublicId ()),
& pbs . AuthenticateRequest {
AuthMethodId : s . authMethod . GetPublicId (),
Command : "callback" ,
2022-04-11 14:50:29 -04:00
Attrs : & pbs . AuthenticateRequest_OidcAuthMethodAuthenticateCallbackRequest {
OidcAuthMethodAuthenticateCallbackRequest : tc . attrs ,
},
2021-04-29 14:47:13 -07:00
})
require . NoError ( t , err )
2022-04-11 14:50:29 -04:00
respAttrs := got . GetOidcAuthMethodAuthenticateCallbackResponse ()
2021-04-29 14:47:13 -07:00
assert . Contains ( t , respAttrs . FinalRedirectUrl , fmt . Sprintf ( "%s/authentication-error?" , s . authMethod . GetApiUrl ()))
u , err := url . Parse ( respAttrs . GetFinalRedirectUrl ())
require . NoError ( t , err )
assert . Contains ( t , u . RawQuery , tc . errorSubStr )
})
}
}