feat: URL client id for client credentials#2041
feat: URL client id for client credentials#2041elf-pavlik wants to merge 6 commits intoCommunitySolidServer:mainfrom
Conversation
joachimvh
left a comment
There was a problem hiding this comment.
If there is an existing credential with provided name it responds with an error - is that a breaking change?
Technically yes, but it seems minor enough that we can cheat and not do a major release for this. Same for the ordering of the adapters changing, should it really be needed.
Alternatively it could also be an option to add an optional flag to the class to change the behavior.
src/identity/interaction/client-credentials/CreateClientCredentialsHandler.ts
Outdated
Show resolved
Hide resolved
| res = await fetch(controls.account.clientCredentials, { | ||
| method: 'POST', | ||
| headers: { authorization, 'content-type': 'application/json' }, | ||
| body: JSON.stringify({ name: 'token', webId }), |
There was a problem hiding this comment.
Was there a specific reason to change this?
There was a problem hiding this comment.
This one failed https://github.com/CommunitySolidServer/CommunitySolidServer/actions/runs/15914010572/job/44887876671
Due to new error I added: "Token with this name already exists."
This error message itself could include a hint to omit the name for auto generated uuid
There was a problem hiding this comment.
This makes me think that perhaps we should be more careful about changing the default behaviour here, as this update would break similar setups that might exist. Additionally, the uniqueness check of the label leaks information about which labels exist of other users, which might be a concern in some situations. So I would suggest adding an optional constructor parameter to enable this behaviour (verbatimLabels?), which defaults to false, so existing setups don't change. The configuration generator could then have another option to enable this (I can do this part after this PR is merged). The uniqueness check then only happens when this parameter is set to true. In case it is set to false the uuid is always added.
There was a problem hiding this comment.
Maybe it would make more sense to handle uuid based client ids and URL client ids separately. Especially if there was a verification step #2041 (comment)
There was a problem hiding this comment.
I revereted commit with this change
| "@type": "ClientCredentialsAdapterFactory", | ||
| "webIdStore": { "@id": "urn:solid-server:default:WebIdStore" }, | ||
| "clientCredentialsStore": { "@id": "urn:solid-server:default:ClientCredentialsStore" }, | ||
| "@type": "ClientIdAdapterFactory", | ||
| "converter": { "@id": "urn:solid-server:default:RepresentationConverter" }, | ||
| "source": { | ||
| "@type": "ClientIdAdapterFactory", | ||
| "converter": { "@id": "urn:solid-server:default:RepresentationConverter" }, | ||
| "@type": "ClientCredentialsAdapterFactory", | ||
| "webIdStore": { "@id": "urn:solid-server:default:WebIdStore" }, | ||
| "clientCredentialsStore": { "@id": "urn:solid-server:default:ClientCredentialsStore" }, |
There was a problem hiding this comment.
What is the reason these needed to be swapped? I'm guessing it has something to do with the other adapter trying to fetch the URL label maybe but can you tell me exactly what goes wrong?
There was a problem hiding this comment.
Without that change ClientIdAdapterFactory was trying to fetch that URL, I don't remember if there was a problem if it didn't exist, but when it was able to fetch that ClientID, it was setting token_endpoint_auth_method to none and complaining that it wasn't allowed and it didn't pick credentials passed via Authorization hearder.
I think it doesn't make sense to use ClientIDAdapter at all when ClientCredentialsAdapter handles that client properly, that's why in the end I changed the order. As you can see all other tests are still passing so it doesn't seem to be affecting anything elese, and if that client hasn't been registered for client credential for that webid there should be no problem.
I haven't tested what happens if that user tries to use the same client both with client credential and with authorization code. Should I add integration test for that?
There was a problem hiding this comment.
The ClientIdAdapterFactory was written under the assumption that if the incoming ID is a URL, this is always the class that should handle it, but that breaks here. The "deeper" class always triggers first, so if a client ID is used that is also a credential label the credential adapter will trigger first. But this could potentially cause issues when someone uses a client ID request which happens to also be the label of a credential token (of someone else potentially). So this definitely needs to be investigated what would happen there. I'm not sure if this would work with how the adapters currently work.
There was a problem hiding this comment.
Since only one client credential per Client ID is supported with this approach (#2053 could be an alternative) I think a check similar to linking an existing WebID would make sense here. One would have to prove control over client to get a URL Client ID credential for it. Once such credential is created, it can only be used with it and no more authorization code flow for that client.
| }); | ||
| }); | ||
|
|
||
| describe('using client_credentials - url', (): void => { |
There was a problem hiding this comment.
Why was this entire block added as it differs on only one line from the previous block. Is it to check for an issue related to the reason the order of the components was changed?
There was a problem hiding this comment.
Yes, just changing from string to URL was resulting in a different adapter handing it and failing. I though the safest would be to run the whole describe for both cases to make sure that both string and url are fully functional.
Co-authored-by: Joachim Van Herwegen <joachimvh@gmail.com>
|
I created a discussion in |
|
superseded by #2053 |
|
Since I didn't find anyone else that would be interested in #2053 and changes here would unblock my immediate need, I think I'd better get this one done and keep looking if anyone else finds use for |
|
New approach handles string and URL clientId differently. For string it should be the same as before and for URL it requires ownership validation using the same one as for linking WebID. Since registering client credential for URL will not allow its use with Authorization Code flow, we could add a small warning box in the dev documentation. |
| let label: string; | ||
|
|
||
| if (name && isUrl(name)) { | ||
| // Validate owneship first not to leak existence of credentials! |
There was a problem hiding this comment.
| // Validate owneship first not to leak existence of credentials! | |
| // Validate ownership first, so as not to leak existence of credentials! |
There was a problem hiding this comment.
Thanks! I will most likely need to add a test case for that so I'll include your suggestion in that commit.
📁 Related issues
✍️ Description
It allows to use URL as client_id when creating a client credential.
I only uses uuid if no name was provided
If there is an existing credential with provided name it responds with an error - is that a breaking change?
This approach makes sense to me, if one doesn't care about specific name they can just leave it out and get random uuid.
I had to change order of OIDC adapters to try registered client credential before fetching client id
TBH I'm not sure if this is a new feature or a fix or major
✅ PR check list
Before this pull request can be merged, a core maintainer will check whether