-
Notifications
You must be signed in to change notification settings - Fork 9k
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 support for '{realm}' placeholder in authorizationUrl and tokenUrl #3410
base: master
Are you sure you want to change the base?
Conversation
* Factored out URL handling code into function processUrl * Call processUrl in places where we use authorizationUrl and tokenUrl * Removed tiny bit of redundant code in auths.jsx * Set default/example realm name to 'your-realm' (singular) instead of 'your-realms' (plural) as this parameter is supposed to be singular afaik * Improved documentation for 'realm' in README.md Fixes swagger-api#3406 See also swagger-api#1424
In processUrl, at the end, it adds the query parameters to the URL, but it should first test whether the URL already contains a question mark. Only add a question mark to the URL when it did not already have one, otherwise use ampersand.
@Download - Thanks for taking the time to submit the PR. I'm inclined to not accept the PR as-is for a few reasons:
Once I understand the topic better with your references, I'll ask @shockey to review the code. |
Hi Ron, Can you let me know what I would have to change to get this merged?
Ok, that would be a small and simple change.
It seems as if that's by design? As in, the
Well I am using Keycloak. It has some docs about Realm. It's a pretty big/popular system and it's encoding the realm parameter in the path. Check out their REST API docs, it has the realm parameter all over it. And I see now they use the same convention as you proposed, with curly braces: Apart from the rename of the placeholder I'm not sure what I would have to change to get this in? EDIT: I updated the PR with the new placeholder name |
Changed `'your-realms'` to `'your-realm'` in example in docs as this param has to be singular AFAIK
Thanks @Download ! I am having similar problem with our KeyCloak and Swagger-UI. I hope this PR makes it to upstream. |
@webron Can you maybe re-evaluate? |
@Download I hope to get back to it shortly, a bit overloaded at the moment. Thanks for the reminder and your patience. |
@@ -109,15 +109,14 @@ export default class Auths extends React.Component { | |||
<p>API requires the following scopes. Select which ones you want to grant to Swagger UI.</p> | |||
</div> | |||
{ | |||
definitions.filter( schema => schema.get("type") === "oauth2") | |||
.map( (schema, name) =>{ | |||
oauthDefinitions.map( (schema, name) =>{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oauthDefinitions
is defined above as definitions.filter( schema => schema.get("type") === "oauth2")
so repeating that code here was redundant. I stumbled upon this during my research so I fixed it... Should maybe have been a separate PR.
@@ -115,7 +115,7 @@ const ui = SwaggerUIBundle({...}) | |||
ui.initOAuth({ | |||
clientId: "your-client-id", | |||
clientSecret: "your-client-secret-if-required", | |||
realm: "your-realms", | |||
realm: "your-realm", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaict from all the info I've read on realm
, it's usually like a container around users, roles, etc. So it seems strange to be targeting multiple realms. It for sure won't work with Keycloak. So this is why I think it is better if the example is singular.
@@ -103,7 +103,7 @@ Config Name | Description | |||
--- | --- | |||
client_id | Default clientId. MUST be a string | |||
client_secret | Default clientSecret. MUST be a string | |||
realm | realm query parameter (for oauth1) added to `authorizationUrl` and `tokenUrl` . MUST be a string | |||
realm | The OAuth realm parameter for `authorizationUrl` and `tokenUrl`. Optional. If specified it MUST be a string. If a `{realm}` placeholder is present in the URL path, it will be replaced with this value. If no such placeholder is present, the value will be added as the value for querystring parameter 'realm'. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old docs were very concise. I added some more detail and mentioned the {realm}
placeholder and realm
query parameter explicitly so people (hopefully) understand what it does.
return (<div key={ name }> | ||
<Oauth2 authorized={ authorized } | ||
schema={ schema } | ||
name={ name } /> | ||
</div>) | ||
} | ||
).toArray() | ||
).toArray() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some whitespace conversion by my editor probably, sorry.
@@ -27,6 +27,7 @@ export default class Oauth2 extends React.Component { | |||
let authConfigs = authSelectors.getConfigs() || {} | |||
let username = auth && auth.get("username") || "" | |||
let clientId = auth && auth.get("clientId") || authConfigs.clientId || "" | |||
let realm = auth && auth.get("realm") || authConfigs.realm || "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure we get the realm setting as well
@@ -39,7 +40,8 @@ export default class Oauth2 extends React.Component { | |||
clientSecret: clientSecret, | |||
username: username, | |||
password: "", | |||
passwordType: passwordType | |||
passwordType: passwordType, | |||
realm: realm | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add it to the state so we can access it later
{ ( flow === IMPLICIT || flow === ACCESS_CODE ) && <p>Authorization URL: <code>{ schema.get("authorizationUrl") }</code></p> } | ||
{ ( flow === PASSWORD || flow === ACCESS_CODE || flow === APPLICATION ) && <p>Token URL:<code> { schema.get("tokenUrl") }</code></p> } | ||
{ ( flow === IMPLICIT || flow === ACCESS_CODE ) && <p>Authorization URL: <code>{ processUrl(schema.get("authorizationUrl"), this.state) }</code></p> } | ||
{ ( flow === PASSWORD || flow === ACCESS_CODE || flow === APPLICATION ) && <p>Token URL:<code> { processUrl(schema.get("tokenUrl"), this.state) }</code></p> } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call processUrl()
on the authorizationUrl
and tokenUrl
so we correctly fill in the {realm}
and other parameters.
} | ||
|
||
let url = [schema.get("authorizationUrl"), query.join("&")].join("?") | ||
const url = processUrl(schema.get("authorizationUrl"), authConfigs, query) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removed code above is now part of processUrl
} | ||
} | ||
return result | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the meat of it. The existing code to fill in the configs and additional query params is now in this function, where I also added the bit that does the replacement of the placeholder.
|
||
for (let key in additionalQueryStringParams) { | ||
url += "&" + key + "=" + encodeURIComponent(additionalQueryStringParams[key]) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now done by processUrl
Ugh I did not realize all that conversation would end up here! I guess I should have picked 'Start a Review'. Sorry! Anyway, @webron I added some comments to explain what I did and why. Hopefully this can help you a bit when you get the time to review this. |
@webron, gentle bump 🌞 |
On hold pending @webron ☎️ |
This PR addresses an issue I was having with Keycloak, which adds the realm to the path part of the URL, forcing me to hardcode the realm in the definition.
After this PR is merged, people will be able to use a special placeholder token,
:realm
in the URL and it will be replaced with the realm specified in the call toinitOAuth
:This is what I did:
processUrl
processUrl
in places where we useauthorizationUrl
andtokenUrl
auths.jsx
realm
name to'your-realm'
(singular) instead of'your-realms'
(plural) as this parameter is supposed to be singular afaikI ran the tests. There were no failures but some tests are reported as 'pending'. I am not sure it is normal but I cannot really imagine my changes would have caused this so I ignored it.
This is my first PR for swagger-ui so I think it would be best if you took a moment (extra) to closely inspect my changes. Let me know if you see any issues and I'll try to address them ASAP.
Fixes #3406
See also #1424
EDIT: Oh, in case you wondered why I would choose
:realm
as the token... It's a 'standard' used in Express JS and indeed any server / router built with path-to-regexp. So it (should) feel at home with anyone who has used such systems in the past.EDIT 2: I realized that the system would be much more flexible if
processUrl
does not rely on the URLs having no query parameters to begin with. So I added a commit that tests whether the URL already contains a question mark. If it does it uses ampersand to append the query parameters. This should enable URLs like this:As far as I can tell the 'realm' parameter is not standardized in OAuth and so providers are free to choose their own mechanism (as witnessed by Keycloak's choice for path parameters). So it's probably best to be as flexible as possible here.