Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IAM: fix loading of server state #3011

Merged
merged 3 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions auth/api/iam/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (r Wrapper) Routes(router core.EchoRouter) {
func (r Wrapper) middleware(ctx echo.Context, request interface{}, operationID string, f StrictHandlerFunc) (interface{}, error) {
ctx.Set(core.OperationIDContextKey, operationID)
ctx.Set(core.ModuleNameContextKey, apiModuleName)

// Add http.Request to context, to allow reading URL query parameters
requestCtx := context.WithValue(ctx.Request().Context(), httpRequestContextKey, ctx.Request())
ctx.SetRequest(ctx.Request().WithContext(requestCtx))
Expand Down Expand Up @@ -574,7 +574,7 @@ func createSession(params oauthParameters, ownDID did.DID) *OAuthSession {
session.ClientID = params.get(oauth.ClientIDParam)
session.Scope = params.get(oauth.ScopeParam)
session.ClientState = params.get(oauth.StateParam)
session.ServerState = map[string]interface{}{}
session.ServerState = ServerState{}
session.RedirectURI = params.get(oauth.RedirectURIParam)
session.OwnDID = &ownDID
session.ResponseType = params.get(oauth.ResponseTypeParam)
Expand Down
16 changes: 7 additions & 9 deletions auth/api/iam/openid4vp.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,10 +430,11 @@ func (r Wrapper) handleAuthorizeResponseSubmission(ctx context.Context, request
// we take the existing OAuthSession and add the credential map to it
// the credential map contains InputDescriptor.Id -> VC mappings
// todo: use the InputDescriptor.Path to map the Id to Value@JSONPath since this will be later used to set the state for the access token
oauthSession.ServerState = ServerState{}
oauthSession.ServerState[credentialMapStateKey] = credentialMap
oauthSession.ServerState[presentationsStateKey] = pexEnvelope.Presentations
oauthSession.ServerState[submissionStateKey] = *submission
oauthSession.ServerState = ServerState{
CredentialMap: credentialMap,
Presentations: pexEnvelope.Presentations,
PresentationSubmission: submission,
}

authorizationCode := crypto.GenerateNonce()
err = r.oauthCodeStore().Put(authorizationCode, oauthSession)
Expand Down Expand Up @@ -540,16 +541,14 @@ func (r Wrapper) handleAccessTokenRequest(ctx context.Context, verifier did.DID,
return nil, withCallbackURI(oauthError(oauth.InvalidRequest, fmt.Sprintf("client_id does not match: %s vs %s", oauthSession.ClientID, *clientId)), callbackURI)
}

presentations := oauthSession.ServerState.VerifiablePresentations()
submission := oauthSession.ServerState.PresentationSubmission()
state := oauthSession.ServerState
definition, err := r.policyBackend.PresentationDefinition(ctx, verifier, oauthSession.Scope)
if err != nil {
return nil, withCallbackURI(oauthError(oauth.ServerError, fmt.Sprintf("failed to fetch presentation definition: %s", err.Error())), callbackURI)
}
credentialMap := oauthSession.ServerState.CredentialMap()
subject, _ := did.ParseDID(oauthSession.ClientID)

response, err := r.createAccessToken(verifier, time.Now(), presentations, submission, *definition, oauthSession.Scope, *subject, credentialMap)
response, err := r.createAccessToken(verifier, time.Now(), state.Presentations, state.PresentationSubmission, *definition, oauthSession.Scope, *subject, state.CredentialMap)
if err != nil {
return nil, withCallbackURI(oauthError(oauth.ServerError, fmt.Sprintf("failed to create access token: %s", err.Error())), callbackURI)
}
Expand Down Expand Up @@ -737,7 +736,6 @@ func (r Wrapper) handlePresentationRequest(ctx context.Context, params oauthPara
credentialIDs = append(credentialIDs, matchingCredential.ID.String())
}
}
session.ServerState["openid4vp_credentials"] = credentialIDs

sessionID := uuid.NewString()
err = r.storageEngine.GetSessionDatabase().GetStore(sessionExpiry, session.OwnDID.String(), "session").Put(sessionID, *session)
Expand Down
6 changes: 3 additions & 3 deletions auth/api/iam/openid4vp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,9 +480,9 @@ func Test_handleAccessTokenRequest(t *testing.T) {
OwnDID: &verifierDID,
RedirectURI: redirectURI,
Scope: "scope",
ServerState: map[string]interface{}{
"presentations": []vc.VerifiablePresentation{*vp},
"presentationSubmission": submission,
ServerState: ServerState{
Presentations: []vc.VerifiablePresentation{*vp},
PresentationSubmission: &submission,
},
}
t.Run("ok", func(t *testing.T) {
Expand Down
43 changes: 4 additions & 39 deletions auth/api/iam/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,45 +44,10 @@ type OAuthSession struct {
}

// ServerState is a convenience type for extracting different types of data from the session.
type ServerState map[string]interface{}

const (
credentialMapStateKey = "credentialMap"
presentationsStateKey = "presentations"
submissionStateKey = "presentationSubmission"
)

// VerifiablePresentations returns the verifiable presentations from the server state.
// If the server state does not contain a verifiable presentation, an empty slice is returned.
func (s ServerState) VerifiablePresentations() []vc.VerifiablePresentation {
presentations := make([]vc.VerifiablePresentation, 0)
if val, ok := s[presentationsStateKey]; ok {
// each entry should be castable to a VerifiablePresentation
if arr, ok := val.([]interface{}); ok {
for _, v := range arr {
if vp, ok := v.(vc.VerifiablePresentation); ok {
presentations = append(presentations, vp)
}
}
}
}
return presentations
}

// PresentationSubmission returns the Presentation Submission from the server state.
func (s ServerState) PresentationSubmission() *pe.PresentationSubmission {
if val, ok := s[submissionStateKey].(pe.PresentationSubmission); ok {
return &val
}
return nil
}

// CredentialMap returns the credential map from the server state.
func (s ServerState) CredentialMap() map[string]vc.VerifiableCredential {
if mapped, ok := s[credentialMapStateKey].(map[string]vc.VerifiableCredential); ok {
return mapped
}
return map[string]vc.VerifiableCredential{}
type ServerState struct {
CredentialMap map[string]vc.VerifiableCredential
Presentations []vc.VerifiablePresentation
PresentationSubmission *pe.PresentationSubmission
}

// RedirectSession is the session object that is used to redirect the user to a Nuts node website.
Expand Down
Loading