Skip to content

Commit 8a7c144

Browse files
authored
Merge pull request #80 from FIWARE/authenticon-2
make nonce optional and improve jwt mapping
2 parents a952330 + 865ea40 commit 8a7c144

File tree

4 files changed

+54
-18
lines changed

4 files changed

+54
-18
lines changed

openapi/api_api.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/fiware/VCVerifier/common"
2222
"github.com/fiware/VCVerifier/logging"
2323
"github.com/fiware/VCVerifier/verifier"
24+
"github.com/google/uuid"
2425
"github.com/lestrrat-go/jwx/v3/jwa"
2526
"github.com/lestrrat-go/jwx/v3/jwt"
2627
vdr_jwk "github.com/trustbloc/did-go/method/jwk"
@@ -196,8 +197,7 @@ func AuthorizationEndpoint(c *gin.Context) {
196197
}
197198
if !nonceExists {
198199
logging.Log().Info("Received an authorization request without a nonce.")
199-
c.AbortWithStatusJSON(http.StatusBadRequest, ErrorMessageNoNonce)
200-
return
200+
nonce = uuid.NewString()
201201
}
202202
if !stateExists {
203203
logging.Log().Info("Received an authorization request without a state.")
@@ -235,6 +235,7 @@ func AuthorizationEndpoint(c *gin.Context) {
235235
}
236236

237237
func buildFrontendV2Address(protocol, host, state, clientId, redirectUri, scope, nonce string) string {
238+
logging.Log().Debugf("%s://%s/api/v2/loginQR?state=%s&client_id=%s&redirect_uri=%s&scope=%s&nonce=%s&request_mode=byReference", protocol, host, state, clientId, redirectUri, scope, nonce)
238239
return fmt.Sprintf("%s://%s/api/v2/loginQR?state=%s&client_id=%s&redirect_uri=%s&scope=%s&nonce=%s&request_mode=byReference", protocol, host, state, clientId, redirectUri, scope, nonce)
239240
}
240241

openapi/api_frontend.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
"github.com/fiware/VCVerifier/logging"
1818
"github.com/fiware/VCVerifier/verifier"
19+
"github.com/google/uuid"
1920

2021
"github.com/gin-gonic/gin"
2122
)
@@ -131,9 +132,7 @@ func VerifierLoginQr(c *gin.Context) {
131132

132133
nonce, nonceExists := c.GetQuery("nonce")
133134
if !nonceExists {
134-
c.AbortWithStatusJSON(http.StatusBadRequest, ErrorMessageNoNonce)
135-
// early exit
136-
return
135+
nonce = uuid.NewString()
137136
}
138137

139138
requestMode, requestModeExists := c.GetQuery("request_mode")

verifier/verifier.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
"golang.org/x/exp/slices"
2020

21+
"github.com/PaesslerAG/jsonpath"
2122
common "github.com/fiware/VCVerifier/common"
2223
configModel "github.com/fiware/VCVerifier/config"
2324
"github.com/fiware/VCVerifier/gaiax"
@@ -682,14 +683,31 @@ func buildInclusion(credential *verifiable.Credential, inclusionConfig configMod
682683

683684
inclusion = make(map[string]interface{})
684685
for _, claim := range inclusionConfig.ClaimsToInclude {
685-
pathParts := strings.Split(claim.OriginalKey, ".")
686-
if val, ok := getValueFromPath(credential.ToRawJSON(), pathParts); ok {
686+
if strings.HasPrefix(claim.OriginalKey, "$") {
687+
logging.Log().Debugf("Claim uses json path: %s from %s", claim.OriginalKey, logging.PrettyPrintObject(credential.ToRawJSON()))
688+
claimValues, err := jsonpath.Get(claim.OriginalKey, credential.ToRawJSON())
689+
690+
if err != nil {
691+
logging.Log().Warnf("Was not able to evaluate path %s", claim.OriginalKey)
692+
continue
693+
}
694+
687695
if claim.NewKey != "" {
688-
setValueAtPath(inclusion, strings.Split(claim.NewKey, "."), val)
696+
setValueAtPath(inclusion, strings.Split(claim.NewKey, "."), claimValues)
689697
} else {
690-
setValueAtPath(inclusion, strings.Split(claim.OriginalKey, "."), val)
698+
setValueAtPath(inclusion, strings.Split(claim.OriginalKey, "."), claimValues)
699+
}
700+
} else {
701+
pathParts := strings.Split(claim.OriginalKey, ".")
702+
if val, ok := getValueFromPath(credential.ToRawJSON(), pathParts); ok {
703+
if claim.NewKey != "" {
704+
setValueAtPath(inclusion, strings.Split(claim.NewKey, "."), val)
705+
} else {
706+
setValueAtPath(inclusion, strings.Split(claim.OriginalKey, "."), val)
707+
}
691708
}
692709
}
710+
693711
}
694712
return inclusion
695713
}
@@ -813,9 +831,11 @@ func (v *CredentialVerifier) AuthenticationResponse(state string, verifiablePres
813831
}
814832
loginSession := loginSessionInterface.(loginSession)
815833

816-
// TODO extract into separate policy
834+
credentialsByType, _ := extractCredentialTypes(verifiablePresentation)
817835
trustedChain, _ := verifyChain(verifiablePresentation.Credentials())
836+
var credentialsToBeIncluded []map[string]interface{}
818837

838+
flatClaims := false
819839
for _, credential := range verifiablePresentation.Credentials() {
820840

821841
verificationContext, err := v.getTrustRegistriesValidationContext(loginSession.clientId, credential.Contents().Types, loginSession.scope)
@@ -845,21 +865,27 @@ func (v *CredentialVerifier) AuthenticationResponse(state string, verifiablePres
845865
logging.Log().Infof("VC %s is not valid.", logging.PrettyPrintObject(credential))
846866
return sameDevice, ErrorInvalidVC
847867
}
868+
shouldBeIncluded, inclusionConfig := v.shouldBeIncluded(loginSession.clientId, loginSession.scope, credential.Contents().Types)
869+
if shouldBeIncluded {
870+
credentialsToBeIncluded = append(credentialsToBeIncluded, buildInclusion(credential, inclusionConfig))
871+
}
872+
flatClaims, _ = v.credentialsConfig.GetFlatClaims(loginSession.clientId, loginSession.scope)
848873
}
849874
}
850875

851876
// we ignore the error here, since the only consequence is that sub will be empty.
852877
hostname, _ := getHostName(loginSession.callback)
853878

854-
//TODO: properly handle inclusion config
855-
856-
var toBeIncluded []map[string]interface{}
857-
for _, credential := range verifiablePresentation.Credentials() {
858-
toBeIncluded = append(toBeIncluded, credential.ToRawJSON())
879+
if len(credentialsToBeIncluded) == 0 {
880+
vcTypes := []string{}
881+
for k := range credentialsByType {
882+
vcTypes = append(vcTypes, k)
883+
}
884+
logging.Log().Warnf("No valid credential type was provided. Provided credential type: %v", vcTypes)
885+
return sameDevice, ErrorNoValidCredentialTypeProvided
859886
}
860887

861-
flatClaims, _ := v.credentialsConfig.GetFlatClaims(loginSession.clientId, loginSession.scope)
862-
token, err := v.generateJWT(toBeIncluded, verifiablePresentation.Holder, hostname, flatClaims)
888+
token, err := v.generateJWT(credentialsToBeIncluded, verifiablePresentation.Holder, hostname, flatClaims)
863889
if err != nil {
864890
logging.Log().Warnf("Was not able to create a jwt for %s. Err: %v", state, err)
865891
return sameDevice, err

verifier/verifier_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,17 @@ func TestAuthenticationResponse(t *testing.T) {
551551
testKey, _ := jwk.Import(ecdsaKey)
552552
jwk.AssignKeyID(testKey)
553553
nonceGenerator := mockNonceGenerator{staticValues: []string{"authCode"}}
554-
credentialsConfig := mockCredentialConfig{}
554+
credentialsConfig := mockCredentialConfig{
555+
mockScopes: map[string]map[string]configModel.ScopeEntry{"clientId": {
556+
"": {
557+
Credentials: []configModel.Credential{{
558+
Type: "VerifiableCredential",
559+
JwtInclusion: configModel.JwtInclusion{Enabled: true},
560+
}},
561+
},
562+
},
563+
},
564+
}
555565
verifier := CredentialVerifier{did: "did:key:verifier", signingKey: testKey, tokenCache: &tokenCache, sessionCache: &sessionCache, nonceGenerator: &nonceGenerator, validationServices: []ValidationService{&mockExternalSsiKit{tc.verificationResult, tc.verificationError}}, clock: mockClock{}, credentialsConfig: credentialsConfig, clientIdentification: configModel.ClientIdentification{Id: "did:key:verifier"}}
556566

557567
sameDeviceResponse, err := verifier.AuthenticationResponse(tc.requestedState, &tc.testVP)

0 commit comments

Comments
 (0)