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

added presentation_definition endpoint #2492

Merged
merged 13 commits into from
Oct 26, 2023

Conversation

woutslakhorst
Copy link
Member

@woutslakhorst woutslakhorst commented Sep 15, 2023

closes #2491

This RP adds the presentation definition endpoint and client API. A new variable has been added to the OAuth Authorization Server Metadata: presentation_definition_endpoint

@woutslakhorst woutslakhorst force-pushed the feature/2491/presentation_definition_endpoint branch 4 times, most recently from 58c449a to 3da08a9 Compare September 21, 2023 06:56
@woutslakhorst woutslakhorst marked this pull request as ready for review September 21, 2023 06:58
Copy link
Member

@gerardsn gerardsn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dealing with some of comments should probably deferred

auth/api/iam/api.go Outdated Show resolved Hide resolved
auth/api/iam/api.go Show resolved Hide resolved
auth/api/iam/api.go Outdated Show resolved Hide resolved
docs/_static/auth/iam.yaml Outdated Show resolved Hide resolved
docs/_static/auth/iam.yaml Outdated Show resolved Hide resolved
auth/api/iam/api.go Outdated Show resolved Hide resolved
Comment on lines 160 to 162
type: array
items:
"$ref": "#/components/schemas/PresentationDefinition"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenID4VP flow requires a single PD for a similar request. Perhaps we should combine the different PDs in to single PD and add a group label per PD source. This allows selection of a single group to comply with within the combined PD using Submission Requirements.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like 1 PE flow instead of 1 per backend as well. I think this example illustrates what we want to do: https://identity.foundation/presentation-exchange/spec/v2.0.0/#submission-requirement-1

{
  "presentation_definition": {
    "input_descriptors": [
      {
        "name": "Geregistreede zorgorganisatie",
        "purpose": "Verificatie dat de zorgorganisatie erkend is door CIBG",
        "group": ["local", "mitz"],
        "constraints": "has NutsCareOrganization"
      },
      {
        "name": "Mitz Toestemmingen",
        "purpose": "Mag gebruikmaken van toestemmingen in Mitz",
        "group": ["mitz"],
        "constraints": "has MitzCredential"
      }
    ]
  },
  "submission_requirements": [
    {
      "name": "Toegang tot bronsysteem",
      "rule": "pick",
      "min": 1,
      "from_nested": [
        {
          "rule": "all",
          "from": "local"
        },
        {
          "rule": "all",
          "from": "mitz"
        }
      ]
    }
  ]
}

Note the min property, requesting at least one matching credential set. The PD backends then don't yield presentation definitions, but a list of input descriptors. Or they could still return a PD, but the Nuts node would only use the input descriptors and discard the rest.

Con: more complex on implementation of the PE spec side ("our" side). But also less complex on the XIS vendor's side (our users), and less calls going back and forth (thus, faster).

I checked the PE issue tracker on Github, and there does not seem to be discussion about whether to remove/keep supporting pick or from_nested

auth/api/iam/api.go Show resolved Hide resolved
auth/api/iam/client.go Outdated Show resolved Hide resolved
auth/api/iam/client.go Outdated Show resolved Hide resolved
// We pass the endpoint url for the presentation definition endpoint because we already retrieved the metadata in a previous step.
// The scopes are evaluated as raw query params and encoded if needed.
func (hb HTTPClient) PresentationDefinition(ctx context.Context, definitionEndpoint string, scopes []string) ([]PresentationDefinition, error) {
presentationDefinitionURL, err := url.Parse(definitionEndpoint)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you want a url.URL, you can just ask for it (string -> url.URL)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You get it as a string from the metadata, so it would move the parsing to the caller. That would duplicate parsing code for every call.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should change the type in the metadata to url.URL, then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting ur.URL in the metadata will require custom marshalling/unmarshalling for the metadata struct.

auth/api/iam/client.go Outdated Show resolved Hide resolved
auth/api/iam/client.go Outdated Show resolved Hide resolved
docs/_static/auth/iam.yaml Show resolved Hide resolved
docs/_static/auth/iam.yaml Outdated Show resolved Hide resolved
docs/_static/auth/iam.yaml Show resolved Hide resolved
added tests

refactor of http Test TLS Server

added comment

add a DIDToURL method for webdid

added comment

added test case

PR feedback

test fix

remove generated client
added implementation of the presentation definition endpoint

test fix

added API client for presentation definition
@woutslakhorst woutslakhorst force-pushed the feature/2491/presentation_definition_endpoint branch from 1cdae8c to 9b1c8cf Compare October 3, 2023 12:35
Comment on lines 257 to 259
return PresentationDefinition400JSONResponse{
Error: "invalid_scope",
}, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return PresentationDefinition400JSONResponse{
Error: "invalid_scope",
}, nil
return OAuth2Error{
Code: InvalidScope,
}, nil

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compile error due to missing methods on that type (oapi-codegen specific)

// We pass the endpoint url for the presentation definition endpoint because we already retrieved the metadata in a previous step.
// The scopes are evaluated as raw query params and encoded if needed.
func (hb HTTPClient) PresentationDefinition(ctx context.Context, definitionEndpoint string, scopes []string) ([]PresentationDefinition, error) {
presentationDefinitionURL, err := url.Parse(definitionEndpoint)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should change the type in the metadata to url.URL, then?

auth/api/iam/types.go Show resolved Hide resolved
docs/_static/auth/iam.yaml Outdated Show resolved Hide resolved
docs/_static/auth/iam.yaml Outdated Show resolved Hide resolved
Comment on lines 160 to 162
type: array
items:
"$ref": "#/components/schemas/PresentationDefinition"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like 1 PE flow instead of 1 per backend as well. I think this example illustrates what we want to do: https://identity.foundation/presentation-exchange/spec/v2.0.0/#submission-requirement-1

{
  "presentation_definition": {
    "input_descriptors": [
      {
        "name": "Geregistreede zorgorganisatie",
        "purpose": "Verificatie dat de zorgorganisatie erkend is door CIBG",
        "group": ["local", "mitz"],
        "constraints": "has NutsCareOrganization"
      },
      {
        "name": "Mitz Toestemmingen",
        "purpose": "Mag gebruikmaken van toestemmingen in Mitz",
        "group": ["mitz"],
        "constraints": "has MitzCredential"
      }
    ]
  },
  "submission_requirements": [
    {
      "name": "Toegang tot bronsysteem",
      "rule": "pick",
      "min": 1,
      "from_nested": [
        {
          "rule": "all",
          "from": "local"
        },
        {
          "rule": "all",
          "from": "mitz"
        }
      ]
    }
  ]
}

Note the min property, requesting at least one matching credential set. The PD backends then don't yield presentation definitions, but a list of input descriptors. Or they could still return a PD, but the Nuts node would only use the input descriptors and discard the rest.

Con: more complex on implementation of the PE spec side ("our" side). But also less complex on the XIS vendor's side (our users), and less calls going back and forth (thus, faster).

I checked the PE issue tracker on Github, and there does not seem to be discussion about whether to remove/keep supporting pick or from_nested

@woutslakhorst
Copy link
Member Author

woutslakhorst commented Oct 9, 2023

The PE suggestion won't work since you don't know which one of the backends you pick will actually give you access. The patient specific scope will only be checked after a client submitted a VP. If a client picks the wrong one, it'll fail and does not retry. There's no complexity on the CIS side since it's all handled by the node.

@woutslakhorst
Copy link
Member Author

#2540 describes additional features required for Submission Requirement Feature.

Copy link
Member

@gerardsn gerardsn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just the one comment


// PresentationDefinition retrieves the presentation definition from the presentation definition endpoint (as specified by RFC021) for the given scope.
func (hb HTTPClient) PresentationDefinition(ctx context.Context, definitionEndpoint string, scopes []string) (*PresentationDefinition, error) {
presentationDefinitionURL, err := url.Parse(definitionEndpoint)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL comes from an external source. Validate using core.ParsePublicURL to require https, and no reserved addresses like localhost.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also changed the parsing so it will allow IPs in non-strictmode

Copy link
Member

@gerardsn gerardsn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think allowing IP in non-strictmode is going to be possible since parsing of did:web fails for IP addresses. But it might make unit tests easier if this is allowed?

@@ -85,7 +85,7 @@ func (hb HTTPClient) OAuthAuthorizationServerMetadata(ctx context.Context, webDI

// PresentationDefinition retrieves the presentation definition from the presentation definition endpoint (as specified by RFC021) for the given scope.
func (hb HTTPClient) PresentationDefinition(ctx context.Context, definitionEndpoint string, scopes []string) (*PresentationDefinition, error) {
presentationDefinitionURL, err := url.Parse(definitionEndpoint)
presentationDefinitionURL, err := core.ParsePublicURL(definitionEndpoint, !hb.config.Strictmode)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The third input was never intended to be optional, but having to add the scheme every time is annoying since strictmode forces the following

if strictmode {
	issuerURL, err = core.ParsePublicURL(issuer, false, "https")
} else {
	issuerURL, err = core.ParsePublicURL(issuer, true, "https", "http")
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merging #2560 should make this easier

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmmm #2560 flipped the 2nd argument, although the PR build succeeds, after merging it'll fail....

@woutslakhorst
Copy link
Member Author

@reinkrul waiting for your review

gerardsn and others added 2 commits October 25, 2023 15:13
* refactor ParsePublicURL

* add tests
Copy link
Member

@reinkrul reinkrul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small remarks

auth/api/iam/error.go Outdated Show resolved Hide resolved
auth/api/iam/error.go Outdated Show resolved Hide resolved
@woutslakhorst woutslakhorst merged commit 6d4bef3 into master Oct 26, 2023
6 checks passed
@woutslakhorst woutslakhorst deleted the feature/2491/presentation_definition_endpoint branch October 26, 2023 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

use presentation definition endpoint to get presentation definition from other party
3 participants